Fix generating csr.csv file
[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_sdram, sdram_init
8
9
10 __all__ = ["soc_software_packages", "soc_directory",
11 "Builder", "builder_args", "builder_argdict"]
12
13
14 soc_software_packages = [
15 "libcompiler_rt",
16 "libbase",
17 "libnet",
18 "bios"
19 ]
20
21
22 soc_directory = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
23
24
25 def _makefile_escape(s):
26 return s.replace("\\", "\\\\")
27
28
29 class Builder:
30 def __init__(self, soc, output_dir=None,
31 compile_software=True, compile_gateware=True,
32 gateware_toolchain_path=None,
33 csr_csv=None):
34 self.soc = soc
35 if output_dir is None:
36 output_dir = "soc_{}_{}".format(
37 soc.__class__.__name__.lower(),
38 soc.platform.name)
39 # From Python doc: makedirs() will become confused if the path
40 # elements to create include '..'
41 self.output_dir = os.path.abspath(output_dir)
42 self.compile_software = compile_software
43 self.compile_gateware = compile_gateware
44 self.gateware_toolchain_path = gateware_toolchain_path
45 self.csr_csv = csr_csv
46
47 self.software_packages = []
48 for name in soc_software_packages:
49 self.add_software_package(name)
50
51 def add_software_package(self, name, src_dir=None):
52 if src_dir is None:
53 src_dir = os.path.join(soc_directory, "software", name)
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
71 variables_contents = []
72 def define(k, v):
73 variables_contents.append("{}={}\n".format(k, _makefile_escape(v)))
74 for k, v in cpu_interface.get_cpu_mak(cpu_type):
75 define(k, v)
76 define("SOC_DIRECTORY", soc_directory)
77 variables_contents.append("export BUILDINC_DIRECTORY\n")
78 define("BUILDINC_DIRECTORY", buildinc_dir)
79 for name, src_dir in self.software_packages:
80 define(name.upper() + "_DIRECTORY", src_dir)
81 write_to_file(
82 os.path.join(generated_dir, "variables.mak"),
83 "".join(variables_contents))
84
85 write_to_file(
86 os.path.join(generated_dir, "output_format.ld"),
87 cpu_interface.get_linker_output_format(cpu_type))
88 write_to_file(
89 os.path.join(generated_dir, "regions.ld"),
90 cpu_interface.get_linker_regions(memory_regions))
91
92 write_to_file(
93 os.path.join(generated_dir, "mem.h"),
94 cpu_interface.get_mem_header(memory_regions, flash_boot_address))
95 write_to_file(
96 os.path.join(generated_dir, "csr.h"),
97 cpu_interface.get_csr_header(csr_regions, constants))
98
99 if sdram_phy_settings is not None:
100 write_to_file(
101 os.path.join(generated_dir, "sdram_phy.h"),
102 sdram_init.get_sdram_phy_header(sdram_phy_settings))
103
104 def _generate_csr_csv(self):
105 memory_regions = self.soc.get_memory_regions()
106 csr_regions = self.soc.get_csr_regions()
107 constants = self.soc.get_constants()
108
109 csr_dir = os.path.dirname(os.path.realpath(self.csr_csv))
110 os.makedirs(csr_dir, exist_ok=True)
111 write_to_file(
112 self.csr_csv,
113 cpu_interface.get_csr_csv(csr_regions, constants, memory_regions))
114
115 def _prepare_software(self):
116 for name, src_dir in self.software_packages:
117 dst_dir = os.path.join(self.output_dir, "software", name)
118 os.makedirs(dst_dir, exist_ok=True)
119
120 def _generate_software(self, compile_bios=True):
121 for name, src_dir in self.software_packages:
122 if name == "bios" and not compile_bios:
123 pass
124 else:
125 dst_dir = os.path.join(self.output_dir, "software", name)
126 makefile = os.path.join(src_dir, "Makefile")
127 if self.compile_software:
128 subprocess.check_call(["make", "-C", dst_dir, "-f", makefile])
129
130 def _initialize_rom(self):
131 bios_file = os.path.join(self.output_dir, "software", "bios",
132 "bios.bin")
133 endianness = cpu_interface.cpu_endianness[self.soc.cpu_type]
134 with open(bios_file, "rb") as boot_file:
135 boot_data = []
136 while True:
137 w = boot_file.read(4)
138 if not w:
139 break
140 if endianness == 'little':
141 boot_data.append(struct.unpack("<I", w)[0])
142 else:
143 boot_data.append(struct.unpack(">I", w)[0])
144 self.soc.initialize_rom(boot_data)
145
146 def build(self, toolchain_path=None, **kwargs):
147 self.soc.finalize()
148
149 os.makedirs(self.output_dir, exist_ok=True)
150
151 if self.soc.cpu_type is not None:
152 self._prepare_software()
153 self._generate_includes()
154 self._generate_software(not self.soc.integrated_rom_initialized)
155 if self.soc.integrated_rom_size and self.compile_software:
156 if not self.soc.integrated_rom_initialized:
157 self._initialize_rom()
158
159 if self.csr_csv is not None:
160 self._generate_csr_csv()
161
162 if self.gateware_toolchain_path is not None:
163 toolchain_path = self.gateware_toolchain_path
164
165 if "run" not in kwargs:
166 kwargs["run"] = self.compile_gateware
167 vns = self.soc.build(build_dir=os.path.join(self.output_dir, "gateware"),
168 toolchain_path=toolchain_path, **kwargs)
169 return vns
170
171
172 def builder_args(parser):
173 parser.add_argument("--output-dir", default=None,
174 help="output directory for generated "
175 "source files and binaries")
176 parser.add_argument("--no-compile-software", action="store_true",
177 help="do not compile the software, only generate "
178 "build infrastructure")
179 parser.add_argument("--no-compile-gateware", action="store_true",
180 help="do not compile the gateware, only generate "
181 "HDL source files and build scripts")
182 parser.add_argument("--gateware-toolchain-path", default=None,
183 help="set gateware toolchain (ISE, Quartus, etc.) "
184 "installation path")
185 parser.add_argument("--csr-csv", default=None,
186 help="store CSR map in CSV format into the "
187 "specified file")
188
189
190 def builder_argdict(args):
191 return {
192 "output_dir": args.output_dir,
193 "compile_software": not args.no_compile_software,
194 "compile_gateware": not args.no_compile_gateware,
195 "gateware_toolchain_path": args.gateware_toolchain_path,
196 "csr_csv": args.csr_csv
197 }