phy/model: review/cleanup DFITimingsChecker.

This commit is contained in:
Florent Kermarrec 2020-04-13 18:10:07 +02:00
parent 64c2be5d63
commit 962dcd7d9a
1 changed files with 71 additions and 34 deletions

View File

@ -123,13 +123,15 @@ class SDRAMCMD:
self.enc = enc
self.idx = idx
class TimingRule:
def __init__(self, prev: str, curr: str, delay: int):
self.name = prev+"->"+curr
self.name = prev + "->" + curr
self.prev = prev
self.curr = curr
self.delay = delay
class DFITimingsChecker(Module):
CMDS = [
# Name, cs & ras & cas & we value
@ -176,7 +178,6 @@ class DFITimingsChecker(Module):
def add_rule(self, prev, curr, delay):
if not isinstance(delay, int):
delay = self.timings[delay]
self.rules.append(TimingRule(prev, curr, delay))
def add_rules(self):
@ -186,14 +187,12 @@ class DFITimingsChecker(Module):
# Convert ns to ps
def ns_to_ps(self, val):
return int(val * 1000)
return int(val * 1e3)
def ck_ns_to_ps(self, val, tck):
c, t = val
c = 0 if c is None else c * tck
t = 0 if t is None else t
return self.ns_to_ps(max(c, t))
def prepare_timings(self, timings, refresh_mode, memtype):
@ -219,36 +218,35 @@ class DFITimingsChecker(Module):
new_timings["tRC"] = new_timings["tRAS"] + new_timings["tRP"]
# adjust timings relative to write burst - tWR & tWTR
# Adjust timings relative to write burst - tWR & tWTR
wrburst = burst_lengths[memtype] if memtype == "SDR" else burst_lengths[memtype] // 2
wrburst = (new_timings["tCK"] * (wrburst-1))
wrburst = (new_timings["tCK"] * (wrburst - 1))
new_timings["tWR"] = new_timings["tWR"] + wrburst
new_timings["tWTR"] = new_timings["tWTR"] + wrburst
self.timings = new_timings
def __init__(self, dfi, nbanks, nphases, timings, refresh_mode, memtype, verbose=False):
ref_limit = {"1x": 9, "2x": 17, "4x": 36}
self.prepare_timings(timings, refresh_mode, memtype)
self.add_cmds()
self.add_rules()
cnt = Signal(64)
self.sync += cnt.eq(cnt+nphases)
self.sync += cnt.eq(cnt + nphases)
phases = [getattr(dfi, "p"+str(n)) for n in range(nphases)]
phases = [getattr(dfi, "p" + str(n)) for n in range(nphases)]
last_cmd_ps = [[Signal.like(cnt) for _ in range(len(self.cmds))] for _ in range(nbanks)]
last_cmd = [Signal(4) for i in range(nbanks)]
last_cmd = [Signal(4) for i in range(nbanks)]
act_ps = Array([Signal().like(cnt) for i in range(4)])
act_ps = Array([Signal().like(cnt) for i in range(4)])
act_curr = Signal(max=4)
ref_issued = Signal(nphases)
for np, phase in enumerate(phases):
ps = Signal().like(cnt)
self.comb += ps.eq((cnt+np)*self.timings["tCK"])
self.comb += ps.eq((cnt + np)*self.timings["tCK"])
state = Signal(4)
self.comb += state.eq(Cat(phase.we_n, phase.cas_n, phase.ras_n, phase.cs_n))
all_banks = Signal()
@ -264,9 +262,15 @@ class DFITimingsChecker(Module):
# Print debug information
if verbose:
for _, cmd in self.cmds.items():
self.sync += If(state == cmd.enc, If(all_banks,
Display("[%016dps] P%0d "+cmd.name, ps, np)).Else(
Display("[%016dps] P%0d B%0d "+cmd.name, ps, np, phase.bank)))
self.sync += [
If(state == cmd.enc,
If(all_banks,
Display("[%016dps] P%0d " + cmd.name, ps, np)
).Else(
Display("[%016dps] P%0d B%0d " + cmd.name, ps, np, phase.bank)
)
)
]
# Bank command monitoring
for i in range(nbanks):
@ -278,9 +282,12 @@ class DFITimingsChecker(Module):
for _, prev in self.cmds.items():
for rule in self.rules:
if rule.prev == prev.name and rule.curr == curr.name:
self.sync += If(cmd_recv & (last_cmd[i] == prev.enc) &
(ps < (last_cmd_ps[i][prev.idx] + rule.delay)),
Display("[%016dps] {} violation on bank %0d".format(rule.name), ps, i))
self.sync += [
If(cmd_recv & (last_cmd[i] == prev.enc) &
(ps < (last_cmd_ps[i][prev.idx] + rule.delay)),
Display("[%016dps] {} violation on bank %0d".format(rule.name), ps, i)
)
]
# Save command timestamp in an array
self.sync += If(cmd_recv, last_cmd_ps[i][curr.idx].eq(ps), last_cmd[i].eq(state))
@ -291,18 +298,24 @@ class DFITimingsChecker(Module):
self.comb += act_next.eq(act_curr+1)
# act_curr points to newest ACT timestamp
self.sync += If(cmd_recv & (ps < (act_ps[act_curr] + self.timings["tRRD"])),
Display("[%016dps] tRRD violation on bank %0d", ps, i))
self.sync += [
If(cmd_recv & (ps < (act_ps[act_curr] + self.timings["tRRD"])),
Display("[%016dps] tRRD violation on bank %0d", ps, i)
)
]
# act_next points to the oldest ACT timestamp
self.sync += If(cmd_recv & (ps < (act_ps[act_next] + self.timings["tFAW"])),
Display("[%016dps] tFAW violation on bank %0d", ps, i))
self.sync += [
If(cmd_recv & (ps < (act_ps[act_next] + self.timings["tFAW"])),
Display("[%016dps] tFAW violation on bank %0d", ps, i)
)
]
# Save ACT timestamp in a circular buffer
self.sync += If(cmd_recv, act_ps[act_next].eq(ps), act_curr.eq(act_next))
# tREFI
ref_ps = Signal().like(cnt)
ref_ps = Signal().like(cnt)
ref_ps_mod = Signal().like(cnt)
ref_ps_diff = Signal(min=-2**63, max=2**63)
curr_diff = Signal().like(ref_ps_diff)
@ -310,31 +323,55 @@ class DFITimingsChecker(Module):
self.comb += curr_diff.eq(ps - (ref_ps + self.timings["tREFI"]))
# Work in 64ms periods
self.sync += If(ref_ps_mod < int(64e9),
ref_ps_mod.eq(ref_ps_mod + nphases * self.timings["tCK"])).Else(ref_ps_mod.eq(0))
self.sync += [
If(ref_ps_mod < int(64e9),
ref_ps_mod.eq(ref_ps_mod + nphases * self.timings["tCK"])
).Else(
ref_ps_mod.eq(0)
)
]
# Update timestamp and difference
self.sync += If(ref_issued != 0, ref_ps.eq(ps), ref_ps_diff.eq(ref_ps_diff - curr_diff))
self.sync += If((ref_ps_mod == 0) & (ref_ps_diff > 0),
Display("[%016dps] tREFI violation (64ms period): %0d", ps, ref_ps_diff))
self.sync += [
If((ref_ps_mod == 0) & (ref_ps_diff > 0),
Display("[%016dps] tREFI violation (64ms period): %0d", ps, ref_ps_diff)
)
]
# Report any refresh periods longer than tREFI
if verbose:
ref_done = Signal()
self.sync += If(ref_issued != 0, ref_done.eq(1),
If(~ref_done, Display("[%016dps] Late refresh", ps)))
self.sync += [
If(ref_issued != 0,
ref_done.eq(1),
If(~ref_done,
Display("[%016dps] Late refresh", ps)
)
)
]
self.sync += If((curr_diff > 0) & ref_done & (ref_issued == 0),
Display("[%016dps] tREFI violation", ps), ref_done.eq(0))
self.sync += [
If((curr_diff > 0) & ref_done & (ref_issued == 0),
Display("[%016dps] tREFI violation", ps),
ref_done.eq(0)
)
]
# There is a maximum delay between refreshes on >=DDR
ref_limit = {"1x": 9, "2x": 17, "4x": 36}
if memtype != "SDR":
refresh_mode = "1x" if refresh_mode is None else refresh_mode
ref_done = Signal()
self.sync += If(ref_issued != 0, ref_done.eq(1))
self.sync += If((ref_issued == 0) & ref_done & (ref_ps > (ps + ref_limit[refresh_mode] * self.timings['tREFI'])),
Display("[%016dps] tREFI violation (too many postponed refreshes)", ps), ref_done.eq(0))
self.sync += [
If((ref_issued == 0) & ref_done &
(ref_ps > (ps + ref_limit[refresh_mode] * self.timings['tREFI'])),
Display("[%016dps] tREFI violation (too many postponed refreshes)", ps),
ref_done.eq(0)
)
]
# SDRAM PHY Model ----------------------------------------------------------------------------------