Coverage for tsfpga/vivado/simlib_common.py: 85%

61 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-29 20:01 +0000

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

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

3# 

4# This file is part of the tsfpga project, a project platform for modern FPGA development. 

5# https://tsfpga.com 

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

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

8 

9# Standard libraries 

10import platform 

11import zipfile 

12from shutil import make_archive 

13 

14# First party libraries 

15from tsfpga.system_utils import create_file, delete 

16from tsfpga.vivado.common import get_vivado_version 

17 

18 

19class VivadoSimlibCommon: 

20 

21 """ 

22 Class for handling Vivado simlib used for simulation. Keeps track of when a 

23 (re)compile is needed. 

24 

25 This is a parent class that defines an interface and some common methods. 

26 See child classes for details: :class:`.VivadoSimlibGhdl`, :class:`.VivadoSimlibCommercial`. 

27 """ 

28 

29 # The version of this class. Can be bumped to force a re-compile if e.g. the TCL script changes 

30 # or the output folder structure is updated. 

31 _format_version_id = 2 

32 

33 # Set in child class to a list of strings. The libraries that shall be compiled and added to 

34 # VUnit project. 

35 library_names = None 

36 

37 # Set in child class to a pathlib.Path object. The path to the "vivado" executable. 

38 _vivado_path = None 

39 

40 # Set in child class to a pathlib.Path object. The path where simlib shall be compiled. 

41 output_path = None 

42 

43 def compile_if_needed(self): 

44 """ 

45 Compile if needed (if :meth:`compile_is_needed <.compile_is_needed>` condition is not 

46 fulfilled). 

47 """ 

48 if self.compile_is_needed: 

49 self.compile() 

50 return True 

51 return False 

52 

53 @property 

54 def compile_is_needed(self): 

55 """ 

56 If there is compiled simlib available that matches 

57 

58 * Operating system 

59 * Vivado version 

60 * Simulator version 

61 

62 then there should not be a recompile. 

63 

64 .. note:: 

65 Child implementations might add further conditions. 

66 

67 Return: 

68 True if compiled simlib is not available. False otherwise. 

69 """ 

70 if self._done_token.exists(): 

71 return False 

72 return True 

73 

74 def compile(self): 

75 """ 

76 Compile simlib. 

77 """ 

78 delete(self._done_token) 

79 print(f"Compiling Vivado simlib in {self.output_path}") 

80 

81 self._compile() 

82 

83 create_file(self._done_token, "Done!") 

84 

85 def _compile(self): 

86 """ 

87 Compile simlib. 

88 """ 

89 raise NotImplementedError() 

90 

91 def add_to_vunit_project(self): 

92 """ 

93 Add the compiled simlib to your VUnit project. 

94 """ 

95 self._add_to_vunit_project() 

96 

97 def _add_to_vunit_project(self): 

98 raise NotImplementedError() 

99 

100 @property 

101 def artifact_name(self): 

102 """ 

103 str: The name of the folder where simlib is or will be compiled. 

104 Follows a format ``vivado-simlib-WW.XX.YY.ZZ`` suitable for storage and versioning 

105 in Artifactory. 

106 """ 

107 return self.output_path.name 

108 

109 def to_archive(self): 

110 """ 

111 Compress compiled simlib to an archive. 

112 

113 Return: 

114 pathlib.Path: Path to the archive. 

115 """ 

116 make_archive(self.output_path, "zip", self.output_path) 

117 archive = self.output_path.parent / (self.output_path.name + ".zip") 

118 return archive 

119 

120 def from_archive(self, archive): 

121 """ 

122 Unpack compiled simlib from an existing archive. 

123 

124 Arguments: 

125 archive (pathlib.Path): Path to a zip archive with previously compiled simlib. 

126 """ 

127 with zipfile.ZipFile(archive, "r") as zip_handle: 

128 zip_handle.extractall(self.output_path) 

129 

130 def _get_version_tag(self): 

131 tag = "vivado-simlib-" 

132 tag += self._get_operating_system_tag() 

133 tag += f".{self._get_vivado_version_tag()}" 

134 tag += f".{self._get_simulator_tag()}" 

135 tag += f".format_{self._format_version_id}" 

136 

137 return tag 

138 

139 def _get_operating_system_tag(self): 

140 """ 

141 Return e.g. "linux". 

142 """ 

143 return self._format_version(platform.system()) 

144 

145 def _get_vivado_version_tag(self): 

146 """ 

147 Return e.g. "vivado_2021_2". 

148 """ 

149 vivado_version = get_vivado_version(self._vivado_path) 

150 

151 return self._format_version(f"vivado_{vivado_version}") 

152 

153 def _get_simulator_tag(self): 

154 raise NotImplementedError() 

155 

156 @staticmethod 

157 def _format_version(version): 

158 """ 

159 Format version string to something suitable for artifactory versioning. 

160 """ 

161 return version.replace(".", "_").replace("-", "_").lower() 

162 

163 @property 

164 def _done_token(self): 

165 """ 

166 Path to "done" token file. 

167 """ 

168 return self.output_path / "done.txt"