soc/integration/builder: call do_exit with vns when build is done.
[litex.git] / litex / soc / integration / builder.py
1 # This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
2 # This file is Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
3 # This file is Copyright (c) 2019 Mateusz Holenko <mholenko@antmicro.com>
4 # This file is Copyright (c) 2018 Peter Gielda <pgielda@antmicro.com>
5 # This file is Copyright (c) 2018 Sergiusz Bazanski <q3k@q3k.org>
6 # This file is Copyright (c) 2016-2017 Tim 'mithro' Ansell <mithro@mithis.com>
7 # This file is Copyright (c) 2018 William D. Jones <thor0505@comcast.net>
8 # License: BSD
9
10
11 import os
12 import subprocess
13 import struct
14 import shutil
15
16 from litex.build.tools import write_to_file
17 from litex.soc.integration import cpu_interface, soc_core, soc_sdram
18
19 from litedram.init import get_sdram_phy_c_header
20
21 __all__ = ["soc_software_packages", "soc_directory",
22 "Builder", "builder_args", "builder_argdict"]
23
24
25 soc_software_packages = [
26 "libcompiler_rt",
27 "libbase",
28 "libnet",
29 "bios"
30 ]
31
32
33 soc_directory = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
34
35
36 def _makefile_escape(s):
37 return s.replace("\\", "\\\\")
38
39
40 class Builder:
41 def __init__(self, soc, output_dir=None,
42 compile_software=True, compile_gateware=True,
43 gateware_toolchain_path=None,
44 csr_json=None, csr_csv=None):
45 self.soc = soc
46 if output_dir is None:
47 output_dir = "soc_{}_{}".format(
48 soc.__class__.__name__.lower(),
49 soc.platform.name)
50 # From Python doc: makedirs() will become confused if the path
51 # elements to create include '..'
52 self.output_dir = os.path.abspath(output_dir)
53 self.compile_software = compile_software
54 self.compile_gateware = compile_gateware
55 self.gateware_toolchain_path = gateware_toolchain_path
56 self.csr_csv = csr_csv
57 self.csr_json = csr_json
58
59 self.software_packages = []
60 for name in soc_software_packages:
61 self.add_software_package(name)
62
63 def add_software_package(self, name, src_dir=None):
64 if src_dir is None:
65 src_dir = os.path.join(soc_directory, "software", name)
66 self.software_packages.append((name, src_dir))
67
68 def _generate_includes(self):
69 cpu_type = self.soc.cpu_type
70 memory_regions = self.soc.get_memory_regions()
71 flash_boot_address = getattr(self.soc, "flash_boot_address", None)
72 shadow_base = getattr(self.soc, "shadow_base", None)
73 csr_regions = self.soc.get_csr_regions()
74 constants = self.soc.get_constants()
75
76 buildinc_dir = os.path.join(self.output_dir, "software", "include")
77 generated_dir = os.path.join(buildinc_dir, "generated")
78 os.makedirs(generated_dir, exist_ok=True)
79
80 variables_contents = []
81 def define(k, v):
82 variables_contents.append("{}={}\n".format(k, _makefile_escape(v)))
83 for k, v in cpu_interface.get_cpu_mak(self.soc.cpu):
84 define(k, v)
85 # Distinguish between LiteX and MiSoC.
86 define("LITEX", "1")
87 # Distinguish between applications running from main RAM and
88 # flash for user-provided software packages.
89 exec_profiles = {
90 "COPY_TO_MAIN_RAM" : "0",
91 "EXECUTE_IN_PLACE" : "0"
92 }
93 if "main_ram" in (m[0] for m in memory_regions):
94 exec_profiles["COPY_TO_MAIN_RAM"] = "1"
95 else:
96 exec_profiles["EXECUTE_IN_PLACE"] = "1"
97 for k, v in exec_profiles.items():
98 define(k, v)
99 define("SOC_DIRECTORY", soc_directory)
100 variables_contents.append("export BUILDINC_DIRECTORY\n")
101 define("BUILDINC_DIRECTORY", buildinc_dir)
102 for name, src_dir in self.software_packages:
103 define(name.upper() + "_DIRECTORY", src_dir)
104 write_to_file(
105 os.path.join(generated_dir, "variables.mak"),
106 "".join(variables_contents))
107 write_to_file(
108 os.path.join(generated_dir, "output_format.ld"),
109 cpu_interface.get_linker_output_format(self.soc.cpu))
110 write_to_file(
111 os.path.join(generated_dir, "regions.ld"),
112 cpu_interface.get_linker_regions(memory_regions))
113 write_to_file(
114 os.path.join(generated_dir, "mem.h"),
115 cpu_interface.get_mem_header(memory_regions, flash_boot_address, shadow_base))
116 write_to_file(
117 os.path.join(generated_dir, "csr.h"),
118 cpu_interface.get_csr_header(csr_regions, constants))
119 write_to_file(
120 os.path.join(generated_dir, "git.h"),
121 cpu_interface.get_git_header()
122 )
123
124 if isinstance(self.soc, soc_sdram.SoCSDRAM):
125 if hasattr(self.soc, "sdram"):
126 write_to_file(
127 os.path.join(generated_dir, "sdram_phy.h"),
128 get_sdram_phy_c_header(
129 self.soc.sdram.controller.settings.phy,
130 self.soc.sdram.controller.settings.timing))
131
132 def _generate_csr_map(self, csr_json=None, csr_csv=None):
133 memory_regions = self.soc.get_memory_regions()
134 csr_regions = self.soc.get_csr_regions()
135 constants = self.soc.get_constants()
136
137 shadow_base = getattr(self.soc, "shadow_base", None)
138 if shadow_base:
139 constants.append(('shadow_base', shadow_base))
140
141 flash_boot_address = getattr(self.soc, "flash_boot_address", None)
142 if flash_boot_address:
143 constants.append(('flash_boot_address', flash_boot_address))
144
145 if csr_json is not None:
146 csr_dir = os.path.dirname(os.path.realpath(csr_json))
147 os.makedirs(csr_dir, exist_ok=True)
148 write_to_file(csr_json, cpu_interface.get_csr_json(csr_regions, constants, memory_regions))
149
150 if csr_csv is not None:
151 csr_dir = os.path.dirname(os.path.realpath(csr_csv))
152 os.makedirs(csr_dir, exist_ok=True)
153 write_to_file(csr_csv, cpu_interface.get_csr_csv(csr_regions, constants, memory_regions))
154
155 def _prepare_software(self):
156 for name, src_dir in self.software_packages:
157 dst_dir = os.path.join(self.output_dir, "software", name)
158 os.makedirs(dst_dir, exist_ok=True)
159
160 def _generate_software(self, compile_bios=True):
161 for name, src_dir in self.software_packages:
162 if name == "bios" and not compile_bios:
163 pass
164 else:
165 dst_dir = os.path.join(self.output_dir, "software", name)
166 makefile = os.path.join(src_dir, "Makefile")
167 if self.compile_software:
168 subprocess.check_call(["make", "-C", dst_dir, "-f", makefile])
169
170 def _initialize_rom(self):
171 bios_file = os.path.join(self.output_dir, "software", "bios","bios.bin")
172 bios_data = soc_core.get_mem_data(bios_file, self.soc.cpu.endianness)
173 self.soc.initialize_rom(bios_data)
174
175 def build(self, toolchain_path=None, **kwargs):
176 self.soc.finalize()
177
178 os.makedirs(self.output_dir, exist_ok=True)
179
180 if self.soc.cpu_type is not None:
181 self._prepare_software()
182 self._generate_includes()
183 self._generate_software(not self.soc.integrated_rom_initialized)
184 if self.soc.integrated_rom_size and self.compile_software:
185 if not self.soc.integrated_rom_initialized:
186 self._initialize_rom()
187
188 self._generate_csr_map(self.csr_json, self.csr_csv)
189
190 if self.gateware_toolchain_path is not None:
191 toolchain_path = self.gateware_toolchain_path
192
193 if "run" not in kwargs:
194 kwargs["run"] = self.compile_gateware
195 vns = self.soc.build(build_dir=os.path.join(self.output_dir, "gateware"),
196 toolchain_path=toolchain_path, **kwargs)
197 self.soc.do_exit(vns=vns)
198 return vns
199
200
201 def builder_args(parser):
202 parser.add_argument("--output-dir", default=None,
203 help="output directory for generated "
204 "source files and binaries")
205 parser.add_argument("--no-compile-software", action="store_true",
206 help="do not compile the software, only generate "
207 "build infrastructure")
208 parser.add_argument("--no-compile-gateware", action="store_true",
209 help="do not compile the gateware, only generate "
210 "HDL source files and build scripts")
211 parser.add_argument("--gateware-toolchain-path", default=None,
212 help="set gateware toolchain (ISE, Quartus, etc.) "
213 "installation path")
214 parser.add_argument("--csr-csv", default=None,
215 help="store CSR map in CSV format into the "
216 "specified file")
217 parser.add_argument("--csr-json", default=None,
218 help="store CSR map in JSON format into the "
219 "specified file")
220
221
222 def builder_argdict(args):
223 return {
224 "output_dir": args.output_dir,
225 "compile_software": not args.no_compile_software,
226 "compile_gateware": not args.no_compile_gateware,
227 "gateware_toolchain_path": args.gateware_toolchain_path,
228 "csr_csv": args.csr_csv
229 }