From 26564ba93cf342a191dc68d31194caf81c7c0c6a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 6 Mar 2020 18:56:28 +0100 Subject: [PATCH] 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. --- litedram/phy/ecp5ddrphy.py | 101 +++++++------ litedram/phy/gensdrphy.py | 51 ++++--- litedram/phy/s6ddrphy.py | 34 +++-- litedram/phy/s7ddrphy.py | 301 +++++++++++++++++++------------------ litedram/phy/usddrphy.py | 277 +++++++++++++++++----------------- 5 files changed, 396 insertions(+), 368 deletions(-) diff --git a/litedram/phy/ecp5ddrphy.py b/litedram/phy/ecp5ddrphy.py index f3fbac2..a6ca0f0 100644 --- a/litedram/phy/ecp5ddrphy.py +++ b/litedram/phy/ecp5ddrphy.py @@ -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() diff --git a/litedram/phy/gensdrphy.py b/litedram/phy/gensdrphy.py index 244293f..f80c39d 100644 --- a/litedram/phy/gensdrphy.py +++ b/litedram/phy/gensdrphy.py @@ -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) diff --git a/litedram/phy/s6ddrphy.py b/litedram/phy/s6ddrphy.py index 3691c58..d43aab6 100644 --- a/litedram/phy/s6ddrphy.py +++ b/litedram/phy/s6ddrphy.py @@ -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) diff --git a/litedram/phy/s7ddrphy.py b/litedram/phy/s7ddrphy.py index 99bdbd4..9340528 100644 --- a/litedram/phy/s7ddrphy.py +++ b/litedram/phy/s7ddrphy.py @@ -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() diff --git a/litedram/phy/usddrphy.py b/litedram/phy/usddrphy.py index 7bef085..3de6850 100644 --- a/litedram/phy/usddrphy.py +++ b/litedram/phy/usddrphy.py @@ -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()