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
« 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# --------------------------------------------------------------------------------------------------
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 if registers is None:
91 # 'io_constraints_top' example build has no registers.
92 return
94 hook_note = """
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"""
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 )
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 )
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 )
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 )
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 )
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 )
152 registers.add_constant(
153 name="build_hostname",
154 value=platform.node(),
155 description="The hostname where this FPGA was built." + hook_note,
156 )
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 )
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 )
172class TsfpgaExampleVivadoNetlistProject(VivadoNetlistProject):
173 """
174 Example Vivado project class for netlist builds.
175 Shows how to override and extend the base behavior.
176 """
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")
190 return super().pre_create(generics=generics, kwargs=kwargs)