phys: integrate PHYPadsCombiner.

pads can now be passed to the PHY as:

# DRAM Chips with common command/address lines (traditional):
pads = platform.request("ddram")

# DRAM Chips with dissociated command/address lines:
pads = [platform.request("ddram", 0), platform.request("ddram", 1)]

LiteDRAM controller will automatically adapts itself to this combined pads.
This commit is contained in:
Florent Kermarrec 2020-03-06 18:56:28 +01:00
parent 5e068f412b
commit 26564ba93c
5 changed files with 396 additions and 368 deletions

View File

@ -82,6 +82,7 @@ class ECP5DDRPHYInit(Module):
class ECP5DDRPHY(Module, AutoCSR): class ECP5DDRPHY(Module, AutoCSR):
def __init__(self, pads, sys_clk_freq=100e6): def __init__(self, pads, sys_clk_freq=100e6):
pads = PHYPadsCombiner(pads)
memtype = "DDR3" memtype = "DDR3"
tck = 2/(2*2*sys_clk_freq) tck = 2/(2*2*sys_clk_freq)
addressbits = len(pads.a) addressbits = len(pads.a)
@ -138,61 +139,65 @@ class ECP5DDRPHY(Module, AutoCSR):
bl8_sel = Signal() bl8_sel = Signal()
# Clock ------------------------------------------------------------------------------------ # Iterate on pads groups -------------------------------------------------------------------
for i in range(len(pads.clk_p)): for pads_group in range(len(pads.groups)):
sd_clk_se = Signal() pads.sel_group(pads_group)
self.specials += Instance("ODDRX2F",
i_RST = ResetSignal("sys2x"),
i_ECLK = ClockSignal("sys2x"),
i_SCLK = ClockSignal(),
i_D0 = 0,
i_D1 = 1,
i_D2 = 0,
i_D3 = 1,
o_Q = pads.clk_p[i]
)
# Addresses and Commands ------------------------------------------------------------------- # Clock ------------------------------------------------------------------------------------
for i in range(addressbits): for i in range(len(pads.clk_p)):
self.specials += Instance("ODDRX2F", sd_clk_se = Signal()
i_RST = ResetSignal("sys2x"),
i_ECLK = ClockSignal("sys2x"),
i_SCLK = ClockSignal(),
i_D0 = dfi.phases[0].address[i],
i_D1 = dfi.phases[0].address[i],
i_D2 = dfi.phases[1].address[i],
i_D3 = dfi.phases[1].address[i],
o_Q = pads.a[i]
)
for i in range(bankbits):
self.specials += Instance("ODDRX2F",
i_RST = ResetSignal("sys2x"),
i_ECLK = ClockSignal("sys2x"),
i_SCLK = ClockSignal(),
i_D0 = dfi.phases[0].bank[i],
i_D1 = dfi.phases[0].bank[i],
i_D2 = dfi.phases[1].bank[i],
i_D3 = dfi.phases[1].bank[i],
o_Q = pads.ba[i]
)
controls = ["ras_n", "cas_n", "we_n", "cke", "odt"]
if hasattr(pads, "reset_n"):
controls.append("reset_n")
if hasattr(pads, "cs_n"):
controls.append("cs_n")
for name in controls:
for i in range(len(getattr(pads, name))):
self.specials += Instance("ODDRX2F", self.specials += Instance("ODDRX2F",
i_RST = ResetSignal("sys2x"), i_RST = ResetSignal("sys2x"),
i_ECLK = ClockSignal("sys2x"), i_ECLK = ClockSignal("sys2x"),
i_SCLK = ClockSignal(), i_SCLK = ClockSignal(),
i_D0 = getattr(dfi.phases[0], name)[i], i_D0 = 0,
i_D1 = getattr(dfi.phases[0], name)[i], i_D1 = 1,
i_D2 = getattr(dfi.phases[1], name)[i], i_D2 = 0,
i_D3 = getattr(dfi.phases[1], name)[i], i_D3 = 1,
o_Q = getattr(pads, name)[i] o_Q = pads.clk_p[i]
) )
# Addresses and Commands -------------------------------------------------------------------
for i in range(addressbits):
self.specials += Instance("ODDRX2F",
i_RST = ResetSignal("sys2x"),
i_ECLK = ClockSignal("sys2x"),
i_SCLK = ClockSignal(),
i_D0 = dfi.phases[0].address[i],
i_D1 = dfi.phases[0].address[i],
i_D2 = dfi.phases[1].address[i],
i_D3 = dfi.phases[1].address[i],
o_Q = pads.a[i]
)
for i in range(bankbits):
self.specials += Instance("ODDRX2F",
i_RST = ResetSignal("sys2x"),
i_ECLK = ClockSignal("sys2x"),
i_SCLK = ClockSignal(),
i_D0 = dfi.phases[0].bank[i],
i_D1 = dfi.phases[0].bank[i],
i_D2 = dfi.phases[1].bank[i],
i_D3 = dfi.phases[1].bank[i],
o_Q = pads.ba[i]
)
controls = ["ras_n", "cas_n", "we_n", "cke", "odt"]
if hasattr(pads, "reset_n"):
controls.append("reset_n")
if hasattr(pads, "cs_n"):
controls.append("cs_n")
for name in controls:
for i in range(len(getattr(pads, name))):
self.specials += Instance("ODDRX2F",
i_RST = ResetSignal("sys2x"),
i_ECLK = ClockSignal("sys2x"),
i_SCLK = ClockSignal(),
i_D0 = getattr(dfi.phases[0], name)[i],
i_D1 = getattr(dfi.phases[0], name)[i],
i_D2 = getattr(dfi.phases[1], name)[i],
i_D3 = getattr(dfi.phases[1], name)[i],
o_Q = getattr(pads, name)[i]
)
# DQ --------------------------------------------------------------------------------------- # DQ ---------------------------------------------------------------------------------------
oe_dq = Signal() oe_dq = Signal()
oe_dqs = Signal() oe_dqs = Signal()

View File

@ -18,13 +18,14 @@ from migen import *
from migen.genlib.record import * from migen.genlib.record import *
from migen.fhdl.specials import Tristate from migen.fhdl.specials import Tristate
from litedram.common import PhySettings from litedram.common import *
from litedram.phy.dfi import * from litedram.phy.dfi import *
# Generic SDR PHY ---------------------------------------------------------------------------------- # Generic SDR PHY ----------------------------------------------------------------------------------
class GENSDRPHY(Module): class GENSDRPHY(Module):
def __init__(self, pads, cl=2): def __init__(self, pads, cl=2):
pads = PHYPadsCombiner(pads)
addressbits = len(pads.a) addressbits = len(pads.a)
bankbits = len(pads.ba) bankbits = len(pads.ba)
nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
@ -52,33 +53,39 @@ class GENSDRPHY(Module):
# # # # # #
# Addresses and Commands ------------------------------------------------------------------- # Iterate on pads groups -------------------------------------------------------------------
self.sync += [ for pads_group in range(len(pads.groups)):
pads.a.eq(dfi.p0.address), pads.sel_group(pads_group)
pads.ba.eq(dfi.p0.bank),
pads.cas_n.eq(dfi.p0.cas_n), # Addresses and Commands ---------------------------------------------------------------
pads.ras_n.eq(dfi.p0.ras_n), self.sync += [
pads.we_n.eq(dfi.p0.we_n) pads.a.eq(dfi.p0.address),
] pads.ba.eq(dfi.p0.bank),
if hasattr(pads, "cke"): pads.cas_n.eq(dfi.p0.cas_n),
self.sync += pads.cke.eq(dfi.p0.cke) pads.ras_n.eq(dfi.p0.ras_n),
if hasattr(pads, "cs_n"): pads.we_n.eq(dfi.p0.we_n)
self.sync += pads.cs_n.eq(dfi.p0.cs_n) ]
if hasattr(pads, "cke"):
self.sync += pads.cke.eq(dfi.p0.cke)
if hasattr(pads, "cs_n"):
self.sync += pads.cs_n.eq(dfi.p0.cs_n)
# DQ/DQS/DM Data --------------------------------------------------------------------------- # DQ/DQS/DM Data ---------------------------------------------------------------------------
dq_o = Signal(databits) dq_o = Signal(databits)
dq_oe = Signal() dq_oe = Signal()
dq_i = Signal(databits) dq_i = Signal(databits)
self.sync += dq_o.eq(dfi.p0.wrdata) self.sync += dq_o.eq(dfi.p0.wrdata)
self.specials += Tristate(pads.dq, dq_o, dq_oe, dq_i) for i in range(len(pads.dq)):
self.specials += Tristate(pads.dq[i], dq_o[i], dq_oe, dq_i[i])
if hasattr(pads, "dm"): if hasattr(pads, "dm"):
assert len(pads.dm)*8 == databits assert len(pads.dm)*8 == databits
self.sync += \ for i in range(len(pads.dm)):
If(dfi.p0.wrdata_en, self.sync += \
pads.dm.eq(dfi.p0.wrdata_mask) If(dfi.p0.wrdata_en,
).Else( pads.dm[i].eq(dfi.p0.wrdata_mask)
pads.dm.eq(0) ).Else(
) pads.dm[i].eq(0)
)
dq_in = Signal(databits) dq_in = Signal(databits)
self.sync.sys_ps += dq_in.eq(dq_i) self.sync.sys_ps += dq_in.eq(dq_i)
self.sync += dfi.p0.rddata.eq(dq_in) self.sync += dfi.p0.rddata.eq(dq_in)

View File

@ -27,12 +27,13 @@ from migen import *
from migen.genlib.record import * from migen.genlib.record import *
from migen.fhdl.decorators import ClockDomainsRenamer from migen.fhdl.decorators import ClockDomainsRenamer
from litedram.common import PhySettings from litedram.common import *
from litedram.phy.dfi import * from litedram.phy.dfi import *
class S6HalfRateDDRPHY(Module): class S6HalfRateDDRPHY(Module):
def __init__(self, pads, memtype, rd_bitslip, wr_bitslip, dqs_ddr_alignment): def __init__(self, pads, memtype, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
pads = PHYPadsCombiner(pads)
if memtype not in ["DDR", "LPDDR", "DDR2", "DDR3"]: if memtype not in ["DDR", "LPDDR", "DDR2", "DDR3"]:
raise NotImplementedError("S6HalfRateDDRPHY only supports DDR, LPDDR, DDR2 and DDR3") raise NotImplementedError("S6HalfRateDDRPHY only supports DDR, LPDDR, DDR2 and DDR3")
addressbits = len(pads.a) addressbits = len(pads.a)
@ -130,19 +131,23 @@ class S6HalfRateDDRPHY(Module):
r_dfi[n].we_n.eq(phase.we_n) r_dfi[n].we_n.eq(phase.we_n)
] ]
# output cmds # Iterate on pads groups -------------------------------------------------------------------
sd_sdram_half += [ for pads_group in range(len(pads.groups)):
pads.a.eq(r_dfi[phase_sel].address), pads.sel_group(pads_group)
pads.ba.eq(r_dfi[phase_sel].bank),
pads.cke.eq(r_dfi[phase_sel].cke), # output cmds
pads.ras_n.eq(r_dfi[phase_sel].ras_n), sd_sdram_half += [
pads.cas_n.eq(r_dfi[phase_sel].cas_n), pads.a.eq(r_dfi[phase_sel].address),
pads.we_n.eq(r_dfi[phase_sel].we_n) pads.ba.eq(r_dfi[phase_sel].bank),
] pads.cke.eq(r_dfi[phase_sel].cke),
# optional pads pads.ras_n.eq(r_dfi[phase_sel].ras_n),
for name in "reset_n", "cs_n", "odt": pads.cas_n.eq(r_dfi[phase_sel].cas_n),
if hasattr(pads, name): pads.we_n.eq(r_dfi[phase_sel].we_n)
sd_sdram_half += getattr(pads, name).eq(getattr(r_dfi[phase_sel], name)) ]
# optional pads
for name in "reset_n", "cs_n", "odt":
if hasattr(pads, name):
sd_sdram_half += getattr(pads, name).eq(getattr(r_dfi[phase_sel], name))
# Bitslip ---------------------------------------------------------------------------------- # Bitslip ----------------------------------------------------------------------------------
bitslip_cnt = Signal(4) bitslip_cnt = Signal(4)
@ -406,6 +411,7 @@ class S6HalfRateDDRPHY(Module):
class S6QuarterRateDDRPHY(Module): class S6QuarterRateDDRPHY(Module):
def __init__(self, pads, rd_bitslip, wr_bitslip, dqs_ddr_alignment): def __init__(self, pads, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
pads = PHYPadsCombiner(pads)
addressbits = len(pads.a) addressbits = len(pads.a)
bankbits = len(pads.ba) bankbits = len(pads.ba)
nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n) nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)

View File

@ -25,6 +25,7 @@ class S7DDRPHY(Module, AutoCSR):
iodelay_clk_freq = 200e6, iodelay_clk_freq = 200e6,
cmd_latency = 0): cmd_latency = 0):
assert not (memtype == "DDR3" and nphases == 2) # FIXME: Needs BL8 support for nphases=2 assert not (memtype == "DDR3" and nphases == 2) # FIXME: Needs BL8 support for nphases=2
pads = PHYPadsCombiner(pads)
tck = 2/(2*nphases*sys_clk_freq) tck = 2/(2*nphases*sys_clk_freq)
addressbits = len(pads.a) addressbits = len(pads.a)
bankbits = len(pads.ba) bankbits = len(pads.ba)
@ -93,144 +94,15 @@ class S7DDRPHY(Module, AutoCSR):
# # # # # #
# Clock ------------------------------------------------------------------------------------ # Iterate on pads groups -------------------------------------------------------------------
ddr_clk = "sys2x" if nphases == 2 else "sys4x" for pads_group in range(len(pads.groups)):
for i in range(len(pads.clk_p)): pads.sel_group(pads_group)
sd_clk_se_nodelay = Signal()
sd_clk_se_delayed = Signal()
self.specials += Instance("OSERDESE2",
p_SERDES_MODE = "MASTER",
p_DATA_WIDTH = 2*nphases,
p_TRISTATE_WIDTH = 1,
p_DATA_RATE_OQ = "DDR",
p_DATA_RATE_TQ = "BUF",
i_RST = ResetSignal(),
i_CLK = ClockSignal(ddr_clk),
i_CLKDIV = ClockSignal(),
i_D1 = 0,
i_D2 = 1,
i_D3 = 0,
i_D4 = 1,
i_D5 = 0,
i_D6 = 1,
i_D7 = 0,
i_D8 = 1,
o_OQ = sd_clk_se_nodelay,
i_OCE = 1,
)
if with_odelay:
self.specials += Instance("ODELAYE2",
p_SIGNAL_PATTERN = "DATA",
p_DELAY_SRC = "ODATAIN",
p_CINVCTRL_SEL = "FALSE",
p_HIGH_PERFORMANCE_MODE = "TRUE",
p_PIPE_SEL = "FALSE",
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
p_ODELAY_TYPE = "VARIABLE",
p_ODELAY_VALUE = 0,
i_C = ClockSignal(),
i_LD = self._cdly_rst.re,
i_LDPIPEEN = 0,
i_CE = self._cdly_inc.re,
i_INC = 1,
o_ODATAIN = sd_clk_se_nodelay,
o_DATAOUT = sd_clk_se_delayed,
)
self.specials += Instance("OBUFDS",
i_I = sd_clk_se_delayed if with_odelay else sd_clk_se_nodelay,
o_O = pads.clk_p[i],
o_OB = pads.clk_n[i]
)
# Addresses and Commands ------------------------------------------------------------------- # Clock --------------------------------------------------------------------------------
for i in range(addressbits): ddr_clk = "sys2x" if nphases == 2 else "sys4x"
address = Signal() for i in range(len(pads.clk_p)):
self.specials += Instance("OSERDESE2", sd_clk_se_nodelay = Signal()
p_SERDES_MODE = "MASTER", sd_clk_se_delayed = Signal()
p_DATA_WIDTH = 2*nphases,
p_TRISTATE_WIDTH = 1,
p_DATA_RATE_OQ = "DDR",
p_DATA_RATE_TQ = "BUF",
i_RST = ResetSignal(),
i_CLK = ClockSignal(ddr_clk),
i_CLKDIV = ClockSignal(),
i_D1 = dfi.phases[0].address[i],
i_D2 = dfi.phases[0].address[i],
i_D3 = dfi.phases[1].address[i],
i_D4 = dfi.phases[1].address[i],
i_D5 = dfi.phases[2].address[i],
i_D6 = dfi.phases[2].address[i],
i_D7 = dfi.phases[3].address[i],
i_D8 = dfi.phases[3].address[i],
i_OCE = 1,
o_OQ = address if with_odelay else pads.a[i],
)
if with_odelay:
self.specials += Instance("ODELAYE2",
p_SIGNAL_PATTERN = "DATA",
p_DELAY_SRC = "ODATAIN",
p_CINVCTRL_SEL = "FALSE",
p_HIGH_PERFORMANCE_MODE = "TRUE",
p_PIPE_SEL = "FALSE",
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
p_ODELAY_TYPE = "VARIABLE",
p_ODELAY_VALUE = 0,
i_C = ClockSignal(),
i_LD = self._cdly_rst.re,
i_LDPIPEEN = 0,
i_CE = self._cdly_inc.re,
i_INC = 1,
o_ODATAIN = address,
o_DATAOUT = pads.a[i],
)
for i in range(bankbits):
bank = Signal()
self.specials += Instance("OSERDESE2",
p_SERDES_MODE = "MASTER",
p_DATA_WIDTH = 2*nphases,
p_TRISTATE_WIDTH = 1,
p_DATA_RATE_OQ = "DDR",
p_DATA_RATE_TQ = "BUF",
i_RST = ResetSignal(),
i_CLK = ClockSignal(ddr_clk),
i_CLKDIV = ClockSignal(),
i_D1 = dfi.phases[0].bank[i],
i_D2 = dfi.phases[0].bank[i],
i_D3 = dfi.phases[1].bank[i],
i_D4 = dfi.phases[1].bank[i],
i_D5 = dfi.phases[2].bank[i],
i_D6 = dfi.phases[2].bank[i],
i_D7 = dfi.phases[3].bank[i],
i_D8 = dfi.phases[3].bank[i],
i_OCE = 1,
o_OQ = bank if with_odelay else pads.ba[i],
)
if with_odelay:
self.specials += Instance("ODELAYE2",
p_SIGNAL_PATTERN = "DATA",
p_DELAY_SRC = "ODATAIN",
p_CINVCTRL_SEL = "FALSE",
p_HIGH_PERFORMANCE_MODE = "TRUE",
p_PIPE_SEL = "FALSE",
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
p_ODELAY_TYPE = "VARIABLE",
p_ODELAY_VALUE = 0,
i_C = ClockSignal(),
i_LD = self._cdly_rst.re,
i_LDPIPEEN = 0,
i_CE = self._cdly_inc.re,
i_INC = 1,
o_ODATAIN = bank,
o_DATAOUT = pads.ba[i],
)
controls = ["ras_n", "cas_n", "we_n", "cke", "odt"]
if hasattr(pads, "reset_n"):
controls.append("reset_n")
if hasattr(pads, "cs_n"):
controls.append("cs_n")
for name in controls:
for i in range(len(getattr(pads, name))):
cmd = Signal()
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,
@ -240,16 +112,63 @@ class S7DDRPHY(Module, AutoCSR):
i_RST = ResetSignal(), i_RST = ResetSignal(),
i_CLK = ClockSignal(ddr_clk), i_CLK = ClockSignal(ddr_clk),
i_CLKDIV = ClockSignal(), i_CLKDIV = ClockSignal(),
i_D1 = getattr(dfi.phases[0], name)[i], i_D1 = 0,
i_D2 = getattr(dfi.phases[0], name)[i], i_D2 = 1,
i_D3 = getattr(dfi.phases[1], name)[i], i_D3 = 0,
i_D4 = getattr(dfi.phases[1], name)[i], i_D4 = 1,
i_D5 = getattr(dfi.phases[2], name)[i], i_D5 = 0,
i_D6 = getattr(dfi.phases[2], name)[i], i_D6 = 1,
i_D7 = getattr(dfi.phases[3], name)[i], i_D7 = 0,
i_D8 = getattr(dfi.phases[3], name)[i], i_D8 = 1,
o_OQ = sd_clk_se_nodelay,
i_OCE = 1, i_OCE = 1,
o_OQ = cmd if with_odelay else getattr(pads, name)[i], )
if with_odelay:
self.specials += Instance("ODELAYE2",
p_SIGNAL_PATTERN = "DATA",
p_DELAY_SRC = "ODATAIN",
p_CINVCTRL_SEL = "FALSE",
p_HIGH_PERFORMANCE_MODE = "TRUE",
p_PIPE_SEL = "FALSE",
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
p_ODELAY_TYPE = "VARIABLE",
p_ODELAY_VALUE = 0,
i_C = ClockSignal(),
i_LD = self._cdly_rst.re,
i_LDPIPEEN = 0,
i_CE = self._cdly_inc.re,
i_INC = 1,
o_ODATAIN = sd_clk_se_nodelay,
o_DATAOUT = sd_clk_se_delayed,
)
self.specials += Instance("OBUFDS",
i_I = sd_clk_se_delayed if with_odelay else sd_clk_se_nodelay,
o_O = pads.clk_p[i],
o_OB = pads.clk_n[i]
)
# Addresses and Commands -------------------------------------------------------------------
for i in range(addressbits):
address = Signal()
self.specials += Instance("OSERDESE2",
p_SERDES_MODE = "MASTER",
p_DATA_WIDTH = 2*nphases,
p_TRISTATE_WIDTH = 1,
p_DATA_RATE_OQ = "DDR",
p_DATA_RATE_TQ = "BUF",
i_RST = ResetSignal(),
i_CLK = ClockSignal(ddr_clk),
i_CLKDIV = ClockSignal(),
i_D1 = dfi.phases[0].address[i],
i_D2 = dfi.phases[0].address[i],
i_D3 = dfi.phases[1].address[i],
i_D4 = dfi.phases[1].address[i],
i_D5 = dfi.phases[2].address[i],
i_D6 = dfi.phases[2].address[i],
i_D7 = dfi.phases[3].address[i],
i_D8 = dfi.phases[3].address[i],
i_OCE = 1,
o_OQ = address if with_odelay else pads.a[i],
) )
if with_odelay: if with_odelay:
self.specials += Instance("ODELAYE2", self.specials += Instance("ODELAYE2",
@ -266,9 +185,95 @@ class S7DDRPHY(Module, AutoCSR):
i_LDPIPEEN = 0, i_LDPIPEEN = 0,
i_CE = self._cdly_inc.re, i_CE = self._cdly_inc.re,
i_INC = 1, i_INC = 1,
o_ODATAIN = cmd, o_ODATAIN = address,
o_DATAOUT = getattr(pads, name)[i], o_DATAOUT = pads.a[i],
) )
for i in range(bankbits):
bank = Signal()
self.specials += Instance("OSERDESE2",
p_SERDES_MODE = "MASTER",
p_DATA_WIDTH = 2*nphases,
p_TRISTATE_WIDTH = 1,
p_DATA_RATE_OQ = "DDR",
p_DATA_RATE_TQ = "BUF",
i_RST = ResetSignal(),
i_CLK = ClockSignal(ddr_clk),
i_CLKDIV = ClockSignal(),
i_D1 = dfi.phases[0].bank[i],
i_D2 = dfi.phases[0].bank[i],
i_D3 = dfi.phases[1].bank[i],
i_D4 = dfi.phases[1].bank[i],
i_D5 = dfi.phases[2].bank[i],
i_D6 = dfi.phases[2].bank[i],
i_D7 = dfi.phases[3].bank[i],
i_D8 = dfi.phases[3].bank[i],
i_OCE = 1,
o_OQ = bank if with_odelay else pads.ba[i],
)
if with_odelay:
self.specials += Instance("ODELAYE2",
p_SIGNAL_PATTERN = "DATA",
p_DELAY_SRC = "ODATAIN",
p_CINVCTRL_SEL = "FALSE",
p_HIGH_PERFORMANCE_MODE = "TRUE",
p_PIPE_SEL = "FALSE",
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
p_ODELAY_TYPE = "VARIABLE",
p_ODELAY_VALUE = 0,
i_C = ClockSignal(),
i_LD = self._cdly_rst.re,
i_LDPIPEEN = 0,
i_CE = self._cdly_inc.re,
i_INC = 1,
o_ODATAIN = bank,
o_DATAOUT = pads.ba[i],
)
controls = ["ras_n", "cas_n", "we_n", "cke", "odt"]
if hasattr(pads, "reset_n"):
controls.append("reset_n")
if hasattr(pads, "cs_n"):
controls.append("cs_n")
for name in controls:
for i in range(len(getattr(pads, name))):
cmd = Signal()
self.specials += Instance("OSERDESE2",
p_SERDES_MODE = "MASTER",
p_DATA_WIDTH = 2*nphases,
p_TRISTATE_WIDTH = 1,
p_DATA_RATE_OQ = "DDR",
p_DATA_RATE_TQ = "BUF",
i_RST = ResetSignal(),
i_CLK = ClockSignal(ddr_clk),
i_CLKDIV = ClockSignal(),
i_D1 = getattr(dfi.phases[0], name)[i],
i_D2 = getattr(dfi.phases[0], name)[i],
i_D3 = getattr(dfi.phases[1], name)[i],
i_D4 = getattr(dfi.phases[1], name)[i],
i_D5 = getattr(dfi.phases[2], name)[i],
i_D6 = getattr(dfi.phases[2], name)[i],
i_D7 = getattr(dfi.phases[3], name)[i],
i_D8 = getattr(dfi.phases[3], name)[i],
i_OCE = 1,
o_OQ = cmd if with_odelay else getattr(pads, name)[i],
)
if with_odelay:
self.specials += Instance("ODELAYE2",
p_SIGNAL_PATTERN = "DATA",
p_DELAY_SRC = "ODATAIN",
p_CINVCTRL_SEL = "FALSE",
p_HIGH_PERFORMANCE_MODE = "TRUE",
p_PIPE_SEL = "FALSE",
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
p_ODELAY_TYPE = "VARIABLE",
p_ODELAY_VALUE = 0,
i_C = ClockSignal(),
i_LD = self._cdly_rst.re,
i_LDPIPEEN = 0,
i_CE = self._cdly_inc.re,
i_INC = 1,
o_ODATAIN = cmd,
o_DATAOUT = getattr(pads, name)[i],
)
# DQS and DM ------------------------------------------------------------------------------- # DQS and DM -------------------------------------------------------------------------------
oe_dqs = Signal() oe_dqs = Signal()

View File

@ -24,6 +24,7 @@ class USDDRPHY(Module, AutoCSR):
iodelay_clk_freq = 200e6, iodelay_clk_freq = 200e6,
cmd_latency = 0, cmd_latency = 0,
sim_device = "ULTRASCALE"): sim_device = "ULTRASCALE"):
pads = PHYPadsCombiner(pads)
tck = 2/(2*4*sys_clk_freq) tck = 2/(2*4*sys_clk_freq)
addressbits = len(pads.a) addressbits = len(pads.a)
if memtype == "DDR4": if memtype == "DDR4":
@ -93,49 +94,13 @@ class USDDRPHY(Module, AutoCSR):
# # # # # #
# Clock ------------------------------------------------------------------------------------ # Iterate on pads groups -------------------------------------------------------------------
clk_o_nodelay = Signal() for pads_group in range(len(pads.groups)):
clk_o_delayed = Signal() pads.sel_group(pads_group)
self.specials += [
Instance("OSERDESE3",
p_SIM_DEVICE = sim_device,
p_DATA_WIDTH = 8,
p_INIT = 0,
p_IS_RST_INVERTED = 0,
p_IS_CLK_INVERTED = 0,
p_IS_CLKDIV_INVERTED = 0,
i_RST = ResetSignal(),
i_CLK = ClockSignal("sys4x"),
i_CLKDIV = ClockSignal(),
i_D = 0b10101010,
o_OQ = clk_o_nodelay,
),
Instance("ODELAYE3",
p_SIM_DEVICE = sim_device,
p_CASCADE = "NONE",
p_UPDATE_MODE = "ASYNC",
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
p_DELAY_FORMAT = "TIME",
p_DELAY_TYPE = "VARIABLE",
p_DELAY_VALUE = 0,
i_RST = self._cdly_rst.re,
i_CLK = ClockSignal(),
i_EN_VTC = self._en_vtc.storage,
i_CE = self._cdly_inc.re,
i_INC = 1,
i_ODATAIN = clk_o_nodelay,
o_DATAOUT = clk_o_delayed,
),
Instance("OBUFDS",
i_I = clk_o_delayed,
o_O = pads.clk_p,
o_OB = pads.clk_n,
)
]
# Addresses and Commands ------------------------------------------------------------------- # Clock ------------------------------------------------------------------------------------
for i in range(addressbits if memtype=="DDR3" else addressbits-3): clk_o_nodelay = Signal()
a_o_nodelay = Signal() clk_o_delayed = Signal()
self.specials += [ self.specials += [
Instance("OSERDESE3", Instance("OSERDESE3",
p_SIM_DEVICE = sim_device, p_SIM_DEVICE = sim_device,
@ -147,11 +112,8 @@ class USDDRPHY(Module, AutoCSR):
i_RST = ResetSignal(), i_RST = ResetSignal(),
i_CLK = ClockSignal("sys4x"), i_CLK = ClockSignal("sys4x"),
i_CLKDIV = ClockSignal(), i_CLKDIV = ClockSignal(),
i_D = Cat(dfi.phases[0].address[i], dfi.phases[0].address[i], i_D = 0b10101010,
dfi.phases[1].address[i], dfi.phases[1].address[i], o_OQ = clk_o_nodelay,
dfi.phases[2].address[i], dfi.phases[2].address[i],
dfi.phases[3].address[i], dfi.phases[3].address[i]),
o_OQ = a_o_nodelay,
), ),
Instance("ODELAYE3", Instance("ODELAYE3",
p_SIM_DEVICE = sim_device, p_SIM_DEVICE = sim_device,
@ -166,99 +128,142 @@ class USDDRPHY(Module, AutoCSR):
i_EN_VTC = self._en_vtc.storage, i_EN_VTC = self._en_vtc.storage,
i_CE = self._cdly_inc.re, i_CE = self._cdly_inc.re,
i_INC = 1, i_INC = 1,
i_ODATAIN = a_o_nodelay, i_ODATAIN = clk_o_nodelay,
o_DATAOUT = pads.a[i], o_DATAOUT = clk_o_delayed,
),
Instance("OBUFDS",
i_I = clk_o_delayed,
o_O = pads.clk_p,
o_OB = pads.clk_n,
) )
] ]
pads_ba = Signal(bankbits) # Addresses and Commands -------------------------------------------------------------------
if memtype == "DDR3": for i in range(addressbits if memtype=="DDR3" else addressbits-3):
self.comb += pads.ba.eq(pads_ba) a_o_nodelay = Signal()
else: self.specials += [
self.comb += pads.ba.eq(pads_ba[:len(pads.ba)]) Instance("OSERDESE3",
self.comb += pads.bg.eq(pads_ba[len(pads.ba):]) p_SIM_DEVICE = sim_device,
for i in range(bankbits): p_DATA_WIDTH = 8,
ba_o_nodelay = Signal() p_INIT = 0,
self.specials += [ p_IS_RST_INVERTED = 0,
Instance("OSERDESE3", p_IS_CLK_INVERTED = 0,
p_SIM_DEVICE = sim_device, p_IS_CLKDIV_INVERTED = 0,
p_DATA_WIDTH = 8, i_RST = ResetSignal(),
p_INIT = 0, i_CLK = ClockSignal("sys4x"),
p_IS_RST_INVERTED = 0, i_CLKDIV = ClockSignal(),
p_IS_CLK_INVERTED = 0, i_D = Cat(dfi.phases[0].address[i], dfi.phases[0].address[i],
p_IS_CLKDIV_INVERTED = 0, dfi.phases[1].address[i], dfi.phases[1].address[i],
i_RST = ResetSignal(), dfi.phases[2].address[i], dfi.phases[2].address[i],
i_CLK = ClockSignal("sys4x"), dfi.phases[3].address[i], dfi.phases[3].address[i]),
i_CLKDIV = ClockSignal(), o_OQ = a_o_nodelay,
i_D = Cat( ),
dfi.phases[0].bank[i], dfi.phases[0].bank[i], Instance("ODELAYE3",
dfi.phases[1].bank[i], dfi.phases[1].bank[i], p_SIM_DEVICE = sim_device,
dfi.phases[2].bank[i], dfi.phases[2].bank[i], p_CASCADE = "NONE",
dfi.phases[3].bank[i], dfi.phases[3].bank[i]), p_UPDATE_MODE = "ASYNC",
o_OQ = ba_o_nodelay, p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
), p_DELAY_FORMAT = "TIME",
Instance("ODELAYE3", p_DELAY_TYPE = "VARIABLE",
p_SIM_DEVICE = sim_device, p_DELAY_VALUE = 0,
p_CASCADE = "NONE", i_RST = self._cdly_rst.re,
p_UPDATE_MODE = "ASYNC", i_CLK = ClockSignal(),
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6, i_EN_VTC = self._en_vtc.storage,
p_DELAY_FORMAT = "TIME", i_CE = self._cdly_inc.re,
p_DELAY_TYPE = "VARIABLE", i_INC = 1,
p_DELAY_VALUE = 0, i_ODATAIN = a_o_nodelay,
i_RST = self._cdly_rst.re, o_DATAOUT = pads.a[i],
i_CLK = ClockSignal(), )
i_EN_VTC = self._en_vtc.storage, ]
i_CE = self._cdly_inc.re,
i_INC = 1,
i_ODATAIN = ba_o_nodelay,
o_DATAOUT = pads_ba[i],
)
]
controls = ["ras_n", "cas_n", "we_n", "cke", "odt"] pads_ba = Signal(bankbits)
if hasattr(pads, "reset_n"): if memtype == "DDR3":
controls.append("reset_n") self.comb += pads.ba.eq(pads_ba)
if hasattr(pads, "cs_n"): else:
controls.append("cs_n") self.comb += pads.ba.eq(pads_ba[:len(pads.ba)])
if hasattr(pads, "act_n"): self.comb += pads.bg.eq(pads_ba[len(pads.ba):])
controls.append("act_n") for i in range(bankbits):
for name in controls: ba_o_nodelay = Signal()
x_o_nodelay = Signal() self.specials += [
self.specials += [ Instance("OSERDESE3",
Instance("OSERDESE3", p_SIM_DEVICE = sim_device,
p_SIM_DEVICE = sim_device, p_DATA_WIDTH = 8,
p_DATA_WIDTH = 8, p_INIT = 0,
p_INIT = 0, p_IS_RST_INVERTED = 0,
p_IS_RST_INVERTED = 0, p_IS_CLK_INVERTED = 0,
p_IS_CLK_INVERTED = 0, p_IS_CLKDIV_INVERTED = 0,
p_IS_CLKDIV_INVERTED = 0, i_RST = ResetSignal(),
i_RST = ResetSignal(), i_CLK = ClockSignal("sys4x"),
i_CLK = ClockSignal("sys4x"), i_CLKDIV = ClockSignal(),
i_CLKDIV = ClockSignal(), i_D = Cat(
i_D = Cat( dfi.phases[0].bank[i], dfi.phases[0].bank[i],
getattr(dfi.phases[0], name), getattr(dfi.phases[0], name), dfi.phases[1].bank[i], dfi.phases[1].bank[i],
getattr(dfi.phases[1], name), getattr(dfi.phases[1], name), dfi.phases[2].bank[i], dfi.phases[2].bank[i],
getattr(dfi.phases[2], name), getattr(dfi.phases[2], name), dfi.phases[3].bank[i], dfi.phases[3].bank[i]),
getattr(dfi.phases[3], name), getattr(dfi.phases[3], name)), o_OQ = ba_o_nodelay,
o_OQ = x_o_nodelay, ),
), Instance("ODELAYE3",
Instance("ODELAYE3", p_SIM_DEVICE = sim_device,
p_SIM_DEVICE = sim_device, p_CASCADE = "NONE",
p_CASCADE = "NONE", p_UPDATE_MODE = "ASYNC",
p_UPDATE_MODE = "ASYNC", p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6, p_DELAY_FORMAT = "TIME",
p_DELAY_FORMAT = "TIME", p_DELAY_TYPE = "VARIABLE",
p_DELAY_TYPE = "VARIABLE", p_DELAY_VALUE = 0,
p_DELAY_VALUE = 0, i_RST = self._cdly_rst.re,
i_RST = self._cdly_rst.re, i_CLK = ClockSignal(),
i_CLK = ClockSignal(), i_EN_VTC = self._en_vtc.storage,
i_EN_VTC = self._en_vtc.storage, i_CE = self._cdly_inc.re,
i_CE = self._cdly_inc.re, i_INC = 1,
i_INC = 1, i_ODATAIN = ba_o_nodelay,
i_ODATAIN = x_o_nodelay, o_DATAOUT = pads_ba[i],
o_DATAOUT = getattr(pads, name), )
) ]
]
controls = ["ras_n", "cas_n", "we_n", "cke", "odt"]
if hasattr(pads, "reset_n"):
controls.append("reset_n")
if hasattr(pads, "cs_n"):
controls.append("cs_n")
if hasattr(pads, "act_n"):
controls.append("act_n")
for name in controls:
x_o_nodelay = Signal()
self.specials += [
Instance("OSERDESE3",
p_SIM_DEVICE = sim_device,
p_DATA_WIDTH = 8,
p_INIT = 0,
p_IS_RST_INVERTED = 0,
p_IS_CLK_INVERTED = 0,
p_IS_CLKDIV_INVERTED = 0,
i_RST = ResetSignal(),
i_CLK = ClockSignal("sys4x"),
i_CLKDIV = ClockSignal(),
i_D = Cat(
getattr(dfi.phases[0], name), getattr(dfi.phases[0], name),
getattr(dfi.phases[1], name), getattr(dfi.phases[1], name),
getattr(dfi.phases[2], name), getattr(dfi.phases[2], name),
getattr(dfi.phases[3], name), getattr(dfi.phases[3], name)),
o_OQ = x_o_nodelay,
),
Instance("ODELAYE3",
p_SIM_DEVICE = sim_device,
p_CASCADE = "NONE",
p_UPDATE_MODE = "ASYNC",
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
p_DELAY_FORMAT = "TIME",
p_DELAY_TYPE = "VARIABLE",
p_DELAY_VALUE = 0,
i_RST = self._cdly_rst.re,
i_CLK = ClockSignal(),
i_EN_VTC = self._en_vtc.storage,
i_CE = self._cdly_inc.re,
i_INC = 1,
i_ODATAIN = x_o_nodelay,
o_DATAOUT = getattr(pads, name),
)
]
# DQS and DM ------------------------------------------------------------------------------- # DQS and DM -------------------------------------------------------------------------------
oe_dqs = Signal() oe_dqs = Signal()