soc: add add_sdram
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 10 Feb 2020 15:01:19 +0000 (16:01 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 10 Feb 2020 15:01:19 +0000 (16:01 +0100)
litex/soc/integration/soc.py
litex/soc/integration/soc_sdram.py

index 99a74a4348b30dfdc48dd28e8011ec85a43c9789..0453fe20d5b46d745a4e7d50e2d09eb65a5d4baa 100755 (executable)
@@ -1,10 +1,12 @@
 # This file is Copyright (c) 2014-2020 Florent Kermarrec <florent@enjoy-digital.fr>
 # This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
+# This file is Copyright (c) 2019 Gabriel L. Somlo <somlo@cmu.edu>
 # License: BSD
 
 import logging
 import time
 import datetime
+from math import log2
 
 from migen import *
 
@@ -17,6 +19,9 @@ from litex.soc.interconnect import csr_bus
 from litex.soc.interconnect import wishbone
 from litex.soc.interconnect import wishbone2csr
 
+from litedram.core import LiteDRAMCore
+from litedram.frontend.wishbone import LiteDRAMWishbone2Native
+
 # TODO:
 # - replace raise with exit on logging error.
 # - add configurable CSR paging.
@@ -799,6 +804,98 @@ class SoC(Module):
         self.csr.add("uart", use_loc_if_exists=True)
         self.irq.add("uart", use_loc_if_exists=True)
 
+    def add_sdram(self, name,
+        phy,
+        geom_settings,
+        timing_settings,
+        l2_cache_size           = 8192,
+        l2_cache_min_data_width = 128,
+        l2_cache_reverse        = True,
+        origin                  = 0x40000000,
+        max_sdram_size          = None,
+        **kwargs):
+
+        # LiteDRAM core ----------------------------------------------------------------------------
+        self.submodules.sdram = LiteDRAMCore(
+            phy             = phy,
+            geom_settings   = geom_settings,
+            timing_settings = timing_settings,
+            clk_freq        = self.sys_clk_freq,
+            **kwargs)
+
+        # LiteDRAM port ----------------------------------------------------------------------------
+        port = self.sdram.crossbar.get_port()
+        port.data_width = 2**int(log2(port.data_width)) # Round to nearest power of 2
+
+        # Main RAM size ----------------------------------------------------------------------------
+        main_ram_size = 2**(geom_settings.bankbits +
+                            geom_settings.rowbits +
+                            geom_settings.colbits)*phy.settings.databits//8
+        if self.max_sdram_size is not None:
+            main_ram_size = min(main_ram_size, self.max_sdram_size)
+        self.bus.add_region("main_ram", SoCRegion(origin, main_ram_size))
+
+        # SoC [<--> L2 Cache] <--> LiteDRAM --------------------------------------------------------
+        if self.cpu.name == "rocket":
+            # Rocket has its own I/D L1 cache: connect directly to LiteDRAM, also bypassing MMIO/CSR wb bus:
+            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()(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)
+            # Register main_ram region (so it will be added to generated/mem.h):
+            self.bus.region.add_memory_region("main_ram", SoCRegion(origin, main_ram_size))
+        elif self.with_wishbone:
+            # Insert L2 cache inbetween Wishbone bus and LiteDRAM
+            l2_cache_size = max(l2_cache_size, int(2*port.data_width/8)) # L2 has a minimal size, use it if lower
+            l2_cache_size = 2**int(log2(l2_cache_size))                  # Round to nearest power of 2
+            self.add_config("L2_SIZE", l2_cache_size)
+
+            # SoC <--> L2 Cache Wishbone interface -------------------------------------------------
+            wb_sdram = wishbone.Interface()
+            self.bus.add_slave("main_ram", wb_sdram, SoCRegion(origin=origin, size=main_ram_size))
+
+            # L2 Cache -----------------------------------------------------------------------------
+            l2_cache_data_width = max(port.data_width, l2_cache_min_data_width)
+            l2_cache = wishbone.Cache(
+                cachesize = l2_cache_size//4,
+                master    = wb_sdram,
+                slave     = wishbone.Interface(l2_cache_data_width),
+                reverse   = l2_cache_reverse)
+            # XXX Vivado ->2018.2 workaround, Vivado is not able to map correctly our L2 cache.
+            # Issue is reported to Xilinx, Remove this if ever fixed by Xilinx...
+            from litex.build.xilinx.vivado import XilinxVivadoToolchain
+            if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
+                from migen.fhdl.simplify import FullMemoryWE
+                self.submodules.l2_cache = FullMemoryWE()(l2_cache)
+            else:
+                self.submodules.l2_cache = l2_cache
+
+            # L2 Cache <--> LiteDRAM bridge --------------------------------------------------------
+            self.submodules.wishbone_bridge = LiteDRAMWishbone2Native(self.l2_cache.slave, port)
+
     # SoC finalization -----------------------------------------------------------------------------
     def do_finalize(self):
         self.logger.info(colorer("-"*80, color="bright"))
index 9b961c143184b5568973eb6bd0a875eb8e497385..397eb20b9458a84a43eb27df902bdf45571b508f 100644 (file)
@@ -12,10 +12,6 @@ from migen.genlib.record import *
 from litex.soc.interconnect import wishbone
 from litex.soc.integration.soc_core import *
 
-from litedram.frontend.wishbone import *
-from litedram.frontend.axi import *
-from litedram.core import LiteDRAMCore
-
 __all__ = ["SoCSDRAM", "soc_sdram_args", "soc_sdram_argdict"]
 
 # SoCSDRAM -----------------------------------------------------------------------------------------
@@ -29,109 +25,22 @@ class SoCSDRAM(SoCCore):
 
     def __init__(self, platform, clk_freq, l2_size=8192, l2_reverse=True, min_l2_data_width=128, max_sdram_size=None, **kwargs):
         SoCCore.__init__(self, platform, clk_freq, **kwargs)
-        if not self.integrated_main_ram_size:
-            if self.cpu_type is not None and self.csr_data_width > 32:
-                 raise NotImplementedError("BIOS supports SDRAM initialization only for csr_data_width<=32")
         self.l2_size           = l2_size
         self.l2_reverse        = l2_reverse
         self.min_l2_data_width = min_l2_data_width
         self.max_sdram_size    = max_sdram_size
 
-        self._sdram_phy    = []
-        self._wb_sdram_ifs = []
-        self._wb_sdram     = wishbone.Interface()
-
-    def add_wb_sdram_if(self, interface):
-        if self.finalized:
-            raise FinalizeError
-        self._wb_sdram_ifs.append(interface)
-
     def register_sdram(self, phy, geom_settings, timing_settings, **kwargs):
-        assert not self._sdram_phy
-        self._sdram_phy.append(phy) # encapsulate in list to prevent CSR scanning
-
-        # LiteDRAM core ----------------------------------------------------------------------------
-        self.submodules.sdram = LiteDRAMCore(
-            phy             = phy,
-            geom_settings   = geom_settings,
-            timing_settings = timing_settings,
-            clk_freq        = self.clk_freq,
-            **kwargs)
-
-        # LiteDRAM port ------------------------------------------------------------------------
-        port = self.sdram.crossbar.get_port()
-        port.data_width = 2**int(log2(port.data_width)) # Round to nearest power of 2
-
-        # Main RAM size ------------------------------------------------------------------------
-        main_ram_size = 2**(geom_settings.bankbits +
-                            geom_settings.rowbits +
-                            geom_settings.colbits)*phy.settings.databits//8
-        if self.max_sdram_size is not None:
-            main_ram_size = min(main_ram_size, self.max_sdram_size)
-
-        # SoC [<--> L2 Cache] <--> LiteDRAM ----------------------------------------------------
-        if self.cpu.name == "rocket":
-            # Rocket has its own I/D L1 cache: connect directly to LiteDRAM, also bypassing MMIO/CSR wb bus:
-            if port.data_width == self.cpu.mem_axi.data_width:
-                print("# Matching AXI MEM data width ({})\n".format(port.data_width))
-                # straightforward AXI link, no data_width conversion needed:
-                self.submodules += LiteDRAMAXI2Native(self.cpu.mem_axi, port,
-                                                      base_address=self.mem_map["main_ram"])
-            else:
-                print("# Converting MEM data width: ram({}) to cpu({}), via Wishbone\n".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()(AXI2Wishbone(self.cpu.mem_axi, 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(litedram_wb, port,
-                                                           base_address=self.mem_map["main_ram"])
-                self.submodules += wishbone.Converter(mem_wb, litedram_wb)
-            # Register main_ram region (so it will be added to generated/mem.h):
-            self.add_memory_region("main_ram", self.mem_map["main_ram"], main_ram_size)
-        elif self.with_wishbone:
-            # Insert L2 cache inbetween Wishbone bus and LiteDRAM
-            l2_size = max(self.l2_size, int(2*port.data_width/8)) # L2 has a minimal size, use it if lower
-            l2_size = 2**int(log2(l2_size))                       # Round to nearest power of 2
-
-            # SoC <--> L2 Cache Wishbone interface -------------------------------------------------
-            wb_sdram = wishbone.Interface()
-            self.add_wb_sdram_if(wb_sdram)
-            self.register_mem("main_ram", self.mem_map["main_ram"], wb_sdram, main_ram_size)
-
-            # L2 Cache -----------------------------------------------------------------------------
-            l2_data_width = max(port.data_width, self.min_l2_data_width)
-            l2_cache = wishbone.Cache(
-                cachesize = l2_size//4,
-                master    = self._wb_sdram,
-                slave     = wishbone.Interface(l2_data_width),
-                reverse   = self.l2_reverse)
-            # XXX Vivado ->2018.2 workaround, Vivado is not able to map correctly our L2 cache.
-            # Issue is reported to Xilinx, Remove this if ever fixed by Xilinx...
-            from litex.build.xilinx.vivado import XilinxVivadoToolchain
-            if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
-                from migen.fhdl.simplify import FullMemoryWE
-                self.submodules.l2_cache = FullMemoryWE()(l2_cache)
-            else:
-                self.submodules.l2_cache = l2_cache
-            self.config["L2_SIZE"] = l2_size
-
-            # L2 Cache <--> LiteDRAM bridge --------------------------------------------------------
-            self.submodules.wishbone_bridge = LiteDRAMWishbone2Native(self.l2_cache.slave, port)
-
-    def do_finalize(self):
-        if not self.integrated_main_ram_size:
-            if not self._sdram_phy:
-                raise FinalizeError("Need to call SoCSDRAM.register_sdram()")
-
-            # Arbitrate wishbone interfaces to the DRAM
-            if len(self._wb_sdram_ifs) != 0:
-                self.submodules.wb_sdram_con = wishbone.Arbiter(self._wb_sdram_ifs, self._wb_sdram)
-        SoCCore.do_finalize(self)
-
+        self.add_sdram("sdram",
+            phy                     = phy,
+            geom_settings           = geom_settings,
+            timing_settings         = timing_settings,
+            l2_cache_size           = self.l2_size,
+            l2_cache_min_data_width = self.min_l2_data_width,
+            l2_cache_reverse        = self.l2_reverse,
+            max_sdram_size          = self.max_sdram_size,
+            **kwargs,
+        )
 
 # SoCSDRAM arguments --------------------------------------------------------------------------------