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 

9 

10from .register import Register 

11from .register_array import RegisterArray 

12from .register_code_generator import RegisterCodeGenerator 

13 

14 

15class RegisterVhdlGenerator(RegisterCodeGenerator): 

16 """ 

17 Generate a VHDL package with register information. 

18 """ 

19 

20 def __init__(self, module_name, generated_info): 

21 self.module_name = module_name 

22 self.generated_info = generated_info 

23 

24 @staticmethod 

25 def _comment(comment, indentation=0): 

26 indent = " " * indentation 

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

28 

29 def _header(self): 

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

31 

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

33 if register_array is None: 

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

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

36 

37 def _register_function_signature(self, register, register_array): 

38 return ( 

39 "function " 

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

41 ) 

42 

43 def _register_indexes(self, register_objects): 

44 vhdl = "" 

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

46 if register_array is None: 

47 vhdl += ( 

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

49 ) 

50 else: 

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

52 if vhdl: 

53 vhdl += "\n" 

54 

55 return vhdl 

56 

57 def _array_length_constant_name(self, register_array): 

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

59 

60 def _array_constants(self, register_objects): 

61 vhdl = "" 

62 for register_object in register_objects: 

63 if isinstance(register_object, RegisterArray): 

64 constant = self._array_length_constant_name(register_object) 

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

66 if vhdl: 

67 vhdl += "\n" 

68 

69 return vhdl 

70 

71 def _register_map(self, register_objects): 

72 if not register_objects: 

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

74 return "" 

75 

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

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

78 

79 last_index = register_objects[-1].index 

80 vhdl = f"""\ 

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

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

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

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

85 

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

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

88 

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

90 

91""" 

92 

93 return vhdl 

94 

95 def _register_map_body(self, register_objects): 

96 if not register_objects: 

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

98 return "" 

99 

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

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

102 

103 register_definitions = [] 

104 default_values = [] 

105 vhdl_array_index = 0 

106 for register_object in register_objects: 

107 if isinstance(register_object, Register): 

108 idx = self._register_name(register_object) 

109 opening = f"{vhdl_array_index} => " 

110 

111 register_definitions.append( 

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

113 ) 

114 default_values.append( 

115 f"{opening}std_logic_vector(to_signed({register_object.default_value}, 32))" 

116 ) 

117 

118 vhdl_array_index = vhdl_array_index + 1 

119 else: 

120 for array_index in range(register_object.length): 

121 for register in register_object.registers: 

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

123 opening = f"{vhdl_array_index} => " 

124 

125 register_definitions.append( 

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

127 ) 

128 default_values.append( 

129 f"{opening}std_logic_vector(to_signed({register.default_value}, 32))" 

130 ) 

131 

132 vhdl_array_index = vhdl_array_index + 1 

133 

134 array_element_separator = ",\n " 

135 vhdl = f"""\ 

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

137 {array_element_separator.join(register_definitions)} 

138 ); 

139 

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

141 {array_element_separator.join(default_values)} 

142 ); 

143 

144""" 

145 

146 return vhdl 

147 

148 def _register_fields(self, register_objects): 

149 vhdl = "" 

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

151 for field in register.fields: 

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

153 

154 if field.width == 1: 

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

156 else: 

157 vhdl += ( 

158 f" subtype {name} is natural range " 

159 f"{field.width + field.base_index - 1} downto {field.base_index};\n" 

160 ) 

161 

162 if register.fields: 

163 vhdl += "\n" 

164 

165 return vhdl 

166 

167 def _array_index_functions(self, register_objects): 

168 vhdl = "" 

169 for register_object in register_objects: 

170 if isinstance(register_object, RegisterArray): 

171 num_registers = len(register_object.registers) 

172 array_length = self._array_length_constant_name(register_object) 

173 for register in register_object.registers: 

174 vhdl += f"""\ 

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

176 begin 

177 assert array_index < {array_length} 

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

179 severity failure; 

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

181 end function; 

182 

183""" 

184 

185 return vhdl 

186 

187 def _constants(self, constants): 

188 vhdl = "" 

189 for constant in constants: 

190 vhdl += ( 

191 " constant " 

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

193 ) 

194 if vhdl: 

195 vhdl += "\n" 

196 

197 return vhdl 

198 

199 def get_package(self, register_objects, constants): 

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

201 

202 vhdl = f"""\ 

203{self._header()} 

204library ieee; 

205use ieee.std_logic_1164.all; 

206use ieee.numeric_std.all; 

207 

208library reg_file; 

209use reg_file.reg_file_pkg.all; 

210 

211 

212package {pkg_name} is 

213 

214{self._register_indexes(register_objects)}\ 

215{self._array_constants(register_objects)}\ 

216{self._register_map(register_objects)}\ 

217{self._register_fields(register_objects)}\ 

218{self._constants(constants)}\ 

219end package; 

220 

221package body {pkg_name} is 

222 

223{self._array_index_functions(register_objects)}\ 

224{self._register_map_body(register_objects)}\ 

225end package body; 

226""" 

227 

228 return vhdl