fix: ERR-0026 SDRAM tMRD datasheet-unit mismatch at 64MHz

Real Alliance Memory AS4C4M16SA-6TIN datasheet (Rev 5.0, Table 17)
specifies tMRD as a fixed 2-tCK cycle count, not an ns value.
sdram_controller.v modeled it via ns_to_cycles(12), which rounded to
2 cycles by coincidence at every previously-tested frequency
(100/133/166MHz) but rounds to only 1 cycle at the real 64MHz board
target -- an under-provisioned one-time init sequence. Fixed by
hardcoding T_MRD=2, matching how CAS_LATENCY is already modeled.

Verified zero regression: full 9-config legacy sweep + a new
dedicated 64MHz config (461/461 PASS each), N=2/N=4 D-Stress
(identical cycle counts), board-level smoke test (11/11 PASS).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
This commit is contained in:
2026-09-06 18:27:36 +02:00
co-authored by Claude Sonnet 5
parent d6376e8f2a
commit 8890b0abc2
3 changed files with 80 additions and 1 deletions
+21
View File
@@ -2140,3 +2140,24 @@ and the new host-arb arbitration layer) -- this was deliberately not
attempted before now, since running the real toolchain against RTL
known to compute wrong answers would not have been a meaningful
result. That reason no longer applies.
DEC-0038
DATE: 2026-09-06
DECISION:
The SDRAM datasheet-parameter audit (PRE-PCB VERIFICATION FREEZE,
section 8) is CLOSED. Every timing parameter in hardware/v2/nms/rtl/
sdram_controller.v was cross-checked against the real Alliance Memory
AS4C4M16SA-6TIN datasheet (Rev 5.0, Table 17) at the real 64MHz target
frequency, not merely re-cited from a previous, uncross-checked
baseline. This found and closed ERR-0026 (T_MRD unit mismatch -- see
errors.log), the only genuine discrepancy found. tRCD, tRP, tRAS,
tWR, tMRD, tREFI are all now confirmed correct at 64MHz with zero
regression to the existing bit-exact regression suite. See
hardware/v2/docs/PRE_PCB_VERIFICATION.md for the full parameter-by-
parameter table (DATASHEET PARAMETER -> REQUIRED VALUE -> RTL VALUE ->
STATUS).
This REVISES CHIP_READINESS.md/OPEN_ITEMS.md's own prior "SDRAM
datasheet-parameter cross-check: OPEN (sim-level only)" status to
CLOSED.
+44
View File
@@ -1244,3 +1244,47 @@ STATUS: ERR-0025 (Parts A and B) fully RESOLVED. The physical SPI host
interface is now verified correct end-to-end (SPI -> dependency_
manager -> compute -> SDRAM -> result) under both tight and realistic-
gap job pacing, with zero regression to the STEP19 baseline.
ERR-0026 -- T_MRD datasheet-unit mismatch (SDRAM init sequence, 64MHz)
DATE: 2026-09-06
FOUND DURING: PRE-PCB VERIFICATION FREEZE, section-8 SDRAM datasheet-
level audit (real Alliance Memory AS4C4M16SA-6TIN datasheet, Rev 5.0,
Oct 2018, Table 17 "Electrical Characteristics/AC Operating
Conditions", -6 speed grade).
ROOT CAUSE: hardware/v2/nms/rtl/sdram_controller.v modeled tMRD (LOAD
MODE REGISTER -> any command spacing) as `ns_to_cycles(12)`, i.e. as
if it were a nanosecond-based timing spec like tRCD/tRP. The real
datasheet specifies tMRD as a FIXED CYCLE COUNT, "2 tCK", independent
of clock frequency -- the same category of spec as CAS_LATENCY, which
this same file already correctly models as a fixed value two lines
below. `ns_to_cycles(12)` rounds to exactly 2 cycles at every
frequency this design had previously been tested at (100/133/166MHz),
so the wrong unit model was silently masked by coincidence. At the
real V2 board's own 64MHz operating point it rounds to only 1 cycle --
one cycle short of the real, fixed 2-tCK minimum -- a genuine,
datasheet-violating under-provisioning of the one-time SDRAM power-up/
mode-register-set sequence. Confirmed NOT a bug in tRCD/tRP (correctly
ns-based, correctly use ns_to_cycles()), tRAS (satisfied by construction:
the fixed tRCD+CAS_LATENCY+BURST_LEN dispatch sequence is always >=6
cycles, 93.75ns >= the real 42ns minimum at 64MHz), or tWR (folded in
conservatively via T_RP+1, giving 3 cycles >= the real 2-tCK minimum).
FIX: hardcoded `localparam T_MRD = 2;` (matching how CAS_LATENCY is
already modeled), replacing `localparam T_MRD = ns_to_cycles(12);`.
Only affects the one-time SDRAM init sequence, not per-transaction
timing.
VERIFICATION (all via Verilator, the trusted tool per DEC-0004):
- tb_sdram_controller.v: full 9-config legacy sweep (100/133/166MHz
x BURST_LEN 1/4/8), 461/461 PASS each config, zero regression.
- tb_sdram_controller.v: NEW dedicated 64MHz/BURST_LEN=4 config (the
real board target, not covered by the legacy sweep) -- 461/461
PASS, confirming the fix is correct at the frequency where the
bug actually manifested.
- tb_nms_dstress_sdram_unified.v N=2: 49788 cycles, 256/256
bit-exact -- IDENTICAL to pre-fix (expected: T_MRD only affects
one-time init, not steady-state per-transaction timing).
- tb_nms_dstress_sdram_unified.v N=4: 49771 cycles, 256/256
bit-exact -- IDENTICAL to pre-fix.
- tb_fpga_neural_v2_top_smoke.v: 11/11 PASS, unaffected.
STATUS: RESOLVED. Files changed: hardware/v2/nms/rtl/sdram_
controller.v (single localparam, plus explanatory comment).
+15 -1
View File
@@ -99,7 +99,21 @@ module sdram_controller #(
// (tRCD + CAS_LATENCY + BURST_LEN data cycles, always >= 3+3+1=7
// even at the narrowest BURST_LEN=1) already comfortably exceeds
// it by construction before auto-precharge can begin internally.
localparam T_MRD = ns_to_cycles(12); // LOAD MODE REGISTER -> any command
// tMRD is specified by the real AS4C4M16SA-6TIN datasheet (Table 17)
// as a FIXED CYCLE COUNT ("2 tCK"), not a nanosecond value -- unlike
// tRCD/tRP, which genuinely are ns-based and correctly belong behind
// ns_to_cycles(). A previous draft modeled tMRD as ns_to_cycles(12),
// an assumed-equivalent ns figure that happened to round up to
// exactly 2 cycles at every frequency this design had been tested at
// (100/133/166MHz), silently masking the wrong unit model. At the
// real V2 board's own 64MHz operating point, ns_to_cycles(12) rounds
// to only 1 cycle -- one cycle short of the real, fixed 2-tCK
// minimum -- found via this step's own fresh datasheet-level audit
// (real Alliance Memory AS4C4M16SA-6TIN datasheet Rev.5.0, Table 17).
// Fixed by hardcoding the real, frequency-independent requirement
// directly, matching how CAS_LATENCY (also a real fixed-cycle spec)
// is already modeled two lines below.
localparam T_MRD = 2; // LOAD MODE REGISTER -> any command (tMRD = 2 tCK, fixed)
localparam T_INIT_US= 200; // power-up wait, real datasheet value
localparam T_INIT = T_INIT_US * CLK_FREQ_MHZ;
localparam CAS_LATENCY = 3; // fixed for this part/speed grade