Skip to content

SPD Structure and Timebase

Lukas edited this page Jul 20, 2026 · 1 revision

SPD Structure and Timebase (MTB / FTB)

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.

Why timings are encoded as tick counts, not floats

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.

Why 350.000ns tRFC1 isn't a coincidence

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.

CRC-16: why the tool checks it before trusting anything

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.

The memory-type and timebase-encoding guards

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.

Clone this wiki locally