Coverage for tsfpga/examples/vivado/project.py: 0%
39 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-18 20:51 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-18 20:51 +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# --------------------------------------------------------------------------------------------------
9import datetime
10import platform
11import random
12from pathlib import Path
13from typing import TYPE_CHECKING, Any
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
20if TYPE_CHECKING:
21 from hdl_registers.register_list import RegisterList
23THIS_DIR = Path(__file__).parent
26class TsfpgaExampleVivadoProject(VivadoProject):
27 """
28 Example Vivado project class.
29 Shows how to override and extend the base behavior.
30 """
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")
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)
51 return super().pre_create(generics=generics, kwargs=kwargs)
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.
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)
72 return super().pre_build(generics=generics, kwargs=kwargs)
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
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
90 hook_note = """
92Note that this constant is added by a Python build hook.
93It is available in the FPGA build flow and the generated software code,
94but never in the simulation flow.
95"""
97 registers.add_constant(
98 name="expected_build_id",
99 value=generics["build_id"],
100 description="""\
101The build ID for this FPGA build.
102The value read from the **build_id** register shall be equal to this constant."""
103 + hook_note,
104 )
106 registers.add_constant(
107 name="build_project_name",
108 value=self.name,
109 description=(
110 "The name of the build project that executed the build of this FPGA." + hook_note
111 ),
112 )
114 registers.add_constant(
115 name="build_generics",
116 value=", ".join(f"{key}={value}" for key, value in generics.items()),
117 description=(
118 "The generic values that were set to the top level when building this FPGA."
119 + hook_note
120 ),
121 )
123 registers.add_constant(
124 name="build_vivado_version",
125 value=get_vivado_version(vivado_path=self._vivado_path),
126 description=("The Vivado version that this FPGA was built with." + hook_note),
127 )
129 registers.add_constant(
130 name="build_git_commit",
131 value=get_git_commit(directory=REPO_ROOT),
132 description="""\
133The left-most characters of the git commit hash that this FPGA was built from.
134If there were local changes in the git repository, this will be noted in parenthesis.
135"""
136 + hook_note,
137 )
139 registers.add_constant(
140 name="build_time",
141 # Specific timezone is not needed, it just needs to be consistent.
142 value=(
143 datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # noqa: DTZ005
144 ),
145 description="A string describing at what time and date the FPGA was built." + hook_note,
146 )
148 registers.add_constant(
149 name="build_hostname",
150 value=platform.node(),
151 description="The hostname where this FPGA was built." + hook_note,
152 )
154 registers.add_constant(
155 name="build_operating_system",
156 value=platform.system(),
157 description="The operating that this FPGA was built on." + hook_note,
158 )
160 registers.add_constant(
161 name="build_operating_system_info",
162 value=platform.version() + " " + platform.platform(),
163 description="More information about the operating system that this FPGA was built on."
164 + hook_note,
165 )
168class TsfpgaExampleVivadoNetlistProject(VivadoNetlistProject):
169 """
170 Example Vivado project class for netlist builds.
171 Shows how to override and extend the base behavior.
172 """
174 def pre_create(
175 self,
176 generics: dict[str, Any],
177 **kwargs: Any, # noqa: ANN401
178 ) -> bool:
179 """
180 Override parent method to add custom behavior.
181 Update TCL sources just before project creation.
182 """
183 self.tcl_sources.append(THIS_DIR / "tcl" / "example_vivado_messages.tcl")
184 self.tcl_sources.append(THIS_DIR / "tcl" / "example_vivado_netlist_messages.tcl")
186 return super().pre_create(generics=generics, kwargs=kwargs)