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(
|
wck_sync = TappedDelayLine(
|
||||||
signal = self.adapter.wck_sync,
|
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
|
self.submodules += wck_sync
|
||||||
wck_sync_taps = Array([wck_sync.input, *wck_sync.taps])
|
wck_sync_taps = Array([wck_sync.input, *wck_sync.taps])
|
||||||
|
@ -313,43 +313,23 @@ class LPDDR5PHY(Module, AutoCSR):
|
||||||
"toggle_4:1": "-_-_-_-_",
|
"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
|
assert frange.t_wckpre_static > 0 # The algorithm assumes it's never 0
|
||||||
|
|
||||||
wck_fsm = FSM()
|
wck_fsm = FSM()
|
||||||
self.submodules += wck_fsm
|
self.submodules += wck_fsm
|
||||||
wck_fsm.act("DISABLED",
|
wck_fsm.act("DISABLED",
|
||||||
wck_pattern.eq(bitpattern(patterns["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[frange.t_wckenl_wr] == WCKSyncType.WR,
|
||||||
If(wck_sync_taps[max(0, frange.t_wckenl_wr - 1)] == WCKSyncType.WR,
|
NextState("STATIC")
|
||||||
on_disabled(frange.t_wckenl_wr)
|
).Elif(wck_sync_taps[frange.t_wckenl_rd] == WCKSyncType.RD,
|
||||||
).Elif(wck_sync_taps[max(0, frange.t_wckenl_rd - 1)] == WCKSyncType.RD,
|
NextState("STATIC")
|
||||||
on_disabled(frange.t_wckenl_rd)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
wck_fsm.act("STATIC",
|
wck_fsm.act("STATIC",
|
||||||
wck_pattern.eq(bitpattern(patterns["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")
|
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")
|
NextState("TOGGLE")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -516,14 +516,14 @@ class LPDDR5Tests(unittest.TestCase):
|
||||||
# tWCKENL_WR starts counting from first command (CAS) so we add command latency,
|
# 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
|
# then preamble, then toggle for the whole burst, then postamble for tWCKPST=2.5tCK
|
||||||
# (but for now we assume that WCK is never disabled)
|
# (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,
|
chunk_size=4,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_lpddr5_wck_sync_4to1_write(self):
|
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
|
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
|
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
|
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,
|
# 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
|
# then preamble, then toggle for the whole burst, then postamble for tWCKPST=2.5tCK
|
||||||
# (but for now we assume that WCK is never disabled)
|
# (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",
|
"cs": "01100000",
|
||||||
},
|
},
|
||||||
"sys4x_270": {
|
"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,
|
chunk_size=4,
|
||||||
|
@ -624,7 +624,7 @@ class LPDDR5Tests(unittest.TestCase):
|
||||||
"cs": "01100000",
|
"cs": "01100000",
|
||||||
},
|
},
|
||||||
"sys8x_270": {
|
"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