From b24943e6919c0d9b284d3d67266c353628371370 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 16:21:02 +0200 Subject: [PATCH 01/18] bench/genesys2: add litescope on ddrphy.dfi. --- bench/genesys2.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bench/genesys2.py b/bench/genesys2.py index 3d5cb75..7d9a6ac 100755 --- a/bench/genesys2.py +++ b/bench/genesys2.py @@ -97,6 +97,15 @@ class BenchSoC(SoCCore): self.add_csr("ethphy") self.add_etherbone(phy=self.ethphy) + # Analyzer --------------------------------------------------------------------------------- + from litescope import LiteScopeAnalyzer + analyzer_signals = [self.ddrphy.dfi] + self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals, + depth = 512, + clock_domain = "sys", + csr_csv = "analyzer.csv") + self.add_csr("analyzer") + # Leds ------------------------------------------------------------------------------------- from litex.soc.cores.led import LedChaser self.submodules.leds = LedChaser( From fcd1b2ca2ba1a708e3eb191503cd796a54918cc1 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 16:22:08 +0200 Subject: [PATCH 02/18] phy/s7ddrphy: reduce write_latency on controller by 1 sys_clk (to allow BitSlip). --- litedram/phy/s7ddrphy.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/litedram/phy/s7ddrphy.py b/litedram/phy/s7ddrphy.py index fd5075a..442c81c 100644 --- a/litedram/phy/s7ddrphy.py +++ b/litedram/phy/s7ddrphy.py @@ -98,7 +98,7 @@ class S7DDRPHY(Module, AutoCSR): cl = cl, cwl = cwl, read_latency = cl_sys_latency + 6, - write_latency = cwl_sys_latency, + write_latency = cwl_sys_latency - 1, cmd_latency = cmd_latency, cmd_delay = cmd_delay, ) @@ -264,6 +264,9 @@ class S7DDRPHY(Module, AutoCSR): # DM --------------------------------------------------------------------------------------- for i in range(databits//8): dm_o_nodelay = Signal() + _dm = Cat(*[dfi.phases[n//2].wrdata_mask[n%2*databits//8+i] for n in range(8)]) + dm = Signal(8) + self.sync += dm.eq(_dm) self.specials += Instance("OSERDESE2", p_SERDES_MODE = "MASTER", p_DATA_WIDTH = 2*nphases, @@ -273,7 +276,7 @@ class S7DDRPHY(Module, AutoCSR): i_RST = ResetSignal() | self._rst.storage, i_CLK = ClockSignal(ddr_clk), i_CLKDIV = ClockSignal(), - **{f"i_D{n+1}": dfi.phases[n//2].wrdata_mask[n%2*databits//8+i] for n in range(8)}, + **{f"i_D{n+1}": dm[n] for n in range(8)}, i_OCE = 1, o_OQ = dm_o_nodelay if with_odelay else pads.dm[i], ) @@ -308,6 +311,9 @@ class S7DDRPHY(Module, AutoCSR): dq_i_delayed = Signal() dq_t = Signal() dq_i_data = Signal(8) + _dq = Cat(*[dfi.phases[n//2].wrdata[n%2*databits+i] for n in range(8)]) + dq = Signal(8) + self.sync += dq.eq(_dq) self.specials += Instance("OSERDESE2", p_SERDES_MODE = "MASTER", p_DATA_WIDTH = 2*nphases, @@ -317,7 +323,7 @@ class S7DDRPHY(Module, AutoCSR): i_RST = ResetSignal() | self._rst.storage, i_CLK = ClockSignal(ddr_clk), i_CLKDIV = ClockSignal(), - **{f"i_D{n+1}": dfi.phases[n//2].wrdata[n%2*databits+i] for n in range(8)}, + **{f"i_D{n+1}": dq[n] for n in range(8)}, i_TCE = 1, i_T1 = ~dq_oe_delay.output, o_TQ = dq_t, From c16628531a568417dc5e23c0d39388bed9e72166 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 16:56:22 +0200 Subject: [PATCH 03/18] common/BitSlip: allow passing i/o signals as parameters. --- litedram/common.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/litedram/common.py b/litedram/common.py index 69eb1a3..dd58618 100644 --- a/litedram/common.py +++ b/litedram/common.py @@ -117,11 +117,11 @@ class PHYPadsCombiner: # BitSlip ------------------------------------------------------------------------------------------ class BitSlip(Module): - def __init__(self, dw, rst=None, slp=None, cycles=1): - self.i = Signal(dw) - self.o = Signal(dw) - self.rst = Signal() if rst is None else rst - self.slp = Signal() if slp is None else slp + def __init__(self, dw, i=None, o=None, rst=None, slp=None, cycles=1): + self.i = Signal(dw) if i is None else i + self.o = Signal(dw) if o is None else o + self.rst = Signal() if rst is None else rst + self.slp = Signal() if slp is None else slp # # # From 6e8d37c8735158a11000f2e5309b91cfb803a0df Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 16:57:12 +0200 Subject: [PATCH 04/18] phy/s7ddrphy: replace dm/dq delays with BitSlip. --- litedram/phy/s7ddrphy.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/litedram/phy/s7ddrphy.py b/litedram/phy/s7ddrphy.py index 442c81c..88b143e 100644 --- a/litedram/phy/s7ddrphy.py +++ b/litedram/phy/s7ddrphy.py @@ -98,7 +98,7 @@ class S7DDRPHY(Module, AutoCSR): cl = cl, cwl = cwl, read_latency = cl_sys_latency + 6, - write_latency = cwl_sys_latency - 1, + write_latency = cwl_sys_latency - 2, cmd_latency = cmd_latency, cmd_delay = cmd_delay, ) @@ -264,9 +264,10 @@ class S7DDRPHY(Module, AutoCSR): # DM --------------------------------------------------------------------------------------- for i in range(databits//8): dm_o_nodelay = Signal() - _dm = Cat(*[dfi.phases[n//2].wrdata_mask[n%2*databits//8+i] for n in range(8)]) - dm = Signal(8) - self.sync += dm.eq(_dm) + dm_o_bitslip = BitSlip(8, + i = Cat(*[dfi.phases[n//2].wrdata_mask[n%2*databits//8+i] for n in range(8)]), + cycles = 1) + self.submodules += dm_o_bitslip self.specials += Instance("OSERDESE2", p_SERDES_MODE = "MASTER", p_DATA_WIDTH = 2*nphases, @@ -276,7 +277,7 @@ class S7DDRPHY(Module, AutoCSR): i_RST = ResetSignal() | self._rst.storage, i_CLK = ClockSignal(ddr_clk), i_CLKDIV = ClockSignal(), - **{f"i_D{n+1}": dm[n] for n in range(8)}, + **{f"i_D{n+1}": dm_o_bitslip.o[n] for n in range(8)}, i_OCE = 1, o_OQ = dm_o_nodelay if with_odelay else pads.dm[i], ) @@ -311,9 +312,10 @@ class S7DDRPHY(Module, AutoCSR): dq_i_delayed = Signal() dq_t = Signal() dq_i_data = Signal(8) - _dq = Cat(*[dfi.phases[n//2].wrdata[n%2*databits+i] for n in range(8)]) - dq = Signal(8) - self.sync += dq.eq(_dq) + dq_o_bitslip = BitSlip(8, + i = Cat(*[dfi.phases[n//2].wrdata[n%2*databits+i] for n in range(8)]), + cycles = 1) + self.submodules += dq_o_bitslip self.specials += Instance("OSERDESE2", p_SERDES_MODE = "MASTER", p_DATA_WIDTH = 2*nphases, @@ -323,7 +325,7 @@ class S7DDRPHY(Module, AutoCSR): i_RST = ResetSignal() | self._rst.storage, i_CLK = ClockSignal(ddr_clk), i_CLKDIV = ClockSignal(), - **{f"i_D{n+1}": dq[n] for n in range(8)}, + **{f"i_D{n+1}": dq_o_bitslip.o[n] for n in range(8)}, i_TCE = 1, i_T1 = ~dq_oe_delay.output, o_TQ = dq_t, From 732df044136347bcf2a36e46115c05cf71a28270 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 17:16:21 +0200 Subject: [PATCH 05/18] common/Bitslip: add assert on cycles. --- litedram/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litedram/common.py b/litedram/common.py index dd58618..94f9481 100644 --- a/litedram/common.py +++ b/litedram/common.py @@ -122,6 +122,7 @@ class BitSlip(Module): self.o = Signal(dw) if o is None else o self.rst = Signal() if rst is None else rst self.slp = Signal() if slp is None else slp + assert cycles >= 1 # # # From 3fddff3a1191541544526997da585107d33f1d30 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 17:37:24 +0200 Subject: [PATCH 06/18] common/BitSlip: shift output by one bit (allow 1 cycle latency on writes), set reset value to cycles*dw-1. --- litedram/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litedram/common.py b/litedram/common.py index 94f9481..f7eb088 100644 --- a/litedram/common.py +++ b/litedram/common.py @@ -126,7 +126,7 @@ class BitSlip(Module): # # # - value = Signal(max=cycles*dw) + value = Signal(max=cycles*dw, reset=cycles*dw-1) self.sync += If(self.slp, value.eq(value + 1)) self.sync += If(self.rst, value.eq(0)) @@ -134,7 +134,7 @@ class BitSlip(Module): self.sync += r.eq(Cat(r[dw:], self.i)) cases = {} for i in range(cycles*dw): - cases[i] = self.o.eq(r[i:dw+i]) + cases[i] = self.o.eq(r[i+1:dw+i+1]) self.comb += Case(value, cases) # TappedDelayLine ---------------------------------------------------------------------------------- From 0ac23fde52cbe365924a064b52772234dd0f5e8b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 18:08:36 +0200 Subject: [PATCH 07/18] phy/s7ddrphy: increase write_latency by 1 (now possible with previous BitSlip chantges). --- litedram/phy/s7ddrphy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litedram/phy/s7ddrphy.py b/litedram/phy/s7ddrphy.py index 88b143e..b4d4619 100644 --- a/litedram/phy/s7ddrphy.py +++ b/litedram/phy/s7ddrphy.py @@ -98,7 +98,7 @@ class S7DDRPHY(Module, AutoCSR): cl = cl, cwl = cwl, read_latency = cl_sys_latency + 6, - write_latency = cwl_sys_latency - 2, + write_latency = cwl_sys_latency - 1, cmd_latency = cmd_latency, cmd_delay = cmd_delay, ) From 83d70a3eb9aefd6b4714310508a417f88adef420 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 18:17:47 +0200 Subject: [PATCH 08/18] phy/s7ddrphy: also add bitslip on dqs. --- litedram/phy/s7ddrphy.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/litedram/phy/s7ddrphy.py b/litedram/phy/s7ddrphy.py index b4d4619..26960f2 100644 --- a/litedram/phy/s7ddrphy.py +++ b/litedram/phy/s7ddrphy.py @@ -212,8 +212,9 @@ class S7DDRPHY(Module, AutoCSR): postamble = dqs_postamble, wlevel_en = self._wlevel_en.storage, wlevel_strobe = self._wlevel_strobe.re, - register = not with_odelay) - self.submodules += dqs_oe_delay, dqs_pattern + register = False) # FIXME: fix not with_odelay case. + dqs_bitslip = BitSlip(8, i=dqs_pattern.o, cycles=1) + self.submodules += dqs_oe_delay, dqs_pattern, dqs_bitslip self.comb += dqs_oe_delay.input.eq(dqs_preamble | dqs_oe | dqs_postamble) for i in range(databits//8): dqs_o_no_delay = Signal() @@ -228,7 +229,7 @@ class S7DDRPHY(Module, AutoCSR): i_RST = ResetSignal() | self._rst.storage, i_CLK = ClockSignal(ddr_clk) if with_odelay else ClockSignal(ddr_clk+"_dqs"), i_CLKDIV = ClockSignal(), - **{f"i_D{n+1}": dqs_pattern.o[n] for n in range(8)}, + **{f"i_D{n+1}": dqs_bitslip.o[n] for n in range(8)}, i_OCE = 1, o_OFB = dqs_o_no_delay if with_odelay else Signal(), o_OQ = Signal() if with_odelay else dqs_o_no_delay, @@ -264,7 +265,7 @@ class S7DDRPHY(Module, AutoCSR): # DM --------------------------------------------------------------------------------------- for i in range(databits//8): dm_o_nodelay = Signal() - dm_o_bitslip = BitSlip(8, + dm_o_bitslip = BitSlip(8, i = Cat(*[dfi.phases[n//2].wrdata_mask[n%2*databits//8+i] for n in range(8)]), cycles = 1) self.submodules += dm_o_bitslip @@ -312,7 +313,7 @@ class S7DDRPHY(Module, AutoCSR): dq_i_delayed = Signal() dq_t = Signal() dq_i_data = Signal(8) - dq_o_bitslip = BitSlip(8, + dq_o_bitslip = BitSlip(8, i = Cat(*[dfi.phases[n//2].wrdata[n%2*databits+i] for n in range(8)]), cycles = 1) self.submodules += dq_o_bitslip From 9787b868e8245d4b01336f414d9367413c62076c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 18:52:45 +0200 Subject: [PATCH 09/18] phy/s7ddrphy: add dynamic control of dq/dm/dqs bitslips. --- litedram/phy/s7ddrphy.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/litedram/phy/s7ddrphy.py b/litedram/phy/s7ddrphy.py index 26960f2..052003f 100644 --- a/litedram/phy/s7ddrphy.py +++ b/litedram/phy/s7ddrphy.py @@ -82,6 +82,9 @@ class S7DDRPHY(Module, AutoCSR): self._wdly_dqs_rst = CSR() self._wdly_dqs_inc = CSR() + self._wdly_dq_bitslip_rst = CSR() + self._wdly_dq_bitslip = CSR() + self._rdphase = CSRStorage(int(math.log2(nphases)), reset=rdphase) self._wrphase = CSRStorage(int(math.log2(nphases)), reset=wrphase) @@ -208,18 +211,23 @@ class S7DDRPHY(Module, AutoCSR): dqs_postamble = Signal() dqs_oe_delay = TappedDelayLine(ntaps=2 if nphases == 4 else 1) dqs_pattern = DQSPattern( - preamble = dqs_preamble, - postamble = dqs_postamble, + #preamble = dqs_preamble, # FIXME + #postamble = dqs_postamble, # FIXME wlevel_en = self._wlevel_en.storage, wlevel_strobe = self._wlevel_strobe.re, - register = False) # FIXME: fix not with_odelay case. - dqs_bitslip = BitSlip(8, i=dqs_pattern.o, cycles=1) - self.submodules += dqs_oe_delay, dqs_pattern, dqs_bitslip + register = not with_odelay) + self.submodules += dqs_oe_delay, dqs_pattern self.comb += dqs_oe_delay.input.eq(dqs_preamble | dqs_oe | dqs_postamble) for i in range(databits//8): dqs_o_no_delay = Signal() dqs_o_delayed = Signal() dqs_t = Signal() + dqs_bitslip = BitSlip(8, + i = dqs_pattern.o, + rst = self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re, + slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re, + cycles = 1) + self.submodules += dqs_bitslip self.specials += Instance("OSERDESE2", p_SERDES_MODE = "MASTER", p_DATA_WIDTH = 2*nphases, @@ -267,6 +275,8 @@ class S7DDRPHY(Module, AutoCSR): dm_o_nodelay = Signal() dm_o_bitslip = BitSlip(8, i = Cat(*[dfi.phases[n//2].wrdata_mask[n%2*databits//8+i] for n in range(8)]), + rst = self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re, + slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re, cycles = 1) self.submodules += dm_o_bitslip self.specials += Instance("OSERDESE2", @@ -315,6 +325,8 @@ class S7DDRPHY(Module, AutoCSR): dq_i_data = Signal(8) dq_o_bitslip = BitSlip(8, i = Cat(*[dfi.phases[n//2].wrdata[n%2*databits+i] for n in range(8)]), + rst = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip_rst.re, + slp = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip.re, cycles = 1) self.submodules += dq_o_bitslip self.specials += Instance("OSERDESE2", From 1d450bac572ec3b97f3e0871441e7f5191c7d40c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 19:40:40 +0200 Subject: [PATCH 10/18] common/BitSlip: reset value to value.reset. --- litedram/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litedram/common.py b/litedram/common.py index f7eb088..10d8eeb 100644 --- a/litedram/common.py +++ b/litedram/common.py @@ -128,7 +128,7 @@ class BitSlip(Module): value = Signal(max=cycles*dw, reset=cycles*dw-1) self.sync += If(self.slp, value.eq(value + 1)) - self.sync += If(self.rst, value.eq(0)) + self.sync += If(self.rst, value.eq(value.reset)) r = Signal((cycles+1)*dw, reset_less=True) self.sync += r.eq(Cat(r[dw:], self.i)) From 5d528cbad07e6066b80d58b109795d79e2d6f35b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Oct 2020 19:50:18 +0200 Subject: [PATCH 11/18] phy/usddrphy: add write leveling bitslip support on dq/dm/dqs (similar to s7ddrphy). --- litedram/phy/usddrphy.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/litedram/phy/usddrphy.py b/litedram/phy/usddrphy.py index e0ceecd..046b8be 100644 --- a/litedram/phy/usddrphy.py +++ b/litedram/phy/usddrphy.py @@ -81,6 +81,9 @@ class USDDRPHY(Module, AutoCSR): self._wdly_dqs_rst = CSR() self._wdly_dqs_inc = CSR() + self._wdly_dq_bitslip_rst = CSR() + self._wdly_dq_bitslip = CSR() + self._rdphase = CSRStorage(2, reset=rdphase) self._wrphase = CSRStorage(2, reset=wrphase) @@ -97,7 +100,7 @@ class USDDRPHY(Module, AutoCSR): cl = cl, cwl = cwl, read_latency = cl_sys_latency + 5, - write_latency = cwl_sys_latency, + write_latency = cwl_sys_latency - 1, cmd_latency = cmd_latency, cmd_delay = cmd_delay, ) @@ -228,8 +231,8 @@ class USDDRPHY(Module, AutoCSR): dqs_postamble = Signal() dqs_oe_delay = TappedDelayLine(ntaps=1) dqs_pattern = DQSPattern( - preamble = dqs_preamble, - postamble = dqs_postamble, + #preamble = dqs_preamble, # FIXME + #postamble = dqs_postamble, # FIXME wlevel_en = self._wlevel_en.storage, wlevel_strobe = self._wlevel_strobe.re) self.submodules += dqs_oe_delay, dqs_pattern @@ -247,6 +250,12 @@ class USDDRPHY(Module, AutoCSR): dqs_taps_done.eq(1), self._half_sys8x_taps.status.eq(dqs_taps) ) + dqs_bitslip = BitSlip(8, + i = dqs_pattern.o, + rst = self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re, + slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re, + cycles = 1) + self.submodules += dqs_bitslip if x4_dimm_mode: dqs_pads = ((pads.dqs_p[i*2], pads.dqs_n[i*2]), (pads.dqs_p[i*2 + 1], pads.dqs_n[i*2 + 1])) else: @@ -267,7 +276,7 @@ class USDDRPHY(Module, AutoCSR): i_CLK = ClockSignal("sys4x"), i_CLKDIV = ClockSignal(), i_T = ~dqs_oe_delay.output, - i_D = dqs_pattern.o, + i_D = dqs_bitslip.o, o_OQ = dqs_nodelay, o_T_OUT = dqs_t, @@ -303,6 +312,12 @@ class USDDRPHY(Module, AutoCSR): for i in range(databits//8): if hasattr(pads, "dm"): dm_o_nodelay = Signal() + dm_o_bitslip = BitSlip(8, + i = Cat(*[dfi.phases[n//2].wrdata_mask[n%2*databits//8+i] for n in range(8)]), + rst = self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re, + slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re, + cycles = 1) + self.submodules += dm_o_bitslip self.specials += [ Instance("OSERDESE3", p_SIM_DEVICE = device, @@ -314,7 +329,7 @@ class USDDRPHY(Module, AutoCSR): i_RST = ResetSignal() | self._rst.storage, i_CLK = ClockSignal("sys4x"), i_CLKDIV = ClockSignal(), - i_D = Cat(*[dfi.phases[n//2].wrdata_mask[n%2*databits//8+i] for n in range(8)]), + i_D = dm_o_bitslip.o, o_OQ = dm_o_nodelay, ), Instance("ODELAYE3", @@ -348,6 +363,12 @@ class USDDRPHY(Module, AutoCSR): dq_i_nodelay = Signal() dq_i_delayed = Signal() dq_t = Signal() + dq_o_bitslip = BitSlip(8, + i = Cat(*[dfi.phases[n//2].wrdata[n%2*databits+i] for n in range(8)]), + rst = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip_rst.re, + slp = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip.re, + cycles = 1) + self.submodules += dq_o_bitslip self.specials += Instance("OSERDESE3", p_SIM_DEVICE = device, p_DATA_WIDTH = 8, @@ -358,7 +379,7 @@ class USDDRPHY(Module, AutoCSR): i_RST = ResetSignal() | self._rst.storage, i_CLK = ClockSignal("sys4x"), i_CLKDIV = ClockSignal(), - i_D = Cat(*[dfi.phases[n//2].wrdata[n%2*databits+i] for n in range(8)]), + i_D = dq_o_bitslip.o, i_T = ~dq_oe_delay.output, o_OQ = dq_o_nodelay, o_T_OUT = dq_t, From a1e8bcb53c1aae01ae6aa675f0c67a4aacbc34d3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 12 Oct 2020 10:41:33 +0200 Subject: [PATCH 12/18] phy/s7/usddrphy: reset bitslip modules with rst CSR. --- litedram/phy/s7ddrphy.py | 8 ++++---- litedram/phy/usddrphy.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/litedram/phy/s7ddrphy.py b/litedram/phy/s7ddrphy.py index 052003f..868244c 100644 --- a/litedram/phy/s7ddrphy.py +++ b/litedram/phy/s7ddrphy.py @@ -224,7 +224,7 @@ class S7DDRPHY(Module, AutoCSR): dqs_t = Signal() dqs_bitslip = BitSlip(8, i = dqs_pattern.o, - rst = self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re, + rst = (self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re) | self._rst.storage, slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re, cycles = 1) self.submodules += dqs_bitslip @@ -275,7 +275,7 @@ class S7DDRPHY(Module, AutoCSR): dm_o_nodelay = Signal() dm_o_bitslip = BitSlip(8, i = Cat(*[dfi.phases[n//2].wrdata_mask[n%2*databits//8+i] for n in range(8)]), - rst = self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re, + rst = (self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re) | self._rst.storage, slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re, cycles = 1) self.submodules += dm_o_bitslip @@ -325,7 +325,7 @@ class S7DDRPHY(Module, AutoCSR): dq_i_data = Signal(8) dq_o_bitslip = BitSlip(8, i = Cat(*[dfi.phases[n//2].wrdata[n%2*databits+i] for n in range(8)]), - rst = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip_rst.re, + rst = (self._dly_sel.storage[i//8] & self._wdly_dq_bitslip_rst.re) | self._rst.storage, slp = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip.re, cycles = 1) self.submodules += dq_o_bitslip @@ -346,7 +346,7 @@ class S7DDRPHY(Module, AutoCSR): o_OQ = dq_o_nodelay, ) dq_i_bitslip = BitSlip(8, - rst = self._dly_sel.storage[i//8] & self._rdly_dq_bitslip_rst.re, + rst = (self._dly_sel.storage[i//8] & self._rdly_dq_bitslip_rst.re) | self._rst.storage, slp = self._dly_sel.storage[i//8] & self._rdly_dq_bitslip.re, cycles = 1) self.submodules += dq_i_bitslip diff --git a/litedram/phy/usddrphy.py b/litedram/phy/usddrphy.py index 046b8be..6f91e0c 100644 --- a/litedram/phy/usddrphy.py +++ b/litedram/phy/usddrphy.py @@ -252,7 +252,7 @@ class USDDRPHY(Module, AutoCSR): ) dqs_bitslip = BitSlip(8, i = dqs_pattern.o, - rst = self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re, + rst = (self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re) | self._rst.storage, slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re, cycles = 1) self.submodules += dqs_bitslip @@ -314,7 +314,7 @@ class USDDRPHY(Module, AutoCSR): dm_o_nodelay = Signal() dm_o_bitslip = BitSlip(8, i = Cat(*[dfi.phases[n//2].wrdata_mask[n%2*databits//8+i] for n in range(8)]), - rst = self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re, + rst = (self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re) | self._rst.storage, slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re, cycles = 1) self.submodules += dm_o_bitslip @@ -365,7 +365,7 @@ class USDDRPHY(Module, AutoCSR): dq_t = Signal() dq_o_bitslip = BitSlip(8, i = Cat(*[dfi.phases[n//2].wrdata[n%2*databits+i] for n in range(8)]), - rst = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip_rst.re, + rst = (self._dly_sel.storage[i//8] & self._wdly_dq_bitslip_rst.re) | self._rst.storage, slp = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip.re, cycles = 1) self.submodules += dq_o_bitslip @@ -385,7 +385,7 @@ class USDDRPHY(Module, AutoCSR): o_T_OUT = dq_t, ) dq_i_bitslip = BitSlip(8, - rst = self._dly_sel.storage[i//8] & self._rdly_dq_bitslip_rst.re, + rst = (self._dly_sel.storage[i//8] & self._rdly_dq_bitslip_rst.re) | self._rst.storage, slp = self._dly_sel.storage[i//8] & self._rdly_dq_bitslip.re, cycles = 1) self.submodules += dq_i_bitslip From 97b4029be73ea5e30b1fe26d3bc2ba43fc0f9d01 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 12 Oct 2020 15:50:35 +0200 Subject: [PATCH 13/18] litedram/init: pass write latency calibration capability to software. --- litedram/init.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litedram/init.py b/litedram/init.py index 169a286..6baf31c 100644 --- a/litedram/init.py +++ b/litedram/init.py @@ -508,6 +508,7 @@ def get_sdram_phy_c_header(phy_settings, timing_settings): if phytype in ["USDDRPHY", "USPDDRPHY"]: r += "#define SDRAM_PHY_WRITE_LEVELING_REINIT\n" if phytype in ["USDDRPHY", "USPDDRPHY", "A7DDRPHY", "K7DDRPHY", "V7DDRPHY", "ECP5DDRPHY"]: + r += "#define SDRAM_PHY_WRITE_LATENCY_CALIBRATION_CAPABLE\n" r += "#define SDRAM_PHY_READ_LEVELING_CAPABLE\n" # Define number of modules/delays/bitslips From a18d04da4298b338d0c88021dee3196b7d358f2a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 12 Oct 2020 18:32:41 +0200 Subject: [PATCH 14/18] phy/s7ddrphy: simplify cmd_latency (set it to 1 as default except for a7ddrphy). --- litedram/phy/s7ddrphy.py | 12 ++++++------ litedram/phy/usddrphy.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/litedram/phy/s7ddrphy.py b/litedram/phy/s7ddrphy.py index 868244c..985bf52 100644 --- a/litedram/phy/s7ddrphy.py +++ b/litedram/phy/s7ddrphy.py @@ -29,7 +29,7 @@ class S7DDRPHY(Module, AutoCSR): nphases = 4, sys_clk_freq = 100e6, iodelay_clk_freq = 200e6, - cmd_latency = 0, + cmd_latency = 1, cmd_delay = None): assert not (memtype == "DDR3" and nphases == 2) phytype = self.__class__.__name__ @@ -448,17 +448,17 @@ class S7DDRPHY(Module, AutoCSR): # Xilinx Virtex7 (S7DDRPHY with odelay) ------------------------------------------------------------ class V7DDRPHY(S7DDRPHY): - def __init__(self, pads, cmd_latency=1, **kwargs): + 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, cmd_latency=1, **kwargs): - S7DDRPHY.__init__(self, pads, cmd_latency=cmd_latency, with_odelay=True, **kwargs) + 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, cmd_latency=0, **kwargs): - S7DDRPHY.__init__(self, pads, cmd_latency=0, with_odelay=False, **kwargs) + def __init__(self, pads, **kwargs): + S7DDRPHY.__init__(self, pads, with_odelay=False, cmd_latency=0, **kwargs) diff --git a/litedram/phy/usddrphy.py b/litedram/phy/usddrphy.py index 6f91e0c..c401550 100644 --- a/litedram/phy/usddrphy.py +++ b/litedram/phy/usddrphy.py @@ -486,5 +486,5 @@ class USDDRPHY(Module, AutoCSR): # Xilinx Ultrascale Plus DDR3/DDR4 PHY ------------------------------------------------------------- class USPDDRPHY(USDDRPHY): - def __init__(self, pads, cmd_latency=1, **kwargs): - USDDRPHY.__init__(self, pads, cmd_latency=cmd_latency, **kwargs) + def __init__(self, pads, **kwargs): + USDDRPHY.__init__(self, pads, **kwargs) From 60c68bf9499aa18470fabb3739c19b0a8c05053f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 12 Oct 2020 18:47:44 +0200 Subject: [PATCH 15/18] init/get_sdram_phy_c_header: fix ECPDDRPHY case. --- litedram/init.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litedram/init.py b/litedram/init.py index 6baf31c..7fa6cb8 100644 --- a/litedram/init.py +++ b/litedram/init.py @@ -507,9 +507,11 @@ def get_sdram_phy_c_header(phy_settings, timing_settings): r += "#define SDRAM_PHY_WRITE_LEVELING_CAPABLE\n" if phytype in ["USDDRPHY", "USPDDRPHY"]: r += "#define SDRAM_PHY_WRITE_LEVELING_REINIT\n" - if phytype in ["USDDRPHY", "USPDDRPHY", "A7DDRPHY", "K7DDRPHY", "V7DDRPHY", "ECP5DDRPHY"]: + if phytype in ["USDDRPHY", "USPDDRPHY", "A7DDRPHY", "K7DDRPHY", "V7DDRPHY"]: r += "#define SDRAM_PHY_WRITE_LATENCY_CALIBRATION_CAPABLE\n" r += "#define SDRAM_PHY_READ_LEVELING_CAPABLE\n" + if phytype in ["ECP5DDRPHY"]: + r += "#define SDRAM_PHY_READ_LEVELING_CAPABLE\n" # Define number of modules/delays/bitslips if phytype in ["USDDRPHY", "USPDDRPHY"]: From df73b982ee3aa6ecb4eff12b5f998e8e5b9d0c70 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 12 Oct 2020 18:50:31 +0200 Subject: [PATCH 16/18] test/reference: update --- test/reference/ddr3_init.h | 1 + test/reference/ddr4_init.h | 1 + 2 files changed, 2 insertions(+) diff --git a/test/reference/ddr3_init.h b/test/reference/ddr3_init.h index d7e47c5..f399bed 100644 --- a/test/reference/ddr3_init.h +++ b/test/reference/ddr3_init.h @@ -25,6 +25,7 @@ #define SDRAM_PHY_RDPHASE 0 #define SDRAM_PHY_WRPHASE 1 #define SDRAM_PHY_WRITE_LEVELING_CAPABLE +#define SDRAM_PHY_WRITE_LATENCY_CALIBRATION_CAPABLE #define SDRAM_PHY_READ_LEVELING_CAPABLE #define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2 #define SDRAM_PHY_DELAYS 32 diff --git a/test/reference/ddr4_init.h b/test/reference/ddr4_init.h index 4691ac3..6abf3c9 100644 --- a/test/reference/ddr4_init.h +++ b/test/reference/ddr4_init.h @@ -26,6 +26,7 @@ #define SDRAM_PHY_WRPHASE 2 #define SDRAM_PHY_WRITE_LEVELING_CAPABLE #define SDRAM_PHY_WRITE_LEVELING_REINIT +#define SDRAM_PHY_WRITE_LATENCY_CALIBRATION_CAPABLE #define SDRAM_PHY_READ_LEVELING_CAPABLE #define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2 #define SDRAM_PHY_DELAYS 512 From 1ee4fa25c4ece921d5ee4e30e7eb66d093face68 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 12 Oct 2020 19:25:34 +0200 Subject: [PATCH 17/18] phy/ecp5ddrphy: add rst CSR. --- litedram/phy/ecp5ddrphy.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/litedram/phy/ecp5ddrphy.py b/litedram/phy/ecp5ddrphy.py index 939e213..c74ce3f 100644 --- a/litedram/phy/ecp5ddrphy.py +++ b/litedram/phy/ecp5ddrphy.py @@ -108,6 +108,8 @@ class ECP5DDRPHY(Module, AutoCSR): cwl_sys_latency = get_sys_latency(nphases, cwl) # Registers -------------------------------------------------------------------------------- + self._rst = CSRStorage() + self._dly_sel = CSRStorage(databits//8) self._rdly_dq_rst = CSR() @@ -154,7 +156,7 @@ class ECP5DDRPHY(Module, AutoCSR): for i in range(len(pads.clk_p)): sd_clk_se = Signal() self.specials += Instance("ODDRX2F", - i_RST = ResetSignal("sys"), + i_RST = ResetSignal("sys") | self._rst.storage, i_SCLK = ClockSignal("sys"), i_ECLK = ClockSignal("sys2x"), **{f"i_D{n}": (0b1010 >> n) & 0b1 for n in range(4)}, @@ -177,7 +179,7 @@ class ECP5DDRPHY(Module, AutoCSR): pad = getattr(pads, pad_name) for i in range(len(pad)): self.specials += Instance("ODDRX2F", - i_RST = ResetSignal("sys"), + i_RST = ResetSignal("sys") | self._rst.storage, i_SCLK = ClockSignal("sys"), i_ECLK = ClockSignal("sys2x"), **{f"i_D{n}": getattr(dfi.phases[n//2], dfi_name)[i] for n in range(4)}, @@ -210,7 +212,7 @@ class ECP5DDRPHY(Module, AutoCSR): p_DQS_LO_DEL_ADJ = "MINUS", p_DQS_LO_DEL_VAL = 4, # Clocks / Reset - i_RST = ResetSignal("sys"), + i_RST = ResetSignal("sys") | self._rst.storage, i_SCLK = ClockSignal("sys"), i_ECLK = ClockSignal("sys2x"), i_DDRDEL = self.init.delay, @@ -252,7 +254,7 @@ class ECP5DDRPHY(Module, AutoCSR): dqs_oe_n = Signal() self.specials += [ Instance("ODDRX2DQSB", - i_RST = ResetSignal("sys"), + i_RST = ResetSignal("sys") | self._rst.storage, i_SCLK = ClockSignal("sys"), i_ECLK = ClockSignal("sys2x"), i_DQSW = dqsw, @@ -260,7 +262,7 @@ class ECP5DDRPHY(Module, AutoCSR): o_Q = dqs ), Instance("TSHX2DQSA", - i_RST = ResetSignal("sys"), + i_RST = ResetSignal("sys") | self._rst.storage, i_SCLK = ClockSignal("sys"), i_ECLK = ClockSignal("sys2x"), i_DQSW = dqsw, @@ -283,7 +285,7 @@ class ECP5DDRPHY(Module, AutoCSR): dm_bl8_cases[1] = dm_o_data_muxed.eq(dm_o_data_d[4:]) self.sync += Case(bl8_chunk, dm_bl8_cases) self.specials += Instance("ODDRX2DQA", - i_RST = ResetSignal("sys"), + i_RST = ResetSignal("sys") | self._rst.storage, i_SCLK = ClockSignal("sys"), i_ECLK = ClockSignal("sys2x"), i_DQSW270 = dqsw270, @@ -310,7 +312,7 @@ class ECP5DDRPHY(Module, AutoCSR): self.sync += Case(bl8_chunk, dq_bl8_cases) self.specials += [ Instance("ODDRX2DQA", - i_RST = ResetSignal("sys"), + i_RST = ResetSignal("sys") | self._rst.storage, i_SCLK = ClockSignal("sys"), i_ECLK = ClockSignal("sys2x"), i_DQSW270 = dqsw270, @@ -319,7 +321,7 @@ class ECP5DDRPHY(Module, AutoCSR): ) ] dq_i_bitslip = BitSlip(4, - rst = self._dly_sel.storage[i] & self._rdly_dq_bitslip_rst.re, + rst = (self._dly_sel.storage[i] & self._rdly_dq_bitslip_rst.re) | self._rst.storage, slp = self._dly_sel.storage[i] & self._rdly_dq_bitslip.re, cycles = 1) self.submodules += dq_i_bitslip @@ -333,7 +335,7 @@ class ECP5DDRPHY(Module, AutoCSR): o_Z = dq_i_delayed ), Instance("IDDRX2DQA", - i_RST = ResetSignal("sys"), + i_RST = ResetSignal("sys") | self._rst.storage, i_SCLK = ClockSignal("sys"), i_ECLK = ClockSignal("sys2x"), i_DQSR90 = dqsr90, @@ -350,7 +352,7 @@ class ECP5DDRPHY(Module, AutoCSR): self.comb += dfi.phases[n//4].rddata[n%4*databits+j].eq(dq_i_data[n]) self.specials += [ Instance("TSHX2DQA", - i_RST = ResetSignal("sys"), + i_RST = ResetSignal("sys") | self._rst.storage, i_SCLK = ClockSignal("sys"), i_ECLK = ClockSignal("sys2x"), i_DQSW270 = dqsw270, From 80b5ed30e9c74f5b5e5328b118685ceefee8e313 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 12 Oct 2020 19:40:00 +0200 Subject: [PATCH 18/18] phy/ecp5ddrphy: reintegrate old BitSlip (issue with new one on ECP5). --- litedram/phy/ecp5ddrphy.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/litedram/phy/ecp5ddrphy.py b/litedram/phy/ecp5ddrphy.py index c74ce3f..241ac0f 100644 --- a/litedram/phy/ecp5ddrphy.py +++ b/litedram/phy/ecp5ddrphy.py @@ -24,6 +24,30 @@ from litex.soc.interconnect.csr import * from litedram.common import * from litedram.phy.dfi import * +# BitSlip ------------------------------------------------------------------------------------------ + +# FIXME: Use BitSlip from litedram.common. + +class BitSlip(Module): + def __init__(self, dw, rst=None, slp=None, cycles=1): + self.i = Signal(dw) + self.o = Signal(dw) + self.rst = Signal() if rst is None else rst + self.slp = Signal() if slp is None else slp + + # # # + + value = Signal(max=cycles*dw) + self.sync += If(self.slp, value.eq(value + 1)) + self.sync += If(self.rst, value.eq(0)) + + r = Signal((cycles+1)*dw, reset_less=True) + self.sync += r.eq(Cat(r[dw:], self.i)) + cases = {} + for i in range(cycles*dw): + cases[i] = self.o.eq(r[i:dw+i]) + self.comb += Case(value, cases) + # Lattice ECP5 DDR PHY Initialization -------------------------------------------------------------- class ECP5DDRPHYInit(Module):