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