enjoy-digital / litedram

Small footprint and configurable DRAM core
Other
365 stars 115 forks source link

DFI rate converter - 2nd attempt #269

Closed jedrzejboczar closed 2 years ago

jedrzejboczar commented 2 years ago

This is an update and refactor of https://github.com/enjoy-digital/litedram/pull/258. This change set includes changes from https://github.com/enjoy-digital/litedram/pull/268, please use the following diff to view only the additional changes: https://github.com/antmicro/litedram/compare/jboc/init-refactor...jboc/dfi-converter-new To work it requires the fix from https://github.com/enjoy-digital/litex/pull/986.

As described in the previous PR, DFI rate converter allows to increase frequency ratio between MC and PHY. DFIRateConverter now provides a method to automatically generate wrapper PHY classes: https://github.com/antmicro/litedram/commit/1d880c4db9bb27e9efcf88fe2cfc247bd18c6072. It will update phy settings, but requires that the wrapped PHY class is compatible, i.e. it takes a csr_cdc argument.

The old HalfRateA7DDRPHY example class has been removed. S7DDRPHY has been updated for compatibility with DFIRateConverter (CDC for CSRs, way to use different DDR clock). There is also a convenience function s7ddrphy_with_ratio (https://github.com/antmicro/litedram/commit/f4be065c09499af247969d8f376a3aa6f1dfae6a).

I have successfully tested this on Arty with the following changes:

diff --git a/litex_boards/targets/digilent_arty.py b/litex_boards/targets/digilent_arty.py
index 0001b37..5aee284 100755
--- a/litex_boards/targets/digilent_arty.py
+++ b/litex_boards/targets/digilent_arty.py
@@ -23,6 +23,7 @@ from litex.soc.cores.led import LedChaser

 from litedram.modules import MT41K128M16
 from litedram.phy import s7ddrphy
+from litedram.phy.dfi import DFIRateConverter

 from liteeth.phy.mii import LiteEthPHYMII

@@ -37,8 +38,9 @@ class _CRG(Module):
     def __init__(self, platform, sys_clk_freq, with_mapped_flash):
         self.rst = Signal()
         self.clock_domains.cd_sys       = ClockDomain()
-        self.clock_domains.cd_sys4x     = ClockDomain(reset_less=True)
-        self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True)
+        self.clock_domains.cd_sys2x     = ClockDomain()
+        self.clock_domains.cd_sys8x     = ClockDomain(reset_less=True)
+        self.clock_domains.cd_sys8x_dqs = ClockDomain(reset_less=True)
         self.clock_domains.cd_idelay    = ClockDomain()
         self.clock_domains.cd_eth       = ClockDomain()

@@ -48,14 +50,19 @@ class _CRG(Module):
         self.comb += pll.reset.eq(~platform.request("cpu_reset") | self.rst)
         pll.register_clkin(platform.request("clk100"), 100e6)
         pll.create_clkout(self.cd_sys,       sys_clk_freq)
-        pll.create_clkout(self.cd_sys4x,     4*sys_clk_freq)
-        pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90)
+        pll.create_clkout(self.cd_sys2x,     2*sys_clk_freq, with_reset=False)
+        pll.create_clkout(self.cd_sys8x,     8*sys_clk_freq)
+        pll.create_clkout(self.cd_sys8x_dqs, 8*sys_clk_freq, phase=90)
         pll.create_clkout(self.cd_idelay,    200e6)
         pll.create_clkout(self.cd_eth,       25e6)
         platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst.

         self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay)

+        # Make sure sys2x counters are reset syncronized to sys clock
+        # Then we can safely pass `serdes_reset_cnt=0` to DFIRateConverter
+        self.comb += self.cd_sys2x.rst.eq(self.cd_sys.rst)
+
         self.comb += platform.request("eth_ref_clk").eq(self.cd_eth.clk)

 # BaseSoC ------------------------------------------------------------------------------------------
@@ -68,6 +75,7 @@ class BaseSoC(SoCCore):
         SoCCore.__init__(self, platform, sys_clk_freq,
             ident          = "LiteX SoC on Arty A7",
             ident_version  = ident_version,
+            integrated_rom_mode="rw",
             **kwargs)

         # CRG --------------------------------------------------------------------------------------
@@ -75,13 +83,12 @@ class BaseSoC(SoCCore):

         # DDR3 SDRAM -------------------------------------------------------------------------------
         if not self.integrated_main_ram_size:
-            self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"),
-                memtype        = "DDR3",
-                nphases        = 4,
-                sys_clk_freq   = sys_clk_freq)
+            ratio = 2
+            self.submodules.ddrphy = s7ddrphy.s7ddrphy_with_ratio(ratio=ratio)(platform.request("ddram"))
+            sdram_module = MT41K128M16(sys_clk_freq, f"1:{4*ratio}")
             self.add_sdram("sdram",
                 phy           = self.ddrphy,
-                module        = MT41K128M16(sys_clk_freq, "1:4"),
+                module        = sdram_module,
                 l2_cache_size = kwargs.get("l2_size", 8192)
             )

@@ -119,7 +126,7 @@ def main():
     parser.add_argument("--build",               action="store_true",              help="Build bitstream")
     parser.add_argument("--load",                action="store_true",              help="Load bitstream")
     parser.add_argument("--variant",             default="a7-35",                  help="Board variant: a7-35 (default) or a7-100")
-    parser.add_argument("--sys-clk-freq",        default=100e6,                    help="System clock frequency (default: 100MHz)")
+    parser.add_argument("--sys-clk-freq",        default=50e6,                    help="System clock frequency (default: 50MHz)")
     ethopts = parser.add_mutually_exclusive_group()
     ethopts.add_argument("--with-ethernet",      action="store_true",              help="Enable Ethernet support")
     ethopts.add_argument("--with-etherbone",     action="store_true",              help="Enable Etherbone support")
enjoy-digital commented 2 years ago

Excellent work @jedrzejboczar, you are reaching another level of abstraction here! (That would be a good example to show to FPGA designers asking the advantages of designing FPGA in Python :)) cc @mithro @kgugala @mgielda

As always, your code is very clean and the the changes introduced in S7DDRPHY are minimal and looks fine, so we can merge it to allow you to go further.