-
Notifications
You must be signed in to change notification settings - Fork 0
SPD Structure and Timebase
SPD (Serial Presence Detect) is a small EEPROM chip on every DIMM — 512 bytes for DDR4 — that the memory controller reads at boot to learn what the module is and how to talk to it. Understanding its byte-oriented encoding explains a few things that otherwise look arbitrary in this tool's output and source.
SPD chips are about as cheap and simple as a memory device gets — plain byte-addressable EEPROM, no floating-point capability implied or required. So JEDEC's DDR4 SPD spec encodes every timing as an integer tick count against a fixed timebase, rather than as a nanosecond value directly:
-
MTB (Medium Timebase): 125 picoseconds per tick. Most timings
(CL, tRCD, tRP, tRAS, tRC, tRFC, tFAW, tRRD, tCCD_L, tWR, tWTR) are
stored as a tick count in this unit.
nanoseconds = ticks * 0.125. -
FTB (Fine Timebase): 1 picosecond per tick, signed. A small signed
correction added on top of the MTB value for parameters that need
sub-125ps precision — e.g.
tAA = MTB_ticks * 0.125 + FTB_correction * 0.001. Signed because the correction can go either direction (the true value can fall on either side of the nearest 125ps tick).
This two-tier design is exactly why spd_matchtable.py's decoder applies
an s8() (signed-byte) conversion specifically to the FTB correction
bytes and nowhere else — those are the only fields in the base timing
block that are ever negative.
Some timings in this project's reference kit (tRFC1, tRFC2, tRFC4, tFAW)
land on suspiciously round numbers like exactly 350.0ns or 21.0ns. That's
not rounding in this tool's display code — it's because 350 / 0.125 = 2800, a clean integer tick count with no FTB correction needed at
all. Values like tAA = 13.75ns (110 ticks * 0.125) are equally
exact — MTB's 125ps granularity happens to divide many real DDR4 timing
values cleanly, which is presumably part of why 125ps was chosen as the
standard tick size in the first place.
Two 16-bit CRCs are stored in every DDR4 SPD: one covering the base
configuration bytes (0-125), one covering the module-specific bytes
(128-253) — both computed with the same CRC-16/CCITT algorithm (polynomial
0x1021, initialized to zero, no bit reflection). These exist because SPD
data is read over a physical I2C bus and stored on a real (if simple and
reliable) EEPROM — both are subject to the same failure modes as any
digital storage and transport: bit flips from electrical noise, a
partially-completed write during manufacturing, EEPROM wear.
spd-matchtable recomputes both CRCs independently and cross-checked its
own implementation against decode-dimms's own reported CRC values for
this project's reference kit (0xF56C / 0xC6AB) before trusting the
result. A module that fails its own CRC check is excluded from the
computed match table by default — see Worst Case Methodology and the
main repo's RELEASE_NOTES.md for why "the data claims to be internally
consistent" is treated as a prerequisite for trusting it at all, not an
afterthought.
Two bytes act as sanity gates before any timing is trusted: byte 0x02
(memory type, must read 0x0C for DDR4) and byte 0x11 (timebase
encoding, must read 0x00, the only combination the standard MTB=125ps/
FTB=1ps assumption this decoder hardcodes is valid for). Both exist to
catch a genuinely realistic failure mode: a DDR3 module (or any
non-standard SPD) accidentally wired to the DDR4-specific ee1004 kernel
driver — which would otherwise decode as confident, wrong DDR4 numbers
rather than being rejected outright.