Coverage for tsfpga/examples/build_fpga_single_project.py: 0%
56 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-08-29 20:51 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-08-29 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# --------------------------------------------------------------------------------------------------
9"""
10Build FPGA projects from the command line.
11Note that this is an example script that illustrates how FPGA build projects can be built one
12by one.
13This is not the recommended standard build flow, see 'build_fpga.py' instead.
15The benefit of building one by one is that build status is written directly to STDOUT.
16"""
18from __future__ import annotations
20import sys
21from pathlib import Path
22from typing import TYPE_CHECKING, Callable
24# Do PYTHONPATH insert() instead of append() to prefer any local repo checkout over any pip install.
25REPO_ROOT = Path(__file__).parent.parent.parent.resolve()
26sys.path.insert(0, str(REPO_ROOT))
28# Import before others since it modifies PYTHONPATH.
29import tsfpga.examples.example_pythonpath # noqa: F401
31from tsfpga.build_project_list import BuildProjectList
32from tsfpga.examples.build_fpga import collect_artifacts
33from tsfpga.examples.build_fpga_utils import arguments, generate_register_artifacts
34from tsfpga.examples.example_env import TSFPGA_EXAMPLES_TEMP_DIR, get_tsfpga_example_modules
36if TYPE_CHECKING:
37 import argparse
39 from tsfpga.module_list import ModuleList
40 from tsfpga.vivado.project import VivadoProject
43def main() -> None:
44 """
45 Main function for building single FPGA projects.
46 Note that this is not the recommended standard build flow, see 'build_fpga.py' instead.
47 """
48 args = arguments(default_temp_dir=TSFPGA_EXAMPLES_TEMP_DIR)
49 modules = get_tsfpga_example_modules()
50 projects = BuildProjectList(
51 modules=modules,
52 project_filters=args.project_filters,
53 include_netlist_not_top_builds=args.netlist_builds,
54 no_color=args.no_color,
55 )
57 sys.exit(
58 setup_and_run(
59 modules=modules,
60 projects=projects,
61 args=args,
62 collect_artifacts_function=collect_artifacts,
63 )
64 )
67def setup_and_run( # noqa: C901, PLR0911, PLR0912
68 modules: ModuleList,
69 projects: BuildProjectList,
70 args: argparse.Namespace,
71 collect_artifacts_function: Callable[[VivadoProject, Path], bool] | None,
72) -> int:
73 """
74 Setup and execute build projects one by one.
75 As instructed by the arguments.
77 Note that this is not the recommended standard build flow, see 'build_fpga.py' instead.
79 Note that this functions is a modified clone of the one in 'build_fpga_utils.py'.
81 Arguments:
82 modules: When running a register generation, registers from these
83 modules will be included.
84 projects: These build projects will be built.
85 args: Command line argument namespace.
86 collect_artifacts_function: Function pointer to a function that collects build artifacts.
87 Will be run after a successful implementation build.
88 The function must return ``True`` if successful and ``False`` otherwise.
89 It will receive the ``project`` and ``output_path`` as arguments.
90 Can be ``None`` if no special artifact collection operation shall be run.
92 Return:
93 0 if everything passed, otherwise non-zero.
94 Can be used for system exit code.
95 """
96 if args.list_only:
97 print(projects)
98 return 0
100 if args.generate_registers_only:
101 # Generate register output from all modules. Note that this is not used by the
102 # build flow or simulation flow, it is only for the user to inspect the artifacts.
103 generate_register_artifacts(
104 modules=modules, output_path=args.projects_path.parent / "registers"
105 )
106 return 0
108 if args.open:
109 for project in projects.projects:
110 project.open(
111 project_path=projects.get_build_project_path(
112 project=project, projects_path=args.projects_path
113 )
114 )
116 return 0
118 if args.collect_artifacts_only:
119 # We have to assume that the projects exist if the user sent this argument.
120 # The 'collect_artifacts_function' call below will probably fail if it does not.
121 create_ok = True
123 else:
124 create_ok = True
126 for project in projects.projects:
127 project_path = projects.get_build_project_path(
128 project=project, projects_path=args.projects_path
129 )
131 if (not args.use_existing_project) or (not project_path.exists()):
132 create_ok &= project.create(
133 project_path=project_path, ip_cache_path=args.ip_cache_path
134 )
136 if not create_ok:
137 return 1
139 if args.create_only:
140 return 0
142 # If doing only synthesis, there are no artifacts to collect.
143 collect_artifacts_function = (
144 None if (args.synth_only or args.netlist_builds) else collect_artifacts_function
145 )
147 if args.collect_artifacts_only:
148 assert collect_artifacts_function is not None, "No artifact collection available"
150 for project in projects.projects:
151 assert collect_artifacts_function(
152 project=project,
153 output_path=projects.get_build_project_output_path(
154 project=project, projects_path=args.projects_path, output_path=args.output_path
155 ),
156 )
158 return 0
160 build_ok = True
161 for project in projects.projects:
162 project_output_path = projects.get_build_project_output_path(
163 project=project, projects_path=args.projects_path, output_path=args.output_path
164 )
166 build_result = project.build(
167 project_path=projects.get_build_project_path(
168 project=project, projects_path=args.projects_path
169 ),
170 output_path=project_output_path,
171 synth_only=args.synth_only,
172 from_impl=args.from_impl,
173 )
174 build_ok &= build_result.success
176 if build_result.success and (collect_artifacts_function is not None):
177 build_ok &= collect_artifacts_function(project=project, output_path=project_output_path)
179 if build_ok:
180 return 0
182 return 1
185if __name__ == "__main__":
186 main()