From 576b96ba839ff86c7a32e69aae7aa9ee58f9175d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 19 Jan 2022 19:32:57 +0100 Subject: [PATCH 1/5] cores/cpu: Switch to automatic CPUs collection. Simplify code/maintenance and will also enable out-of-tree CPUs support. --- litex/soc/cores/cpu/__init__.py | 116 +++++++++++--------------------- 1 file changed, 40 insertions(+), 76 deletions(-) diff --git a/litex/soc/cores/cpu/__init__.py b/litex/soc/cores/cpu/__init__.py index 76ebeb116..76f64a8cb 100644 --- a/litex/soc/cores/cpu/__init__.py +++ b/litex/soc/cores/cpu/__init__.py @@ -1,10 +1,14 @@ # # This file is part of LiteX. # -# Copyright (c) 2015-2020 Florent Kermarrec +# Copyright (c) 2015-2022 Florent Kermarrec # Copyright (c) 2017-2018 Tim 'mithro' Ansell # SPDX-License-Identifier: BSD-2-Clause +import os +import inspect +import importlib + from migen import * # CPU ---------------------------------------------------------------------------------------------- @@ -30,14 +34,14 @@ class CPU(Module): pass class CPUNone(CPU): - variants = ["standard"] - data_width = 32 - endianness = "little" - reset_address = 0x00000000 - io_regions = {0x00000000: 0x100000000} # origin, length - periph_buses = [] - memory_buses = [] - mem_map = { + variants = ["standard"] + data_width = 32 + endianness = "little" + reset_address = 0x00000000 + io_regions = {0x00000000: 0x100000000} # origin, length + periph_buses = [] + memory_buses = [] + mem_map = { "csr" : 0x00000000, "ethmac" : 0x00020000, # FIXME: Remove. "spiflash" : 0x10000000, # FIXME: Remove. @@ -70,76 +74,36 @@ CPU_GCC_TRIPLE_RISCV64 = ( # CPUS --------------------------------------------------------------------------------------------- -# LM32 -from litex.soc.cores.cpu.lm32 import LM32 +def collect_cpus(): + cpus = { + # None. + "None" : CPUNone, + # External (CPU class provided externally by design/user) + "external" : None, + } + path = os.path.dirname(__file__) -# OpenRisc -from litex.soc.cores.cpu.mor1kx import MOR1KX -from litex.soc.cores.cpu.marocchino import Marocchino + # Search for CPUs in cpu directory. + for file in os.listdir(path): -# OpenPower -from litex.soc.cores.cpu.microwatt import Microwatt + # Verify that it's a path... + cpu_path = os.path.join(os.path.dirname(__file__), file) + if not os.path.isdir(cpu_path): + continue -# RISC-V (32-bit) -from litex.soc.cores.cpu.serv import SERV -from litex.soc.cores.cpu.femtorv import FemtoRV -from litex.soc.cores.cpu.picorv32 import PicoRV32 -from litex.soc.cores.cpu.minerva import Minerva -from litex.soc.cores.cpu.vexriscv import VexRiscv -from litex.soc.cores.cpu.vexriscv_smp import VexRiscvSMP -from litex.soc.cores.cpu.ibex import Ibex -from litex.soc.cores.cpu.cv32e40p import CV32E40P + # ... and that core.py is present. + cpu_core = os.path.join(cpu_path, "core.py") + if not os.path.exists(cpu_core): + continue -# RISC-V (64-bit) -from litex.soc.cores.cpu.rocket import RocketRV64 -from litex.soc.cores.cpu.blackparrot import BlackParrotRV64 + # OK, it seems to be a CPU; now get the class and add it to dict. + cpu = file + cpu_module = f"litex.soc.cores.cpu.{cpu}.core" + for cpu_name, cpu_cls in inspect.getmembers(importlib.import_module(cpu_module), inspect.isclass): + if cpu.replace("_", "") == cpu_name.lower(): + cpus[cpu] = cpu_cls -# Zynq -from litex.soc.cores.cpu.zynq7000 import Zynq7000 + # Return collected CPUs. + return cpus -# EOS-S3 -from litex.soc.cores.cpu.eos_s3 import EOS_S3 - -# Gowin EMCU -from litex.soc.cores.cpu.gowin_emcu import GowinEMCU - -CPUS = { - # None - "None" : CPUNone, - - # External (CPU class provided externally by design/user) - "external" : None, - - # LM32 - "lm32" : LM32, - - # OpenRisc - "mor1kx" : MOR1KX, - "marocchino" : Marocchino, - - # OpenPower - "microwatt" : Microwatt, - - # RISC-V (32-bit) - "serv" : SERV, - "femtorv" : FemtoRV, - "picorv32" : PicoRV32, - "minerva" : Minerva, - "vexriscv" : VexRiscv, - "vexriscv_smp": VexRiscvSMP, - "ibex" : Ibex, - "cv32e40p" : CV32E40P, - - # RISC-V (64-bit) - "rocket" : RocketRV64, - "blackparrot" : BlackParrotRV64, - - # Zynq - "zynq7000" : Zynq7000, - - # EOS-S3 - "eos_s3" : EOS_S3, - - # Gowin EMCU - 'gowin_emcu' : GowinEMCU -} +CPUS = collect_cpus() From ba142121292fb88a994b7cf535c7bb6a346ebe85 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jan 2022 08:49:58 +0100 Subject: [PATCH 2/5] cores/cpu: Avoid duplication between CPU_GCC_TRIPLE_RISCV64/CPU_GCC_TRIPLE_RISCV32, CPU_GCC_TRIPLE_RISCV32 is just an extension of CPU_GCC_TRIPLE_RISCV64. --- litex/soc/cores/cpu/__init__.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/litex/soc/cores/cpu/__init__.py b/litex/soc/cores/cpu/__init__.py index 76f64a8cb..58bf5013b 100644 --- a/litex/soc/cores/cpu/__init__.py +++ b/litex/soc/cores/cpu/__init__.py @@ -47,21 +47,6 @@ class CPUNone(CPU): "spiflash" : 0x10000000, # FIXME: Remove. } -CPU_GCC_TRIPLE_RISCV32 = ( - "riscv64-unknown-elf", - "riscv64-unknown-linux-gnu", - "riscv32-unknown-elf", - "riscv32-unknown-linux-gnu", - "riscv64-elf", - "riscv32-elf", - "riscv-none-embed", - "riscv-none-elf", - "riscv64-linux", - "riscv64-linux-gnu", - "riscv-sifive-elf", - "riscv64-none-elf", -) - CPU_GCC_TRIPLE_RISCV64 = ( "riscv64-unknown-elf", "riscv64-unknown-linux-gnu", @@ -72,6 +57,14 @@ CPU_GCC_TRIPLE_RISCV64 = ( "riscv64-none-elf", ) +CPU_GCC_TRIPLE_RISCV32 = CPU_GCC_TRIPLE_RISCV64 + ( + "riscv32-unknown-elf", + "riscv32-unknown-linux-gnu", + "riscv32-elf", + "riscv-none-embed", + "riscv-none-elf", +) + # CPUS --------------------------------------------------------------------------------------------- def collect_cpus(): From c675acb868d44d7b46dc88515206723376e8fa23 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jan 2022 09:18:10 +0100 Subject: [PATCH 3/5] cores/cpu: Add out-of-tree CPUs support (By searching CPUs in execution directory). --- litex/soc/cores/cpu/__init__.py | 44 ++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/litex/soc/cores/cpu/__init__.py b/litex/soc/cores/cpu/__init__.py index 58bf5013b..c86a7fff5 100644 --- a/litex/soc/cores/cpu/__init__.py +++ b/litex/soc/cores/cpu/__init__.py @@ -6,6 +6,7 @@ # SPDX-License-Identifier: BSD-2-Clause import os +import sys import inspect import importlib @@ -74,27 +75,36 @@ def collect_cpus(): # External (CPU class provided externally by design/user) "external" : None, } - path = os.path.dirname(__file__) + paths = [ + # Add litex.soc.cores.cpu path. + os.path.dirname(__file__), + # Add execution path. + os.getcwd() + ] - # Search for CPUs in cpu directory. - for file in os.listdir(path): + exec_dir = os.getcwd() - # Verify that it's a path... - cpu_path = os.path.join(os.path.dirname(__file__), file) - if not os.path.isdir(cpu_path): - continue + # Search for CPUs in paths. + for path in paths: + for file in os.listdir(path): - # ... and that core.py is present. - cpu_core = os.path.join(cpu_path, "core.py") - if not os.path.exists(cpu_core): - continue + # Verify that it's a path... + cpu_path = os.path.join(path, file) + if not os.path.isdir(cpu_path): + continue - # OK, it seems to be a CPU; now get the class and add it to dict. - cpu = file - cpu_module = f"litex.soc.cores.cpu.{cpu}.core" - for cpu_name, cpu_cls in inspect.getmembers(importlib.import_module(cpu_module), inspect.isclass): - if cpu.replace("_", "") == cpu_name.lower(): - cpus[cpu] = cpu_cls + # ... and that core.py is present. + cpu_core = os.path.join(cpu_path, "core.py") + if not os.path.exists(cpu_core): + continue + + # OK, it seems to be a CPU; now get the class and add it to dict. + cpu = file + cpu_module = f"{cpu}" + sys.path.append(path) + for cpu_name, cpu_cls in inspect.getmembers(importlib.import_module(cpu_module), inspect.isclass): + if cpu.replace("_", "") == cpu_name.lower(): + cpus[cpu] = cpu_cls # Return collected CPUs. return cpus From bdc22770e97e9e7b5b64ea1a7a1caac6095f6131 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jan 2022 09:25:39 +0100 Subject: [PATCH 4/5] cores/cpu: Deprecate external CPU class support (advantageously replaced by out-of-tree support which is more flexible). --- litex/soc/cores/cpu/__init__.py | 7 +------ litex/soc/integration/soc.py | 9 ++------- litex/soc/integration/soc_core.py | 3 --- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/litex/soc/cores/cpu/__init__.py b/litex/soc/cores/cpu/__init__.py index c86a7fff5..611ead38b 100644 --- a/litex/soc/cores/cpu/__init__.py +++ b/litex/soc/cores/cpu/__init__.py @@ -69,12 +69,7 @@ CPU_GCC_TRIPLE_RISCV32 = CPU_GCC_TRIPLE_RISCV64 + ( # CPUS --------------------------------------------------------------------------------------------- def collect_cpus(): - cpus = { - # None. - "None" : CPUNone, - # External (CPU class provided externally by design/user) - "external" : None, - } + cpus = {"None" : CPUNone} paths = [ # Add litex.soc.cores.cpu path. os.path.dirname(__file__), diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 734898b8b..3ef6a7186 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -884,7 +884,7 @@ class SoC(Module): self.add_config("CSR_DATA_WIDTH", self.csr.data_width) self.add_config("CSR_ALIGNMENT", self.csr.alignment) - def add_cpu(self, name="vexriscv", variant="standard", cls=None, reset_address=None, cfu=None): + def add_cpu(self, name="vexriscv", variant="standard", reset_address=None, cfu=None): # Check that CPU is supported. if name not in cpu.CPUS.keys(): self.logger.error("{} CPU {}, supporteds: {}.".format( @@ -894,12 +894,7 @@ class SoC(Module): raise SoCError() # Add CPU. - if name == "external" and cls is None: - self.logger.error("{} CPU requires {} to be specified.".format( - colorer(name), - colorer("cpu_cls", color="red"))) - raise SoCError() - cpu_cls = cls if cls is not None else cpu.CPUS[name] + cpu_cls = cpu.CPUS[name] if (variant not in cpu_cls.variants) and (cpu_cls is not cpu.CPUNone): self.logger.error("{} CPU variant {}, supporteds: {}.".format( colorer(variant), diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index 3802f20c5..6aaae1e0f 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -69,7 +69,6 @@ class SoCCore(LiteXSoC): cpu_type = "vexriscv", cpu_reset_address = None, cpu_variant = None, - cpu_cls = None, cpu_cfu = None, # CFU parameters @@ -149,7 +148,6 @@ class SoCCore(LiteXSoC): self.cpu_type = cpu_type self.cpu_variant = cpu_variant - self.cpu_cls = cpu_cls # ROM. # Initialize ROM from binary file when provided. @@ -187,7 +185,6 @@ class SoCCore(LiteXSoC): name = str(cpu_type), variant = "standard" if cpu_variant is None else cpu_variant, reset_address = None if integrated_rom_size else cpu_reset_address, - cls = cpu_cls, cfu = cpu_cfu) # Add User's interrupts From 681f474c660606512c6b1055e568c4dded899382 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jan 2022 09:25:49 +0100 Subject: [PATCH 5/5] CHANGEs: Update. --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index b859ff84e..e0c13c942 100644 --- a/CHANGES +++ b/CHANGES @@ -20,11 +20,13 @@ - cpu/eos_s3: Add LiteX BIOS/Bare Metal software support. - litex_sim: Add .json support for --rom/ram/sdram-init. - soc/add_uart: Allow multiple UARTs in the same design. + - cores/cpu: Add out-of-tree support. [> API changes/Deprecation -------------------------- - Fully deprecate SoCSDRAM/SPIFlash core (replaced by LiteSPI). - UART "bridge" name deprecated in favor of "crossover" (already supported). + - "external" CPU class support deprecated (replaced by out-of-tree support). [> 2021.12, released on January 5th 2022 ----------------------------------------