Coverage for tsfpga/examples/build_fpga_single_project.py: 0%
56 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-04 20:52 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-04 20:52 +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
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
38 from collections.abc import Callable
40 from tsfpga.module_list import ModuleList
41 from tsfpga.vivado.project import VivadoProject
44def main() -> None:
45 """
46 Main function for building single FPGA projects.
47 Note that this is not the recommended standard build flow, see 'build_fpga.py' instead.
48 """
49 args = arguments(default_temp_dir=TSFPGA_EXAMPLES_TEMP_DIR)
50 modules = get_tsfpga_example_modules()
51 projects = BuildProjectList(
52 modules=modules,
53 project_filters=args.project_filters,
54 include_netlist_not_top_builds=args.netlist_builds,
55 no_color=args.no_color,
56 )
58 sys.exit(
59 setup_and_run(
60 modules=modules,
61 projects=projects,
62 args=args,
63 collect_artifacts_function=collect_artifacts,
64 )
65 )
68def setup_and_run( # noqa: C901, PLR0911, PLR0912
69 modules: ModuleList,
70 projects: BuildProjectList,
71 args: argparse.Namespace,
72 collect_artifacts_function: Callable[[VivadoProject, Path], bool] | None,
73) -> int:
74 """
75 Setup and execute build projects one by one.
76 As instructed by the arguments.
78 Note that this is not the recommended standard build flow, see 'build_fpga.py' instead.
80 Note that this functions is a modified clone of the one in 'build_fpga_utils.py'.
82 Arguments:
83 modules: When running a register generation, registers from these
84 modules will be included.
85 projects: These build projects will be built.
86 args: Command line argument namespace.
87 collect_artifacts_function: Function pointer to a function that collects build artifacts.
88 Will be run after a successful implementation build.
89 The function must return ``True`` if successful and ``False`` otherwise.
90 It will receive the ``project`` and ``output_path`` as arguments.
91 Can be ``None`` if no special artifact collection operation shall be run.
93 Return:
94 0 if everything passed, otherwise non-zero.
95 Can be used for system exit code.
96 """
97 if args.list_only:
98 print(projects)
99 return 0
101 if args.generate_registers_only:
102 # Generate register output from all modules. Note that this is not used by the
103 # build flow or simulation flow, it is only for the user to inspect the artifacts.
104 generate_register_artifacts(
105 modules=modules, output_path=args.projects_path.parent / "registers"
106 )
107 return 0
109 if args.open:
110 for project in projects.projects:
111 project.open(
112 project_path=projects.get_build_project_path(
113 project=project, projects_path=args.projects_path
114 )
115 )
117 return 0
119 if args.collect_artifacts_only:
120 # We have to assume that the projects exist if the user sent this argument.
121 # The 'collect_artifacts_function' call below will probably fail if it does not.
122 create_ok = True
124 else:
125 create_ok = True
127 for project in projects.projects:
128 project_path = projects.get_build_project_path(
129 project=project, projects_path=args.projects_path
130 )
132 if (not args.use_existing_project) or (not project_path.exists()):
133 create_ok &= project.create(
134 project_path=project_path, ip_cache_path=args.ip_cache_path
135 )
137 if not create_ok:
138 return 1
140 if args.create_only:
141 return 0
143 # If doing only synthesis, there are no artifacts to collect.
144 collect_artifacts_function = (
145 None if (args.synth_only or args.netlist_builds) else collect_artifacts_function
146 )
148 if args.collect_artifacts_only:
149 assert collect_artifacts_function is not None, "No artifact collection available"
151 for project in projects.projects:
152 assert collect_artifacts_function(
153 project=project,
154 output_path=projects.get_build_project_output_path(
155 project=project, projects_path=args.projects_path, output_path=args.output_path
156 ),
157 )
159 return 0
161 build_ok = True
162 for project in projects.projects:
163 project_output_path = projects.get_build_project_output_path(
164 project=project, projects_path=args.projects_path, output_path=args.output_path
165 )
167 build_result = project.build(
168 project_path=projects.get_build_project_path(
169 project=project, projects_path=args.projects_path
170 ),
171 output_path=project_output_path,
172 synth_only=args.synth_only,
173 from_impl=args.from_impl,
174 )
175 build_ok &= build_result.success
177 if build_result.success and (collect_artifacts_function is not None):
178 build_ok &= collect_artifacts_function(project=project, output_path=project_output_path)
180 if build_ok:
181 return 0
183 return 1
186if __name__ == "__main__":
187 main()