diff --git a/litedram/phy/ecp5ddrphy.py b/litedram/phy/ecp5ddrphy.py index dc342fd..57e63d0 100644 --- a/litedram/phy/ecp5ddrphy.py +++ b/litedram/phy/ecp5ddrphy.py @@ -89,6 +89,7 @@ class ECP5DDRPHY(Module, AutoCSR): nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) databits = len(pads.dq) nphases = 2 + assert databits%8 == 0 # Init ------------------------------------------------------------------------------------- self.submodules.init = ClockDomainsRenamer("init")(ECP5DDRPHYInit("sys2x")) @@ -115,19 +116,19 @@ class ECP5DDRPHY(Module, AutoCSR): rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl) wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl) self.settings = PhySettings( - memtype=memtype, - databits=databits, - dfi_databits=4*databits, - nranks=nranks, - nphases=nphases, - rdphase=rdphase, - wrphase=wrphase, - rdcmdphase=rdcmdphase, - wrcmdphase=wrcmdphase, - cl=cl, - cwl=cwl, - read_latency=2 + cl_sys_latency + 2 + log2_int(4//nphases) + 6, - write_latency=cwl_sys_latency + memtype = memtype, + databits = databits, + dfi_databits = 4*databits, + nranks = nranks, + nphases = nphases, + rdphase = rdphase, + wrphase = wrphase, + rdcmdphase = rdcmdphase, + wrcmdphase = wrcmdphase, + cl = cl, + cwl = cwl, + read_latency = 2 + cl_sys_latency + 2 + log2_int(4//nphases) + 6, + write_latency = cwl_sys_latency ) # DFI Interface ---------------------------------------------------------------------------- diff --git a/litedram/phy/gensdrphy.py b/litedram/phy/gensdrphy.py index fd80213..244293f 100644 --- a/litedram/phy/gensdrphy.py +++ b/litedram/phy/gensdrphy.py @@ -21,35 +21,38 @@ from migen.fhdl.specials import Tristate from litedram.common import PhySettings from litedram.phy.dfi import * +# Generic SDR PHY ---------------------------------------------------------------------------------- class GENSDRPHY(Module): def __init__(self, pads, cl=2): addressbits = len(pads.a) - bankbits = len(pads.ba) - nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) - databits = len(pads.dq) + bankbits = len(pads.ba) + nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) + databits = len(pads.dq) assert databits%8 == 0 + # PHY settings ----------------------------------------------------------------------------- self.settings = PhySettings( - memtype="SDR", - databits=databits, - dfi_databits=databits, - nranks=nranks, - nphases=1, - rdphase=0, - wrphase=0, - rdcmdphase=0, - wrcmdphase=0, - cl=cl, - read_latency=cl + 2, - write_latency=0 + memtype = "SDR", + databits = databits, + dfi_databits = databits, + nranks = nranks, + nphases = 1, + rdphase = 0, + wrphase = 0, + rdcmdphase = 0, + wrcmdphase = 0, + cl = cl, + read_latency = cl + 2, + write_latency = 0 ) + # DFI Interface ---------------------------------------------------------------------------- self.dfi = dfi = Interface(addressbits, bankbits, nranks, databits) # # # - # Command/address + # Addresses and Commands ------------------------------------------------------------------- self.sync += [ pads.a.eq(dfi.p0.address), pads.ba.eq(dfi.p0.bank), @@ -62,7 +65,7 @@ class GENSDRPHY(Module): if hasattr(pads, "cs_n"): self.sync += pads.cs_n.eq(dfi.p0.cs_n) - # DQ/DQS/DM data + # DQ/DQS/DM Data --------------------------------------------------------------------------- dq_o = Signal(databits) dq_oe = Signal() dq_i = Signal(databits) @@ -80,7 +83,7 @@ class GENSDRPHY(Module): self.sync.sys_ps += dq_in.eq(dq_i) self.sync += dfi.p0.rddata.eq(dq_in) - # DQ/DM control + # DQ/DM Control ---------------------------------------------------------------------------- wrdata_en = Signal() self.sync += wrdata_en.eq(dfi.p0.wrdata_en) self.comb += dq_oe.eq(wrdata_en) diff --git a/litedram/phy/s6ddrphy.py b/litedram/phy/s6ddrphy.py index 2c59393..3691c58 100644 --- a/litedram/phy/s6ddrphy.py +++ b/litedram/phy/s6ddrphy.py @@ -36,49 +36,53 @@ class S6HalfRateDDRPHY(Module): if memtype not in ["DDR", "LPDDR", "DDR2", "DDR3"]: raise NotImplementedError("S6HalfRateDDRPHY only supports DDR, LPDDR, DDR2 and DDR3") addressbits = len(pads.a) - bankbits = len(pads.ba) - nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) - databits = len(pads.dq) - nphases = 2 + bankbits = len(pads.ba) + nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) + databits = len(pads.dq) + nphases = 2 + assert databits%8 == 0 + # PHY settings ----------------------------------------------------------------------------- if memtype == "DDR3": self.settings = PhySettings( - memtype="DDR3", - databits=databits, - dfi_databits=2*databits, - nranks=nranks, - nphases=nphases, - rdphase=0, - wrphase=1, - rdcmdphase=1, - wrcmdphase=0, - cl=5, - cwl=6, - read_latency=6, - write_latency=2 + memtype = "DDR3", + databits = databits, + dfi_databits = 2*databits, + nranks = nranks, + nphases = nphases, + rdphase = 0, + wrphase = 1, + rdcmdphase = 1, + wrcmdphase = 0, + cl = 5, + cwl = 6, + read_latency = 6, + write_latency = 2 ) else: self.settings = PhySettings( - memtype=memtype, - databits=databits, - dfi_databits=2*databits, - nranks=nranks, - nphases=nphases, - rdphase=0, - wrphase=1, - rdcmdphase=1, - wrcmdphase=0, - cl=3, - read_latency=5, - write_latency=0 + memtype = memtype, + databits = databits, + dfi_databits = 2*databits, + nranks = nranks, + nphases = nphases, + rdphase = 0, + wrphase = 1, + rdcmdphase = 1, + wrcmdphase = 0, + cl = 3, + read_latency = 5, + write_latency = 0 ) + # DFI Interface ---------------------------------------------------------------------------- self.dfi = dfi = Interface(addressbits, bankbits, nranks, 2*databits, nphases) self.clk4x_wr_strb = Signal() self.clk4x_rd_strb = Signal() # # # + # Clock ------------------------------------------------------------------------------------ # sys_clk : system clk, used for dfi interface # sdram_half_clk : half rate sdram clk # sdram_full_wr_clk : full rate sdram write clk @@ -91,9 +95,7 @@ class S6HalfRateDDRPHY(Module): sdram_full_wr_clk = ClockSignal("sdram_full_wr") sdram_full_rd_clk = ClockSignal("sdram_full_rd") - # - # Command/address - # + # Addresses and Commands ------------------------------------------------------------------- # select active phase # sys_clk ----____----____ @@ -142,9 +144,7 @@ class S6HalfRateDDRPHY(Module): if hasattr(pads, name): sd_sdram_half += getattr(pads, name).eq(getattr(r_dfi[phase_sel], name)) - # - # Bitslip - # + # Bitslip ---------------------------------------------------------------------------------- bitslip_cnt = Signal(4) bitslip_inc = Signal() @@ -157,9 +157,7 @@ class S6HalfRateDDRPHY(Module): ) ] - # - # DQ/DQS/DM data - # + # DQ/DQS/DM data --------------------------------------------------------------------------- sdram_half_clk_n = Signal() self.comb += sdram_half_clk_n.eq(~sdram_half_clk) @@ -365,10 +363,7 @@ class S6HalfRateDDRPHY(Module): i_SHIFTIN4=0, ) - - # - # DQ/DQS/DM control - # + # DQ/DQS/DM control ------------------------------------------------------------------------ # write wrdata_en = Signal() @@ -411,35 +406,39 @@ class S6HalfRateDDRPHY(Module): class S6QuarterRateDDRPHY(Module): def __init__(self, pads, rd_bitslip, wr_bitslip, dqs_ddr_alignment): - half_rate_phy = S6HalfRateDDRPHY(pads, "DDR3", rd_bitslip, wr_bitslip, dqs_ddr_alignment) - self.submodules += ClockDomainsRenamer("sys2x")(half_rate_phy) - addressbits = len(pads.a) bankbits = len(pads.ba) nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) databits = len(pads.dq) nphases = 4 - self.settings = PhySettings( - memtype="DDR3", - databits=databits, - dfi_databits=2*databits, - nranks=nranks, - nphases=nphases, - rdphase=0, - wrphase=1, - rdcmdphase=1, - wrcmdphase=0, - cl=5, - cwl=6, - read_latency=6//2+1, - write_latency=2//2 - ) - - self.dfi = dfi = Interface(addressbits, bankbits, nranks, 2*databits, nphases) + # HalfRate PHY ----------------------------------------------------------------------------- + half_rate_phy = S6HalfRateDDRPHY(pads, "DDR3", rd_bitslip, wr_bitslip, dqs_ddr_alignment) + self.submodules += ClockDomainsRenamer("sys2x")(half_rate_phy) self.clk8x_wr_strb = half_rate_phy.clk4x_wr_strb self.clk8x_rd_strb = half_rate_phy.clk4x_rd_strb + # PHY settings ----------------------------------------------------------------------------- + self.settings = PhySettings( + memtype = "DDR3", + databits = databits, + dfi_databits = 2*databits, + nranks = nranks, + nphases = nphases, + rdphase = 0, + wrphase = 1, + rdcmdphase = 1, + wrcmdphase = 0, + cl = 5, + cwl = 6, + read_latency = 6//2+1, + write_latency = 2//2 + ) + + # DFI Interface ---------------------------------------------------------------------------- + self.dfi = dfi = Interface(addressbits, bankbits, nranks, 2*databits, nphases) + + # Clock ------------------------------------------------------------------------------------ # sys_clk : system clk, used for dfi interface # sys2x_clk : 2x system clk sd_sys = getattr(self.sync, "sys") @@ -463,7 +462,7 @@ class S6QuarterRateDDRPHY(Module): phase_sys2x.eq(~phase_sel) ] - # DFI adaptation + # DFI adaptation --------------------------------------------------------------------------- # Commands and writes dfi_omit = set(["rddata", "rddata_valid", "wrdata_en"]) diff --git a/litedram/phy/s7ddrphy.py b/litedram/phy/s7ddrphy.py index eefcb40..e7bc32d 100644 --- a/litedram/phy/s7ddrphy.py +++ b/litedram/phy/s7ddrphy.py @@ -16,16 +16,18 @@ from litex.soc.interconnect.csr import * from litedram.common import * from litedram.phy.dfi import * +# Xilinx Series7 DDR2/DDR3 PHY --------------------------------------------------------------------- class S7DDRPHY(Module, AutoCSR): def __init__(self, pads, with_odelay, memtype="DDR3", nphases=4, sys_clk_freq=100e6, iodelay_clk_freq=200e6, cmd_latency=0): assert not (memtype == "DDR3" and nphases == 2) # FIXME: Needs BL8 support for nphases=2 - tck = 2/(2*nphases*sys_clk_freq) + tck = 2/(2*nphases*sys_clk_freq) addressbits = len(pads.a) - bankbits = len(pads.ba) - nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) - databits = len(pads.dq) - nphases = nphases + bankbits = len(pads.ba) + nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) + databits = len(pads.dq) + nphases = nphases + assert databits%8 == 0 iodelay_tap_average = { 200e6: 78e-12, @@ -33,6 +35,8 @@ class S7DDRPHY(Module, AutoCSR): 400e6: 39e-12, # Only valid for -3 and -2/2E speed grades } + # Registers -------------------------------------------------------------------------------- + self._dly_sel = CSRStorage(databits//8) half_sys8x_taps = math.floor(tck/(4*iodelay_tap_average[iodelay_clk_freq])) self._half_sys8x_taps = CSRStorage(5, reset=half_sys8x_taps) @@ -45,46 +49,47 @@ class S7DDRPHY(Module, AutoCSR): self._dly_sel = CSRStorage(databits//8) - self._rdly_dq_rst = CSR() - self._rdly_dq_inc = CSR() + self._rdly_dq_rst = CSR() + self._rdly_dq_inc = CSR() self._rdly_dq_bitslip_rst = CSR() - self._rdly_dq_bitslip = CSR() + self._rdly_dq_bitslip = CSR() if with_odelay: - self._wdly_dq_rst = CSR() - self._wdly_dq_inc = CSR() + self._wdly_dq_rst = CSR() + self._wdly_dq_inc = CSR() self._wdly_dqs_rst = CSR() self._wdly_dqs_inc = CSR() - # compute phy settings - cl, cwl = get_cl_cw(memtype, tck) - cl_sys_latency = get_sys_latency(nphases, cl) - cwl = cwl + cmd_latency + # PHY settings ----------------------------------------------------------------------------- + cl, cwl = get_cl_cw(memtype, tck) + cl_sys_latency = get_sys_latency(nphases, cl) + cwl = cwl + cmd_latency cwl_sys_latency = get_sys_latency(nphases, cwl) rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl) wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl) self.settings = PhySettings( - memtype=memtype, - databits=databits, - dfi_databits=2*databits, - nranks=nranks, - nphases=nphases, - rdphase=rdphase, - wrphase=wrphase, - rdcmdphase=rdcmdphase, - wrcmdphase=wrcmdphase, - cl=cl, - cwl=cwl - cmd_latency, - read_latency=2 + cl_sys_latency + 2 + 3, - write_latency=cwl_sys_latency + memtype = memtype, + databits = databits, + dfi_databits = 2*databits, + nranks = nranks, + nphases = nphases, + rdphase = rdphase, + wrphase = wrphase, + rdcmdphase = rdcmdphase, + wrcmdphase = wrcmdphase, + cl = cl, + cwl = cwl - cmd_latency, + read_latency = 2 + cl_sys_latency + 2 + 3, + write_latency = cwl_sys_latency ) + # DFI Interface ---------------------------------------------------------------------------- self.dfi = dfi = Interface(addressbits, bankbits, nranks, 2*databits, 4) # # # - # Clock + # Clock ------------------------------------------------------------------------------------ ddr_clk = "sys2x" if nphases == 2 else "sys4x" for i in range(len(pads.clk_p)): sd_clk_se_nodelay = Signal() @@ -123,7 +128,7 @@ class S7DDRPHY(Module, AutoCSR): o_OB=pads.clk_n[i] ) - # Addresses and commands + # Addresses and Commands ------------------------------------------------------------------- for i in range(addressbits): address = Signal() self.specials += \ @@ -224,7 +229,7 @@ class S7DDRPHY(Module, AutoCSR): o_ODATAIN=cmd, o_DATAOUT=getattr(pads, name)[i] ) - # DQS and DM + # DQS and DM ------------------------------------------------------------------------------- oe_dqs = Signal() dqs_preamble = Signal() dqs_postamble = Signal() @@ -324,7 +329,7 @@ class S7DDRPHY(Module, AutoCSR): o_O=pads.dqs_p[i], o_OB=pads.dqs_n[i] ) - # DQ + # DQ --------------------------------------------------------------------------------------- oe_dq = Signal() for i in range(databits): dq_o_nodelay = Signal() @@ -416,7 +421,7 @@ class S7DDRPHY(Module, AutoCSR): io_IO=pads.dq[i] ) - # Flow control + # Flow control ----------------------------------------------------------------------------- # # total read latency: # 2 cycles through OSERDESE2 @@ -468,16 +473,20 @@ class S7DDRPHY(Module, AutoCSR): ~last_wrdata_en[dqs_sys_latency]), ] +# Xilinx Virtex7 (S7DDRPHY with odelay) ------------------------------------------------------------ class V7DDRPHY(S7DDRPHY): def __init__(self, pads, **kwargs): S7DDRPHY.__init__(self, pads, with_odelay=True, **kwargs) +# Xilinx Kintex7 (S7DDRPHY with odelay) ------------------------------------------------------------ class K7DDRPHY(S7DDRPHY): def __init__(self, pads, **kwargs): S7DDRPHY.__init__(self, pads, with_odelay=True, **kwargs) +# Xilinx Artix7 (S7DDRPHY without odelay, sys2/4x_dqs generated in CRG with 90° phase vs sys2/4x) -- + class A7DDRPHY(S7DDRPHY): def __init__(self, pads, **kwargs): S7DDRPHY.__init__(self, pads, with_odelay=False, **kwargs) diff --git a/litedram/phy/usddrphy.py b/litedram/phy/usddrphy.py index b57dfbd..f59aeff 100644 --- a/litedram/phy/usddrphy.py +++ b/litedram/phy/usddrphy.py @@ -15,6 +15,7 @@ from litex.soc.interconnect.csr import * from litedram.common import * from litedram.phy.dfi import * +# Xilinx Ultrascale DDR3/DDR4 PHY ------------------------------------------------------------------ class USDDRPHY(Module, AutoCSR): def __init__(self, pads, memtype="DDR3", sys_clk_freq=100e6, iodelay_clk_freq=200e6, cmd_latency=0): @@ -23,18 +24,20 @@ class USDDRPHY(Module, AutoCSR): if memtype == "DDR4": addressbits += 3 # cas_n/ras_n/we_n multiplexed with address bankbits = len(pads.ba) if memtype == "DDR3" else len(pads.ba) + len(pads.bg) - nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) + nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) databits = len(pads.dq) - nphases = 4 + nphases = 4 + assert databits%8 == 0 if hasattr(pads, "ten"): self.comb += pads.ten.eq(0) + # Registers -------------------------------------------------------------------------------- self._en_vtc = CSRStorage(reset=1) self._half_sys8x_taps = CSRStatus(9) - self._wlevel_en = CSRStorage() + self._wlevel_en = CSRStorage() self._wlevel_strobe = CSR() self._cdly_rst = CSR() @@ -42,40 +45,41 @@ class USDDRPHY(Module, AutoCSR): self._dly_sel = CSRStorage(databits//8) - self._rdly_dq_rst = CSR() - self._rdly_dq_inc = CSR() + self._rdly_dq_rst = CSR() + self._rdly_dq_inc = CSR() self._rdly_dq_bitslip_rst = CSR() - self._rdly_dq_bitslip = CSR() + self._rdly_dq_bitslip = CSR() - self._wdly_dq_rst = CSR() - self._wdly_dq_inc = CSR() + self._wdly_dq_rst = CSR() + self._wdly_dq_inc = CSR() self._wdly_dqs_rst = CSR() self._wdly_dqs_inc = CSR() - # compute phy settings - cl, cwl = get_cl_cw(memtype, tck) - cwl = cwl + cmd_latency - cl_sys_latency = get_sys_latency(nphases, cl) + # PHY settings ----------------------------------------------------------------------------- + cl, cwl = get_cl_cw(memtype, tck) + cwl = cwl + cmd_latency + cl_sys_latency = get_sys_latency(nphases, cl) cwl_sys_latency = get_sys_latency(nphases, cwl) rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl) wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl) self.settings = PhySettings( - memtype=memtype, - databits=databits, - dfi_databits=2*databits, - nranks=nranks, - nphases=nphases, - rdphase=rdphase, - wrphase=wrphase, - rdcmdphase=rdcmdphase, - wrcmdphase=wrcmdphase, - cl=cl, - cwl=cwl - cmd_latency, - read_latency=2 + cl_sys_latency + 1 + 3, - write_latency=cwl_sys_latency + memtype = memtype, + databits = databits, + dfi_databits = 2*databits, + nranks = nranks, + nphases = nphases, + rdphase = rdphase, + wrphase = wrphase, + rdcmdphase = rdcmdphase, + wrcmdphase = wrcmdphase, + cl = cl, + cwl = cwl - cmd_latency, + read_latency = 2 + cl_sys_latency + 1 + 3, + write_latency = cwl_sys_latency ) + # DFI Interface ---------------------------------------------------------------------------- self.dfi = dfi = Interface(addressbits, bankbits, nranks, 2*databits, nphases) if memtype == "DDR4": dfi = Interface(addressbits, bankbits, nranks, 2*databits, nphases) @@ -83,7 +87,7 @@ class USDDRPHY(Module, AutoCSR): # # # - # Clock + # Clock ------------------------------------------------------------------------------------ clk_o_nodelay = Signal() clk_o_delayed = Signal() self.specials += [ @@ -114,7 +118,7 @@ class USDDRPHY(Module, AutoCSR): ) ] - # Addresses and commands + # Addresses and Commands ------------------------------------------------------------------- for i in range(addressbits if memtype=="DDR3" else addressbits-3): a_o_nodelay = Signal() self.specials += [ @@ -212,7 +216,7 @@ class USDDRPHY(Module, AutoCSR): ) ] - # DQS and DM + # DQS and DM ------------------------------------------------------------------------------- oe_dqs = Signal() dqs_serdes_pattern = Signal(8) self.comb += \ @@ -258,8 +262,7 @@ class USDDRPHY(Module, AutoCSR): dqs_delayed = Signal() dqs_t = Signal() if i == 0: - # Store initial DQS DELAY_VALUE (in taps) to - # be able to reload DELAY_VALUE after reset. + # Store initial DQS DELAY_VALUE (in taps) to be able to reload DELAY_VALUE after reset. dqs_taps = Signal(9) dqs_taps_timer = WaitTimer(2**16) self.submodules += dqs_taps_timer @@ -303,7 +306,7 @@ class USDDRPHY(Module, AutoCSR): ) ] - # DQ + # DQ --------------------------------------------------------------------------------------- oe_dq = Signal() for i in range(databits): dq_o_nodelay = Signal() @@ -390,7 +393,7 @@ class USDDRPHY(Module, AutoCSR): dfi.phases[3].rddata[databits+i].eq(dq_bitslip.o[7]), ] - # Flow control + # Flow control ----------------------------------------------------------------------------- # # total read latency: # 2 cycles through OSERDESE2