Merge pull request #201 from antmicro/jboc/spd-read

modules/spd: save SPD data in SDRAMModule
This commit is contained in:
enjoy-digital 2020-06-01 21:16:58 +02:00 committed by GitHub
commit d62fd24c81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 22 deletions

View File

@ -48,46 +48,49 @@ def _twos_complement(value, nbits):
def _word(msb, lsb):
return (msb << 8) | lsb
# most signifficant (upper) / least signifficant (lower) nibble
def _msn(byte):
return _read_field(byte, nbits=4, shift=4)
def _lsn(byte):
return _read_field(byte, nbits=4, shift=0)
class DDR3SPDData:
memtype = "DDR3"
_speedgrades = [800, 1066, 1333, 1600, 1866, 2133]
def __init__(self, spd_data):
# Geometry ---------------------------------------------------------------------------------
self.get_geometry(spd_data)
self.init_timebase(spd_data)
self.get_timings(spd_data)
def get_geometry(self, data):
bankbits = {
0b000: 3,
0b001: 4,
0b010: 5,
0b011: 6,
}[_read_field(spd_data[4], nbits=3, shift=4)]
}[_read_field(data[4], nbits=3, shift=4)]
rowbits = {
0b000: 12,
0b001: 13,
0b010: 14,
0b011: 15,
0b100: 16,
}[_read_field(spd_data[5], nbits=3, shift=3)]
}[_read_field(data[5], nbits=3, shift=3)]
colbits = {
0b000: 9,
0b001: 10,
0b010: 11,
0b011: 12,
}[_read_field(spd_data[5], nbits=3, shift=0)]
}[_read_field(data[5], nbits=3, shift=0)]
self.nbanks = 2**bankbits
self.nrows = 2**rowbits
self.ncols = 2**colbits
# Timings ----------------------------------------------------------------------------------
self.init_timebase(spd_data)
# most signifficant (upper) / least signifficant (lower) nibble
def msn(byte):
return _read_field(byte, nbits=4, shift=4)
def lsn(byte):
return _read_field(byte, nbits=4, shift=0)
def get_timings(self, spd_data):
b = spd_data
tck_min = self.txx_ns(mtb=b[12], ftb=b[34])
taa_min = self.txx_ns(mtb=b[16], ftb=b[35])
@ -95,12 +98,12 @@ class DDR3SPDData:
trcd_min = self.txx_ns(mtb=b[18], ftb=b[36])
trrd_min = self.txx_ns(mtb=b[19])
trp_min = self.txx_ns(mtb=b[20], ftb=b[37])
tras_min = self.txx_ns(mtb=_word(lsn(b[21]), b[22]))
trc_min = self.txx_ns(mtb=_word(msn(b[21]), b[23]), ftb=b[38])
tras_min = self.txx_ns(mtb=_word(_lsn(b[21]), b[22]))
trc_min = self.txx_ns(mtb=_word(_msn(b[21]), b[23]), ftb=b[38])
trfc_min = self.txx_ns(mtb=_word(b[25], b[24]))
twtr_min = self.txx_ns(mtb=b[26])
trtp_min = self.txx_ns(mtb=b[27])
tfaw_min = self.txx_ns(mtb=_word(lsn(b[28]), b[29]))
tfaw_min = self.txx_ns(mtb=_word(_lsn(b[28]), b[29]))
technology_timings = _TechnologyTimings(
tREFI = 64e6/8192, # 64ms/8192ops
@ -142,20 +145,19 @@ class DDR3SPDData:
ftb = _twos_complement(ftb, 8)
return mtb * self.medium_timebase_ns + ftb * self.fine_timebase_ns
@staticmethod
def speedgrade_freq(tck_ns):
@classmethod
def speedgrade_freq(cls, tck_ns):
# Calculate rounded speedgrade frequency from tck_min
freq_mhz = (1 / (tck_ns * 1e-9)) / 1e6
freq_mhz *= 2 # clock rate -> transfer rate (DDR)
speedgrades = [800, 1066, 1333, 1600, 1866, 2133]
for f in speedgrades:
for f in cls._speedgrades:
# Due to limited tck accuracy of 1ps, calculations may yield higher
# frequency than in reality (e.g. for DDR3-1866: tck=1.071 ns ->
# -> f=1867.4 MHz, while real is f=1866.6(6) MHz).
max_error = 2
if abs(freq_mhz - f) < max_error:
return f
raise ValueError("Transfer rate = {:.2f} does not correspond to any DDR3 speedgrade"
raise ValueError("Transfer rate = {:.2f} does not correspond to any speedgrade"
.format(freq_mhz))
def parse_spd_hexdump(filename):
@ -286,6 +288,8 @@ class SDRAMModule:
ncols = spd.ncols
technology_timings = spd.technology_timings
speedgrade_timings = spd.speedgrade_timings
# Save data for runtime verification
_spd_data = spd_data
nphases = {
"SDR": 1,

View File

@ -43,6 +43,12 @@ class TestSPD(unittest.TestCase):
for tck, speedgrade in tck_to_speedgrade.items():
self.assertEqual(speedgrade, DDR3SPDData.speedgrade_freq(tck))
def test_spd_data(self):
# Verify that correct _spd_data is added to SDRAMModule
data = load_spd_reference("MT16KTF1G64HZ-1G6P1.csv")
module = SDRAMModule.from_spd_data(data, 125e6)
self.assertEqual(module._spd_data, data)
def compare_geometry(self, module, module_ref):
self.assertEqual(module.nbanks, module_ref.nbanks)
self.assertEqual(module.nrows, module_ref.nrows)