lpddr5: sim: fix non-syncronized pipe in simulation

Signed-off-by: Alessandro Comodi <acomodi@antmicro.com>
This commit is contained in:
Alessandro Comodi 2021-09-15 12:38:54 +02:00
parent 50ba27eb4c
commit d7e2c82795
2 changed files with 47 additions and 10 deletions

View File

@ -18,6 +18,8 @@ from litedram.common import TappedDelayLine
from litedram.phy.utils import edge, delayed
from litedram.phy.sim_utils import SimLogger, Timing, PulseTiming, log_level_getter
from litedram.phy.lpddr5.basephy import get_frange
CMD_INFO_LAYOUT = [
("we", 1),
@ -33,7 +35,7 @@ gtkw_dbg = {}
class LPDDR5Sim(Module, AutoCSR):
"""LPDDR5 DRAM simulation
"""
def __init__(self, pads, *, ck_freq, log_level, logger_kwargs, check_timings=True):
def __init__(self, pads, *, ck_freq, wck_ck_ratio, log_level, logger_kwargs, check_timings=True):
log_level = log_level_getter(log_level)
self.clock_domains.cd_ck = ClockDomain(reset_less=True)
@ -61,6 +63,8 @@ class LPDDR5Sim(Module, AutoCSR):
data = DataSim(pads, cmd_info,
latency_ready = cmd.data_timer.ready_p,
mode_regs = cmd.mode_regs,
ck_freq = ck_freq,
wck_ck_ratio = wck_ck_ratio,
logger_kwargs = logger_kwargs,
log_level = log_level
)
@ -222,6 +226,7 @@ class ModeRegisters(Module, AutoCSR):
],
)
class Sync(list):
# Helper for combining comb and sync
def __init__(self, arg):
@ -701,7 +706,7 @@ class CommandsSim(Module, AutoCSR):
class DataSim(Module, AutoCSR):
def __init__(self, pads, cmd_info, latency_ready, mode_regs, *, log_level, logger_kwargs, nrows=32768, ncols=1024, nbanks=16):
def __init__(self, pads, cmd_info, latency_ready, mode_regs, ck_freq, wck_ck_ratio, *, log_level, logger_kwargs, nrows=32768, ncols=1024, nbanks=16):
self.submodules.log = SimLogger(log_level=log_level("data"), **logger_kwargs)
# CommandsSim produces the data required for handling a data command via cmd_info endpoint.
@ -709,17 +714,48 @@ class DataSim(Module, AutoCSR):
# and store the information in a FIFO, so that it is possible to pipeline data commands.
self.submodules.cmd_buf = stream.PipeValid(CMD_INFO_LAYOUT)
gtkw_dbg["cmd_buf"] = self.cmd_buf
# The CommandsSim data handling generated command is clocked under the system clock domain.
# Instead, the DataSim is clocked in the wck clock domain.
# Given that, with a dynamic wck regime, wck needs to get through a preamble phase where it
# is not active for a certain amount of clock cycles, the command buffer pipeline may not
# be able to see changes in the data commands generated by CommandSim.
#
# The following logic verifies whether a delay needs to be added and adds it accordingly to
# the data command, so that the pipe stream can intercept the various commands from the ck
# domain correctly.
twck = 1 / (ck_freq * wck_ck_ratio)
frange = get_frange(twck, wck_ck_ratio).for_set(wl_set="A", rl_set=0)
taps = max(1, max(frange.t_wckenl_wr, frange.t_wckenl_rd) + frange.t_wckpre_static) - 1
def delay_cmd_info(signals):
for signal in signals:
tapped_delay = ClockDomainsRenamer("ck")(TappedDelayLine(getattr(cmd_info, signal), ntaps=taps))
setattr(self.submodules, f"{signal}_tap", tapped_delay)
self.comb += [
getattr(self.cmd_buf.sink, signal).eq(reduce(or_, getattr(self, f"{signal}_tap").taps[0:taps])),
]
if taps > 0:
delay_cmd_info([tup[0] for tup in CMD_INFO_LAYOUT] + ["valid", "ready", "first", "last"])
else:
self.comb += [
cmd_info.connect(self.cmd_buf.sink, omit={"ready", "valid"}),
# to latch a command only once we use an edge here, which we can do as there is no way
# for 2 valid commands cycle-by-cycle
self.cmd_buf.sink.valid.eq(edge(self, cmd_info.valid)),
# if for some reason buffer hasn't been cleared, then we have an error
If(self.cmd_buf.sink.valid & ~self.cmd_buf.sink.ready,
self.log.error("Simulator internal error: CMD-to-DATA overflow")
),
]
self.comb += [
cmd_info.connect(self.cmd_buf.sink, omit={"ready", "valid"}),
cmd_info.ready.eq(1),
# to latch a command only once we use an edge here, which we can do as there is no way
# for 2 valid commands cycle-by-cycle
self.cmd_buf.sink.valid.eq(edge(self, cmd_info.valid)),
# if for some reason buffer hasn't been cleared, then we have an error
If(self.cmd_buf.sink.valid & ~self.cmd_buf.sink.ready,
self.log.error("Simulator internal error: CMD-to-DATA overflow")
),
]
cmd = self.cmd_buf.source
# DRAM Memory storage

View File

@ -168,6 +168,7 @@ class SimSoC(SoCCore):
self.submodules.lpddr5sim = LPDDR5Sim(
pads = self.ddrphy.pads,
ck_freq = dfi_converter_ratio*sys_clk_freq,
wck_ck_ratio = wck_ck_ratio,
check_timings = not disable_delay,
log_level = log_level,
logger_kwargs = dict(