commit
412e9a5c51
|
@ -72,7 +72,8 @@ def get_dram_ios(core_config):
|
|||
Subsignal("clk_p", Pins("X")),
|
||||
Subsignal("clk_n", Pins("X")),
|
||||
Subsignal("cke", Pins("X")),
|
||||
Subsignal("odt", Pins("X")),
|
||||
Subsignal("odt", Pins(
|
||||
"X "*core_config["sdram_rank_nb"])),
|
||||
Subsignal("reset_n", Pins("X"))
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,12 +6,13 @@ bankbits_max = 3
|
|||
|
||||
|
||||
class PhySettings:
|
||||
def __init__(self, memtype, dfi_databits,
|
||||
def __init__(self, memtype, nranks, dfi_databits,
|
||||
nphases,
|
||||
rdphase, wrphase,
|
||||
rdcmdphase, wrcmdphase,
|
||||
cl, read_latency, write_latency, cwl=None):
|
||||
self.memtype = memtype
|
||||
self.nranks = nranks
|
||||
self.dfi_databits = dfi_databits
|
||||
|
||||
self.nphases = nphases
|
||||
|
@ -79,9 +80,11 @@ def data_layout(data_width):
|
|||
|
||||
class LiteDRAMInterface(Record):
|
||||
def __init__(self, address_align, settings):
|
||||
self.address_width = settings.geom.rowbits + settings.geom.colbits - address_align
|
||||
rankbits = log2_int(settings.phy.nranks)
|
||||
self.address_width = settings.geom.rowbits + settings.geom.colbits + rankbits - address_align
|
||||
self.data_width = settings.phy.dfi_databits*settings.phy.nphases
|
||||
self.nbanks = 2**settings.geom.bankbits
|
||||
self.nbanks = settings.phy.nranks*(2**settings.geom.bankbits)
|
||||
self.nranks = settings.phy.nranks
|
||||
self.settings = settings
|
||||
|
||||
layout = [("bank"+str(i), cmd_layout(self.address_width)) for i in range(self.nbanks)]
|
||||
|
|
|
@ -27,14 +27,14 @@ class _AddressSlicer:
|
|||
|
||||
|
||||
class BankMachine(Module):
|
||||
def __init__(self, n, aw, address_align, settings):
|
||||
def __init__(self, n, aw, address_align, nranks, settings):
|
||||
self.req = req = Record(cmd_layout(aw))
|
||||
self.refresh_req = Signal()
|
||||
self.refresh_gnt = Signal()
|
||||
self.ras_allowed = ras_allowed = Signal()
|
||||
self.cas_allowed = cas_allowed = Signal()
|
||||
a = settings.geom.addressbits
|
||||
ba = settings.geom.bankbits
|
||||
ba = settings.geom.bankbits + log2_int(nranks)
|
||||
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba))
|
||||
|
||||
# # #
|
||||
|
|
|
@ -40,8 +40,10 @@ class LiteDRAMController(Module):
|
|||
}
|
||||
address_align = log2_int(burst_lengths[phy_settings.memtype])
|
||||
|
||||
self.dfi = dfi.Interface(geom_settings.addressbits,
|
||||
self.dfi = dfi.Interface(
|
||||
geom_settings.addressbits,
|
||||
geom_settings.bankbits,
|
||||
phy_settings.nranks,
|
||||
phy_settings.dfi_databits,
|
||||
phy_settings.nphases)
|
||||
|
||||
|
@ -54,10 +56,11 @@ class LiteDRAMController(Module):
|
|||
self.submodules.refresher = Refresher(self.settings)
|
||||
|
||||
bank_machines = []
|
||||
for i in range(2**geom_settings.bankbits):
|
||||
for i in range(phy_settings.nranks*(2**geom_settings.bankbits)):
|
||||
bank_machine = BankMachine(i,
|
||||
self.interface.address_width,
|
||||
address_align,
|
||||
phy_settings.nranks,
|
||||
settings)
|
||||
bank_machines.append(bank_machine)
|
||||
self.submodules += bank_machine
|
||||
|
|
|
@ -3,6 +3,7 @@ from operator import add, or_, and_
|
|||
|
||||
from migen import *
|
||||
from migen.genlib.roundrobin import *
|
||||
from migen.genlib.coding import Decoder
|
||||
|
||||
from litex.soc.interconnect import stream
|
||||
from litex.soc.interconnect.csr import AutoCSR
|
||||
|
@ -93,21 +94,31 @@ class _Steerer(Module):
|
|||
return cmd.valid & getattr(cmd, attr)
|
||||
|
||||
for phase, sel in zip(dfi.phases, self.sel):
|
||||
self.comb += [
|
||||
phase.cke.eq(1),
|
||||
phase.cs_n.eq(0)
|
||||
]
|
||||
if hasattr(phase, "odt"):
|
||||
self.comb += phase.odt.eq(1)
|
||||
self.comb += phase.cke.eq(1)
|
||||
if hasattr(phase, "reset_n"):
|
||||
self.comb += phase.reset_n.eq(1)
|
||||
|
||||
nranks = len(phase.cs_n)
|
||||
rankbits = log2_int(nranks)
|
||||
if hasattr(phase, "odt"):
|
||||
self.comb += phase.odt.eq(2**rankbits - 1) # FIXME: dynamic drive for multi-rank
|
||||
if rankbits:
|
||||
rank_decoder = Decoder(rankbits)
|
||||
self.submodules += rank_decoder
|
||||
self.comb += rank_decoder.i.eq((Array(cmd.ba[-rankbits:] for cmd in commands)[sel]))
|
||||
self.sync += phase.cs_n.eq(~rank_decoder.o)
|
||||
self.sync += phase.bank.eq(Array(cmd.ba[:-rankbits] for cmd in commands)[sel])
|
||||
else:
|
||||
self.sync += phase.cs_n.eq(0)
|
||||
self.sync += phase.bank.eq(Array(cmd.ba[:] for cmd in commands)[sel])
|
||||
|
||||
self.sync += [
|
||||
phase.address.eq(Array(cmd.a for cmd in commands)[sel]),
|
||||
phase.bank.eq(Array(cmd.ba for cmd in commands)[sel]),
|
||||
phase.cas_n.eq(~Array(cmd.cas for cmd in commands)[sel]),
|
||||
phase.ras_n.eq(~Array(cmd.ras for cmd in commands)[sel]),
|
||||
phase.we_n.eq(~Array(cmd.we for cmd in commands)[sel])
|
||||
]
|
||||
|
||||
rddata_ens = Array(valid_and(cmd, "is_read") for cmd in commands)
|
||||
wrdata_ens = Array(valid_and(cmd, "is_write") for cmd in commands)
|
||||
self.sync += [
|
||||
|
@ -190,7 +201,7 @@ class Multiplexer(Module, AutoCSR):
|
|||
|
||||
# Command steering
|
||||
nop = Record(cmd_request_layout(settings.geom.addressbits,
|
||||
settings.geom.bankbits))
|
||||
log2_int(len(bank_machines))))
|
||||
# nop must be 1st
|
||||
commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd]
|
||||
(STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4)
|
||||
|
|
|
@ -9,8 +9,8 @@ from litedram.core.multiplexer import *
|
|||
class Refresher(Module):
|
||||
def __init__(self, settings):
|
||||
# 1st command 1 cycle after assertion of ready
|
||||
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(settings.geom.addressbits,
|
||||
settings.geom.bankbits))
|
||||
self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(
|
||||
settings.geom.addressbits, settings.geom.bankbits + log2_int(settings.phy.nranks)))
|
||||
|
||||
# # #
|
||||
|
||||
|
|
|
@ -17,12 +17,12 @@ class PhaseInjector(Module, AutoCSR):
|
|||
|
||||
self.comb += [
|
||||
If(self._command_issue.re,
|
||||
phase.cs_n.eq(~self._command.storage[0]),
|
||||
phase.cs_n.eq(Replicate(~self._command.storage[0], len(phase.cs_n))),
|
||||
phase.we_n.eq(~self._command.storage[1]),
|
||||
phase.cas_n.eq(~self._command.storage[2]),
|
||||
phase.ras_n.eq(~self._command.storage[3])
|
||||
).Else(
|
||||
phase.cs_n.eq(1),
|
||||
phase.cs_n.eq(Replicate(1, len(phase.cs_n))),
|
||||
phase.we_n.eq(1),
|
||||
phase.cas_n.eq(1),
|
||||
phase.ras_n.eq(1)
|
||||
|
@ -38,10 +38,10 @@ class PhaseInjector(Module, AutoCSR):
|
|||
|
||||
|
||||
class DFIInjector(Module, AutoCSR):
|
||||
def __init__(self, addressbits, bankbits, databits, nphases=1):
|
||||
inti = dfi.Interface(addressbits, bankbits, databits, nphases)
|
||||
self.slave = dfi.Interface(addressbits, bankbits, databits, nphases)
|
||||
self.master = dfi.Interface(addressbits, bankbits, databits, nphases)
|
||||
def __init__(self, addressbits, bankbits, nranks, databits, nphases=1):
|
||||
inti = dfi.Interface(addressbits, bankbits, nranks, databits, nphases)
|
||||
self.slave = dfi.Interface(addressbits, bankbits, nranks, databits, nphases)
|
||||
self.master = dfi.Interface(addressbits, bankbits, nranks, databits, nphases)
|
||||
|
||||
self._control = CSRStorage(4) # sel, cke, odt, reset_n
|
||||
|
||||
|
|
|
@ -17,11 +17,13 @@ class LiteDRAMCrossbar(Module):
|
|||
|
||||
self.rca_bits = controller.address_width
|
||||
self.nbanks = controller.nbanks
|
||||
self.nranks = controller.nranks
|
||||
self.cmd_buffer_depth = controller.settings.cmd_buffer_depth
|
||||
self.read_latency = controller.settings.phy.read_latency + 1
|
||||
self.write_latency = controller.settings.phy.write_latency + 1
|
||||
|
||||
self.bank_bits = log2_int(self.nbanks, False)
|
||||
self.rank_bits = log2_int(self.nranks, False)
|
||||
|
||||
self.masters = []
|
||||
|
||||
|
@ -42,7 +44,7 @@ class LiteDRAMCrossbar(Module):
|
|||
data_width = self.controller.data_width
|
||||
|
||||
# crossbar port
|
||||
port = LiteDRAMNativePort(mode, self.rca_bits + self.bank_bits, self.controller.data_width, "sys", len(self.masters), with_reordering)
|
||||
port = LiteDRAMNativePort(mode, self.rca_bits + self.bank_bits - self.rank_bits, self.controller.data_width, "sys", len(self.masters), with_reordering)
|
||||
self.masters.append(port)
|
||||
|
||||
# clock domain crossing
|
||||
|
@ -177,8 +179,8 @@ class LiteDRAMCrossbar(Module):
|
|||
self.comb += master.wdata.bank.eq(wbank)
|
||||
|
||||
def split_master_addresses(self, bank_bits, rca_bits, cba_shift):
|
||||
m_ba = [] # bank address
|
||||
m_rca = [] # row and column address
|
||||
m_ba = [] # bank address
|
||||
m_rca = [] # row and column address
|
||||
for master in self.masters:
|
||||
cba = Signal(self.bank_bits)
|
||||
rca = Signal(self.rca_bits)
|
||||
|
|
|
@ -2,12 +2,12 @@ from migen import *
|
|||
from migen.genlib.record import *
|
||||
|
||||
|
||||
def phase_cmd_description(addressbits, bankbits):
|
||||
def phase_cmd_description(addressbits, bankbits, nranks):
|
||||
return [
|
||||
("address", addressbits, DIR_M_TO_S),
|
||||
("bank", bankbits, DIR_M_TO_S),
|
||||
("cas_n", 1, DIR_M_TO_S),
|
||||
("cs_n", 1, DIR_M_TO_S),
|
||||
("cs_n", nranks, DIR_M_TO_S),
|
||||
("ras_n", 1, DIR_M_TO_S),
|
||||
("we_n", 1, DIR_M_TO_S),
|
||||
("cke", 1, DIR_M_TO_S),
|
||||
|
@ -32,21 +32,21 @@ def phase_rddata_description(databits):
|
|||
]
|
||||
|
||||
|
||||
def phase_description(addressbits, bankbits, databits):
|
||||
r = phase_cmd_description(addressbits, bankbits)
|
||||
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):
|
||||
def __init__(self, addressbits, bankbits, databits, nphases=1):
|
||||
layout = [("p"+str(i), phase_description(addressbits, bankbits, databits)) for i in range(nphases)]
|
||||
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:
|
||||
p.cas_n.reset = 1
|
||||
p.cs_n.reset = 1
|
||||
p.cs_n.reset = (2**nranks-1)
|
||||
p.ras_n.reset = 1
|
||||
p.we_n.reset = 1
|
||||
|
||||
|
|
|
@ -47,9 +47,12 @@ class S7DDRPHY(Module, AutoCSR):
|
|||
tck = 2/(2*nphases*sys_clk_freq)
|
||||
addressbits = len(pads.a)
|
||||
bankbits = len(pads.ba)
|
||||
if hasattr(pads, "cs_n"):
|
||||
nranks = len(pads.cs_n)
|
||||
databits = len(pads.dq)
|
||||
nphases = nphases
|
||||
|
||||
|
||||
iodelay_tap_average = {
|
||||
200e6: 78e-12,
|
||||
300e6: 52e-12,
|
||||
|
@ -86,6 +89,7 @@ class S7DDRPHY(Module, AutoCSR):
|
|||
self.settings = PhySettings(
|
||||
memtype=memtype,
|
||||
dfi_databits=2*databits,
|
||||
nranks=nranks,
|
||||
nphases=nphases,
|
||||
rdphase=rdphase,
|
||||
wrphase=wrphase,
|
||||
|
@ -97,7 +101,7 @@ class S7DDRPHY(Module, AutoCSR):
|
|||
write_latency=cwl_sys_latency
|
||||
)
|
||||
|
||||
self.dfi = Interface(addressbits, bankbits, 2*databits, 4)
|
||||
self.dfi = Interface(addressbits, bankbits, nranks, 2*databits, 4)
|
||||
|
||||
# # #
|
||||
|
||||
|
@ -158,11 +162,26 @@ class S7DDRPHY(Module, AutoCSR):
|
|||
i_D5=self.dfi.phases[2].bank[i], i_D6=self.dfi.phases[2].bank[i],
|
||||
i_D7=self.dfi.phases[3].bank[i], i_D8=self.dfi.phases[3].bank[i]
|
||||
)
|
||||
if hasattr(pads, "cs_n"):
|
||||
for i in range(nranks):
|
||||
self.specials += \
|
||||
Instance("OSERDESE2",
|
||||
p_DATA_WIDTH=2*nphases, p_TRISTATE_WIDTH=1,
|
||||
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
|
||||
p_SERDES_MODE="MASTER",
|
||||
|
||||
o_OQ=pads.cs_n[i],
|
||||
i_OCE=1,
|
||||
i_RST=ResetSignal(),
|
||||
i_CLK=ClockSignal(ddr_clk), i_CLKDIV=ClockSignal(),
|
||||
i_D1=self.dfi.phases[0].cs_n[i], i_D2=self.dfi.phases[0].cs_n[i],
|
||||
i_D3=self.dfi.phases[1].cs_n[i], i_D4=self.dfi.phases[1].cs_n[i],
|
||||
i_D5=self.dfi.phases[2].cs_n[i], i_D6=self.dfi.phases[2].cs_n[i],
|
||||
i_D7=self.dfi.phases[3].cs_n[i], i_D8=self.dfi.phases[3].cs_n[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:
|
||||
self.specials += \
|
||||
Instance("OSERDESE2",
|
||||
|
|
Loading…
Reference in New Issue