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:
parent
5e068f412b
commit
26564ba93c
|
@ -82,6 +82,7 @@ class ECP5DDRPHYInit(Module):
|
|||
|
||||
class ECP5DDRPHY(Module, AutoCSR):
|
||||
def __init__(self, pads, sys_clk_freq=100e6):
|
||||
pads = PHYPadsCombiner(pads)
|
||||
memtype = "DDR3"
|
||||
tck = 2/(2*2*sys_clk_freq)
|
||||
addressbits = len(pads.a)
|
||||
|
@ -138,61 +139,65 @@ class ECP5DDRPHY(Module, AutoCSR):
|
|||
|
||||
bl8_sel = Signal()
|
||||
|
||||
# Clock ------------------------------------------------------------------------------------
|
||||
for i in range(len(pads.clk_p)):
|
||||
sd_clk_se = Signal()
|
||||
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]
|
||||
)
|
||||
# Iterate on pads groups -------------------------------------------------------------------
|
||||
for pads_group in range(len(pads.groups)):
|
||||
pads.sel_group(pads_group)
|
||||
|
||||
# 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))):
|
||||
# Clock ------------------------------------------------------------------------------------
|
||||
for i in range(len(pads.clk_p)):
|
||||
sd_clk_se = Signal()
|
||||
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]
|
||||
i_D0 = 0,
|
||||
i_D1 = 1,
|
||||
i_D2 = 0,
|
||||
i_D3 = 1,
|
||||
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 ---------------------------------------------------------------------------------------
|
||||
oe_dq = Signal()
|
||||
oe_dqs = Signal()
|
||||
|
|
|
@ -18,13 +18,14 @@ from migen import *
|
|||
from migen.genlib.record import *
|
||||
from migen.fhdl.specials import Tristate
|
||||
|
||||
from litedram.common import PhySettings
|
||||
from litedram.common import *
|
||||
from litedram.phy.dfi import *
|
||||
|
||||
# Generic SDR PHY ----------------------------------------------------------------------------------
|
||||
|
||||
class GENSDRPHY(Module):
|
||||
def __init__(self, pads, cl=2):
|
||||
pads = PHYPadsCombiner(pads)
|
||||
addressbits = len(pads.a)
|
||||
bankbits = len(pads.ba)
|
||||
nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
|
||||
|
@ -52,33 +53,39 @@ class GENSDRPHY(Module):
|
|||
|
||||
# # #
|
||||
|
||||
# Addresses and Commands -------------------------------------------------------------------
|
||||
self.sync += [
|
||||
pads.a.eq(dfi.p0.address),
|
||||
pads.ba.eq(dfi.p0.bank),
|
||||
pads.cas_n.eq(dfi.p0.cas_n),
|
||||
pads.ras_n.eq(dfi.p0.ras_n),
|
||||
pads.we_n.eq(dfi.p0.we_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)
|
||||
# Iterate on pads groups -------------------------------------------------------------------
|
||||
for pads_group in range(len(pads.groups)):
|
||||
pads.sel_group(pads_group)
|
||||
|
||||
# Addresses and Commands ---------------------------------------------------------------
|
||||
self.sync += [
|
||||
pads.a.eq(dfi.p0.address),
|
||||
pads.ba.eq(dfi.p0.bank),
|
||||
pads.cas_n.eq(dfi.p0.cas_n),
|
||||
pads.ras_n.eq(dfi.p0.ras_n),
|
||||
pads.we_n.eq(dfi.p0.we_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_o = Signal(databits)
|
||||
dq_o = Signal(databits)
|
||||
dq_oe = Signal()
|
||||
dq_i = Signal(databits)
|
||||
dq_i = Signal(databits)
|
||||
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"):
|
||||
assert len(pads.dm)*8 == databits
|
||||
self.sync += \
|
||||
If(dfi.p0.wrdata_en,
|
||||
pads.dm.eq(dfi.p0.wrdata_mask)
|
||||
).Else(
|
||||
pads.dm.eq(0)
|
||||
)
|
||||
for i in range(len(pads.dm)):
|
||||
self.sync += \
|
||||
If(dfi.p0.wrdata_en,
|
||||
pads.dm[i].eq(dfi.p0.wrdata_mask)
|
||||
).Else(
|
||||
pads.dm[i].eq(0)
|
||||
)
|
||||
dq_in = Signal(databits)
|
||||
self.sync.sys_ps += dq_in.eq(dq_i)
|
||||
self.sync += dfi.p0.rddata.eq(dq_in)
|
||||
|
|
|
@ -27,12 +27,13 @@ from migen import *
|
|||
from migen.genlib.record import *
|
||||
from migen.fhdl.decorators import ClockDomainsRenamer
|
||||
|
||||
from litedram.common import PhySettings
|
||||
from litedram.common import *
|
||||
from litedram.phy.dfi import *
|
||||
|
||||
|
||||
class S6HalfRateDDRPHY(Module):
|
||||
def __init__(self, pads, memtype, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
|
||||
pads = PHYPadsCombiner(pads)
|
||||
if memtype not in ["DDR", "LPDDR", "DDR2", "DDR3"]:
|
||||
raise NotImplementedError("S6HalfRateDDRPHY only supports DDR, LPDDR, DDR2 and DDR3")
|
||||
addressbits = len(pads.a)
|
||||
|
@ -130,19 +131,23 @@ class S6HalfRateDDRPHY(Module):
|
|||
r_dfi[n].we_n.eq(phase.we_n)
|
||||
]
|
||||
|
||||
# output cmds
|
||||
sd_sdram_half += [
|
||||
pads.a.eq(r_dfi[phase_sel].address),
|
||||
pads.ba.eq(r_dfi[phase_sel].bank),
|
||||
pads.cke.eq(r_dfi[phase_sel].cke),
|
||||
pads.ras_n.eq(r_dfi[phase_sel].ras_n),
|
||||
pads.cas_n.eq(r_dfi[phase_sel].cas_n),
|
||||
pads.we_n.eq(r_dfi[phase_sel].we_n)
|
||||
]
|
||||
# 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))
|
||||
# Iterate on pads groups -------------------------------------------------------------------
|
||||
for pads_group in range(len(pads.groups)):
|
||||
pads.sel_group(pads_group)
|
||||
|
||||
# output cmds
|
||||
sd_sdram_half += [
|
||||
pads.a.eq(r_dfi[phase_sel].address),
|
||||
pads.ba.eq(r_dfi[phase_sel].bank),
|
||||
pads.cke.eq(r_dfi[phase_sel].cke),
|
||||
pads.ras_n.eq(r_dfi[phase_sel].ras_n),
|
||||
pads.cas_n.eq(r_dfi[phase_sel].cas_n),
|
||||
pads.we_n.eq(r_dfi[phase_sel].we_n)
|
||||
]
|
||||
# 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_cnt = Signal(4)
|
||||
|
@ -406,6 +411,7 @@ class S6HalfRateDDRPHY(Module):
|
|||
|
||||
class S6QuarterRateDDRPHY(Module):
|
||||
def __init__(self, pads, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
|
||||
pads = PHYPadsCombiner(pads)
|
||||
addressbits = len(pads.a)
|
||||
bankbits = len(pads.ba)
|
||||
nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
|
||||
|
|
|
@ -25,6 +25,7 @@ class S7DDRPHY(Module, AutoCSR):
|
|||
iodelay_clk_freq = 200e6,
|
||||
cmd_latency = 0):
|
||||
assert not (memtype == "DDR3" and nphases == 2) # FIXME: Needs BL8 support for nphases=2
|
||||
pads = PHYPadsCombiner(pads)
|
||||
tck = 2/(2*nphases*sys_clk_freq)
|
||||
addressbits = len(pads.a)
|
||||
bankbits = len(pads.ba)
|
||||
|
@ -93,144 +94,15 @@ class S7DDRPHY(Module, AutoCSR):
|
|||
|
||||
# # #
|
||||
|
||||
# Clock ------------------------------------------------------------------------------------
|
||||
ddr_clk = "sys2x" if nphases == 2 else "sys4x"
|
||||
for i in range(len(pads.clk_p)):
|
||||
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]
|
||||
)
|
||||
# Iterate on pads groups -------------------------------------------------------------------
|
||||
for pads_group in range(len(pads.groups)):
|
||||
pads.sel_group(pads_group)
|
||||
|
||||
# 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:
|
||||
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()
|
||||
# Clock --------------------------------------------------------------------------------
|
||||
ddr_clk = "sys2x" if nphases == 2 else "sys4x"
|
||||
for i in range(len(pads.clk_p)):
|
||||
sd_clk_se_nodelay = Signal()
|
||||
sd_clk_se_delayed = Signal()
|
||||
self.specials += Instance("OSERDESE2",
|
||||
p_SERDES_MODE = "MASTER",
|
||||
p_DATA_WIDTH = 2*nphases,
|
||||
|
@ -240,16 +112,63 @@ class S7DDRPHY(Module, AutoCSR):
|
|||
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_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,
|
||||
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:
|
||||
self.specials += Instance("ODELAYE2",
|
||||
|
@ -266,9 +185,95 @@ class S7DDRPHY(Module, AutoCSR):
|
|||
i_LDPIPEEN = 0,
|
||||
i_CE = self._cdly_inc.re,
|
||||
i_INC = 1,
|
||||
o_ODATAIN = cmd,
|
||||
o_DATAOUT = getattr(pads, name)[i],
|
||||
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",
|
||||
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 -------------------------------------------------------------------------------
|
||||
oe_dqs = Signal()
|
||||
|
|
|
@ -24,6 +24,7 @@ class USDDRPHY(Module, AutoCSR):
|
|||
iodelay_clk_freq = 200e6,
|
||||
cmd_latency = 0,
|
||||
sim_device = "ULTRASCALE"):
|
||||
pads = PHYPadsCombiner(pads)
|
||||
tck = 2/(2*4*sys_clk_freq)
|
||||
addressbits = len(pads.a)
|
||||
if memtype == "DDR4":
|
||||
|
@ -93,49 +94,13 @@ class USDDRPHY(Module, AutoCSR):
|
|||
|
||||
# # #
|
||||
|
||||
# Clock ------------------------------------------------------------------------------------
|
||||
clk_o_nodelay = Signal()
|
||||
clk_o_delayed = 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 = 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,
|
||||
)
|
||||
]
|
||||
# Iterate on pads groups -------------------------------------------------------------------
|
||||
for pads_group in range(len(pads.groups)):
|
||||
pads.sel_group(pads_group)
|
||||
|
||||
# Addresses and Commands -------------------------------------------------------------------
|
||||
for i in range(addressbits if memtype=="DDR3" else addressbits-3):
|
||||
a_o_nodelay = Signal()
|
||||
# Clock ------------------------------------------------------------------------------------
|
||||
clk_o_nodelay = Signal()
|
||||
clk_o_delayed = Signal()
|
||||
self.specials += [
|
||||
Instance("OSERDESE3",
|
||||
p_SIM_DEVICE = sim_device,
|
||||
|
@ -147,11 +112,8 @@ class USDDRPHY(Module, AutoCSR):
|
|||
i_RST = ResetSignal(),
|
||||
i_CLK = ClockSignal("sys4x"),
|
||||
i_CLKDIV = ClockSignal(),
|
||||
i_D = Cat(dfi.phases[0].address[i], dfi.phases[0].address[i],
|
||||
dfi.phases[1].address[i], dfi.phases[1].address[i],
|
||||
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,
|
||||
i_D = 0b10101010,
|
||||
o_OQ = clk_o_nodelay,
|
||||
),
|
||||
Instance("ODELAYE3",
|
||||
p_SIM_DEVICE = sim_device,
|
||||
|
@ -166,99 +128,142 @@ class USDDRPHY(Module, AutoCSR):
|
|||
i_EN_VTC = self._en_vtc.storage,
|
||||
i_CE = self._cdly_inc.re,
|
||||
i_INC = 1,
|
||||
i_ODATAIN = a_o_nodelay,
|
||||
o_DATAOUT = pads.a[i],
|
||||
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,
|
||||
)
|
||||
]
|
||||
|
||||
pads_ba = Signal(bankbits)
|
||||
if memtype == "DDR3":
|
||||
self.comb += pads.ba.eq(pads_ba)
|
||||
else:
|
||||
self.comb += pads.ba.eq(pads_ba[:len(pads.ba)])
|
||||
self.comb += pads.bg.eq(pads_ba[len(pads.ba):])
|
||||
for i in range(bankbits):
|
||||
ba_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(
|
||||
dfi.phases[0].bank[i], dfi.phases[0].bank[i],
|
||||
dfi.phases[1].bank[i], dfi.phases[1].bank[i],
|
||||
dfi.phases[2].bank[i], dfi.phases[2].bank[i],
|
||||
dfi.phases[3].bank[i], dfi.phases[3].bank[i]),
|
||||
o_OQ = ba_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 = ba_o_nodelay,
|
||||
o_DATAOUT = pads_ba[i],
|
||||
)
|
||||
]
|
||||
# Addresses and Commands -------------------------------------------------------------------
|
||||
for i in range(addressbits if memtype=="DDR3" else addressbits-3):
|
||||
a_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(dfi.phases[0].address[i], dfi.phases[0].address[i],
|
||||
dfi.phases[1].address[i], dfi.phases[1].address[i],
|
||||
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",
|
||||
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 = a_o_nodelay,
|
||||
o_DATAOUT = pads.a[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")
|
||||
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),
|
||||
)
|
||||
]
|
||||
pads_ba = Signal(bankbits)
|
||||
if memtype == "DDR3":
|
||||
self.comb += pads.ba.eq(pads_ba)
|
||||
else:
|
||||
self.comb += pads.ba.eq(pads_ba[:len(pads.ba)])
|
||||
self.comb += pads.bg.eq(pads_ba[len(pads.ba):])
|
||||
for i in range(bankbits):
|
||||
ba_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(
|
||||
dfi.phases[0].bank[i], dfi.phases[0].bank[i],
|
||||
dfi.phases[1].bank[i], dfi.phases[1].bank[i],
|
||||
dfi.phases[2].bank[i], dfi.phases[2].bank[i],
|
||||
dfi.phases[3].bank[i], dfi.phases[3].bank[i]),
|
||||
o_OQ = ba_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 = ba_o_nodelay,
|
||||
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")
|
||||
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 -------------------------------------------------------------------------------
|
||||
oe_dqs = Signal()
|
||||
|
|
Loading…
Reference in New Issue