From 992f80c68bc6407916ca36fdcea8a19f7e145e81 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 3 Jun 2020 09:35:40 +0200 Subject: [PATCH] litedram_gen: add Ultrascale(+) support and KCU105 config file, remove cmd_delay on 7-series (not automatically calibrated). --- examples/arty.yml | 1 - examples/genesys2.yml | 1 - examples/kcu105.yml | 48 ++++++++++++++ examples/nexys4ddr.yml | 1 - litedram/gen.py | 142 +++++++++++++++++++++++++++++++++-------- 5 files changed, 164 insertions(+), 29 deletions(-) create mode 100644 examples/kcu105.yml diff --git a/examples/arty.yml b/examples/arty.yml index 6c85d31..6e257da 100644 --- a/examples/arty.yml +++ b/examples/arty.yml @@ -8,7 +8,6 @@ "memtype": "DDR3", # DRAM type # PHY ---------------------------------------------------------------------- - "cmd_delay": 0, # Command additional delay (in taps) "cmd_latency": 0, # Command additional latency "sdram_module": "MT41K128M16", # SDRAM modules of the board or SO-DIMM "sdram_module_nb": 2, # Number of byte groups diff --git a/examples/genesys2.yml b/examples/genesys2.yml index bb143f1..b96b69f 100644 --- a/examples/genesys2.yml +++ b/examples/genesys2.yml @@ -8,7 +8,6 @@ "memtype": "DDR3", # DRAM type # PHY ---------------------------------------------------------------------- - "cmd_delay": 0, # Command additional delay (in taps) "cmd_latency": 0, # Command additional latency "sdram_module": "MT41J256M16", # SDRAM modules of the board or SO-DIMM "sdram_module_nb": 4, # Number of byte groups diff --git a/examples/kcu105.yml b/examples/kcu105.yml new file mode 100644 index 0000000..add9156 --- /dev/null +++ b/examples/kcu105.yml @@ -0,0 +1,48 @@ +# This file is Copyright (c) 2020 Florent Kermarrec +# License: BSD + +{ + # General ------------------------------------------------------------------ + "cpu": "vexriscv", # Type of CPU used for init/calib (vexriscv, lm32) + "speedgrade": -2, # FPGA speedgrade + "memtype": "DDR4", # DRAM type + + # PHY ---------------------------------------------------------------------- + "cmd_latency": 0, # Command additional latency + "sdram_module": "EDY4016A", # SDRAM modules of the board or SO-DIMM + "sdram_module_nb": 8, # Number of byte groups + "sdram_rank_nb": 1, # Number of ranks + "sdram_phy": "USDDRPHY", # Type of FPGA PHY + + # Electrical --------------------------------------------------------------- + "rtt_nom": "80ohm", # Nominal termination + "rtt_wr": "80ohm", # Write termination + "ron": "34ohm", # Output driver impedance + + # Frequency ---------------------------------------------------------------- + "input_clk_freq": 200e6, # Input clock frequency + "sys_clk_freq": 150e6, # System clock frequency (DDR_clk = 4 x sys_clk) + "iodelay_clk_freq": 200e6, # IODELAYs reference clock frequency + + # Core --------------------------------------------------------------------- + "cmd_buffer_depth": 16, # Depth of the command buffer + + # User Ports --------------------------------------------------------------- + "user_ports": { + "axi_0" : { + "type": "axi", + "id_width": 32, + }, + "wishbone_0" : { + "type": "wishbone", + }, + "native_0" : { + "type": "native", + }, + "fifo_0" : { + "type": "fifo", + "base": 0x00000000, + "depth": 0x01000000, + }, + }, +} diff --git a/examples/nexys4ddr.yml b/examples/nexys4ddr.yml index 89d9b00..c521136 100644 --- a/examples/nexys4ddr.yml +++ b/examples/nexys4ddr.yml @@ -8,7 +8,6 @@ "memtype": "DDR2", # DRAM type # PHY ---------------------------------------------------------------------- - "cmd_delay": 0, # Command additional delay (in taps) "cmd_latency": 0, # Command additional latency "sdram_module": "MT47H64M16", # SDRAM modules of the board or SO-DIMM "sdram_module_nb": 2, # Number of byte groups diff --git a/litedram/gen.py b/litedram/gen.py index 5117492..2d4cf8f 100755 --- a/litedram/gen.py +++ b/litedram/gen.py @@ -17,8 +17,10 @@ for some use cases it could be interesting to generate a standalone verilog file The standalone core is generated from a YAML configuration file that allows the user to generate easily a custom configuration of the core. -Current version of the generator is limited to DDR2/DDR3 Xilinx 7-Series FPGA and DDR3 on Lattice -ECP5. +Current version of the generator is limited to: +- DDR3 on Lattice ECP5 FPGAs. +- DDR2/DDR3 on Xilinx 7-Series FPGAs. +- DDR4 on Xilinx Ultascale(+) FPGAs. """ import os @@ -86,26 +88,51 @@ def get_common_ios(): ] def get_dram_ios(core_config): - sdram_module = core_config["sdram_module"] - return [ - ("ddram", 0, - Subsignal("a", Pins(log2_int(core_config["sdram_module"].nrows))), - Subsignal("ba", Pins(log2_int(core_config["sdram_module"].nbanks))), - Subsignal("ras_n", Pins(1)), - Subsignal("cas_n", Pins(1)), - Subsignal("we_n", Pins(1)), - Subsignal("cs_n", Pins(core_config["sdram_rank_nb"])), - Subsignal("dm", Pins(core_config["sdram_module_nb"])), - Subsignal("dq", Pins(8*core_config["sdram_module_nb"])), - Subsignal("dqs_p", Pins(core_config["sdram_module_nb"])), - Subsignal("dqs_n", Pins(core_config["sdram_module_nb"])), - Subsignal("clk_p", Pins(core_config["sdram_rank_nb"])), - Subsignal("clk_n", Pins(core_config["sdram_rank_nb"])), - Subsignal("cke", Pins(core_config["sdram_rank_nb"])), - Subsignal("odt", Pins(core_config["sdram_rank_nb"])), - Subsignal("reset_n", Pins(1)) - ), - ] + if core_config["memtype"] in ["DDR2", "DDR3"]: + a_width = log2_int(core_config["sdram_module"].nrows) + return [ + ("ddram", 0, + Subsignal("a", Pins(log2_int(core_config["sdram_module"].nrows))), + Subsignal("ba", Pins(log2_int(core_config["sdram_module"].nbanks))), + Subsignal("ras_n", Pins(1)), + Subsignal("cas_n", Pins(1)), + Subsignal("we_n", Pins(1)), + Subsignal("cs_n", Pins(core_config["sdram_rank_nb"])), + Subsignal("dm", Pins(core_config["sdram_module_nb"])), + Subsignal("dq", Pins(8*core_config["sdram_module_nb"])), + Subsignal("dqs_p", Pins(core_config["sdram_module_nb"])), + Subsignal("dqs_n", Pins(core_config["sdram_module_nb"])), + Subsignal("clk_p", Pins(core_config["sdram_rank_nb"])), + Subsignal("clk_n", Pins(core_config["sdram_rank_nb"])), + Subsignal("cke", Pins(core_config["sdram_rank_nb"])), + Subsignal("odt", Pins(core_config["sdram_rank_nb"])), + Subsignal("reset_n", Pins(1)) + ), + ] + elif core_config["memtype"] == "DDR4": + # On DDR4, A14. A15 and A16 are shared with we_n/cas_n/ras_n + a_width = min(log2_int(core_config["sdram_module"].nrows), 14) + return [ + ("ddram", 0, + Subsignal("a", Pins(a_width)), + Subsignal("ba", Pins(log2_int(core_config["sdram_module"].ngroupbanks))), + Subsignal("bg", Pins(log2_int(core_config["sdram_module"].ngroups))), + Subsignal("ras_n", Pins(1)), + Subsignal("cas_n", Pins(1)), + Subsignal("we_n", Pins(1)), + Subsignal("cs_n", Pins(core_config["sdram_rank_nb"])), + Subsignal("act_n", Pins(1)), + Subsignal("dm", Pins(core_config["sdram_module_nb"])), + Subsignal("dq", Pins(8*core_config["sdram_module_nb"])), + Subsignal("dqs_p", Pins(core_config["sdram_module_nb"])), + Subsignal("dqs_n", Pins(core_config["sdram_module_nb"])), + Subsignal("clk_p", Pins(core_config["sdram_rank_nb"])), + Subsignal("clk_n", Pins(core_config["sdram_rank_nb"])), + Subsignal("cke", Pins(core_config["sdram_rank_nb"])), + Subsignal("odt", Pins(core_config["sdram_rank_nb"])), + Subsignal("reset_n", Pins(1)) + ), + ] def get_native_user_port_ios(_id, aw, dw): return [ @@ -274,6 +301,7 @@ class LiteDRAMS7DDRPHYCRG(Module): clk = platform.request("clk") rst = platform.request("rst") + # Sys PLL self.submodules.sys_pll = sys_pll = S7PLL(speedgrade=core_config["speedgrade"]) self.comb += sys_pll.reset.eq(rst) sys_pll.register_clkin(clk, core_config["input_clk_freq"]) @@ -287,11 +315,52 @@ class LiteDRAMS7DDRPHYCRG(Module): sys_pll.create_clkout(self.cd_sys4x_dqs, 4*core_config["sys_clk_freq"], phase=90) else: raise NotImplementedError - self.comb += platform.request("pll_locked").eq(sys_pll.locked) + # IODelay Ctrl self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_iodelay) +class LiteDRAMUSDDRPHYCRG(Module): + def __init__(self, platform, core_config): + assert core_config["memtype"] in ["DDR4"] + self.clock_domains.cd_por = ClockDomain(reset_less=True) + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys4x = ClockDomain() + self.clock_domains.cd_sys4x_pll = ClockDomain() + self.clock_domains.cd_iodelay = ClockDomain() + + # # # + + clk = platform.request("clk") + rst = platform.request("rst") + + # Power On Reset + por_count = Signal(32, reset=int(core_config["input_clk_freq"]*100/1e3)) # 100ms + por_done = Signal() + self.comb += self.cd_por.clk.eq(clk) + self.comb += por_done.eq(por_count == 0) + self.sync.por += If(~por_done, por_count.eq(por_count - 1)) + + # Sys PLL + self.submodules.sys_pll = sys_pll = USMMCM(speedgrade=core_config["speedgrade"]) + self.comb += sys_pll.reset.eq(rst) + sys_pll.register_clkin(clk, core_config["input_clk_freq"]) + sys_pll.create_clkout(self.cd_iodelay, core_config["iodelay_clk_freq"]) + sys_pll.create_clkout(self.cd_sys4x_pll, 4*core_config["sys_clk_freq"], buf=None) + self.comb += platform.request("pll_locked").eq(sys_pll.locked) + self.specials += [ + Instance("BUFGCE_DIV", name="main_bufgce_div", + p_BUFGCE_DIVIDE=4, + i_CE=por_done, i_I=self.cd_sys4x_pll.clk, o_O=self.cd_sys.clk), + Instance("BUFGCE", name="main_bufgce", + i_CE=por_done, i_I=self.cd_sys4x_pll.clk, o_O=self.cd_sys4x.clk), + AsyncResetSynchronizer(self.cd_sys4x, ~por_done | ~sys_pll.locked | rst), + AsyncResetSynchronizer(self.cd_sys, ~por_done | ~sys_pll.locked | rst), + ] + + # IODelay Ctrl + self.submodules.idelayctrl = USIDELAYCTRL(self.cd_iodelay, cd_sys=self.cd_sys) + # LiteDRAMCoreControl ------------------------------------------------------------------------------ class LiteDRAMCoreControl(Module, AutoCSR): @@ -331,10 +400,15 @@ class LiteDRAMCore(SoCCore): self.submodules.crg = crg = LiteDRAMECP5DDRPHYCRG(platform, core_config) elif core_config["sdram_phy"] in [litedram_phys.A7DDRPHY, litedram_phys.K7DDRPHY, litedram_phys.V7DDRPHY]: self.submodules.crg = LiteDRAMS7DDRPHYCRG(platform, core_config) + elif core_config["sdram_phy"] in [litedram_phys.A7DDRPHY, litedram_phys.USDDRPHY, litedram_phys.USPDDRPHY]: + self.submodules.crg = LiteDRAMUSDDRPHYCRG(platform, core_config) # DRAM ------------------------------------------------------------------------------------- platform.add_extension(get_dram_ios(core_config)) - sdram_module = core_config["sdram_module"](sys_clk_freq, rate={"DDR3": "1:4", "DDR2": "1:2"}[core_config["memtype"]]) + sdram_module = core_config["sdram_module"](sys_clk_freq, rate={ + "DDR2": "1:2", + "DDR3": "1:4", + "DDR4": "1:4"}[core_config["memtype"]]) # Sim if isinstance(platform, SimPlatform): @@ -365,16 +439,30 @@ class LiteDRAMCore(SoCCore): self.submodules.ddrphy = core_config["sdram_phy"]( pads = platform.request("ddram"), memtype = core_config["memtype"], - nphases = 4 if core_config["memtype"] == "DDR3" else 2, + nphases = {"DDR2": 2, "DDR3": 4}[core_config["memtype"]], sys_clk_freq = sys_clk_freq, iodelay_clk_freq = core_config["iodelay_clk_freq"], cmd_latency = core_config["cmd_latency"]) - self.add_constant("CMD_DELAY", core_config["cmd_delay"]) if core_config["memtype"] == "DDR3": self.ddrphy.settings.add_electrical_settings( rtt_nom = core_config["rtt_nom"], rtt_wr = core_config["rtt_wr"], ron = core_config["ron"]) + + # USDDRPHY + elif core_config["sdram_phy"] in [litedram_phys.USDDRPHY, litedram_phys.USPDDRPHY]: + self.submodules.ddrphy = core_config["sdram_phy"]( + pads = platform.request("ddram"), + memtype = core_config["memtype"], + sys_clk_freq = sys_clk_freq, + iodelay_clk_freq = core_config["iodelay_clk_freq"], + cmd_latency = core_config["cmd_latency"]) + self.ddrphy.settings.add_electrical_settings( + rtt_nom = core_config["rtt_nom"], + rtt_wr = core_config["rtt_wr"], + ron = core_config["ron"]) + else: + raise NotImplementedError self.add_csr("ddrphy") controller_settings = controller_settings = ControllerSettings( @@ -571,6 +659,8 @@ def main(): platform = LatticePlatform("LFE5UM5G-45F-8BG381C", io=[], toolchain="trellis") # FIXME: allow other devices. elif core_config["sdram_phy"] in [litedram_phys.A7DDRPHY, litedram_phys.K7DDRPHY, litedram_phys.V7DDRPHY]: platform = XilinxPlatform("", io=[], toolchain="vivado") + elif core_config["sdram_phy"] in [litedram_phys.USDDRPHY, litedram_phys.USPDDRPHY]: + platform = XilinxPlatform("", io=[], toolchain="vivado") else: raise ValueError("Unsupported SDRAM PHY: {}".format(core_config["sdram_phy"]))