Merge pull request #231 from antmicro/jboc/module-timings

Allow to pass all module timings in the format (ck, ns)
This commit is contained in:
enjoy-digital 2021-02-02 09:28:30 +01:00 committed by GitHub
commit 83b31f4f71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 53 deletions

View File

@ -294,6 +294,12 @@ def parse_spd_hexdump(filename):
# SDRAMModule -------------------------------------------------------------------------------------- # SDRAMModule --------------------------------------------------------------------------------------
Frac = namedtuple("Frac", ["num", "denom"])
class Timing(namedtuple("Timing", ["ck", "ns"])):
def __add__(self, other):
return Timing(self.ck + other.ck, self.ns + other.ns)
class SDRAMModule: class SDRAMModule:
"""SDRAM module geometry and timings. """SDRAM module geometry and timings.
@ -320,68 +326,82 @@ class SDRAMModule:
if (fine_refresh_mode is None) and (self.memtype == "DDR4"): if (fine_refresh_mode is None) and (self.memtype == "DDR4"):
fine_refresh_mode = "1x" fine_refresh_mode = "1x"
self.timing_settings = TimingSettings( self.timing_settings = TimingSettings(
tRP = self.ns_to_cycles(self.get("tRP")), tRP = self.ck_ns_to_cycles(self.get("tRP")),
tRCD = self.ns_to_cycles(self.get("tRCD")), tRCD = self.ck_ns_to_cycles(self.get("tRCD")),
tWR = self.ns_to_cycles(self.get("tWR")), tWR = self.ck_ns_to_cycles(self.get("tWR")),
tREFI = self.ns_to_cycles(self.get("tREFI", fine_refresh_mode), False), tREFI = self.ck_ns_to_cycles(self.get("tREFI", fine_refresh_mode), margin=False),
tRFC = self.ck_ns_to_cycles(*self.get("tRFC", fine_refresh_mode)), tRFC = self.ck_ns_to_cycles(self.get("tRFC", fine_refresh_mode)),
tWTR = self.ck_ns_to_cycles(*self.get("tWTR")), tWTR = self.ck_ns_to_cycles(self.get("tWTR")),
tFAW = None if self.get("tFAW") is None else self.ck_ns_to_cycles(*self.get("tFAW")), tFAW = None if self.get("tFAW") is None else self.ck_ns_to_cycles(self.get("tFAW")),
tCCD = None if self.get("tCCD") is None else self.ck_ns_to_cycles(*self.get("tCCD")), tCCD = None if self.get("tCCD") is None else self.ck_ns_to_cycles(self.get("tCCD")),
tRRD = None if self.get("tRRD") is None else self.ck_ns_to_cycles(*self.get("tRRD")), tRRD = None if self.get("tRRD") is None else self.ck_ns_to_cycles(self.get("tRRD")),
tRC = None if self.get("tRAS") is None else self.ns_to_cycles(self.get("tRP") + self.get("tRAS")), tRC = None if self.get("tRAS") is None else self.ck_ns_to_cycles(self.get("tRP") + self.get("tRAS")),
tRAS = None if self.get("tRAS") is None else self.ns_to_cycles(self.get("tRAS")), tRAS = None if self.get("tRAS") is None else self.ck_ns_to_cycles(self.get("tRAS")),
tZQCS = None if self.get("tZQCS") is None else self.ck_ns_to_cycles(*self.get("tZQCS")) tZQCS = None if self.get("tZQCS") is None else self.ck_ns_to_cycles(self.get("tZQCS"))
) )
self.timing_settings.fine_refresh_mode = fine_refresh_mode self.timing_settings.fine_refresh_mode = fine_refresh_mode
def get(self, name, key=None): def get(self, name, key=None):
r = None assert name in _speedgrade_timings + _technology_timings, "Unknown name: {}".format(name)
if name in _speedgrade_timings: timing = self.get_timing(name)
if hasattr(self, "speedgrade_timings"): if timing is None:
speedgrade = "default" if self.speedgrade is None else self.speedgrade return None
r = getattr(self.speedgrade_timings[speedgrade], name) if (timing is not None) and (key is not None):
else: timing = timing[key]
name = name + "_" + self.speedgrade if self.speedgrade is not None else name if isinstance(timing, tuple):
try: ck, ns = timing
r = getattr(self, name)
except:
pass
else: else:
if hasattr(self, "technology_timings"): ck, ns = 0, timing
r = getattr(self.technology_timings, name) ck = ck or 0
else: ns = ns or 0
try: return Timing(ck, ns)
r = getattr(self, name)
except: def get_timing(self, name):
pass if name in _speedgrade_timings:
if (r is not None) and (key is not None): return self.get_speedgrade_timing(name)
r = r[key] return self.get_technology_timing(name)
return r
def get_speedgrade_timing(self, name):
if hasattr(self, "speedgrade_timings"):
speedgrade = "default" if self.speedgrade is None else self.speedgrade
return getattr(self.speedgrade_timings[speedgrade], name)
name = name + "_" + self.speedgrade if self.speedgrade is not None else name
try:
return getattr(self, name)
except:
pass
def get_technology_timing(self, name):
if hasattr(self, "technology_timings"):
return getattr(self.technology_timings, name)
else:
try:
return getattr(self, name)
except:
pass
def ns_to_cycles(self, t, margin=True): def ns_to_cycles(self, t, margin=True):
clk_period_ns = 1e9/self.clk_freq clk_period_ns = 1e9/self.clk_freq
if margin: t += self.margin if margin else 0
margins = {
"1:1" : 0,
"1:2" : clk_period_ns/2,
"1:4" : 3*clk_period_ns/4
}
t += margins[self.rate]
return ceil(t/clk_period_ns) return ceil(t/clk_period_ns)
def ck_to_cycles(self, c): def ck_to_cycles(self, c):
d = { return ceil(c/self.rate_frac.denom)
"1:1" : 1,
"1:2" : 2,
"1:4" : 4
}
return ceil(c/d[self.rate])
def ck_ns_to_cycles(self, c, t): def ck_ns_to_cycles(self, timing, **kwargs):
c = 0 if c is None else c return max(self.ck_to_cycles(timing.ck), self.ns_to_cycles(timing.ns, **kwargs))
t = 0 if t is None else t
return max(self.ck_to_cycles(c), self.ns_to_cycles(t)) @property
def rate_frac(self):
num, denom = map(int, self.rate.split(":"))
assert num == 1, "Rate: numerator must be 1: {}".format(self.rate)
return Frac(num, denom)
@property
def margin(self):
clk_period_ns = 1e9 / self.clk_freq
frac = self.rate_frac
return clk_period_ns * (1 - frac.num/frac.denom)
@classmethod @classmethod
def from_spd_data(cls, spd_data, clk_freq, fine_refresh_mode=None): def from_spd_data(cls, spd_data, clk_freq, fine_refresh_mode=None):

View File

@ -212,10 +212,10 @@ class DFITimingsChecker(Module):
if val is None: if val is None:
val = 0 val = 0
elif key in CK_NS: elif key == "tCK":
val = self.ck_ns_to_ps(val, tck)
else:
val = self.ns_to_ps(val) val = self.ns_to_ps(val)
else:
val = self.ck_ns_to_ps(val, tck)
new_timings[key] = val new_timings[key] = val