phy/model: small cleanup and add TODOs

This commit is contained in:
Florent Kermarrec 2020-01-14 11:17:23 +01:00
parent c07f4a1f1b
commit 7d13136cdb
1 changed files with 58 additions and 40 deletions

View File

@ -1,10 +1,13 @@
# This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr> # This file is Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD # License: BSD
# SDRAM simulation PHY at DFI level # SDRAM simulation PHY at DFI level tested with SDR/DDR/DDR2/LPDDR/DDR3
# tested with SDR/DDR/DDR2/LPDDR/DDR3
# TODO: # TODO:
# - add $display support to LiteX gen and manage timing violations? # - test/add DDR4 support.
# - add init/dump capabilities.
# - add multirank support.
# - add bandwidth/efficiency measurements.
# - add timings checks.
from migen import * from migen import *
@ -13,8 +16,9 @@ from litedram.phy.dfi import *
from functools import reduce from functools import reduce
from operator import or_ from operator import or_
# Bank Model ---------------------------------------------------------------------------------------
class Bank(Module): class BankModel(Module):
def __init__(self, data_width, nrows, ncols, burst_length, we_granularity): def __init__(self, data_width, nrows, ncols, burst_length, we_granularity):
self.activate = Signal() self.activate = Signal()
self.activate_row = Signal(max=nrows) self.activate_row = Signal(max=nrows)
@ -42,10 +46,11 @@ class Bank(Module):
row.eq(self.activate_row) row.eq(self.activate_row)
) )
self.specials.mem = mem = Memory(data_width, nrows*ncols//burst_length) mem = Memory(data_width, nrows*ncols//burst_length)
self.specials.write_port = write_port = mem.get_port(write_capable=True, write_port = mem.get_port(write_capable=True, we_granularity=we_granularity)
we_granularity=we_granularity) read_port = mem.get_port(async_read=True)
self.specials.read_port = read_port = mem.get_port(async_read=True) self.specials += mem, read_port, write_port
self.comb += [ self.comb += [
If(active, If(active,
write_port.adr.eq(row*ncols | self.write_col), write_port.adr.eq(row*ncols | self.write_col),
@ -62,8 +67,9 @@ class Bank(Module):
) )
] ]
# DFI Phase Model ----------------------------------------------------------------------------------
class DFIPhase(Module): class DFIPhaseModel(Module):
def __init__(self, dfi, n): def __init__(self, dfi, n):
phase = getattr(dfi, "p"+str(n)) phase = getattr(dfi, "p"+str(n))
@ -94,44 +100,56 @@ class DFIPhase(Module):
) )
] ]
# SDRAM PHY Model ----------------------------------------------------------------------------------
class SDRAMPHYModel(Module): class SDRAMPHYModel(Module):
def __init__(self, module, settings, we_granularity=8): def __init__(self, module, settings, we_granularity=8):
if settings.memtype in ["SDR"]: # Parameters
burst_length = settings.nphases*1 # command multiplication*SDR burst_length = {
elif settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]: "SDR": 1,
burst_length = settings.nphases*2 # command multiplication*DDR "DDR": 2,
"LPDDR": 2,
"DDR2": 2,
"DDR3": 2,
}[settings.memtype]
addressbits = module.geom_settings.addressbits addressbits = module.geom_settings.addressbits
bankbits = module.geom_settings.bankbits bankbits = module.geom_settings.bankbits
rowbits = module.geom_settings.rowbits rowbits = module.geom_settings.rowbits
colbits = module.geom_settings.colbits colbits = module.geom_settings.colbits
self.settings = settings self.settings = settings
self.module = module self.module = module
self.dfi = Interface(addressbits, bankbits, self.settings.nranks, self.settings.dfi_databits, self.settings.nphases) # DFI Interface
self.dfi = Interface(
addressbits = addressbits,
bankbits = bankbits,
nranks = self.settings.nranks,
databits = self.settings.dfi_databits,
nphases = self.settings.nphases
)
# # # # # #
nbanks = 2**bankbits nbanks = 2**bankbits
nrows = 2**rowbits nrows = 2**rowbits
ncols = 2**colbits ncols = 2**colbits
data_width = self.settings.dfi_databits*self.settings.nphases data_width = self.settings.dfi_databits*self.settings.nphases
# DFI phases # DFI phases -------------------------------------------------------------------------------
phases = [DFIPhase(self.dfi, n) for n in range(self.settings.nphases)] phases = [DFIPhaseModel(self.dfi, n) for n in range(self.settings.nphases)]
self.submodules += phases self.submodules += phases
# banks # Banks ------------------------------------------------------------------------------------
banks = [Bank(data_width, nrows, ncols, burst_length, we_granularity) for i in range(nbanks)] banks = [BankModel(data_width, nrows, ncols, burst_length, we_granularity) for i in range(nbanks)]
self.submodules += banks self.submodules += banks
# connect DFI phases to banks (cmds, write datapath) # Connect DFI phases to Banks (CMDs, Write datapath) ---------------------------------------
for nb, bank in enumerate(banks): for nb, bank in enumerate(banks):
# bank activate # Bank activate
activates = Signal(len(phases)) activates = Signal(len(phases))
cases = {} cases = {}
for np, phase in enumerate(phases): for np, phase in enumerate(phases):
self.comb += activates[np].eq(phase.activate) self.comb += activates[np].eq(phase.activate)
cases[2**np] = [ cases[2**np] = [
@ -140,9 +158,9 @@ class SDRAMPHYModel(Module):
] ]
self.comb += Case(activates, cases) self.comb += Case(activates, cases)
# bank precharge # Bank precharge
precharges = Signal(len(phases)) precharges = Signal(len(phases))
cases = {} cases = {}
for np, phase in enumerate(phases): for np, phase in enumerate(phases):
self.comb += precharges[np].eq(phase.precharge) self.comb += precharges[np].eq(phase.precharge)
cases[2**np] = [ cases[2**np] = [
@ -150,9 +168,9 @@ class SDRAMPHYModel(Module):
] ]
self.comb += Case(precharges, cases) self.comb += Case(precharges, cases)
# bank writes # Bank writes
writes = Signal(len(phases)) writes = Signal(len(phases))
cases = {} cases = {}
for np, phase in enumerate(phases): for np, phase in enumerate(phases):
self.comb += writes[np].eq(phase.write) self.comb += writes[np].eq(phase.write)
cases[2**np] = [ cases[2**np] = [
@ -165,7 +183,7 @@ class SDRAMPHYModel(Module):
bank.write_mask.eq(Cat(*[phase.wrdata_mask for phase in phases])) bank.write_mask.eq(Cat(*[phase.wrdata_mask for phase in phases]))
] ]
# bank reads # Bank reads
reads = Signal(len(phases)) reads = Signal(len(phases))
cases = {} cases = {}
for np, phase in enumerate(phases): for np, phase in enumerate(phases):
@ -176,23 +194,23 @@ class SDRAMPHYModel(Module):
] ]
self.comb += Case(reads, cases) self.comb += Case(reads, cases)
# connect banks to DFI phases (cmds, read datapath) # Connect Banks to DFI phases (CMDs, Read datapath) ----------------------------------------
banks_read = Signal() banks_read = Signal()
banks_read_data = Signal(data_width) banks_read_data = Signal(data_width)
self.comb += [ self.comb += [
banks_read.eq(reduce(or_, [bank.read for bank in banks])), banks_read.eq(reduce(or_, [bank.read for bank in banks])),
banks_read_data.eq(reduce(or_, [bank.read_data for bank in banks])) banks_read_data.eq(reduce(or_, [bank.read_data for bank in banks]))
] ]
# simulate read latency # Simulate read latency --------------------------------------------------------------------
for i in range(self.settings.read_latency): for i in range(self.settings.read_latency):
new_banks_read = Signal() new_banks_read = Signal()
new_banks_read_data = Signal(data_width) new_banks_read_data = Signal(data_width)
self.sync += [ self.sync += [
new_banks_read.eq(banks_read), new_banks_read.eq(banks_read),
new_banks_read_data.eq(banks_read_data) new_banks_read_data.eq(banks_read_data)
] ]
banks_read = new_banks_read banks_read = new_banks_read
banks_read_data = new_banks_read_data banks_read_data = new_banks_read_data
self.comb += [ self.comb += [