6594673ddfd437875ca7ded9f8a207096e06893a
[litex.git] / litex / soc / misoc / integration / builder.py
1 import os
2 import subprocess
3 import struct
4
5 from misoc.integration import cpu_interface, soc_sdram, sdram_init
6
7
8 __all__ = ["misoc_software_packages", "misoc_directory",
9 "Builder", "builder_args", "builder_argdict"]
10
11
12 # in build order (for dependencies)
13 misoc_software_packages = [
14 "libbase",
15 "libcompiler_rt",
16 "libdyld",
17 "libnet",
18 "libunwind",
19 "bios"
20 ]
21
22
23 misoc_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 = "misoc_{}_{}".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 misoc_software_packages:
50 self.add_software_package(
51 name, os.path.join(misoc_directory, "software", name))
52
53 def add_software_package(self, name, src_dir):
54 self.software_packages.append((name, src_dir))
55
56 def _generate_includes(self):
57 cpu_type = self.soc.cpu_type
58 memory_regions = self.soc.get_memory_regions()
59 flash_boot_address = getattr(self.soc, "flash_boot_address", None)
60 csr_regions = self.soc.get_csr_regions()
61 constants = self.soc.get_constants()
62 if isinstance(self.soc, soc_sdram.SoCSDRAM) and self.soc._sdram_phy:
63 sdram_phy_settings = self.soc._sdram_phy[0].settings
64 else:
65 sdram_phy_settings = None
66
67 buildinc_dir = os.path.join(self.output_dir, "software", "include")
68 generated_dir = os.path.join(buildinc_dir, "generated")
69 os.makedirs(generated_dir, exist_ok=True)
70 with open(os.path.join(generated_dir, "variables.mak"), "w") as f:
71 def define(k, v):
72 f.write("{}={}\n".format(k, _makefile_escape(v)))
73 for k, v in cpu_interface.get_cpu_mak(cpu_type):
74 define(k, v)
75 define("MISOC_DIRECTORY", misoc_directory)
76 define("BUILDINC_DIRECTORY", buildinc_dir)
77 for name, src_dir in self.software_packages:
78 define(name.upper() + "_DIRECTORY", src_dir)
79
80 with open(os.path.join(generated_dir, "output_format.ld"), "w") as f:
81 f.write(cpu_interface.get_linker_output_format(cpu_type))
82 with open(os.path.join(generated_dir, "regions.ld"), "w") as f:
83 f.write(cpu_interface.get_linker_regions(memory_regions))
84
85 with open(os.path.join(generated_dir, "mem.h"), "w") as f:
86 f.write(cpu_interface.get_mem_header(memory_regions, flash_boot_address))
87 with open(os.path.join(generated_dir, "csr.h"), "w") as f:
88 f.write(cpu_interface.get_csr_header(csr_regions, constants))
89
90 if sdram_phy_settings is not None:
91 with open(os.path.join(generated_dir, "sdram_phy.h"), "w") as f:
92 f.write(sdram_init.get_sdram_phy_header(sdram_phy_settings))
93
94 if self.csr_csv is not None:
95 with open(self.csr_csv, "w") as f:
96 f.write(cpu_interface.get_csr_csv(csr_regions))
97
98 def _generate_software(self):
99 for name, src_dir in self.software_packages:
100 dst_dir = os.path.join(self.output_dir, "software", name)
101 os.makedirs(dst_dir, exist_ok=True)
102 src = os.path.join(src_dir, "Makefile")
103 dst = os.path.join(dst_dir, "Makefile")
104 try:
105 os.remove(dst)
106 except FileNotFoundError:
107 pass
108 os.symlink(src, dst)
109 if self.compile_software:
110 subprocess.check_call(["make", "-C", dst_dir])
111
112 def _initialize_rom(self):
113 bios_file = os.path.join(self.output_dir, "software", "bios",
114 "bios.bin")
115 if self.soc.integrated_rom_size:
116 with open(bios_file, "rb") as boot_file:
117 boot_data = []
118 while True:
119 w = boot_file.read(4)
120 if not w:
121 break
122 boot_data.append(struct.unpack(">I", w)[0])
123 self.soc.initialize_rom(boot_data)
124
125 def build(self):
126 self.soc.finalize()
127
128 if self.soc.integrated_rom_size and not self.compile_software:
129 raise ValueError("Software must be compiled in order to "
130 "intitialize integrated ROM")
131
132 self._generate_includes()
133 self._generate_software()
134 self._initialize_rom()
135 if self.gateware_toolchain_path is None:
136 kwargs = dict()
137 else:
138 kwargs = {"toolchain_path": self.gateware_toolchain_path}
139 self.soc.build(build_dir=os.path.join(self.output_dir, "gateware"),
140 run=self.compile_gateware, **kwargs)
141
142
143 def builder_args(parser):
144 parser.add_argument("--output-dir", default=None,
145 help="output directory for generated "
146 "source files and binaries")
147 parser.add_argument("--no-compile-software", action="store_true",
148 help="do not compile the software, only generate "
149 "build infrastructure")
150 parser.add_argument("--no-compile-gateware", action="store_true",
151 help="do not compile the gateware, only generate "
152 "HDL source files and build scripts")
153 parser.add_argument("--gateware-toolchain-path", default=None,
154 help="set gateware toolchain (ISE, Quartus, etc.) "
155 "installation path")
156 parser.add_argument("--csr-csv", default=None,
157 help="store CSR map in CSV format into the "
158 "specified file")
159
160
161 def builder_argdict(args):
162 return {
163 "output_dir": args.output_dir,
164 "compile_software": not args.no_compile_software,
165 "compile_gateware": not args.no_compile_gateware,
166 "gateware_toolchain_path": args.gateware_toolchain_path,
167 "csr_csv": args.csr_csv
168 }