Coverage for hdl_registers/generator/vhdl/simulation/wait_until_package.py: 96%

76 statements  

« prev     ^ index     » next       coverage.py v7.6.8, created at 2024-12-01 20:50 +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.register_mode import SoftwareAccessDirection 

16 

17# Local folder libraries 

18from .vhdl_simulation_generator_common import VhdlSimulationGeneratorCommon 

19 

20if TYPE_CHECKING: 

21 # First party libraries 

22 from hdl_registers.field.register_field import RegisterField 

23 from hdl_registers.register import Register 

24 from hdl_registers.register_array import RegisterArray 

25 

26 

27class VhdlSimulationWaitUntilPackageGenerator(VhdlSimulationGeneratorCommon): 

28 """ 

29 Generate VHDL code with ``wait_until_X_equals`` procedures that simplify simulation. 

30 See the :ref:`generator_vhdl` article for usage details. 

31 

32 * For each readable register, a procedure that waits until the register assumes a 

33 given natively-typed record value. 

34 

35 * For each field in each readable register, a procedure that waits until the field assumes a 

36 given natively-typed value. 

37 

38 Uses VUnit Verification Component calls to create bus read operations. 

39 

40 The generated VHDL file needs also the generated packages from 

41 :class:`.VhdlRegisterPackageGenerator` and :class:`.VhdlRecordPackageGenerator`. 

42 """ 

43 

44 __version__ = "1.0.0" 

45 

46 SHORT_DESCRIPTION = "VHDL simulation wait until package" 

47 

48 @property 

49 def output_file(self) -> Path: 

50 """ 

51 Result will be placed in this file. 

52 """ 

53 return self.output_folder / f"{self.name}_register_wait_until_pkg.vhd" 

54 

55 def create(self, **kwargs: Any) -> Path: 

56 """ 

57 See super class for API details. 

58 

59 Overloaded here because this package file shall only be created if the register list 

60 actually has any registers. 

61 """ 

62 return self._create_if_there_are_registers_otherwise_delete_file(**kwargs) 

63 

64 def get_code(self, **kwargs: Any) -> str: 

65 """ 

66 Get a package with ``wait_until_X_equals`` methods for registers/fields. 

67 """ 

68 package_name = self.output_file.stem 

69 

70 vhdl = f"""\ 

71{self.header} 

72library ieee; 

73use ieee.fixed_pkg.all; 

74use ieee.std_logic_1164.all; 

75use ieee.numeric_std.all; 

76 

77library vunit_lib; 

78use vunit_lib.bus_master_pkg.bus_master_t; 

79use vunit_lib.bus_master_pkg.wait_until_read_equals; 

80use vunit_lib.com_types_pkg.max_timeout; 

81use vunit_lib.com_types_pkg.network_t; 

82use vunit_lib.string_ops.hex_image; 

83 

84library common; 

85use common.addr_pkg.addr_t; 

86use common.addr_pkg.addr_width; 

87 

88library reg_file; 

89use reg_file.reg_file_pkg.reg_t; 

90use reg_file.reg_operations_pkg.regs_bus_master; 

91 

92use work.{self.name}_regs_pkg.all; 

93use work.{self.name}_register_record_pkg.all; 

94 

95 

96package {package_name} is 

97 

98{self._declarations()}\ 

99end package; 

100 

101package body {package_name} is 

102 

103{self._implementations()}\ 

104end package body; 

105""" 

106 

107 return vhdl 

108 

109 def _declarations(self) -> str: 

110 """ 

111 Get procedure declarations for all procedures. 

112 """ 

113 separator = self.get_separator_line(indent=2) 

114 vhdl = "" 

115 

116 for register, register_array in self.iterate_software_accessible_registers( 

117 direction=SoftwareAccessDirection.READ 

118 ): 

119 declarations = [] 

120 

121 signature = self._register_wait_until_equals_signature( 

122 register=register, register_array=register_array 

123 ) 

124 declarations.append(f"{signature};\n") 

125 

126 for field in register.fields: 

127 signature = self._field_wait_until_equals_signature( 

128 register=register, register_array=register_array, field=field 

129 ) 

130 declarations.append(f"{signature};\n") 

131 

132 vhdl += separator 

133 vhdl += "\n".join(declarations) 

134 vhdl += separator 

135 vhdl += "\n" 

136 

137 return vhdl 

138 

139 def _register_wait_until_equals_signature( 

140 self, register: "Register", register_array: Optional["RegisterArray"] 

141 ) -> str: 

142 """ 

143 Get signature for a 'wait_until_reg_equals' procedure. 

144 """ 

145 register_name = self.qualified_register_name( 

146 register=register, register_array=register_array 

147 ) 

148 register_description = self.register_description( 

149 register=register, register_array=register_array 

150 ) 

151 

152 if register.fields: 

153 value_type = f"{register_name}_t" 

154 slv_comment = "" 

155 else: 

156 value_type = "reg_t" 

157 slv_comment = ( 

158 " -- Note that '-' can be used as a wildcard in 'value' since 'check_match' is \n" 

159 " -- used to check for equality.\n" 

160 ) 

161 

162 return f"""\ 

163 -- Wait until the {register_description} equals the given 'value'. 

164{slv_comment}\ 

165 procedure wait_until_{register_name}_equals( 

166 signal net : inout network_t; 

167{self.get_array_index_port(register_array=register_array)}\ 

168 value : in {value_type}; 

169 base_address : in addr_t := (others => '0'); 

170 bus_handle : in bus_master_t := regs_bus_master; 

171 timeout : delay_length := max_timeout; 

172 message : string := "" 

173 )\ 

174""" 

175 

176 def _field_wait_until_equals_signature( 

177 self, 

178 register: "Register", 

179 register_array: Optional["RegisterArray"], 

180 field: "RegisterField", 

181 ) -> str: 

182 """ 

183 Get signature for a 'wait_until_field_equals' procedure. 

184 """ 

185 field_name = self.qualified_field_name( 

186 register=register, register_array=register_array, field=field 

187 ) 

188 field_description = self.field_description( 

189 register=register, register_array=register_array, field=field 

190 ) 

191 

192 value_type = self.field_type_name( 

193 register=register, register_array=register_array, field=field 

194 ) 

195 

196 return f"""\ 

197 -- Wait until the {field_description} equals the given 'value'. 

198 procedure wait_until_{field_name}_equals( 

199 signal net : inout network_t; 

200{self.get_array_index_port(register_array=register_array)}\ 

201 value : in {value_type}; 

202 base_address : in addr_t := (others => '0'); 

203 bus_handle : in bus_master_t := regs_bus_master; 

204 timeout : delay_length := max_timeout; 

205 message : string := "" 

206 )\ 

207""" 

208 

209 def _implementations(self) -> str: 

210 """ 

211 Get implementations of all procedures. 

212 """ 

213 separator = self.get_separator_line(indent=2) 

214 vhdl = "" 

215 

216 for register, register_array in self.iterate_software_accessible_registers( 

217 direction=SoftwareAccessDirection.READ 

218 ): 

219 implementations = [] 

220 

221 implementations.append( 

222 self._register_wait_until_equals_implementation( 

223 register=register, register_array=register_array 

224 ) 

225 ) 

226 

227 for field in register.fields: 

228 implementations.append( 

229 self._field_wait_until_equals_implementation( 

230 register=register, register_array=register_array, field=field 

231 ) 

232 ) 

233 

234 vhdl += separator 

235 vhdl += "\n".join(implementations) 

236 vhdl += separator 

237 vhdl += "\n" 

238 

239 return vhdl 

240 

241 def _register_wait_until_equals_implementation( 

242 self, register: "Register", register_array: Optional["RegisterArray"] 

243 ) -> str: 

244 """ 

245 Get implementation for a 'wait_until_reg_equals' procedure. 

246 """ 

247 signature = self._register_wait_until_equals_signature( 

248 register=register, register_array=register_array 

249 ) 

250 

251 conversion = "to_slv(value)" if register.fields else "value" 

252 

253 return f"""\ 

254{signature} is 

255 constant reg_value : reg_t := {conversion}; 

256 

257{self._get_common_constants(register=register, register_array=register_array, field=None)}\ 

258 begin 

259 wait_until_read_equals( 

260 net => net, 

261 bus_handle => bus_handle, 

262 addr => std_ulogic_vector(reg_address), 

263 value => reg_value, 

264 timeout => timeout, 

265 msg => get_message 

266 ); 

267 end procedure; 

268""" 

269 

270 def _field_wait_until_equals_implementation( 

271 self, 

272 register: "Register", 

273 register_array: Optional["RegisterArray"], 

274 field: "RegisterField", 

275 ) -> str: 

276 """ 

277 Get implementation for a 'wait_until_field_equals' procedure. 

278 """ 

279 signature = self._field_wait_until_equals_signature( 

280 register=register, register_array=register_array, field=field 

281 ) 

282 field_name = self.qualified_field_name( 

283 register=register, register_array=register_array, field=field 

284 ) 

285 field_to_slv = self.field_to_slv(field=field, field_name=field_name, value="value") 

286 

287 return f"""\ 

288{signature} is 

289 constant reg_value : reg_t := ( 

290 {field_name} => {field_to_slv}, 

291 others => '-' 

292 ); 

293 

294{self._get_common_constants(register=register, register_array=register_array, field=field)}\ 

295 begin 

296 wait_until_read_equals( 

297 net => net, 

298 bus_handle => bus_handle, 

299 addr => std_ulogic_vector(reg_address), 

300 value => reg_value, 

301 timeout => timeout, 

302 msg => get_message 

303 ); 

304 end procedure; 

305""" 

306 

307 def _get_common_constants( 

308 self, 

309 register: "Register", 

310 register_array: Optional["RegisterArray"], 

311 field: Optional["RegisterField"], 

312 ) -> str: 

313 """ 

314 Get constants code that is common for all 'wait_until_*_equals' procedures. 

315 """ 

316 if field: 

317 field_description = f" the '{field.name}' field in" 

318 else: 

319 field_description = "" 

320 

321 return f"""\ 

322{self.reg_index_constant(register=register, register_array=register_array)}\ 

323{self.reg_address_constant()}\ 

324 

325{self.get_register_array_message(register_array=register_array)}\ 

326{self.get_base_address_message()}\ 

327 constant base_message : string := ( 

328 "Timeout while waiting for{field_description} the '{register.name}' register" 

329 & register_array_message 

330 & base_address_message 

331 & " to equal the given value: " 

332 & to_string(reg_value) 

333 & "." 

334 ); 

335{self.get_message()}\ 

336"""