From 5ef869b9ebdcbfbe037e1fee6a06866a2837a168 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 27 Apr 2020 23:51:17 +0200 Subject: [PATCH] soc/cpu: add memory_buses to cpus and use them in add_sdram. This allows the CPU to have direct buses to the memory and replace the Rocket specific code. --- litex/soc/cores/cpu/__init__.py | 2 + litex/soc/cores/cpu/blackparrot/core.py | 1 + litex/soc/cores/cpu/lm32/core.py | 1 + litex/soc/cores/cpu/microwatt/core.py | 1 + litex/soc/cores/cpu/minerva/core.py | 3 +- litex/soc/cores/cpu/mor1kx/core.py | 4 +- litex/soc/cores/cpu/picorv32/core.py | 5 +- litex/soc/cores/cpu/rocket/core.py | 1 + litex/soc/cores/cpu/serv/core.py | 1 + litex/soc/cores/cpu/vexriscv/core.py | 9 ++- litex/soc/integration/soc.py | 96 +++++++++++++++---------- 11 files changed, 81 insertions(+), 43 deletions(-) diff --git a/litex/soc/cores/cpu/__init__.py b/litex/soc/cores/cpu/__init__.py index d0b11a50..21f7ce5d 100644 --- a/litex/soc/cores/cpu/__init__.py +++ b/litex/soc/cores/cpu/__init__.py @@ -26,6 +26,8 @@ class CPUNone(CPU): data_width = 32 reset_address = 0x00000000 io_regions = {0x00000000: 0x100000000} # origin, length + periph_buses = [] + memory_buses = [] # CPUS --------------------------------------------------------------------------------------------- diff --git a/litex/soc/cores/cpu/blackparrot/core.py b/litex/soc/cores/cpu/blackparrot/core.py index fe220cf2..6b186947 100644 --- a/litex/soc/cores/cpu/blackparrot/core.py +++ b/litex/soc/cores/cpu/blackparrot/core.py @@ -79,6 +79,7 @@ class BlackParrotRV64(CPU): self.interrupt = Signal(4) self.idbus = idbus = wishbone.Interface(data_width=64, adr_width=37) self.periph_buses = [idbus] + self.memory_buses = [] # # # diff --git a/litex/soc/cores/cpu/lm32/core.py b/litex/soc/cores/cpu/lm32/core.py index e1b6bce3..b05e1ede 100644 --- a/litex/soc/cores/cpu/lm32/core.py +++ b/litex/soc/cores/cpu/lm32/core.py @@ -41,6 +41,7 @@ class LM32(CPU): self.dbus = d = wishbone.Interface() self.interrupt = Signal(32) self.periph_buses = [i, d] + self.memory_buses = [] # # # diff --git a/litex/soc/cores/cpu/microwatt/core.py b/litex/soc/cores/cpu/microwatt/core.py index 17b6e3ea..b951959b 100644 --- a/litex/soc/cores/cpu/microwatt/core.py +++ b/litex/soc/cores/cpu/microwatt/core.py @@ -47,6 +47,7 @@ class Microwatt(CPU): self.wb_insn = wb_insn = wishbone.Interface(data_width=64, adr_width=28) self.wb_data = wb_data = wishbone.Interface(data_width=64, adr_width=28) self.periph_buses = [wb_insn, wb_data] + self.memory_buses = [] # # # diff --git a/litex/soc/cores/cpu/minerva/core.py b/litex/soc/cores/cpu/minerva/core.py index 1603fea7..4ec118b0 100644 --- a/litex/soc/cores/cpu/minerva/core.py +++ b/litex/soc/cores/cpu/minerva/core.py @@ -34,10 +34,11 @@ class Minerva(CPU): self.platform = platform self.variant = variant self.reset = Signal() + self.interrupt = Signal(32) self.ibus = wishbone.Interface() self.dbus = wishbone.Interface() self.periph_buses = [self.ibus, self.dbus] - self.interrupt = Signal(32) + self.memory_buses = [] # TODO: create variants self.with_icache = False diff --git a/litex/soc/cores/cpu/mor1kx/core.py b/litex/soc/cores/cpu/mor1kx/core.py index 59ece9ff..d64dd1db 100644 --- a/litex/soc/cores/cpu/mor1kx/core.py +++ b/litex/soc/cores/cpu/mor1kx/core.py @@ -66,10 +66,12 @@ class MOR1KX(CPU): self.platform = platform self.variant = variant self.reset = Signal() + self.interrupt = Signal(32) self.ibus = i = wishbone.Interface() self.dbus = d = wishbone.Interface() self.periph_buses = [i, d] - self.interrupt = Signal(32) + self.memory_buses = [] + if variant == "linux": self.mem_map = self.mem_map_linux diff --git a/litex/soc/cores/cpu/picorv32/core.py b/litex/soc/cores/cpu/picorv32/core.py index 03fc355d..459520bc 100644 --- a/litex/soc/cores/cpu/picorv32/core.py +++ b/litex/soc/cores/cpu/picorv32/core.py @@ -58,11 +58,12 @@ class PicoRV32(CPU): assert variant in CPU_VARIANTS, "Unsupported variant %s" % variant self.platform = platform self.variant = variant + self.trap = Signal() self.reset = Signal() + self.interrupt = Signal(32) self.idbus = idbus = wishbone.Interface() self.periph_buses = [idbus] - self.interrupt = Signal(32) - self.trap = Signal() + self.memory_buses = [] # # # diff --git a/litex/soc/cores/cpu/rocket/core.py b/litex/soc/cores/cpu/rocket/core.py index 7d7afdf6..9af3bed1 100644 --- a/litex/soc/cores/cpu/rocket/core.py +++ b/litex/soc/cores/cpu/rocket/core.py @@ -107,6 +107,7 @@ class RocketRV64(CPU): self.mmio_wb = mmio_wb = wishbone.Interface(data_width=mmio_dw, adr_width=32-log2_int(mmio_dw//8)) self.periph_buses = [mmio_wb] + self.memory_buses = [mem_axi] # # # diff --git a/litex/soc/cores/cpu/serv/core.py b/litex/soc/cores/cpu/serv/core.py index 00f31349..92d49a6f 100644 --- a/litex/soc/cores/cpu/serv/core.py +++ b/litex/soc/cores/cpu/serv/core.py @@ -37,6 +37,7 @@ class SERV(CPU): self.ibus = ibus = wishbone.Interface() self.dbus = dbus = wishbone.Interface() self.periph_buses = [ibus, dbus] + self.memory_buses = [] # # # diff --git a/litex/soc/cores/cpu/vexriscv/core.py b/litex/soc/cores/cpu/vexriscv/core.py index bedd0de5..869fe076 100644 --- a/litex/soc/cores/cpu/vexriscv/core.py +++ b/litex/soc/cores/cpu/vexriscv/core.py @@ -103,14 +103,17 @@ class VexRiscv(CPU, AutoCSR): self.variant = variant self.external_variant = None self.reset = Signal() + self.interrupt = Signal(32) self.ibus = ibus = wishbone.Interface() self.dbus = dbus = wishbone.Interface() self.periph_buses = [ibus, dbus] - self.interrupt = Signal(32) + self.memory_buses = [] + + # # # self.cpu_params = dict( - i_clk=ClockSignal(), - i_reset=ResetSignal() | self.reset, + i_clk = ClockSignal(), + i_reset = ResetSignal() | self.reset, i_externalInterruptArray = self.interrupt, i_timerInterrupt = 0, diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index fbc86b6b..11e8dd2b 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -991,6 +991,7 @@ class LiteXSoC(SoC): **kwargs): # Imports + from litedram.common import LiteDRAMNativePort from litedram.core import LiteDRAMCore from litedram.frontend.wishbone import LiteDRAMWishbone2Native from litedram.frontend.axi import LiteDRAMAXI2Native @@ -1004,50 +1005,73 @@ class LiteXSoC(SoC): **kwargs) self.csr.add("sdram") - # LiteDRAM port - port = self.sdram.crossbar.get_port() - port.data_width = 2**int(log2(port.data_width)) # Round to nearest power of 2 - - # SDRAM size + # Compute/Check SDRAM size sdram_size = 2**(module.geom_settings.bankbits + module.geom_settings.rowbits + module.geom_settings.colbits)*phy.settings.databits//8 if size is not None: sdram_size = min(sdram_size, size) + + # Add SDRAM region self.bus.add_region("main_ram", SoCRegion(origin=origin, size=sdram_size)) # SoC [<--> L2 Cache] <--> LiteDRAM -------------------------------------------------------- - if self.cpu.name == "rocket": - # Rocket has its own I/D L1 cache: connect directly to LiteDRAM when possible. - if port.data_width == self.cpu.mem_axi.data_width: - self.logger.info("Matching AXI MEM data width ({})\n".format(port.data_width)) - self.submodules += LiteDRAMAXI2Native( - axi = self.cpu.mem_axi, - port = port, - base_address = self.bus.regions["main_ram"].origin) - else: - self.logger.info("Converting MEM data width: {} to {} via Wishbone".format( - port.data_width, - self.cpu.mem_axi.data_width)) - # FIXME: replace WB data-width converter with native AXI converter!!! - mem_wb = wishbone.Interface( - data_width = self.cpu.mem_axi.data_width, - adr_width = 32-log2_int(self.cpu.mem_axi.data_width//8)) - # NOTE: AXI2Wishbone FSMs must be reset with the CPU! - mem_a2w = ResetInserter()(axi.AXI2Wishbone( - axi = self.cpu.mem_axi, - wishbone = mem_wb, - base_address = 0)) - self.comb += mem_a2w.reset.eq(ResetSignal() | self.cpu.reset) - self.submodules += mem_a2w - litedram_wb = wishbone.Interface(port.data_width) - self.submodules += LiteDRAMWishbone2Native( - wishbone = litedram_wb, - port = port, - base_address = origin) - self.submodules += wishbone.Converter(mem_wb, litedram_wb) - elif self.with_wishbone: - # Wishbone Slave SDRAM interface + if len(self.cpu.memory_buses): + # When CPU has at least a direct memory bus, connect them directly to LiteDRAM. + for mem_bus in self.cpu.memory_buses: + # Request a LiteDRAM native port. + port = self.sdram.crossbar.get_port() + port.data_width = 2**int(log2(port.data_width)) # Round to nearest power of 2. + + # Check if bus is an AXI bus and connect it. + if isinstance(mem_bus, axi.AXIInterface): + # If same data_width, connect it directly. + if port.data_width == mem_bus.data_width: + self.logger.info("Matching AXI MEM data width ({})\n".format(port.data_width)) + self.submodules += LiteDRAMAXI2Native( + axi = self.cpu.mem_axi, + port = port, + base_address = self.bus.regions["main_ram"].origin) + # If different data_width, do the adaptation and connect it via Wishbone. + else: + self.logger.info("Converting MEM data width: {} to {} via Wishbone".format( + port.data_width, + self.cpu.mem_axi.data_width)) + # FIXME: replace WB data-width converter with native AXI converter!!! + mem_wb = wishbone.Interface( + data_width = self.cpu.mem_axi.data_width, + adr_width = 32-log2_int(self.cpu.mem_axi.data_width//8)) + # NOTE: AXI2Wishbone FSMs must be reset with the CPU! + mem_a2w = ResetInserter()(axi.AXI2Wishbone( + axi = self.cpu.mem_axi, + wishbone = mem_wb, + base_address = 0)) + self.comb += mem_a2w.reset.eq(ResetSignal() | self.cpu.reset) + self.submodules += mem_a2w + litedram_wb = wishbone.Interface(port.data_width) + self.submodules += LiteDRAMWishbone2Native( + wishbone = litedram_wb, + port = port, + base_address = origin) + self.submodules += wishbone.Converter(mem_wb, litedram_wb) + # Check if bus is a Native bus and connect it. + if isinstance(mem_bus, LiteDRAMNativePort): + # If same data_width, connect it directly. + if port.data_width == mem_bus.data_width: + self.comb += mem_bus.cmd.connect(port.cmd) + self.comb += mem_bus.wdata.connect(port.wdata) + self.comb += port.rdata.connect(mem_bus.rdata) + # Else raise Error. + else: + raise NotImplementedError + else: + # When CPU has no direct memory interface, create a Wishbone Slave interface to LiteDRAM. + + # Request a LiteDRAM native port. + port = self.sdram.crossbar.get_port() + port.data_width = 2**int(log2(port.data_width)) # Round to nearest power of 2. + + # Create Wishbone Slave. wb_sdram = wishbone.Interface() self.bus.add_slave("main_ram", wb_sdram) -- 2.30.2