# This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
-# Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
+# This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
from nmigen import *
from nmigen.hdl.rec import *
-def phase_cmd_description(addressbits, bankbits, nranks):
+__ALL__ = ["Interface"]
+
+def phase_description(addressbits, bankbits, nranks, databits):
return [
+ # cmd description
("address", addressbits, DIR_FANOUT),
("bank", bankbits, DIR_FANOUT),
("cas_n", 1, DIR_FANOUT),
("cke", nranks, DIR_FANOUT),
("odt", nranks, DIR_FANOUT),
("reset_n", 1, DIR_FANOUT),
- ("act_n", 1, DIR_FANOUT)
- ]
-
-
-def phase_wrdata_description(databits):
- return [
+ ("act_n", 1, DIR_FANOUT),
+ # wrdata description
("wrdata", databits, DIR_FANOUT),
("wrdata_en", 1, DIR_FANOUT),
- ("wrdata_mask", databits//8, DIR_FANOUT)
- ]
-
-
-def phase_rddata_description(databits):
- return [
+ ("wrdata_mask", databits//8, DIR_FANOUT),
+ # rddata description
("rddata_en", 1, DIR_FANOUT),
("rddata", databits, DIR_FANIN),
- ("rddata_valid", 1, DIR_FANIN)
+ ("rddata_valid", 1, DIR_FANIN),
]
-def phase_description(addressbits, bankbits, nranks, databits):
- r = phase_cmd_description(addressbits, bankbits, nranks)
- r += phase_wrdata_description(databits)
- r += phase_rddata_description(databits)
- return r
-
-
-class Interface(Record):
+class Interface:
def __init__(self, addressbits, bankbits, nranks, databits, nphases=1):
- layout = [("p"+str(i), phase_description(addressbits, bankbits, nranks, databits)) for i in range(nphases)]
- Record.__init__(self, layout)
- self.phases = [getattr(self, "p"+str(i)) for i in range(nphases)]
- for p in self.phases:
+ self.phases = []
+ for p in range(nphases):
+ p = Record(phase_description(addressbits, bankbits, nranks, databits))
+ self.phases += [p]
p.cas_n.reset = 1
p.cs_n.reset = (2**nranks-1)
p.ras_n.reset = 1
p.we_n.reset = 1
p.act_n.reset = 1
- # Returns pairs (DFI-mandated signal name, Migen signal object)
- def get_standard_names(self, m2s=True, s2m=True):
- r = []
- add_suffix = len(self.phases) > 1
- for n, phase in enumerate(self.phases):
- for field, size, direction in phase.layout:
- if (m2s and direction == DIR_FANOUT) or (s2m and direction == DIR_FANIN):
- if add_suffix:
- if direction == DIR_FANOUT:
- suffix = "_p" + str(n)
- else:
- suffix = "_w" + str(n)
- else:
- suffix = ""
- r.append(("dfi_" + field + suffix, getattr(phase, field)))
- return r
-
-
-class Interconnect(Elaboratable):
- def __init__(self, master, slave):
- self._master = master
- self._slave = slave
-
- def elaborate(self, platform):
- m = Module()
- m.d.comb += self._master.connect(self._slave)
- return m
-
-
-class DDR4DFIMux(Elaboratable):
- def __init__(self, dfi_i, dfi_o):
- self.dfi_i = dfi_i
- self.dfi_o = dfi_o
-
- def elaborate(self, platform):
- m = Module()
-
- dfi_i = self.dfi_i
- dfi_o = self.dfi_o
+ def connect(self, target):
+ if not isinstance(target, Interface):
+ raise TypeError("Target must be an instance of Interface, not {!r}"
+ .format(target))
- for i in range(len(dfi_i.phases)):
- p_i = dfi_i.phases[i]
- p_o = dfi_o.phases[i]
- m.d.comb += p_i.connect(p_o)
- with m.If(~p_i.ras_n & p_i.cas_n & p_i.we_n):
- m.d.comb += [
- p_o.act_n.eq(0),
- p_o.we_n.eq(p_i.address[14]),
- p_o.cas_n.eq(p_i.address[15]),
- p_o.ras_n.eq(p_i.address[16]),
- ]
- with m.Else():
- m.d.comb += p_o.act_n.eq(1)
+ ret = []
+ for i in range(min(len(self.phases), len(target.phases))):
+ ret += [self.phases[i].connect(target.phases[i])]
- return m
+ return ret
# This file is Copyright (c) 2019 David Shah <dave@ds0.me>
# This file is Copyright (c) 2019-2020 Florent Kermarrec <florent@enjoy-digital.fr>
+# This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
# License: BSD
# 1:2 frequency-ratio DDR3 PHY for Lattice's ECP5
import math
-# from litex.soc.interconnect.csr import *
-
from nmigen import *
from nmigen.lib.cdc import FFSynchronizer
from nmigen.utils import log2_int
import gram.stream as stream
from gram.common import *
-from gram.phy.dfi import *
+from gram.phy.dfi import Interface
from gram.compat import Timeline
# Lattice ECP5 DDR PHY Initialization --------------------------------------------------------------
self.bus = self._bridge.bus
self.irq = self._bridge.irq
+ addressbits = len(self.pads.a.o)
+ bankbits = len(self.pads.ba.o)
+ nranks = 1 if not hasattr(self.pads, "cs_n") else len(self.pads.cs_n)
+ databits = len(self.pads.dq.oe)
+ self.dfi = Interface(addressbits, bankbits, nranks, 4*databits, 4)
+
def elaborate(self, platform):
m = Module()
- memtype = "DDR3"
tck = 2/(2*2*self._sys_clk_freq)
+ nphases = 2
+ databits = len(self.pads.dq.oe)
+ nranks = 1 if not hasattr(self.pads, "cs_n") else len(self.pads.cs_n)
addressbits = len(self.pads.a.o)
bankbits = len(self.pads.ba.o)
- nranks = 1 if not hasattr(self.pads, "cs_n") else len(self.pads.cs_n)
- databits = len(self.pads.dq.oe)
- nphases = 2
# Init -------------------------------------------------------------------------------------
m.submodules.init = DomainRenamer("init")(ECP5DDRPHYInit("sys2x"))
# Parameters -------------------------------------------------------------------------------
- cl, cwl = get_cl_cw(memtype, tck)
+ cl, cwl = get_cl_cw("DDR3", tck)
cl_sys_latency = get_sys_latency(nphases, cl)
cwl_sys_latency = get_sys_latency(nphases, cwl)
wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl)
self.settings = PhySettings(
phytype = "ECP5DDRPHY",
- memtype = memtype,
+ memtype = "DDR3",
databits = databits,
dfi_databits = 4*databits,
nranks = nranks,
)
# DFI Interface ----------------------------------------------------------------------------
- self.dfi = dfi = Interface(addressbits, bankbits, nranks, 4*databits, 4)
+ dfi = self.dfi
# # #