Coverage for tsfpga / examples / vivado / project.py: 0%

41 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-13 21:33 +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://github.com/tsfpga/tsfpga 

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

8 

9import datetime 

10import platform 

11import random 

12from pathlib import Path 

13from typing import TYPE_CHECKING, Any 

14 

15from tsfpga import REPO_ROOT 

16from tsfpga.git_utils import get_git_commit 

17from tsfpga.vivado.common import get_vivado_version 

18from tsfpga.vivado.project import VivadoNetlistProject, VivadoProject 

19 

20if TYPE_CHECKING: 

21 from hdl_registers.register_list import RegisterList 

22 

23THIS_DIR = Path(__file__).parent 

24 

25 

26class TsfpgaExampleVivadoProject(VivadoProject): 

27 """ 

28 Example Vivado project class. 

29 Shows how to override and extend the base behavior. 

30 """ 

31 

32 def pre_create( 

33 self, 

34 generics: dict[str, Any], 

35 **kwargs: Any, # noqa: ANN401 

36 ) -> bool: 

37 """ 

38 Is called right before the Vivado system call that creates the project. 

39 Override parent method to add custom behavior. 

40 """ 

41 # Add script that elevates the severity of even more Vivado messages, to get more 

42 # quality feedback from the tool. 

43 self.tcl_sources.append(THIS_DIR / "tcl" / "example_vivado_messages.tcl") 

44 

45 # Set 'build_id', which is a generic without a default value, so it is possible to 

46 # build the project in the GUI. 

47 # In a proper command-line build, it will be overridden again in 'pre_build'. 

48 # See 'pre_build' for more information. 

49 self._set_build_id_generic(generics=generics) 

50 

51 return super().pre_create(generics=generics, kwargs=kwargs) 

52 

53 def pre_build( 

54 self, 

55 generics: dict[str, Any], 

56 **kwargs: Any, # noqa: ANN401 

57 ) -> bool: 

58 """ 

59 Is called right before the Vivado system call that builds the project. 

60 Override parent method to add custom behavior. 

61 

62 Note that this function is called after generating register HDL artifacts in the 

63 build flow. 

64 Hence, the register constants we set will only be available in the generated software code, 

65 not in the HDL. 

66 Hence we can run many builds in parallel, without having race conditions between the 

67 different values in HDL on the filesystem. 

68 """ 

69 self._set_build_id_generic(generics=generics) 

70 self._set_build_register_constants(generics=generics) 

71 

72 return super().pre_build(generics=generics, kwargs=kwargs) 

73 

74 def _set_build_id_generic(self, generics: dict[str, Any]) -> None: 

75 """ 

76 Set a random value. 

77 """ 

78 # Set a suitable range so the generic can be handled as a VHDL 'natural'. 

79 # Does not need to be cryptographically secure. 

80 generics["build_id"] = random.randint(1, 2**25 - 1) # noqa: S311 

81 

82 def _set_build_register_constants(self, generics: dict[str, Any]) -> None: 

83 """ 

84 Set register constants with build traceability information. 

85 """ 

86 # Crude way of finding the module that the top-level entity belongs to. 

87 top_module = self.modules.get(module_name=self.top.split("_top")[0]) 

88 registers: RegisterList = top_module.registers 

89 

90 if registers is None: 

91 # 'io_constraints_top' example build has no registers. 

92 return 

93 

94 hook_note = """ 

95 

96Note that this constant is added by a Python build hook. 

97It is available in the FPGA build flow and the generated software code, 

98but never in the simulation flow. 

99""" 

100 

101 registers.add_constant( 

102 name="expected_build_id", 

103 value=generics["build_id"], 

104 description="""\ 

105The build ID for this FPGA build. 

106The value read from the **build_id** register shall be equal to this constant.""" 

107 + hook_note, 

108 ) 

109 

110 registers.add_constant( 

111 name="build_project_name", 

112 value=self.name, 

113 description=( 

114 "The name of the build project that executed the build of this FPGA." + hook_note 

115 ), 

116 ) 

117 

118 registers.add_constant( 

119 name="build_generics", 

120 value=", ".join(f"{key}={value}" for key, value in generics.items()), 

121 description=( 

122 "The generic values that were set to the top level when building this FPGA." 

123 + hook_note 

124 ), 

125 ) 

126 

127 registers.add_constant( 

128 name="build_vivado_version", 

129 value=get_vivado_version(vivado_path=self._vivado_path), 

130 description=("The Vivado version that this FPGA was built with." + hook_note), 

131 ) 

132 

133 registers.add_constant( 

134 name="build_git_commit", 

135 value=get_git_commit(directory=REPO_ROOT), 

136 description="""\ 

137The left-most characters of the git commit hash that this FPGA was built from. 

138If there were local changes in the git repository, this will be noted in parenthesis. 

139""" 

140 + hook_note, 

141 ) 

142 

143 registers.add_constant( 

144 name="build_time", 

145 # Specific timezone is not needed, it just needs to be consistent. 

146 value=( 

147 datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # noqa: DTZ005 

148 ), 

149 description="A string describing at what time and date the FPGA was built." + hook_note, 

150 ) 

151 

152 registers.add_constant( 

153 name="build_hostname", 

154 value=platform.node(), 

155 description="The hostname where this FPGA was built." + hook_note, 

156 ) 

157 

158 registers.add_constant( 

159 name="build_operating_system", 

160 value=platform.system(), 

161 description="The operating that this FPGA was built on." + hook_note, 

162 ) 

163 

164 registers.add_constant( 

165 name="build_operating_system_info", 

166 value=platform.version() + " " + platform.platform(), 

167 description="More information about the operating system that this FPGA was built on." 

168 + hook_note, 

169 ) 

170 

171 

172class TsfpgaExampleVivadoNetlistProject(VivadoNetlistProject): 

173 """ 

174 Example Vivado project class for netlist builds. 

175 Shows how to override and extend the base behavior. 

176 """ 

177 

178 def pre_create( 

179 self, 

180 generics: dict[str, Any], 

181 **kwargs: Any, # noqa: ANN401 

182 ) -> bool: 

183 """ 

184 Override parent method to add custom behavior. 

185 Update TCL sources just before project creation. 

186 """ 

187 self.tcl_sources.append(THIS_DIR / "tcl" / "example_vivado_messages.tcl") 

188 self.tcl_sources.append(THIS_DIR / "tcl" / "example_vivado_netlist_messages.tcl") 

189 

190 return super().pre_create(generics=generics, kwargs=kwargs)