soc/cpu: add memory_buses to cpus and use them in add_sdram.
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 27 Apr 2020 21:51:17 +0000 (23:51 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 27 Apr 2020 21:53:52 +0000 (23:53 +0200)
This allows the CPU to have direct buses to the memory and replace the Rocket specific code.

litex/soc/cores/cpu/__init__.py
litex/soc/cores/cpu/blackparrot/core.py
litex/soc/cores/cpu/lm32/core.py
litex/soc/cores/cpu/microwatt/core.py
litex/soc/cores/cpu/minerva/core.py
litex/soc/cores/cpu/mor1kx/core.py
litex/soc/cores/cpu/picorv32/core.py
litex/soc/cores/cpu/rocket/core.py
litex/soc/cores/cpu/serv/core.py
litex/soc/cores/cpu/vexriscv/core.py
litex/soc/integration/soc.py

index d0b11a50efd3ddd103d161f85cbd02890122a41a..21f7ce5d566a97011e19b6d6306dac319a00f999 100644 (file)
@@ -26,6 +26,8 @@ class CPUNone(CPU):
     data_width           = 32
     reset_address        = 0x00000000
     io_regions           = {0x00000000: 0x100000000} # origin, length
+    periph_buses         = []
+    memory_buses         = []
 
 # CPUS ---------------------------------------------------------------------------------------------
 
index fe220cf2e074a5fc3d0aa23869b0f095ee2311a4..6b186947caf574b47729a8bf668ca347aebfabd5 100644 (file)
@@ -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 = []
 
         # # #
 
index e1b6bce39395af32471341e6a8a164c56762fcbb..b05e1ede4ddbe6d1c1e2e18222f37cead25e50f2 100644 (file)
@@ -41,6 +41,7 @@ class LM32(CPU):
         self.dbus         = d = wishbone.Interface()
         self.interrupt    = Signal(32)
         self.periph_buses = [i, d]
+        self.memory_buses = []
 
         # # #
 
index 17b6e3eaa9a1defc6be30ead2c6ac5dffdeb3e12..b951959b202f2f1dd48d809082675ad28dff0add 100644 (file)
@@ -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 = []
 
         # # #
 
index 1603fea74932d8dd76739ae79b93955cb91f1be6..4ec118b0fe9fb34e5c4c268d1b24cc82267b0759 100644 (file)
@@ -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
index 59ece9ff29f13053312f5cf691bd0cca66fe6782..d64dd1db04676ec830d1757add42bc424a691045 100644 (file)
@@ -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
index 03fc355d24f87786edad8c3d8b1f174887ac884e..459520bc0aa842ebf410173d97dea02a1323c4a1 100644 (file)
@@ -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 = []
 
         # # #
 
index 7d7afdf6c7b614079ba07fb65b2aa8e6a1727481..9af3bed1511851c07795b33f85b130d54fec28c7 100644 (file)
@@ -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]
 
         # # #
 
index 00f3134980ccc1583c05fd5cc6e03e7a6754d462..92d49a6fc56d769b23fc4fd6a3a66cd60363084a 100644 (file)
@@ -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 = []
 
         # # #
 
index bedd0de5af51bf6359020b4cc90dd9478b82d717..869fe07631cf31eba2f41469d69190cc1ab5f8ed 100644 (file)
@@ -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,
index fbc86b6b43045ed14fa8c200068442a99c9c8215..11e8dd2b2f55285ec3ce99cba9a0b327ffff1b66 100644 (file)
@@ -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)