initial multirank support (nbankmachines = nranks * (2**bankbits))

To see:
Configure the 2 ranks. (init commands, leveling)
How to drive ODT?
Pipeline stall while switching ranks?
This commit is contained in:
Florent Kermarrec 2018-09-07 17:59:33 +02:00
parent cc481be81f
commit b1c2739305
9 changed files with 72 additions and 33 deletions

View File

@ -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,12 @@ 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
print(self.address_width)
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)]

View File

@ -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))
# # #

View File

@ -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

View File

@ -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)
]
self.comb += phase.cke.eq(1)
if hasattr(phase, "odt"):
self.comb += phase.odt.eq(1)
self.comb += phase.odt.eq(1) # FIXME: constant for multi-rank?
if hasattr(phase, "reset_n"):
self.comb += phase.reset_n.eq(1)
nranks = len(phase.cs_n)
rankbits = log2_int(nranks)
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)

View File

@ -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)))
# # #

View File

@ -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, nranks, bankbits, databits, nphases)
self.master = dfi.Interface(addressbits, nranks, bankbits, databits, nphases)
self._control = CSRStorage(4) # sel, cke, odt, reset_n

View File

@ -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)

View File

@ -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

View File

@ -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.ba[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",