core/cpu: integrate Zynq as a classical CPU (Zynq7000), deprecate SoCZynq.
[litex.git] / litex / soc / integration / builder.py
index 45bfd4ae6f80f30221bbe05b51bc63259ead77d5..2648e4b0d042ece12a8d541ef74a4de7596e9a4d 100644 (file)
@@ -1,21 +1,40 @@
+# This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
+# This file is Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
+# This file is Copyright (c) 2018-2019 Antmicro <www.antmicro.com>
+# This file is Copyright (c) 2018 Sergiusz Bazanski <q3k@q3k.org>
+# This file is Copyright (c) 2016-2017 Tim 'mithro' Ansell <mithro@mithis.com>
+# This file is Copyright (c) 2018 William D. Jones <thor0505@comcast.net>
+# This file is Copyright (c) 2020 Xiretza <xiretza@xiretza.xyz>
+# This file is Copyright (c) 2020 Piotr Esden-Tempski <piotr@esden.net>
+# License: BSD
+
+
 import os
 import subprocess
 import struct
 import shutil
 
+from litex import get_data_mod
 from litex.build.tools import write_to_file
-from litex.soc.integration import cpu_interface, soc_sdram
-
-from litedram import sdram_init
-
-__all__ = ["soc_software_packages", "soc_directory",
-           "Builder", "builder_args", "builder_argdict"]
+from litex.soc.integration import export, soc_core
+from litex.soc.cores import cpu
+
+__all__ = [
+    "soc_software_packages",
+    "soc_directory",
+    "Builder",
+    "builder_args",
+    "builder_argdict"
+]
 
 
 soc_software_packages = [
     "libcompiler_rt",
     "libbase",
-    "libnet",
+    "liblitedram",
+    "libliteeth",
+    "liblitespi",
+    "liblitesdcard",
     "bios"
 ]
 
@@ -28,22 +47,35 @@ def _makefile_escape(s):
 
 
 class Builder:
-    def __init__(self, soc, output_dir=None,
-                 compile_software=True, compile_gateware=True,
-                 gateware_toolchain_path=None,
-                 csr_csv=None):
+    def __init__(self, soc,
+        output_dir       = None,
+        gateware_dir     = None,
+        software_dir     = None,
+        include_dir      = None,
+        generated_dir    = None,
+        compile_software = True,
+        compile_gateware = True,
+        csr_json         = None,
+        csr_csv          = None,
+        csr_svd          = None,
+        memory_x         = None,
+        bios_options     = None):
         self.soc = soc
-        if output_dir is None:
-            output_dir = "soc_{}_{}".format(
-                soc.__class__.__name__.lower(),
-                soc.platform.name)
-        # From Python doc: makedirs() will become confused if the path
-        # elements to create include '..'
-        self.output_dir = os.path.abspath(output_dir)
+
+        # From Python doc: makedirs() will become confused if the path elements to create include '..'
+        self.output_dir    = os.path.abspath(output_dir    or os.path.join("build", soc.platform.name))
+        self.gateware_dir  = os.path.abspath(gateware_dir  or os.path.join(self.output_dir,   "gateware"))
+        self.software_dir  = os.path.abspath(software_dir  or os.path.join(self.output_dir,   "software"))
+        self.include_dir   = os.path.abspath(include_dir   or os.path.join(self.software_dir, "include"))
+        self.generated_dir = os.path.abspath(generated_dir or os.path.join(self.include_dir,  "generated"))
+
         self.compile_software = compile_software
         self.compile_gateware = compile_gateware
-        self.gateware_toolchain_path = gateware_toolchain_path
-        self.csr_csv = csr_csv
+        self.csr_csv  = csr_csv
+        self.csr_json = csr_json
+        self.csr_svd  = csr_svd
+        self.memory_x = memory_x
+        self.bios_options = bios_options
 
         self.software_packages = []
         for name in soc_software_packages:
@@ -55,143 +87,176 @@ class Builder:
         self.software_packages.append((name, src_dir))
 
     def _generate_includes(self):
-        cpu_type = self.soc.cpu_type
-        cpu_variant = self.soc.cpu_variant
-        memory_regions = self.soc.get_memory_regions()
-        flash_boot_address = getattr(self.soc, "flash_boot_address", None)
-        csr_regions = self.soc.get_csr_regions()
-        constants = self.soc.get_constants()
-
-        buildinc_dir = os.path.join(self.output_dir, "software", "include")
-        generated_dir = os.path.join(buildinc_dir, "generated")
-        os.makedirs(generated_dir, exist_ok=True)
-
-        variables_contents = []
-        def define(k, v):
-            variables_contents.append("{}={}\n".format(k, _makefile_escape(v)))
-        for k, v in cpu_interface.get_cpu_mak(cpu_type, cpu_variant):
-            define(k, v)
-        define("SOC_DIRECTORY", soc_directory)
-        variables_contents.append("export BUILDINC_DIRECTORY\n")
-        define("BUILDINC_DIRECTORY", buildinc_dir)
-        for name, src_dir in self.software_packages:
-            define(name.upper() + "_DIRECTORY", src_dir)
-        write_to_file(
-            os.path.join(generated_dir, "variables.mak"),
-            "".join(variables_contents))
+        os.makedirs(self.include_dir, exist_ok=True)
+        os.makedirs(self.generated_dir, exist_ok=True)
+
+        if self.soc.cpu_type not in [None, "zynq7000"]:
+            variables_contents = []
+            def define(k, v):
+                variables_contents.append("{}={}\n".format(k, _makefile_escape(v)))
+
+            for k, v in export.get_cpu_mak(self.soc.cpu, self.compile_software):
+                define(k, v)
+            define(
+                "COMPILER_RT_DIRECTORY",
+                get_data_mod("software", "compiler_rt").data_location)
+            define("SOC_DIRECTORY", soc_directory)
+            variables_contents.append("export BUILDINC_DIRECTORY\n")
+            define("BUILDINC_DIRECTORY", self.include_dir)
+            for name, src_dir in self.software_packages:
+                define(name.upper() + "_DIRECTORY", src_dir)
+
+            if self.bios_options is not None:
+                for option in self.bios_options:
+                    define(option, "1")
+
+            write_to_file(
+                os.path.join(self.generated_dir, "variables.mak"),
+                "".join(variables_contents))
+            write_to_file(
+                os.path.join(self.generated_dir, "output_format.ld"),
+                export.get_linker_output_format(self.soc.cpu))
+            write_to_file(
+                os.path.join(self.generated_dir, "regions.ld"),
+                export.get_linker_regions(self.soc.mem_regions))
 
         write_to_file(
-            os.path.join(generated_dir, "output_format.ld"),
-            cpu_interface.get_linker_output_format(cpu_type))
+            os.path.join(self.generated_dir, "mem.h"),
+            export.get_mem_header(self.soc.mem_regions))
         write_to_file(
-            os.path.join(generated_dir, "regions.ld"),
-            cpu_interface.get_linker_regions(memory_regions))
-
+            os.path.join(self.generated_dir, "soc.h"),
+            export.get_soc_header(self.soc.constants))
         write_to_file(
-            os.path.join(generated_dir, "mem.h"),
-            cpu_interface.get_mem_header(memory_regions, flash_boot_address))
+            os.path.join(self.generated_dir, "csr.h"),
+            export.get_csr_header(
+                regions   = self.soc.csr_regions,
+                constants = self.soc.constants,
+                csr_base  = self.soc.mem_regions['csr'].origin
+            )
+        )
         write_to_file(
-            os.path.join(generated_dir, "csr.h"),
-            cpu_interface.get_csr_header(csr_regions, constants))
-
-        if isinstance(self.soc, soc_sdram.SoCSDRAM):
-            write_to_file(
-                os.path.join(generated_dir, "sdram_phy.h"),
-                sdram_init.get_sdram_phy_c_header(
+            os.path.join(self.generated_dir, "git.h"),
+            export.get_git_header()
+        )
+
+        if hasattr(self.soc, "sdram"):
+            from litedram.init import get_sdram_phy_c_header
+            write_to_file(os.path.join(self.generated_dir, "sdram_phy.h"),
+                get_sdram_phy_c_header(
                     self.soc.sdram.controller.settings.phy,
                     self.soc.sdram.controller.settings.timing))
 
-    def _generate_csr_csv(self):
-        memory_regions = self.soc.get_memory_regions()
-        csr_regions = self.soc.get_csr_regions()
-        constants = self.soc.get_constants()
-
-        csr_dir = os.path.dirname(os.path.realpath(self.csr_csv))
-        os.makedirs(csr_dir, exist_ok=True)
-        write_to_file(
-            self.csr_csv,
-            cpu_interface.get_csr_csv(csr_regions, constants, memory_regions))
+    def _generate_csr_map(self):
+        if self.csr_json is not None:
+            csr_dir = os.path.dirname(os.path.realpath(self.csr_json))
+            os.makedirs(csr_dir, exist_ok=True)
+            write_to_file(self.csr_json, export.get_csr_json(self.soc.csr_regions, self.soc.constants, self.soc.mem_regions))
 
-    def _prepare_software(self):
+        if self.csr_csv is not None:
+            csr_dir = os.path.dirname(os.path.realpath(self.csr_csv))
+            os.makedirs(csr_dir, exist_ok=True)
+            write_to_file(self.csr_csv, export.get_csr_csv(self.soc.csr_regions, self.soc.constants, self.soc.mem_regions))
+
+        if self.csr_svd is not None:
+            svd_dir = os.path.dirname(os.path.realpath(self.csr_svd))
+            os.makedirs(svd_dir, exist_ok=True)
+            write_to_file(self.csr_svd, export.get_csr_svd(self.soc))
+
+    def _generate_mem_region_map(self):
+        if self.memory_x is not None:
+            memory_x_dir = os.path.dirname(os.path.realpath(self.memory_x))
+            os.makedirs(memory_x_dir, exist_ok=True)
+            write_to_file(self.memory_x, export.get_memory_x(self.soc))
+
+    def _prepare_rom_software(self):
         for name, src_dir in self.software_packages:
-            dst_dir = os.path.join(self.output_dir, "software", name)
+            dst_dir = os.path.join(self.software_dir, name)
             os.makedirs(dst_dir, exist_ok=True)
 
-    def _generate_software(self, compile_bios=True):
+    def _generate_rom_software(self, compile_bios=True):
          for name, src_dir in self.software_packages:
             if name == "bios" and not compile_bios:
                 pass
             else:
-                dst_dir = os.path.join(self.output_dir, "software", name)
+                dst_dir = os.path.join(self.software_dir, name)
                 makefile = os.path.join(src_dir, "Makefile")
                 if self.compile_software:
                     subprocess.check_call(["make", "-C", dst_dir, "-f", makefile])
 
-    def _initialize_rom(self):
-        bios_file = os.path.join(self.output_dir, "software", "bios",
-                                 "bios.bin")
-        endianness =  cpu_interface.cpu_endianness[self.soc.cpu_type]
-        with open(bios_file, "rb") as boot_file:
-            boot_data = []
-            while True:
-                w = boot_file.read(4)
-                if not w:
-                    break
-                if endianness == 'little':
-                    boot_data.append(struct.unpack("<I", w)[0])
-                else:
-                    boot_data.append(struct.unpack(">I", w)[0])
-        self.soc.initialize_rom(boot_data)
-
-    def build(self, toolchain_path=None, **kwargs):
-        self.soc.finalize()
-
-        os.makedirs(self.output_dir, exist_ok=True)
+    def _initialize_rom_software(self):
+        bios_file = os.path.join(self.software_dir, "bios", "bios.bin")
+        bios_data = soc_core.get_mem_data(bios_file, self.soc.cpu.endianness)
+        self.soc.initialize_rom(bios_data)
 
-        if self.soc.cpu_type is not None:
-            self._prepare_software()
-            self._generate_includes()
-            self._generate_software(not self.soc.integrated_rom_initialized)
-            if self.soc.integrated_rom_size and self.compile_software:
-                if not self.soc.integrated_rom_initialized:
-                    self._initialize_rom()
+    def build(self, **kwargs):
+        self.soc.platform.output_dir = self.output_dir
+        os.makedirs(self.gateware_dir, exist_ok=True)
+        os.makedirs(self.software_dir, exist_ok=True)
 
-        if self.csr_csv is not None:
-            self._generate_csr_csv()
+        self.soc.finalize()
 
-        if self.gateware_toolchain_path is not None:
-            toolchain_path = self.gateware_toolchain_path
+        self._generate_includes()
+        self._generate_csr_map()
+        self._generate_mem_region_map()
+        if self.soc.cpu_type is not None:
+            if self.soc.cpu.use_rom:
+                self._prepare_rom_software()
+                self._generate_rom_software(not self.soc.integrated_rom_initialized)
+                if self.soc.integrated_rom_size and self.compile_software:
+                    if not self.soc.integrated_rom_initialized:
+                        self._initialize_rom_software()
 
         if "run" not in kwargs:
             kwargs["run"] = self.compile_gateware
-        vns = self.soc.build(build_dir=os.path.join(self.output_dir, "gateware"),
-                             toolchain_path=toolchain_path, **kwargs)
+        vns = self.soc.build(build_dir=self.gateware_dir, **kwargs)
+        self.soc.do_exit(vns=vns)
         return vns
 
 
 def builder_args(parser):
     parser.add_argument("--output-dir", default=None,
-                        help="output directory for generated "
-                             "source files and binaries")
+                        help="base output directory for generated "
+                             "source files and binaries (customizable "
+                             "with --{gateware,software,include,generated}-dir)")
+    parser.add_argument("--gateware-dir", default=None,
+                        help="output directory for gateware files")
+    parser.add_argument("--software-dir", default=None,
+                        help="base output directory for software files")
+    parser.add_argument("--include-dir", default=None,
+                        help="output directory for header files")
+    parser.add_argument("--generated-dir", default=None,
+                        help="output directory for various generated files")
     parser.add_argument("--no-compile-software", action="store_true",
                         help="do not compile the software, only generate "
                              "build infrastructure")
     parser.add_argument("--no-compile-gateware", action="store_true",
                         help="do not compile the gateware, only generate "
                              "HDL source files and build scripts")
-    parser.add_argument("--gateware-toolchain-path", default=None,
-                        help="set gateware toolchain (ISE, Quartus, etc.) "
-                             "installation path")
     parser.add_argument("--csr-csv", default=None,
                         help="store CSR map in CSV format into the "
                              "specified file")
+    parser.add_argument("--csr-json", default=None,
+                        help="store CSR map in JSON format into the "
+                             "specified file")
+    parser.add_argument("--csr-svd", default=None,
+                        help="store CSR map in SVD format into the "
+                             "specified file")
+    parser.add_argument("--memory-x", default=None,
+                        help="store Mem regions in memory-x format into the "
+                             "specified file")
 
 
 def builder_argdict(args):
     return {
-        "output_dir": args.output_dir,
+        "output_dir":       args.output_dir,
+        "gateware_dir":     args.gateware_dir,
+        "software_dir":     args.software_dir,
+        "include_dir":      args.include_dir,
+        "generated_dir":    args.generated_dir,
         "compile_software": not args.no_compile_software,
         "compile_gateware": not args.no_compile_gateware,
-        "gateware_toolchain_path": args.gateware_toolchain_path,
-        "csr_csv": args.csr_csv
+        "csr_csv":          args.csr_csv,
+        "csr_json":         args.csr_json,
+        "csr_svd":          args.csr_svd,
+        "memory_x":         args.memory_x,
     }