Merge pull request #221 from enjoy-digital/write_latency
Add dynamic write latency calibration.
This commit is contained in:
commit
85fa02afc7
|
@ -97,6 +97,15 @@ class BenchSoC(SoCCore):
|
||||||
self.add_csr("ethphy")
|
self.add_csr("ethphy")
|
||||||
self.add_etherbone(phy=self.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 -------------------------------------------------------------------------------------
|
# Leds -------------------------------------------------------------------------------------
|
||||||
from litex.soc.cores.led import LedChaser
|
from litex.soc.cores.led import LedChaser
|
||||||
self.submodules.leds = LedChaser(
|
self.submodules.leds = LedChaser(
|
||||||
|
|
|
@ -117,23 +117,24 @@ class PHYPadsCombiner:
|
||||||
# BitSlip ------------------------------------------------------------------------------------------
|
# BitSlip ------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
class BitSlip(Module):
|
class BitSlip(Module):
|
||||||
def __init__(self, dw, rst=None, slp=None, cycles=1):
|
def __init__(self, dw, i=None, o=None, rst=None, slp=None, cycles=1):
|
||||||
self.i = Signal(dw)
|
self.i = Signal(dw) if i is None else i
|
||||||
self.o = Signal(dw)
|
self.o = Signal(dw) if o is None else o
|
||||||
self.rst = Signal() if rst is None else rst
|
self.rst = Signal() if rst is None else rst
|
||||||
self.slp = Signal() if slp is None else slp
|
self.slp = Signal() if slp is None else slp
|
||||||
|
assert cycles >= 1
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
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.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)
|
r = Signal((cycles+1)*dw, reset_less=True)
|
||||||
self.sync += r.eq(Cat(r[dw:], self.i))
|
self.sync += r.eq(Cat(r[dw:], self.i))
|
||||||
cases = {}
|
cases = {}
|
||||||
for i in range(cycles*dw):
|
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)
|
self.comb += Case(value, cases)
|
||||||
|
|
||||||
# TappedDelayLine ----------------------------------------------------------------------------------
|
# TappedDelayLine ----------------------------------------------------------------------------------
|
||||||
|
|
|
@ -507,7 +507,10 @@ def get_sdram_phy_c_header(phy_settings, timing_settings):
|
||||||
r += "#define SDRAM_PHY_WRITE_LEVELING_CAPABLE\n"
|
r += "#define SDRAM_PHY_WRITE_LEVELING_CAPABLE\n"
|
||||||
if phytype in ["USDDRPHY", "USPDDRPHY"]:
|
if phytype in ["USDDRPHY", "USPDDRPHY"]:
|
||||||
r += "#define SDRAM_PHY_WRITE_LEVELING_REINIT\n"
|
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"
|
r += "#define SDRAM_PHY_READ_LEVELING_CAPABLE\n"
|
||||||
|
|
||||||
# Define number of modules/delays/bitslips
|
# Define number of modules/delays/bitslips
|
||||||
|
|
|
@ -24,6 +24,30 @@ from litex.soc.interconnect.csr import *
|
||||||
from litedram.common import *
|
from litedram.common import *
|
||||||
from litedram.phy.dfi 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 --------------------------------------------------------------
|
# Lattice ECP5 DDR PHY Initialization --------------------------------------------------------------
|
||||||
|
|
||||||
class ECP5DDRPHYInit(Module):
|
class ECP5DDRPHYInit(Module):
|
||||||
|
@ -108,6 +132,8 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
cwl_sys_latency = get_sys_latency(nphases, cwl)
|
cwl_sys_latency = get_sys_latency(nphases, cwl)
|
||||||
|
|
||||||
# Registers --------------------------------------------------------------------------------
|
# Registers --------------------------------------------------------------------------------
|
||||||
|
self._rst = CSRStorage()
|
||||||
|
|
||||||
self._dly_sel = CSRStorage(databits//8)
|
self._dly_sel = CSRStorage(databits//8)
|
||||||
|
|
||||||
self._rdly_dq_rst = CSR()
|
self._rdly_dq_rst = CSR()
|
||||||
|
@ -154,7 +180,7 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
for i in range(len(pads.clk_p)):
|
for i in range(len(pads.clk_p)):
|
||||||
sd_clk_se = Signal()
|
sd_clk_se = Signal()
|
||||||
self.specials += Instance("ODDRX2F",
|
self.specials += Instance("ODDRX2F",
|
||||||
i_RST = ResetSignal("sys"),
|
i_RST = ResetSignal("sys") | self._rst.storage,
|
||||||
i_SCLK = ClockSignal("sys"),
|
i_SCLK = ClockSignal("sys"),
|
||||||
i_ECLK = ClockSignal("sys2x"),
|
i_ECLK = ClockSignal("sys2x"),
|
||||||
**{f"i_D{n}": (0b1010 >> n) & 0b1 for n in range(4)},
|
**{f"i_D{n}": (0b1010 >> n) & 0b1 for n in range(4)},
|
||||||
|
@ -177,7 +203,7 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
pad = getattr(pads, pad_name)
|
pad = getattr(pads, pad_name)
|
||||||
for i in range(len(pad)):
|
for i in range(len(pad)):
|
||||||
self.specials += Instance("ODDRX2F",
|
self.specials += Instance("ODDRX2F",
|
||||||
i_RST = ResetSignal("sys"),
|
i_RST = ResetSignal("sys") | self._rst.storage,
|
||||||
i_SCLK = ClockSignal("sys"),
|
i_SCLK = ClockSignal("sys"),
|
||||||
i_ECLK = ClockSignal("sys2x"),
|
i_ECLK = ClockSignal("sys2x"),
|
||||||
**{f"i_D{n}": getattr(dfi.phases[n//2], dfi_name)[i] for n in range(4)},
|
**{f"i_D{n}": getattr(dfi.phases[n//2], dfi_name)[i] for n in range(4)},
|
||||||
|
@ -210,7 +236,7 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
p_DQS_LO_DEL_ADJ = "MINUS",
|
p_DQS_LO_DEL_ADJ = "MINUS",
|
||||||
p_DQS_LO_DEL_VAL = 4,
|
p_DQS_LO_DEL_VAL = 4,
|
||||||
# Clocks / Reset
|
# Clocks / Reset
|
||||||
i_RST = ResetSignal("sys"),
|
i_RST = ResetSignal("sys") | self._rst.storage,
|
||||||
i_SCLK = ClockSignal("sys"),
|
i_SCLK = ClockSignal("sys"),
|
||||||
i_ECLK = ClockSignal("sys2x"),
|
i_ECLK = ClockSignal("sys2x"),
|
||||||
i_DDRDEL = self.init.delay,
|
i_DDRDEL = self.init.delay,
|
||||||
|
@ -252,7 +278,7 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
dqs_oe_n = Signal()
|
dqs_oe_n = Signal()
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("ODDRX2DQSB",
|
Instance("ODDRX2DQSB",
|
||||||
i_RST = ResetSignal("sys"),
|
i_RST = ResetSignal("sys") | self._rst.storage,
|
||||||
i_SCLK = ClockSignal("sys"),
|
i_SCLK = ClockSignal("sys"),
|
||||||
i_ECLK = ClockSignal("sys2x"),
|
i_ECLK = ClockSignal("sys2x"),
|
||||||
i_DQSW = dqsw,
|
i_DQSW = dqsw,
|
||||||
|
@ -260,7 +286,7 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
o_Q = dqs
|
o_Q = dqs
|
||||||
),
|
),
|
||||||
Instance("TSHX2DQSA",
|
Instance("TSHX2DQSA",
|
||||||
i_RST = ResetSignal("sys"),
|
i_RST = ResetSignal("sys") | self._rst.storage,
|
||||||
i_SCLK = ClockSignal("sys"),
|
i_SCLK = ClockSignal("sys"),
|
||||||
i_ECLK = ClockSignal("sys2x"),
|
i_ECLK = ClockSignal("sys2x"),
|
||||||
i_DQSW = dqsw,
|
i_DQSW = dqsw,
|
||||||
|
@ -283,7 +309,7 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
dm_bl8_cases[1] = dm_o_data_muxed.eq(dm_o_data_d[4:])
|
dm_bl8_cases[1] = dm_o_data_muxed.eq(dm_o_data_d[4:])
|
||||||
self.sync += Case(bl8_chunk, dm_bl8_cases)
|
self.sync += Case(bl8_chunk, dm_bl8_cases)
|
||||||
self.specials += Instance("ODDRX2DQA",
|
self.specials += Instance("ODDRX2DQA",
|
||||||
i_RST = ResetSignal("sys"),
|
i_RST = ResetSignal("sys") | self._rst.storage,
|
||||||
i_SCLK = ClockSignal("sys"),
|
i_SCLK = ClockSignal("sys"),
|
||||||
i_ECLK = ClockSignal("sys2x"),
|
i_ECLK = ClockSignal("sys2x"),
|
||||||
i_DQSW270 = dqsw270,
|
i_DQSW270 = dqsw270,
|
||||||
|
@ -310,7 +336,7 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
self.sync += Case(bl8_chunk, dq_bl8_cases)
|
self.sync += Case(bl8_chunk, dq_bl8_cases)
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("ODDRX2DQA",
|
Instance("ODDRX2DQA",
|
||||||
i_RST = ResetSignal("sys"),
|
i_RST = ResetSignal("sys") | self._rst.storage,
|
||||||
i_SCLK = ClockSignal("sys"),
|
i_SCLK = ClockSignal("sys"),
|
||||||
i_ECLK = ClockSignal("sys2x"),
|
i_ECLK = ClockSignal("sys2x"),
|
||||||
i_DQSW270 = dqsw270,
|
i_DQSW270 = dqsw270,
|
||||||
|
@ -319,7 +345,7 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
dq_i_bitslip = BitSlip(4,
|
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,
|
slp = self._dly_sel.storage[i] & self._rdly_dq_bitslip.re,
|
||||||
cycles = 1)
|
cycles = 1)
|
||||||
self.submodules += dq_i_bitslip
|
self.submodules += dq_i_bitslip
|
||||||
|
@ -333,7 +359,7 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
o_Z = dq_i_delayed
|
o_Z = dq_i_delayed
|
||||||
),
|
),
|
||||||
Instance("IDDRX2DQA",
|
Instance("IDDRX2DQA",
|
||||||
i_RST = ResetSignal("sys"),
|
i_RST = ResetSignal("sys") | self._rst.storage,
|
||||||
i_SCLK = ClockSignal("sys"),
|
i_SCLK = ClockSignal("sys"),
|
||||||
i_ECLK = ClockSignal("sys2x"),
|
i_ECLK = ClockSignal("sys2x"),
|
||||||
i_DQSR90 = dqsr90,
|
i_DQSR90 = dqsr90,
|
||||||
|
@ -350,7 +376,7 @@ class ECP5DDRPHY(Module, AutoCSR):
|
||||||
self.comb += dfi.phases[n//4].rddata[n%4*databits+j].eq(dq_i_data[n])
|
self.comb += dfi.phases[n//4].rddata[n%4*databits+j].eq(dq_i_data[n])
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("TSHX2DQA",
|
Instance("TSHX2DQA",
|
||||||
i_RST = ResetSignal("sys"),
|
i_RST = ResetSignal("sys") | self._rst.storage,
|
||||||
i_SCLK = ClockSignal("sys"),
|
i_SCLK = ClockSignal("sys"),
|
||||||
i_ECLK = ClockSignal("sys2x"),
|
i_ECLK = ClockSignal("sys2x"),
|
||||||
i_DQSW270 = dqsw270,
|
i_DQSW270 = dqsw270,
|
||||||
|
|
|
@ -29,7 +29,7 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
nphases = 4,
|
nphases = 4,
|
||||||
sys_clk_freq = 100e6,
|
sys_clk_freq = 100e6,
|
||||||
iodelay_clk_freq = 200e6,
|
iodelay_clk_freq = 200e6,
|
||||||
cmd_latency = 0,
|
cmd_latency = 1,
|
||||||
cmd_delay = None):
|
cmd_delay = None):
|
||||||
assert not (memtype == "DDR3" and nphases == 2)
|
assert not (memtype == "DDR3" and nphases == 2)
|
||||||
phytype = self.__class__.__name__
|
phytype = self.__class__.__name__
|
||||||
|
@ -82,6 +82,9 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
self._wdly_dqs_rst = CSR()
|
self._wdly_dqs_rst = CSR()
|
||||||
self._wdly_dqs_inc = 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._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)
|
||||||
|
|
||||||
|
@ -98,7 +101,7 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
cl = cl,
|
cl = cl,
|
||||||
cwl = cwl,
|
cwl = cwl,
|
||||||
read_latency = cl_sys_latency + 6,
|
read_latency = cl_sys_latency + 6,
|
||||||
write_latency = cwl_sys_latency,
|
write_latency = cwl_sys_latency - 1,
|
||||||
cmd_latency = cmd_latency,
|
cmd_latency = cmd_latency,
|
||||||
cmd_delay = cmd_delay,
|
cmd_delay = cmd_delay,
|
||||||
)
|
)
|
||||||
|
@ -208,8 +211,8 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
dqs_postamble = Signal()
|
dqs_postamble = Signal()
|
||||||
dqs_oe_delay = TappedDelayLine(ntaps=2 if nphases == 4 else 1)
|
dqs_oe_delay = TappedDelayLine(ntaps=2 if nphases == 4 else 1)
|
||||||
dqs_pattern = DQSPattern(
|
dqs_pattern = DQSPattern(
|
||||||
preamble = dqs_preamble,
|
#preamble = dqs_preamble, # FIXME
|
||||||
postamble = dqs_postamble,
|
#postamble = dqs_postamble, # FIXME
|
||||||
wlevel_en = self._wlevel_en.storage,
|
wlevel_en = self._wlevel_en.storage,
|
||||||
wlevel_strobe = self._wlevel_strobe.re,
|
wlevel_strobe = self._wlevel_strobe.re,
|
||||||
register = not with_odelay)
|
register = not with_odelay)
|
||||||
|
@ -219,6 +222,12 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
dqs_o_no_delay = Signal()
|
dqs_o_no_delay = Signal()
|
||||||
dqs_o_delayed = Signal()
|
dqs_o_delayed = Signal()
|
||||||
dqs_t = Signal()
|
dqs_t = Signal()
|
||||||
|
dqs_bitslip = BitSlip(8,
|
||||||
|
i = dqs_pattern.o,
|
||||||
|
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
|
||||||
self.specials += Instance("OSERDESE2",
|
self.specials += Instance("OSERDESE2",
|
||||||
p_SERDES_MODE = "MASTER",
|
p_SERDES_MODE = "MASTER",
|
||||||
p_DATA_WIDTH = 2*nphases,
|
p_DATA_WIDTH = 2*nphases,
|
||||||
|
@ -228,7 +237,7 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
i_RST = ResetSignal() | self._rst.storage,
|
i_RST = ResetSignal() | self._rst.storage,
|
||||||
i_CLK = ClockSignal(ddr_clk) if with_odelay else ClockSignal(ddr_clk+"_dqs"),
|
i_CLK = ClockSignal(ddr_clk) if with_odelay else ClockSignal(ddr_clk+"_dqs"),
|
||||||
i_CLKDIV = ClockSignal(),
|
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,
|
i_OCE = 1,
|
||||||
o_OFB = dqs_o_no_delay if with_odelay else Signal(),
|
o_OFB = dqs_o_no_delay if with_odelay else Signal(),
|
||||||
o_OQ = Signal() if with_odelay else dqs_o_no_delay,
|
o_OQ = Signal() if with_odelay else dqs_o_no_delay,
|
||||||
|
@ -264,6 +273,12 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
# DM ---------------------------------------------------------------------------------------
|
# DM ---------------------------------------------------------------------------------------
|
||||||
for i in range(databits//8):
|
for i in range(databits//8):
|
||||||
dm_o_nodelay = Signal()
|
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) | self._rst.storage,
|
||||||
|
slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re,
|
||||||
|
cycles = 1)
|
||||||
|
self.submodules += dm_o_bitslip
|
||||||
self.specials += Instance("OSERDESE2",
|
self.specials += Instance("OSERDESE2",
|
||||||
p_SERDES_MODE = "MASTER",
|
p_SERDES_MODE = "MASTER",
|
||||||
p_DATA_WIDTH = 2*nphases,
|
p_DATA_WIDTH = 2*nphases,
|
||||||
|
@ -273,7 +288,7 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
i_RST = ResetSignal() | self._rst.storage,
|
i_RST = ResetSignal() | self._rst.storage,
|
||||||
i_CLK = ClockSignal(ddr_clk),
|
i_CLK = ClockSignal(ddr_clk),
|
||||||
i_CLKDIV = ClockSignal(),
|
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_o_bitslip.o[n] for n in range(8)},
|
||||||
i_OCE = 1,
|
i_OCE = 1,
|
||||||
o_OQ = dm_o_nodelay if with_odelay else pads.dm[i],
|
o_OQ = dm_o_nodelay if with_odelay else pads.dm[i],
|
||||||
)
|
)
|
||||||
|
@ -308,6 +323,12 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
dq_i_delayed = Signal()
|
dq_i_delayed = Signal()
|
||||||
dq_t = Signal()
|
dq_t = Signal()
|
||||||
dq_i_data = Signal(8)
|
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) | self._rst.storage,
|
||||||
|
slp = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip.re,
|
||||||
|
cycles = 1)
|
||||||
|
self.submodules += dq_o_bitslip
|
||||||
self.specials += Instance("OSERDESE2",
|
self.specials += Instance("OSERDESE2",
|
||||||
p_SERDES_MODE = "MASTER",
|
p_SERDES_MODE = "MASTER",
|
||||||
p_DATA_WIDTH = 2*nphases,
|
p_DATA_WIDTH = 2*nphases,
|
||||||
|
@ -317,7 +338,7 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
i_RST = ResetSignal() | self._rst.storage,
|
i_RST = ResetSignal() | self._rst.storage,
|
||||||
i_CLK = ClockSignal(ddr_clk),
|
i_CLK = ClockSignal(ddr_clk),
|
||||||
i_CLKDIV = ClockSignal(),
|
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_o_bitslip.o[n] for n in range(8)},
|
||||||
i_TCE = 1,
|
i_TCE = 1,
|
||||||
i_T1 = ~dq_oe_delay.output,
|
i_T1 = ~dq_oe_delay.output,
|
||||||
o_TQ = dq_t,
|
o_TQ = dq_t,
|
||||||
|
@ -325,7 +346,7 @@ 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,
|
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,
|
slp = self._dly_sel.storage[i//8] & self._rdly_dq_bitslip.re,
|
||||||
cycles = 1)
|
cycles = 1)
|
||||||
self.submodules += dq_i_bitslip
|
self.submodules += dq_i_bitslip
|
||||||
|
@ -427,17 +448,17 @@ class S7DDRPHY(Module, AutoCSR):
|
||||||
# Xilinx Virtex7 (S7DDRPHY with odelay) ------------------------------------------------------------
|
# Xilinx Virtex7 (S7DDRPHY with odelay) ------------------------------------------------------------
|
||||||
|
|
||||||
class V7DDRPHY(S7DDRPHY):
|
class V7DDRPHY(S7DDRPHY):
|
||||||
def __init__(self, pads, cmd_latency=1, **kwargs):
|
def __init__(self, pads, **kwargs):
|
||||||
S7DDRPHY.__init__(self, pads, with_odelay=True, **kwargs)
|
S7DDRPHY.__init__(self, pads, with_odelay=True, **kwargs)
|
||||||
|
|
||||||
# Xilinx Kintex7 (S7DDRPHY with odelay) ------------------------------------------------------------
|
# Xilinx Kintex7 (S7DDRPHY with odelay) ------------------------------------------------------------
|
||||||
|
|
||||||
class K7DDRPHY(S7DDRPHY):
|
class K7DDRPHY(S7DDRPHY):
|
||||||
def __init__(self, pads, cmd_latency=1, **kwargs):
|
def __init__(self, pads, **kwargs):
|
||||||
S7DDRPHY.__init__(self, pads, cmd_latency=cmd_latency, with_odelay=True, **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) --
|
# Xilinx Artix7 (S7DDRPHY without odelay, sys2/4x_dqs generated in CRG with 90° phase vs sys2/4x) --
|
||||||
|
|
||||||
class A7DDRPHY(S7DDRPHY):
|
class A7DDRPHY(S7DDRPHY):
|
||||||
def __init__(self, pads, cmd_latency=0, **kwargs):
|
def __init__(self, pads, **kwargs):
|
||||||
S7DDRPHY.__init__(self, pads, cmd_latency=0, with_odelay=False, **kwargs)
|
S7DDRPHY.__init__(self, pads, with_odelay=False, cmd_latency=0, **kwargs)
|
||||||
|
|
|
@ -81,6 +81,9 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
self._wdly_dqs_rst = CSR()
|
self._wdly_dqs_rst = CSR()
|
||||||
self._wdly_dqs_inc = CSR()
|
self._wdly_dqs_inc = CSR()
|
||||||
|
|
||||||
|
self._wdly_dq_bitslip_rst = CSR()
|
||||||
|
self._wdly_dq_bitslip = CSR()
|
||||||
|
|
||||||
self._rdphase = CSRStorage(2, reset=rdphase)
|
self._rdphase = CSRStorage(2, reset=rdphase)
|
||||||
self._wrphase = CSRStorage(2, reset=wrphase)
|
self._wrphase = CSRStorage(2, reset=wrphase)
|
||||||
|
|
||||||
|
@ -97,7 +100,7 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
cl = cl,
|
cl = cl,
|
||||||
cwl = cwl,
|
cwl = cwl,
|
||||||
read_latency = cl_sys_latency + 5,
|
read_latency = cl_sys_latency + 5,
|
||||||
write_latency = cwl_sys_latency,
|
write_latency = cwl_sys_latency - 1,
|
||||||
cmd_latency = cmd_latency,
|
cmd_latency = cmd_latency,
|
||||||
cmd_delay = cmd_delay,
|
cmd_delay = cmd_delay,
|
||||||
)
|
)
|
||||||
|
@ -228,8 +231,8 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
dqs_postamble = Signal()
|
dqs_postamble = Signal()
|
||||||
dqs_oe_delay = TappedDelayLine(ntaps=1)
|
dqs_oe_delay = TappedDelayLine(ntaps=1)
|
||||||
dqs_pattern = DQSPattern(
|
dqs_pattern = DQSPattern(
|
||||||
preamble = dqs_preamble,
|
#preamble = dqs_preamble, # FIXME
|
||||||
postamble = dqs_postamble,
|
#postamble = dqs_postamble, # FIXME
|
||||||
wlevel_en = self._wlevel_en.storage,
|
wlevel_en = self._wlevel_en.storage,
|
||||||
wlevel_strobe = self._wlevel_strobe.re)
|
wlevel_strobe = self._wlevel_strobe.re)
|
||||||
self.submodules += dqs_oe_delay, dqs_pattern
|
self.submodules += dqs_oe_delay, dqs_pattern
|
||||||
|
@ -247,6 +250,12 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
dqs_taps_done.eq(1),
|
dqs_taps_done.eq(1),
|
||||||
self._half_sys8x_taps.status.eq(dqs_taps)
|
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) | self._rst.storage,
|
||||||
|
slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re,
|
||||||
|
cycles = 1)
|
||||||
|
self.submodules += dqs_bitslip
|
||||||
if x4_dimm_mode:
|
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]))
|
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:
|
else:
|
||||||
|
@ -267,7 +276,7 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
i_CLK = ClockSignal("sys4x"),
|
i_CLK = ClockSignal("sys4x"),
|
||||||
i_CLKDIV = ClockSignal(),
|
i_CLKDIV = ClockSignal(),
|
||||||
i_T = ~dqs_oe_delay.output,
|
i_T = ~dqs_oe_delay.output,
|
||||||
i_D = dqs_pattern.o,
|
i_D = dqs_bitslip.o,
|
||||||
o_OQ = dqs_nodelay,
|
o_OQ = dqs_nodelay,
|
||||||
o_T_OUT = dqs_t,
|
o_T_OUT = dqs_t,
|
||||||
|
|
||||||
|
@ -303,6 +312,12 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
for i in range(databits//8):
|
for i in range(databits//8):
|
||||||
if hasattr(pads, "dm"):
|
if hasattr(pads, "dm"):
|
||||||
dm_o_nodelay = Signal()
|
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) | self._rst.storage,
|
||||||
|
slp = self._dly_sel.storage[i] & self._wdly_dq_bitslip.re,
|
||||||
|
cycles = 1)
|
||||||
|
self.submodules += dm_o_bitslip
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("OSERDESE3",
|
Instance("OSERDESE3",
|
||||||
p_SIM_DEVICE = device,
|
p_SIM_DEVICE = device,
|
||||||
|
@ -314,7 +329,7 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
i_RST = ResetSignal() | self._rst.storage,
|
i_RST = ResetSignal() | self._rst.storage,
|
||||||
i_CLK = ClockSignal("sys4x"),
|
i_CLK = ClockSignal("sys4x"),
|
||||||
i_CLKDIV = ClockSignal(),
|
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,
|
o_OQ = dm_o_nodelay,
|
||||||
),
|
),
|
||||||
Instance("ODELAYE3",
|
Instance("ODELAYE3",
|
||||||
|
@ -348,6 +363,12 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
dq_i_nodelay = Signal()
|
dq_i_nodelay = Signal()
|
||||||
dq_i_delayed = Signal()
|
dq_i_delayed = Signal()
|
||||||
dq_t = 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) | self._rst.storage,
|
||||||
|
slp = self._dly_sel.storage[i//8] & self._wdly_dq_bitslip.re,
|
||||||
|
cycles = 1)
|
||||||
|
self.submodules += dq_o_bitslip
|
||||||
self.specials += Instance("OSERDESE3",
|
self.specials += Instance("OSERDESE3",
|
||||||
p_SIM_DEVICE = device,
|
p_SIM_DEVICE = device,
|
||||||
p_DATA_WIDTH = 8,
|
p_DATA_WIDTH = 8,
|
||||||
|
@ -358,13 +379,13 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
i_RST = ResetSignal() | self._rst.storage,
|
i_RST = ResetSignal() | self._rst.storage,
|
||||||
i_CLK = ClockSignal("sys4x"),
|
i_CLK = ClockSignal("sys4x"),
|
||||||
i_CLKDIV = ClockSignal(),
|
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,
|
i_T = ~dq_oe_delay.output,
|
||||||
o_OQ = dq_o_nodelay,
|
o_OQ = dq_o_nodelay,
|
||||||
o_T_OUT = dq_t,
|
o_T_OUT = dq_t,
|
||||||
)
|
)
|
||||||
dq_i_bitslip = BitSlip(8,
|
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,
|
slp = self._dly_sel.storage[i//8] & self._rdly_dq_bitslip.re,
|
||||||
cycles = 1)
|
cycles = 1)
|
||||||
self.submodules += dq_i_bitslip
|
self.submodules += dq_i_bitslip
|
||||||
|
@ -465,5 +486,5 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
# Xilinx Ultrascale Plus DDR3/DDR4 PHY -------------------------------------------------------------
|
# Xilinx Ultrascale Plus DDR3/DDR4 PHY -------------------------------------------------------------
|
||||||
|
|
||||||
class USPDDRPHY(USDDRPHY):
|
class USPDDRPHY(USDDRPHY):
|
||||||
def __init__(self, pads, cmd_latency=1, **kwargs):
|
def __init__(self, pads, **kwargs):
|
||||||
USDDRPHY.__init__(self, pads, cmd_latency=cmd_latency, **kwargs)
|
USDDRPHY.__init__(self, pads, **kwargs)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#define SDRAM_PHY_RDPHASE 0
|
#define SDRAM_PHY_RDPHASE 0
|
||||||
#define SDRAM_PHY_WRPHASE 1
|
#define SDRAM_PHY_WRPHASE 1
|
||||||
#define SDRAM_PHY_WRITE_LEVELING_CAPABLE
|
#define SDRAM_PHY_WRITE_LEVELING_CAPABLE
|
||||||
|
#define SDRAM_PHY_WRITE_LATENCY_CALIBRATION_CAPABLE
|
||||||
#define SDRAM_PHY_READ_LEVELING_CAPABLE
|
#define SDRAM_PHY_READ_LEVELING_CAPABLE
|
||||||
#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2
|
#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2
|
||||||
#define SDRAM_PHY_DELAYS 32
|
#define SDRAM_PHY_DELAYS 32
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#define SDRAM_PHY_WRPHASE 2
|
#define SDRAM_PHY_WRPHASE 2
|
||||||
#define SDRAM_PHY_WRITE_LEVELING_CAPABLE
|
#define SDRAM_PHY_WRITE_LEVELING_CAPABLE
|
||||||
#define SDRAM_PHY_WRITE_LEVELING_REINIT
|
#define SDRAM_PHY_WRITE_LEVELING_REINIT
|
||||||
|
#define SDRAM_PHY_WRITE_LATENCY_CALIBRATION_CAPABLE
|
||||||
#define SDRAM_PHY_READ_LEVELING_CAPABLE
|
#define SDRAM_PHY_READ_LEVELING_CAPABLE
|
||||||
#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2
|
#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2
|
||||||
#define SDRAM_PHY_DELAYS 512
|
#define SDRAM_PHY_DELAYS 512
|
||||||
|
|
Loading…
Reference in New Issue