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,6 +139,10 @@ class ECP5DDRPHY(Module, AutoCSR):
bl8_sel = Signal() bl8_sel = Signal()
# Iterate on pads groups -------------------------------------------------------------------
for pads_group in range(len(pads.groups)):
pads.sel_group(pads_group)
# Clock ------------------------------------------------------------------------------------ # Clock ------------------------------------------------------------------------------------
for i in range(len(pads.clk_p)): for i in range(len(pads.clk_p)):
sd_clk_se = Signal() sd_clk_se = 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,7 +53,11 @@ class GENSDRPHY(Module):
# # # # # #
# Addresses and Commands ------------------------------------------------------------------- # Iterate on pads groups -------------------------------------------------------------------
for pads_group in range(len(pads.groups)):
pads.sel_group(pads_group)
# Addresses and Commands ---------------------------------------------------------------
self.sync += [ self.sync += [
pads.a.eq(dfi.p0.address), pads.a.eq(dfi.p0.address),
pads.ba.eq(dfi.p0.bank), pads.ba.eq(dfi.p0.bank),
@ -70,14 +75,16 @@ class GENSDRPHY(Module):
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
for i in range(len(pads.dm)):
self.sync += \ self.sync += \
If(dfi.p0.wrdata_en, If(dfi.p0.wrdata_en,
pads.dm.eq(dfi.p0.wrdata_mask) pads.dm[i].eq(dfi.p0.wrdata_mask)
).Else( ).Else(
pads.dm.eq(0) 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)

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,6 +131,10 @@ class S6HalfRateDDRPHY(Module):
r_dfi[n].we_n.eq(phase.we_n) r_dfi[n].we_n.eq(phase.we_n)
] ]
# Iterate on pads groups -------------------------------------------------------------------
for pads_group in range(len(pads.groups)):
pads.sel_group(pads_group)
# output cmds # output cmds
sd_sdram_half += [ sd_sdram_half += [
pads.a.eq(r_dfi[phase_sel].address), pads.a.eq(r_dfi[phase_sel].address),
@ -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,7 +94,11 @@ class S7DDRPHY(Module, AutoCSR):
# # # # # #
# Clock ------------------------------------------------------------------------------------ # Iterate on pads groups -------------------------------------------------------------------
for pads_group in range(len(pads.groups)):
pads.sel_group(pads_group)
# Clock --------------------------------------------------------------------------------
ddr_clk = "sys2x" if nphases == 2 else "sys4x" ddr_clk = "sys2x" if nphases == 2 else "sys4x"
for i in range(len(pads.clk_p)): for i in range(len(pads.clk_p)):
sd_clk_se_nodelay = Signal() sd_clk_se_nodelay = Signal()

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,6 +94,10 @@ class USDDRPHY(Module, AutoCSR):
# # # # # #
# Iterate on pads groups -------------------------------------------------------------------
for pads_group in range(len(pads.groups)):
pads.sel_group(pads_group)
# Clock ------------------------------------------------------------------------------------ # Clock ------------------------------------------------------------------------------------
clk_o_nodelay = Signal() clk_o_nodelay = Signal()
clk_o_delayed = Signal() clk_o_delayed = Signal()