Coverage for tsfpga/examples/simulation_utils.py: 0%

84 statements  

« prev     ^ index     » next       coverage.py v6.4, created at 2022-05-28 04:01 +0000

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 

9import argparse 

10from shutil import which 

11import sys 

12from pathlib import Path 

13 

14# Do PYTHONPATH insert() instead of append() to prefer any local repo checkout over any pip install 

15PATH_TO_TSFPGA = Path(__file__).parent.parent.resolve() 

16sys.path.insert(0, str(PATH_TO_TSFPGA)) 

17 

18from vunit import VUnitCLI, VUnit 

19from vunit.vivado.vivado import create_compile_order_file, add_from_compile_order_file 

20 

21import tsfpga 

22import tsfpga.create_vhdl_ls_config 

23from tsfpga.module import ModuleList 

24from tsfpga.vivado.ip_cores import VivadoIpCores 

25from tsfpga.vivado.simlib import VivadoSimlib 

26 

27 

28def get_arguments_cli(default_output_path): 

29 """ 

30 Get arguments for the simulation flow. 

31 

32 Arguments: 

33 default_output_path (pathlib.Path): Will be set as default for output path arguments 

34 (both VUnit files and Vivado files). 

35 """ 

36 cli = VUnitCLI() 

37 

38 # Print default values when doing --help 

39 cli.parser.formatter_class = argparse.ArgumentDefaultsHelpFormatter 

40 

41 # Set the supplied default value for VUnit output path. pylint: disable=protected-access 

42 for action in cli.parser._actions: 

43 if action.dest == "output_path": 

44 action.default = default_output_path / "vunit_out" 

45 break 

46 else: 

47 raise AssertionError("VUnit --output-path argument not found") 

48 

49 cli.parser.add_argument( 

50 "--output-path-vivado", 

51 type=Path, 

52 default=default_output_path, 

53 help=( 

54 "where to place Vivado IP core and simlib files. " 

55 "Note that --output-path is for VUnit files" 

56 ), 

57 ) 

58 

59 cli.parser.add_argument( 

60 "--vivado-skip", action="store_true", help="skip all steps that require Vivado" 

61 ) 

62 

63 cli.parser.add_argument( 

64 "--ip-compile", action="store_true", help="force (re)compile of IP cores" 

65 ) 

66 

67 cli.parser.add_argument( 

68 "--simlib-compile", action="store_true", help="force (re)compile of Vivado simlib" 

69 ) 

70 

71 cli.parser.add_argument( 

72 "--vcs-minimal", 

73 action="store_true", 

74 help="compile and run only a minimal set of tests based on Version Control System history", 

75 ) 

76 

77 return cli 

78 

79 

80class SimulationProject: 

81 """ 

82 Class for setting up and handling a VUnit simulation project. Should be reusable in most cases. 

83 """ 

84 

85 def __init__(self, args, enable_preprocessing=False): 

86 """ 

87 Create a VUnit project, configured according to the given arguments. 

88 

89 Arguments: 

90 enable_preprocessing (bool): If ``True``, VUnit location/check preprocessing will 

91 be enabled. 

92 """ 

93 self.vunit_proj = VUnit.from_args(args=args) 

94 self.vunit_proj.add_verification_components() 

95 self.vunit_proj.add_random() 

96 

97 if enable_preprocessing: 

98 self.vunit_proj.enable_location_preprocessing() 

99 self.vunit_proj.enable_check_preprocessing() 

100 

101 self.has_commercial_simulator = self.vunit_proj.get_simulator_name() != "ghdl" 

102 

103 def add_modules(self, args, modules, modules_no_sim=None, **setup_vunit_kwargs): 

104 """ 

105 Add module source files to the VUnit project. 

106 

107 Arguments: 

108 args: Command line argument namespace. 

109 modules (:class:`.ModuleList`): These modules will be included in the 

110 simulation project. 

111 modules_no_sim (:class:`.ModuleList`): These modules will be included in the simulation 

112 project, but their test files will not be added. 

113 setup_vunit_kwargs: Further arguments that will be sent to 

114 :meth:`.BaseModule.setup_vunit` for each module. Note that this is a "kwargs" style 

115 argument; any number of named arguments can be sent. 

116 """ 

117 modules_no_sim = ModuleList() if modules_no_sim is None else modules_no_sim 

118 

119 include_ip_cores = self.has_commercial_simulator and not args.vivado_skip 

120 

121 for module in modules + modules_no_sim: 

122 vunit_library = self.vunit_proj.add_library( 

123 library_name=module.library_name, allow_duplicate=True 

124 ) 

125 simulate_this_module = module not in modules_no_sim 

126 

127 for hdl_file in module.get_simulation_files( 

128 include_tests=simulate_this_module, include_ip_cores=include_ip_cores 

129 ): 

130 if hdl_file.is_vhdl or hdl_file.is_verilog_source: 

131 vunit_library.add_source_file(hdl_file.path) 

132 else: 

133 assert False, f"Can not handle this file: {hdl_file}" 

134 

135 if simulate_this_module: 

136 module.setup_vunit(vunit_proj=self.vunit_proj, **setup_vunit_kwargs) 

137 

138 def add_vivado_simlib(self, args): 

139 """ 

140 Add Vivado simlib to the VUnit project, unless instructed not to by ``args``. 

141 Will compile simlib if necessary. 

142 

143 Arguments: 

144 args: Command line argument namespace from ``simulate.py``. 

145 

146 Return: 

147 :class:`.VivadoSimlibCommon`: The simlib object. 

148 """ 

149 if args.vivado_skip: 

150 return None 

151 

152 return self._add_simlib( 

153 output_path=args.output_path_vivado, force_compile=args.simlib_compile 

154 ) 

155 

156 def _add_simlib(self, output_path, force_compile): 

157 """ 

158 Add Vivado simlib to the VUnit project. Compile if needed. 

159 

160 .. note:: 

161 

162 This method can be overloaded in a child class if you want to do something more 

163 advanced, e.g. fetching compiled simlib from Artifactory. 

164 

165 Arguments: 

166 output_path (pathlib.Path): Compiled simlib will be placed in sub-directory of 

167 this path. 

168 force_compile (bool): Will (re)-compile simlib even if compiled artifacts exist. 

169 

170 Return: 

171 VivadoSimlibCommon: The simlib object. 

172 """ 

173 vivado_simlib = VivadoSimlib.init(output_path, self.vunit_proj) 

174 if force_compile or vivado_simlib.compile_is_needed: 

175 vivado_simlib.compile() 

176 vivado_simlib.to_archive() 

177 

178 vivado_simlib.add_to_vunit_project() 

179 

180 # Code in the "vital2000" package gives GHDL errors such as "result subtype of a pure 

181 # function cannot have access subelements". Hence, relaxed rules need to be enabled when 

182 # using unisim. 

183 self.vunit_proj.set_sim_option("ghdl.elab_flags", ["-frelaxed-rules"]) 

184 

185 return vivado_simlib 

186 

187 def add_vivado_ip_cores( 

188 self, 

189 args, 

190 modules, 

191 vivado_part_name="xc7z020clg400-1", 

192 vivado_ip_core_project_class=None, 

193 ): 

194 """ 

195 Generate IP cores from the modules, unless instructed not to by ``args``. 

196 When running with a commercial simulator they will be added to the VUnit project. 

197 

198 Arguments: 

199 args: Command line argument namespace from ``simulate.py``. 

200 modules (:class:`.ModuleList`): IP cores from these modules will be included in the 

201 simulation project. 

202 vivado_part_name (str): Part name to be used for Vivado IP core project. Might have to 

203 change from default depending on what parts you have available in your 

204 Vivado installation. 

205 vivado_ip_core_project_class: Class to be used for Vivado IP core project. Can be left 

206 at default in most cases. 

207 

208 Return: 

209 pathlib.Path: Path to the Vivado IP core project's ``project`` directory. 

210 """ 

211 if args.vivado_skip: 

212 return None 

213 

214 # Generate IP core simulation files. Might be used for the vhdl_ls config, 

215 # even if they are not added to the simulation project. 

216 ( 

217 ip_core_compile_order_file, 

218 ip_core_vivado_project_directory, 

219 ) = self._generate_ip_core_files( 

220 modules=modules, 

221 output_path=args.output_path_vivado, 

222 force_generate=args.ip_compile, 

223 part_name=vivado_part_name, 

224 vivado_project_class=vivado_ip_core_project_class, 

225 ) 

226 if self.has_commercial_simulator: 

227 add_from_compile_order_file( 

228 vunit_obj=self.vunit_proj, compile_order_file=ip_core_compile_order_file 

229 ) 

230 

231 return ip_core_vivado_project_directory 

232 

233 @staticmethod 

234 def _generate_ip_core_files( 

235 modules, output_path, force_generate, part_name, vivado_project_class=None 

236 ): 

237 """ 

238 Generate Vivado IP core files that are to be added to the VUnit project. 

239 Create a new project to generate files if needed. 

240 

241 Arguments: 

242 modules (:class:`.ModuleList`): IP cores from these modules will be included. 

243 output_path (pathlib.Path): IP core files will be placed in sub-directory of this path. 

244 force_generate (bool): Will (re)-generate files even if they exist. 

245 part_name (str): Vivado part name. 

246 vivado_project_class: Class to be used for Vivado IP core project. 

247 """ 

248 vivado_ip_cores = VivadoIpCores( 

249 modules=modules, 

250 output_path=output_path, 

251 part_name=part_name, 

252 vivado_project_class=vivado_project_class, 

253 ) 

254 

255 if force_generate: 

256 vivado_ip_cores.create_vivado_project() 

257 vivado_project_created = True 

258 else: 

259 vivado_project_created = vivado_ip_cores.create_vivado_project_if_needed() 

260 

261 if vivado_project_created: 

262 # If the IP core Vivado project has been (re)created we need to create 

263 # a new compile order file 

264 create_compile_order_file( 

265 vivado_ip_cores.vivado_project_file, vivado_ip_cores.compile_order_file 

266 ) 

267 

268 return vivado_ip_cores.compile_order_file, vivado_ip_cores.project_directory 

269 

270 

271def create_vhdl_ls_configuration( 

272 output_path, temp_files_path, modules, ip_core_vivado_project_directory=None 

273): 

274 """ 

275 Create config for vhdl_ls (https://github.com/VHDL-LS/rust_hdl). 

276 Granted this might no be the "correct" place for this functionality. 

277 But since the call is somewhat quick (~10 ms), and simulate.py is run "often" it seems an 

278 appropriate place in order to always have an up-to-date vhdl_ls config. 

279 

280 Arguments: 

281 output_path (pathlib.Path): Config file will be placed here. 

282 temp_files_path (pathlib.Path): Some temporary files will be placed here. 

283 modules (:class:`.ModuleList`): These modules will be added. 

284 ip_core_vivado_project_directory (pathlib.Path): Vivado IP core files in this location 

285 will be added. 

286 """ 

287 # Create an empty VUnit project to add files from VUnit and OSVVM library. 

288 # If we were to use the "real" VUnit project that we set up above instead, all the files would 

289 # be in the "preprocessed" folder. Hence we use an "empty" VUnit project, and add all files 

290 # via modules. 

291 vunit_proj = VUnit.from_argv(argv=["--output-path", str(temp_files_path / "vhdl_ls_vunit_out")]) 

292 vunit_proj.add_verification_components() 

293 vunit_proj.add_random() 

294 vunit_proj.add_osvvm() 

295 

296 vivado_location = None if which("vivado") is None else Path(which("vivado")) 

297 tsfpga.create_vhdl_ls_config.create_configuration( 

298 output_path=output_path, 

299 modules=modules, 

300 vunit_proj=vunit_proj, 

301 vivado_location=vivado_location, 

302 ip_core_vivado_project_directory=ip_core_vivado_project_directory, 

303 )