From 8c10f1405b4a07ce0ed866c492f2cb5af592870d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Tue, 24 Aug 2021 15:14:31 +0200 Subject: [PATCH] phy/lpddr5: delay WCK sync FSM transition by 1 cycle With fixed serialization logic WCK sync can be now started later which avoids the need for special logic when tWCKENL=0. --- litedram/phy/lpddr5/basephy.py | 34 +++++++--------------------------- test/test_lpddr5.py | 10 +++++----- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/litedram/phy/lpddr5/basephy.py b/litedram/phy/lpddr5/basephy.py index 3dbfbda..41ea0de 100644 --- a/litedram/phy/lpddr5/basephy.py +++ b/litedram/phy/lpddr5/basephy.py @@ -300,7 +300,7 @@ class LPDDR5PHY(Module, AutoCSR): wck_sync = TappedDelayLine( signal = self.adapter.wck_sync, - ntaps = max(1, max(frange.t_wckenl_wr, frange.t_wckenl_rd) + frange.t_wckpre_static - 1), + ntaps = max(1, max(frange.t_wckenl_wr, frange.t_wckenl_rd) + frange.t_wckpre_static), ) self.submodules += wck_sync wck_sync_taps = Array([wck_sync.input, *wck_sync.taps]) @@ -313,43 +313,23 @@ class LPDDR5PHY(Module, AutoCSR): "toggle_4:1": "-_-_-_-_", } - # When tWCKENL=0 there is a special case: - # tWCKENL=0, tWCKPRE_Static=1: instant static and jump toggle - # tWCKENL=0, tWCKPRE_Static=2: instant static and jump static - # tWCKENL=1, tWCKPRE_Static=1 (and others): jump static, jump toggle - def on_disabled(t_wckenl): - # when there is no tWCKENL we need to use static in this cycle - return If(t_wckenl == 0, - wck_pattern.eq(bitpattern(patterns["static"])), - # If there is only 1 cycle of static, we must jump directly to toggle - If(frange.t_wckpre_static == 1, - NextState("TOGGLE") - ).Else( - NextState("STATIC") - ) - ).Else( - # tWCKENL was > 0, so we just continue to STATIC - NextState("STATIC") - ), - assert frange.t_wckpre_static > 0 # The algorithm assumes it's never 0 wck_fsm = FSM() self.submodules += wck_fsm wck_fsm.act("DISABLED", wck_pattern.eq(bitpattern(patterns["disabled"])), - # Avoid indexing with -1 as it wraps, we just have special logic for tWCKENL=0 - If(wck_sync_taps[max(0, frange.t_wckenl_wr - 1)] == WCKSyncType.WR, - on_disabled(frange.t_wckenl_wr) - ).Elif(wck_sync_taps[max(0, frange.t_wckenl_rd - 1)] == WCKSyncType.RD, - on_disabled(frange.t_wckenl_rd) + If(wck_sync_taps[frange.t_wckenl_wr] == WCKSyncType.WR, + NextState("STATIC") + ).Elif(wck_sync_taps[frange.t_wckenl_rd] == WCKSyncType.RD, + NextState("STATIC") ) ) wck_fsm.act("STATIC", wck_pattern.eq(bitpattern(patterns["static"])), - If(wck_sync_taps[frange.t_wckenl_wr + frange.t_wckpre_static - 1] == WCKSyncType.WR, + If(wck_sync_taps[frange.t_wckenl_wr + frange.t_wckpre_static] == WCKSyncType.WR, NextState("TOGGLE") - ).Elif(wck_sync_taps[frange.t_wckenl_rd + frange.t_wckpre_static - 1] == WCKSyncType.RD, + ).Elif(wck_sync_taps[frange.t_wckenl_rd + frange.t_wckpre_static] == WCKSyncType.RD, NextState("TOGGLE") ) ) diff --git a/test/test_lpddr5.py b/test/test_lpddr5.py index 79a7c4f..08d84be 100644 --- a/test/test_lpddr5.py +++ b/test/test_lpddr5.py @@ -516,14 +516,14 @@ class LPDDR5Tests(unittest.TestCase): # tWCKENL_WR starts counting from first command (CAS) so we add command latency, # then preamble, then toggle for the whole burst, then postamble for tWCKPST=2.5tCK # (but for now we assume that WCK is never disabled) - "wck0": "0000" + wck_preamble + "10 10" * (16//4) + "10 10 1" + "0 10" + "10 10"*2, + "wck0": "0000 0000" + wck_preamble + "10 10" * (16//4) + "10 10 1" + "0 10" + "10 10"*2, }, }, chunk_size=4, ) def test_lpddr5_wck_sync_4to1_write(self): - # Test that correct WCK sequence is generated during WCK sync before burst write for WCK:CK=2:1 + # Test that correct WCK sequence is generated during WCK sync before burst write for WCK:CK=4:1 cases = { # sys_clk_freq: timings 50e6: dict(t_wckenl_wr=0, t_wckenl_static=1, t_wckenl_toggle_wr=2), # data rate 400 MT/s 100e6: dict(t_wckenl_wr=0, t_wckenl_static=1, t_wckenl_toggle_wr=2), # 800 MT/s @@ -559,7 +559,7 @@ class LPDDR5Tests(unittest.TestCase): # tWCKENL_WR starts counting from first command (CAS) so we add command latency, # then preamble, then toggle for the whole burst, then postamble for tWCKPST=2.5tCK # (but for now we assume that WCK is never disabled) - "wck0": "00000000" + wck_preamble + "10101010" * (16//8) + "10101" + "0 10" + "10 10"*2, + "wck0": "00000000 00000000" + wck_preamble + "10101010" * (16//8) + "10101" + "0 10" + "10 10"*2, }, }, ) @@ -591,7 +591,7 @@ class LPDDR5Tests(unittest.TestCase): "cs": "01100000", }, "sys4x_270": { - "wck0": "0000" + wck_preamble + "10 10" * (16//4) + "10 10 1" + "0 10" + "10 10"*2, + "wck0": "0000 0000" + wck_preamble + "10 10" * (16//4) + "10 10 1" + "0 10" + "10 10"*2, }, }, chunk_size=4, @@ -624,7 +624,7 @@ class LPDDR5Tests(unittest.TestCase): "cs": "01100000", }, "sys8x_270": { - "wck0": "00000000" + wck_preamble + "10101010" * (16//8) + "10101" + "0 10" + "10 10"*2, + "wck0": "00000000 00000000" + wck_preamble + "10101010" * (16//8) + "10101" + "0 10" + "10 10"*2, }, }, )