phy/s7ddrphy: add compatibility with DFIRateConverter
This commit is contained in:
parent
1d880c4db9
commit
f4be065c09
|
@ -3,6 +3,7 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
|
# Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
# Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
|
# Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
|
||||||
|
# Copyright (c) 2021 Antmicro <www.antmicro.com>
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
# 1:4, 1:2 frequency-ratio DDR2/DDR3 PHY for Xilinx's Series7
|
# 1:4, 1:2 frequency-ratio DDR2/DDR3 PHY for Xilinx's Series7
|
||||||
|
@ -15,6 +16,7 @@ from operator import or_
|
||||||
import math
|
import math
|
||||||
|
|
||||||
from migen import *
|
from migen import *
|
||||||
|
from migen.genlib.cdc import PulseSynchronizer
|
||||||
|
|
||||||
from litex.soc.interconnect.csr import *
|
from litex.soc.interconnect.csr import *
|
||||||
|
|
||||||
|
@ -32,7 +34,9 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
cl = None,
|
cl = None,
|
||||||
cwl = None,
|
cwl = None,
|
||||||
cmd_latency = 0,
|
cmd_latency = 0,
|
||||||
cmd_delay = None):
|
cmd_delay = None,
|
||||||
|
ddr_clk = None,
|
||||||
|
csr_cdc = None):
|
||||||
assert not (memtype == "DDR3" and nphases == 2)
|
assert not (memtype == "DDR3" and nphases == 2)
|
||||||
phytype = self.__class__.__name__
|
phytype = self.__class__.__name__
|
||||||
pads = PHYPadsCombiner(pads)
|
pads = PHYPadsCombiner(pads)
|
||||||
|
@ -91,6 +95,27 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
self._rdphase = CSRStorage(int(math.log2(nphases)), reset=rdphase)
|
self._rdphase = CSRStorage(int(math.log2(nphases)), reset=rdphase)
|
||||||
self._wrphase = CSRStorage(int(math.log2(nphases)), reset=wrphase)
|
self._wrphase = CSRStorage(int(math.log2(nphases)), reset=wrphase)
|
||||||
|
|
||||||
|
def cdc(i):
|
||||||
|
if csr_cdc is None:
|
||||||
|
return i
|
||||||
|
return csr_cdc(i)
|
||||||
|
|
||||||
|
rdly_dq_rst = cdc(self._rdly_dq_rst.re)
|
||||||
|
rdly_dq_inc = cdc(self._rdly_dq_inc.re)
|
||||||
|
rdly_dq_bitslip_rst = cdc(self._rdly_dq_bitslip_rst.re)
|
||||||
|
rdly_dq_bitslip = cdc(self._rdly_dq_bitslip.re)
|
||||||
|
wlevel_strobe = cdc(self._wlevel_strobe.re)
|
||||||
|
if with_odelay:
|
||||||
|
cdly_rst = cdc(self._cdly_rst.re) | self._rst.storage
|
||||||
|
cdly_inc = cdc(self._cdly_inc.re)
|
||||||
|
wdly_dq_rst = cdc(self._wdly_dq_rst.re)
|
||||||
|
wdly_dq_inc = cdc(self._wdly_dq_inc.re)
|
||||||
|
wdly_dqs_rst = cdc(self._wdly_dqs_rst.re)
|
||||||
|
wdly_dqs_inc = cdc(self._wdly_dqs_inc.re)
|
||||||
|
|
||||||
|
wdly_dq_bitslip_rst = cdc(self._wdly_dq_bitslip_rst.re)
|
||||||
|
wdly_dq_bitslip = cdc(self._wdly_dq_bitslip.re)
|
||||||
|
|
||||||
# PHY settings -----------------------------------------------------------------------------
|
# PHY settings -----------------------------------------------------------------------------
|
||||||
self.settings = PhySettings(
|
self.settings = PhySettings(
|
||||||
phytype = phytype,
|
phytype = phytype,
|
||||||
|
@ -125,7 +150,7 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
pads.sel_group(pads_group)
|
pads.sel_group(pads_group)
|
||||||
|
|
||||||
# Clock --------------------------------------------------------------------------------
|
# Clock --------------------------------------------------------------------------------
|
||||||
ddr_clk = "sys2x" if nphases == 2 else "sys4x"
|
ddr_clk = ddr_clk or ("sys2x" if nphases == 2 else "sys4x")
|
||||||
for i in range(len(pads.clk_p)):
|
for i in range(len(pads.clk_p)):
|
||||||
sd_clk_se_nodelay = Signal()
|
sd_clk_se_nodelay = Signal()
|
||||||
sd_clk_se_delayed = Signal()
|
sd_clk_se_delayed = Signal()
|
||||||
|
@ -153,9 +178,9 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
p_ODELAY_TYPE = "VARIABLE",
|
p_ODELAY_TYPE = "VARIABLE",
|
||||||
p_ODELAY_VALUE = 0,
|
p_ODELAY_VALUE = 0,
|
||||||
i_C = ClockSignal("sys"),
|
i_C = ClockSignal("sys"),
|
||||||
i_LD = self._cdly_rst.re | self._rst.storage,
|
i_LD = cdly_rst | self._rst.storage,
|
||||||
i_LDPIPEEN = 0,
|
i_LDPIPEEN = 0,
|
||||||
i_CE = self._cdly_inc.re,
|
i_CE = cdly_inc,
|
||||||
i_INC = 1,
|
i_INC = 1,
|
||||||
o_ODATAIN = sd_clk_se_nodelay,
|
o_ODATAIN = sd_clk_se_nodelay,
|
||||||
o_DATAOUT = sd_clk_se_delayed,
|
o_DATAOUT = sd_clk_se_delayed,
|
||||||
|
@ -211,9 +236,9 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
p_ODELAY_TYPE = "VARIABLE",
|
p_ODELAY_TYPE = "VARIABLE",
|
||||||
p_ODELAY_VALUE = 0,
|
p_ODELAY_VALUE = 0,
|
||||||
i_C = ClockSignal("sys"),
|
i_C = ClockSignal("sys"),
|
||||||
i_LD = self._cdly_rst.re | self._rst.storage,
|
i_LD = cdly_rst | self._rst.storage,
|
||||||
i_LDPIPEEN = 0,
|
i_LDPIPEEN = 0,
|
||||||
i_CE = self._cdly_inc.re,
|
i_CE = cdly_inc,
|
||||||
i_INC = 1,
|
i_INC = 1,
|
||||||
o_ODATAIN = oq,
|
o_ODATAIN = oq,
|
||||||
o_DATAOUT = pad[i],
|
o_DATAOUT = pad[i],
|
||||||
|
@ -228,7 +253,7 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
#preamble = dqs_preamble, # FIXME
|
#preamble = dqs_preamble, # FIXME
|
||||||
#postamble = dqs_postamble, # FIXME
|
#postamble = dqs_postamble, # FIXME
|
||||||
wlevel_en = self._wlevel_en.storage,
|
wlevel_en = self._wlevel_en.storage,
|
||||||
wlevel_strobe = self._wlevel_strobe.re,
|
wlevel_strobe = wlevel_strobe,
|
||||||
register = not with_odelay)
|
register = not with_odelay)
|
||||||
self.submodules += dqs_oe_delay, dqs_pattern
|
self.submodules += dqs_oe_delay, dqs_pattern
|
||||||
self.comb += dqs_oe_delay.input.eq(dqs_preamble | dqs_oe | dqs_postamble)
|
self.comb += dqs_oe_delay.input.eq(dqs_preamble | dqs_oe | dqs_postamble)
|
||||||
|
@ -238,8 +263,8 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
dqs_t = Signal()
|
dqs_t = Signal()
|
||||||
dqs_bitslip = BitSlip(8,
|
dqs_bitslip = BitSlip(8,
|
||||||
i = dqs_pattern.o,
|
i = dqs_pattern.o,
|
||||||
rst = (self._dly_sel.storage[i] & self._wdly_dq_bitslip_rst.re) | self._rst.storage,
|
rst = (self._dly_sel.storage[i] & wdly_dq_bitslip_rst) | self._rst.storage,
|
||||||
slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re,
|
slp = self._dly_sel.storage[i] & wdly_dq_bitslip,
|
||||||
cycles = 1)
|
cycles = 1)
|
||||||
self.submodules += dqs_bitslip
|
self.submodules += dqs_bitslip
|
||||||
self.specials += Instance("OSERDESE2",
|
self.specials += Instance("OSERDESE2",
|
||||||
|
@ -270,8 +295,8 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
p_ODELAY_TYPE = "VARIABLE",
|
p_ODELAY_TYPE = "VARIABLE",
|
||||||
p_ODELAY_VALUE = half_sys8x_taps,
|
p_ODELAY_VALUE = half_sys8x_taps,
|
||||||
i_C = ClockSignal("sys"),
|
i_C = ClockSignal("sys"),
|
||||||
i_LD = (self._dly_sel.storage[i] & self._wdly_dqs_rst.re) | self._rst.storage,
|
i_LD = (self._dly_sel.storage[i] & wdly_dqs_rst) | self._rst.storage,
|
||||||
i_CE = self._dly_sel.storage[i] & self._wdly_dqs_inc.re,
|
i_CE = self._dly_sel.storage[i] & wdly_dqs_inc,
|
||||||
i_LDPIPEEN = 0,
|
i_LDPIPEEN = 0,
|
||||||
i_INC = 1,
|
i_INC = 1,
|
||||||
o_ODATAIN = dqs_o_no_delay,
|
o_ODATAIN = dqs_o_no_delay,
|
||||||
|
@ -290,8 +315,8 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
dm_o_nodelay = Signal()
|
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)]),
|
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) | self._rst.storage,
|
rst = (self._dly_sel.storage[i] & wdly_dq_bitslip_rst) | self._rst.storage,
|
||||||
slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re,
|
slp = self._dly_sel.storage[i] & wdly_dq_bitslip,
|
||||||
cycles = 1)
|
cycles = 1)
|
||||||
self.submodules += dm_o_bitslip
|
self.submodules += dm_o_bitslip
|
||||||
self.specials += Instance("OSERDESE2",
|
self.specials += Instance("OSERDESE2",
|
||||||
|
@ -318,9 +343,9 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
p_ODELAY_TYPE = "VARIABLE",
|
p_ODELAY_TYPE = "VARIABLE",
|
||||||
p_ODELAY_VALUE = 0,
|
p_ODELAY_VALUE = 0,
|
||||||
i_C = ClockSignal("sys"),
|
i_C = ClockSignal("sys"),
|
||||||
i_LD = (self._dly_sel.storage[i] & self._wdly_dq_rst.re) | self._rst.storage,
|
i_LD = (self._dly_sel.storage[i] & wdly_dq_rst) | self._rst.storage,
|
||||||
i_LDPIPEEN = 0,
|
i_LDPIPEEN = 0,
|
||||||
i_CE = self._dly_sel.storage[i] & self._wdly_dq_inc.re,
|
i_CE = self._dly_sel.storage[i] & wdly_dq_inc,
|
||||||
i_INC = 1,
|
i_INC = 1,
|
||||||
o_ODATAIN = dm_o_nodelay,
|
o_ODATAIN = dm_o_nodelay,
|
||||||
o_DATAOUT = pads.dm[i],
|
o_DATAOUT = pads.dm[i],
|
||||||
|
@ -340,8 +365,8 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
dq_i_data = Signal(8)
|
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)]),
|
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) | self._rst.storage,
|
rst = (self._dly_sel.storage[i//8] & wdly_dq_bitslip_rst) | self._rst.storage,
|
||||||
slp = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip.re,
|
slp = self._dly_sel.storage[i//8] & wdly_dq_bitslip,
|
||||||
cycles = 1)
|
cycles = 1)
|
||||||
self.submodules += dq_o_bitslip
|
self.submodules += dq_o_bitslip
|
||||||
self.specials += Instance("OSERDESE2",
|
self.specials += Instance("OSERDESE2",
|
||||||
|
@ -361,8 +386,8 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
o_OQ = dq_o_nodelay,
|
o_OQ = dq_o_nodelay,
|
||||||
)
|
)
|
||||||
dq_i_bitslip = BitSlip(8,
|
dq_i_bitslip = BitSlip(8,
|
||||||
rst = (self._dly_sel.storage[i//8] & self._rdly_dq_bitslip_rst.re) | self._rst.storage,
|
rst = (self._dly_sel.storage[i//8] & rdly_dq_bitslip_rst) | self._rst.storage,
|
||||||
slp = self._dly_sel.storage[i//8] & self._rdly_dq_bitslip.re,
|
slp = self._dly_sel.storage[i//8] & rdly_dq_bitslip,
|
||||||
cycles = 1)
|
cycles = 1)
|
||||||
self.submodules += dq_i_bitslip
|
self.submodules += dq_i_bitslip
|
||||||
self.specials += Instance("ISERDESE2",
|
self.specials += Instance("ISERDESE2",
|
||||||
|
@ -394,9 +419,9 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
p_ODELAY_TYPE = "VARIABLE",
|
p_ODELAY_TYPE = "VARIABLE",
|
||||||
p_ODELAY_VALUE = 0,
|
p_ODELAY_VALUE = 0,
|
||||||
i_C = ClockSignal("sys"),
|
i_C = ClockSignal("sys"),
|
||||||
i_LD = (self._dly_sel.storage[i//8] & self._wdly_dq_rst.re)| self._rst.storage,
|
i_LD = (self._dly_sel.storage[i//8] & wdly_dq_rst)| self._rst.storage,
|
||||||
i_LDPIPEEN = 0,
|
i_LDPIPEEN = 0,
|
||||||
i_CE = self._dly_sel.storage[i//8] & self._wdly_dq_inc.re,
|
i_CE = self._dly_sel.storage[i//8] & wdly_dq_inc,
|
||||||
i_INC = 1,
|
i_INC = 1,
|
||||||
o_ODATAIN = dq_o_nodelay,
|
o_ODATAIN = dq_o_nodelay,
|
||||||
o_DATAOUT = dq_o_delayed,
|
o_DATAOUT = dq_o_delayed,
|
||||||
|
@ -411,9 +436,9 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
p_IDELAY_TYPE = "VARIABLE",
|
p_IDELAY_TYPE = "VARIABLE",
|
||||||
p_IDELAY_VALUE = 0,
|
p_IDELAY_VALUE = 0,
|
||||||
i_C = ClockSignal("sys"),
|
i_C = ClockSignal("sys"),
|
||||||
i_LD = (self._dly_sel.storage[i//8] & self._rdly_dq_rst.re) | self._rst.storage,
|
i_LD = (self._dly_sel.storage[i//8] & rdly_dq_rst) | self._rst.storage,
|
||||||
i_LDPIPEEN = 0,
|
i_LDPIPEEN = 0,
|
||||||
i_CE = self._dly_sel.storage[i//8] & self._rdly_dq_inc.re,
|
i_CE = self._dly_sel.storage[i//8] & rdly_dq_inc,
|
||||||
i_INC = 1,
|
i_INC = 1,
|
||||||
i_IDATAIN = dq_i_nodelay,
|
i_IDATAIN = dq_i_nodelay,
|
||||||
o_DATAOUT = dq_i_delayed
|
o_DATAOUT = dq_i_delayed
|
||||||
|
@ -460,6 +485,7 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
self.comb += dqs_preamble.eq( wrdata_en.taps[wrtap - 1] & ~wrdata_en.taps[wrtap + 0])
|
self.comb += dqs_preamble.eq( wrdata_en.taps[wrtap - 1] & ~wrdata_en.taps[wrtap + 0])
|
||||||
self.comb += dqs_postamble.eq(wrdata_en.taps[wrtap + 1] & ~wrdata_en.taps[wrtap + 0])
|
self.comb += dqs_postamble.eq(wrdata_en.taps[wrtap + 1] & ~wrdata_en.taps[wrtap + 0])
|
||||||
|
|
||||||
|
|
||||||
# Xilinx Virtex7 (S7DDRPHY with odelay) ------------------------------------------------------------
|
# Xilinx Virtex7 (S7DDRPHY with odelay) ------------------------------------------------------------
|
||||||
|
|
||||||
class V7DDRPHY(S7DDRPHY):
|
class V7DDRPHY(S7DDRPHY):
|
||||||
|
@ -477,3 +503,22 @@ class K7DDRPHY(S7DDRPHY):
|
||||||
class A7DDRPHY(S7DDRPHY):
|
class A7DDRPHY(S7DDRPHY):
|
||||||
def __init__(self, pads, **kwargs):
|
def __init__(self, pads, **kwargs):
|
||||||
S7DDRPHY.__init__(self, pads, with_odelay=False, **kwargs)
|
S7DDRPHY.__init__(self, pads, with_odelay=False, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def s7ddrphy_with_ratio(ratio, phy_cls=A7DDRPHY, ddr_clk=None, serdes_reset_cnt=0):
|
||||||
|
"""Generate PHY class that uses DFIRateConverter to increase MC:PHY frequecy ratio"""
|
||||||
|
ddr_clk = ddr_clk or f"sys{4*ratio}x"
|
||||||
|
|
||||||
|
# Generate new class that wraps the original PHY
|
||||||
|
wrapper_cls = DFIRateConverter.phy_wrapper(
|
||||||
|
phy_cls = phy_cls,
|
||||||
|
ratio = ratio,
|
||||||
|
serdes_reset_cnt = serdes_reset_cnt,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create a wrapper that will ensure that correct ddr_clk kwarg is passed to the PHY
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
sys_clk_freq = kwargs.pop("sys_clk_freq", 100e6)
|
||||||
|
return wrapper_cls(*args, ddr_clk=ddr_clk, sys_clk_freq=ratio * sys_clk_freq, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
Loading…
Reference in New Issue