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.
This commit is contained in:
parent
32a56ffe28
commit
8c10f1405b
|
@ -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")
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue