DDR · Module 14
tRRD — Row-to-Row Delay
Two different banks does not mean unconstrained parallelism. tRRD spaces activates across banks, published as the greater of a cycle floor and an absolute time — with a verified value that depends on page size.
Chapter 14.6 moved column commands from bank-local to shared scope. This chapter does the same for activates, and it removes an assumption that has survived six chapters:
Two different banks does not mean unconstrained parallelism.
Activating bank 0 and activating bank 9 are operations on banks that are independent in state, whose own bank-local obligations have nothing to say about each other. And they still contend — because activating a row draws on resources the banks share.
tRRD is also the one parameter in this module where I have a fully verified real value with its complete context, including a dependence nobody expects: it varies with the device's page size.
1. The Obligation, in Five Parts
PARAMETER tRRD (DDR4: tRRD_S and tRRD_L — see §4)
1 triggering event ACTIVATE accepted on any bank
2 constrained event the NEXT ACTIVATE, to a DIFFERENT bank
3 resource SHARED activation resources;
DDR4 refines by bank group. See §3.
4 magnitude the GREATER of a cycle floor and an
absolute time. VERIFIED — see §4.
5 sense MINIMUM SEPARATION
─────────────────────────────────────────────────────────────────
consequence next ACTIVATE not before
prev_act_cycle + max(nCK_floor,
ceil(abs_min / tCK))Part 4 is new. Every parameter so far has had a magnitude in one unit — nanoseconds for tRCD, tRP, tRAS and tRC; cycles for tCCD. tRRD is the first in this module published both ways at once, with the greater required. Chapter 13.2 §5 introduced that form using this exact parameter; §4 completes the story.
The follow-up questions:
What re-arms it? Every accepted ACTIVATE, to any bank. Same shared-scope statement as tCCD's.
What can dominate it? tRP, for an activate following a precharge to that bank. tRC, for an activate to the same bank. And tFAW, which is a rolling window rather than a pairwise spacing and can dominate both. Chapter 14.4 §5's trace had tRRD in the applicable set and satisfied — it was never the controlling one there, which is typical for a short trace and misleading.
Cycle or absolute-time component? Both, which is the chapter.
Does generation matter? Yes — §4 labels everything DDR4 and §5 is explicit about DDR5.
2. Same Bank Against Different Bank
The fastest way to see what tRRD is for is to put it beside tRC.
ACT bank 0 ──── tRC ────▶ next ACT bank 0 BANK-LOCAL (14.4)
ACT bank 0 ──── tRRD ────▶ next ACT bank 9 SHARED (this)Two obligations, both ACTIVATE-to-ACTIVATE, distinguished entirely by whether the target is the same bank. And they have very different magnitudes: Chapter 14.4 §3 verified tRC at 45.75 ns for a DDR4-3200 grade, while §4 below verifies tRRD_S at a few nanoseconds. Activating a different bank is far cheaper than recycling the same one — which is the entire architectural argument for having many banks.
But cheaper is not free, and the reason is worth getting right.
The scope consequence is Chapter 14.6's, repeated for activates. A per-bank countdown cannot express this obligation: bank 9's counter has never been told about bank 0. It is the same category error, with the same fast and wrong failure and the same signature — single-bank tests pass, and the violation rate rises with bank parallelism.
3. The Bank-Group Refinement
Chapter 14.6 §3 established the one topology fact this module asserts: DDR4 organises banks into groups, and accesses in different groups can be spaced more closely than accesses in the same group.
That refinement applies to activates exactly as it applies to column commands, giving two requirements:
different bank group → the SHORTER requirement (tRRD_S)
same bank group → the LONGER requirement (tRRD_L)So a candidate ACTIVATE to a different bank is subject to one of two magnitudes, selected by a property of the pair — the same pair-dependent shape Chapter 14.6 §4 introduced.
And the same architectural lever follows: steering consecutive activates into different bank groups pays the shorter spacing. For a workload that activates rows frequently — a miss-heavy one — that is a direct throughput difference arising purely from how addresses map onto banks, which is Module 18's subject.
4. The Verified Value, With Its Full Context
This is the chapter's centrepiece, because it is the one place in this module where I can give a real number with everything needed to make it meaningful.
5. DDR5 — Not Established Here
6. The Crossover — Where the Two Terms Trade Places
Now the arithmetic that makes §4's dual-term form interesting rather than merely unusual.
Resolve the DDR4-2400, 1KB figure — the greater of 4 nCK or 3.3 ns — at several clock periods. Hold the absolute term fixed to isolate the conversion, exactly as Chapter 13.2 §8 did, and note as that chapter did that a real speed-grade table adjusts the absolute term too:
| Data rate | tCK | ceil(3.3 / tCK) | cycle floor | max | Governed by |
|---|---|---|---|---|---|
| DDR4-1600 | 1.250 ns | 3 | 4 | 4 | cycle floor |
| DDR4-2400 | 0.8333 ns | 4 | 4 | 4 | tie |
| DDR4-2933 | 0.6819 ns | 5 | 4 | 5 | absolute |
| DDR4-3200 | 0.625 ns | 6 | 4 | 6 | absolute |
The crossover sits at DDR4-2400, where the two terms tie at 4 cycles — which is almost certainly not a coincidence, given that 3.3 ns is the DDR4-2400 figure.
That is a genuinely useful thing to have learned from verified data: the dual-term form plus a per-grade absolute value is how a specification keeps a physical requirement at a roughly constant cycle cost across a device family.
7. RTL — Resolving Two Group Classes, and Reusing What Exists
Collision check. Chapter 4.5's bank_group_spacer implements group-scoped activate spacing with per-group countdowns and distinct stall reasons. Chapter 13.2's timing_spec_resolver resolves one max(nCK, ns) specification and reports which term governs. Chapter 14.6's column_turnaround_matrix selects a magnitude from a pair-dependent table.
Between them, the enforcement is already built. bank_group_spacer is the right block for holding the spacing, and this chapter reuses it rather than building a third group-scoped countdown.
What is not built is the thing §6 just did by hand: resolving two dual-term specifications and comparing their crossovers. timing_spec_resolver handles one specification. tRRD needs two — same-group and different-group — and the interesting output is not either resolved value but the pair, plus which term governs each.
The engineering problem. Resolve both group classes' dual-term specifications at the current clock period, report both magnitudes for bank_group_spacer to consume, and report which term governs each so an architect can answer the faster-bin question.
Classification: configuration-time arithmetic, expressed as combinational RTL. The same honest classification Chapter 13.2 §7 gave its resolver, and for the same reason: in a real controller this runs once per frequency change, in firmware.
// ─────────────────────────────────────────────────────────────────────
// activate_spacing_resolver
//
// CLASSIFICATION
// Configuration-time arithmetic, expressed as combinational RTL.
// Pure function of tck_ps. No clock, no state, no timekeeping.
//
// WHAT IT MODELS
// §6's resolution, for BOTH DDR4 bank-group classes at once:
// cycles_S = max(FLOOR_S_NCK, ceil(ABS_S_PS / tCK))
// cycles_L = max(FLOOR_L_NCK, ceil(ABS_L_PS / tCK))
// plus, for each, WHICH term governs -- which is the output an
// architect actually wants, because it predicts whether the
// constraint worsens in a faster speed bin.
//
// WHAT IT DOES NOT MODEL
// Any physical process. ABS_*_PS are numbers from a vendor table;
// this block has no idea what circuitry they describe. It also does
// NOT enforce anything -- Chapter 4.5's bank_group_spacer holds the
// countdowns and this block only supplies its magnitudes.
//
// RELATIONSHIP TO EXISTING RTL
// This is a FEEDER for bank_group_spacer, not a replacement. It is
// also two instances' worth of Chapter 13.2's timing_spec_resolver
// logic brought together so the two classes can be COMPARED -- the
// comparison is the new part, and a design could equally
// instantiate that resolver twice and compare outside. Doing it in
// one block makes the ORDERING invariant checkable; see §8's P3.
//
// UNITS -- stated once, obeyed everywhere
// ABS_*_PS and tck_ps are PICOSECONDS.
// FLOOR_*_NCK and the outputs are CK CYCLES.
// tck_ps is the CK PERIOD, not a data-rate interval. Chapter 13.2
// §12 covers the cost of that confusion: every obligation wrong by
// a factor of two.
//
// PAGE SIZE
// §4 verified that the absolute term depends on the device's page
// size -- 3.3 ns at 1KB versus 5.3 ns at 2KB for DDR4-2400. That is
// why ABS_*_PS are PARAMETERS to be programmed from the specific
// device's table and not constants baked in here.
// ─────────────────────────────────────────────────────────────────────
module activate_spacing_resolver #(
// DIFFERENT bank group -- DDR4's "_S". Verified form: greater of a
// cycle floor and an absolute time (§4).
parameter int FLOOR_S_NCK = 4,
parameter int ABS_S_PS = 3300,
// SAME bank group -- DDR4's "_L". Longer by construction.
parameter int FLOOR_L_NCK = 4,
parameter int ABS_L_PS = 6000,
parameter int TCK_PS_W = 16,
parameter int CYC_W = 8
) (
input logic [TCK_PS_W-1:0] tck_ps,
// ── Magnitudes for bank_group_spacer to enforce.
output logic [CYC_W-1:0] cycles_diff_group,
output logic [CYC_W-1:0] cycles_same_group,
// ── Which term governs each class. High = the absolute term won, so
// that class is PHYSICS-LIMITED at this frequency and its cycle
// count RISES if the clock rises. §6's architect question.
output logic diff_abs_governs,
output logic same_abs_governs,
// ── Invariant check, published rather than assumed: the same-group
// requirement must not resolve shorter than the different-group
// one. A violation here means the programmed table is wrong.
output logic ordering_violation,
output logic tck_invalid,
output logic overflow
);
// ── Elaboration guards.
if ((FLOOR_S_NCK < 0) || (FLOOR_L_NCK < 0)) begin : g_floor
initial $fatal(1, "activate_spacing_resolver: floors must be >= 0");
end
if ((ABS_S_PS < 0) || (ABS_L_PS < 0)) begin : g_abs
initial $fatal(1, "activate_spacing_resolver: abs terms must be >= 0");
end
// A class with neither term constrains nothing -- almost certainly a
// wiring mistake, so refused loudly rather than resolving to zero.
if ((FLOOR_S_NCK == 0) && (ABS_S_PS == 0)) begin : g_empty_s
initial $fatal(1, "activate_spacing_resolver: _S has no terms");
end
if ((FLOOR_L_NCK == 0) && (ABS_L_PS == 0)) begin : g_empty_l
initial $fatal(1, "activate_spacing_resolver: _L has no terms");
end
// CYC_W bounded so the overflow detector cannot itself overflow --
// the same structural guard Chapter 13.2 §7 used.
if ((CYC_W < 1) || (CYC_W > 30)) begin : g_cyc
initial $fatal(1, "activate_spacing_resolver: CYC_W must be 1..30");
end
if (TCK_PS_W < 1) begin : g_tck
initial $fatal(1, "activate_spacing_resolver: TCK_PS_W must be >= 1");
end
localparam int MAX_CYCLES = (1 << CYC_W) - 1;
int unsigned tck_u;
int unsigned abs_s_cyc, abs_l_cyc;
int unsigned req_s, req_l;
always_comb begin
tck_u = 32'(tck_ps);
tck_invalid = (tck_u == 32'd0);
// ── §6's integer ceiling, twice. ceil(a/b) == (a + b - 1) / b,
// guarded against the zero divisor. An ABS term of 0 yields 0
// for any b >= 1, which is correct: no absolute component
// contributes no absolute-derived cycles.
if (tck_invalid) begin
abs_s_cyc = 32'd0;
abs_l_cyc = 32'd0;
end else begin
abs_s_cyc = (32'(ABS_S_PS) + tck_u - 32'd1) / tck_u;
abs_l_cyc = (32'(ABS_L_PS) + tck_u - 32'd1) / tck_u;
end
// ── The max, per class, and which term won. STRICT comparison, so
// a tie reports the floor as governing -- which is the
// conservative reading of §6's crossover and matches Chapter
// 13.2 §7's convention exactly.
req_s = (abs_s_cyc > 32'(FLOOR_S_NCK)) ? abs_s_cyc
: 32'(FLOOR_S_NCK);
diff_abs_governs = (abs_s_cyc > 32'(FLOOR_S_NCK));
req_l = (abs_l_cyc > 32'(FLOOR_L_NCK)) ? abs_l_cyc
: 32'(FLOOR_L_NCK);
same_abs_governs = (abs_l_cyc > 32'(FLOOR_L_NCK));
// ── Range check then saturate. Saturation is the safe failure:
// too long is slow, too short violates the contract.
overflow = (req_s > 32'(MAX_CYCLES)) || (req_l > 32'(MAX_CYCLES));
cycles_diff_group = (req_s > 32'(MAX_CYCLES)) ? CYC_W'(MAX_CYCLES)
: CYC_W'(req_s);
cycles_same_group = (req_l > 32'(MAX_CYCLES)) ? CYC_W'(MAX_CYCLES)
: CYC_W'(req_l);
// ── The invariant. Reported, not enforced: silently clamping a
// bad table would hide a configuration error.
ordering_violation = !tck_invalid
&& (cycles_same_group < cycles_diff_group);
end
endmoduleInterface contract. Two magnitudes out, for Chapter 4.5's bank_group_spacer to consume as its DIFF_GAP and SAME_GAP. This block enforces nothing and holds no obligation; naming the outputs cycles_* rather than *_ok says so.
Parameter contract. ABS_S_PS and ABS_L_PS are parameters because §4 verified they depend on page size — 3.3 ns at 1KB against 5.3 ns at 2KB for the same speed grade. A block with these baked in would be wrong on half the parts in a family. CYC_W is bounded at 30 so 1 << CYC_W stays inside a signed 32-bit int.
Why the casts are safe. CYC_W'(MAX_CYCLES) is exact by construction. CYC_W'(req_s) and CYC_W'(req_l) are each reached only on the false branch of their own range test — the comparison guards the cast immediately above it, which is the pattern Chapter 13.2 §7 established.
Corner cases. tck_ps == 0: refused via tck_invalid, and both absolute terms contribute nothing, so the outputs degenerate to the floors — which a consumer must not trust, hence the flag. An absolute term of 0: that class is always floor-governed at every frequency. A floor of 0: always absolute-governed whenever the absolute term yields anything. Exact tie: reports floor-governed, per the strict comparison — and §6 showed the real DDR4-3200 figure sits exactly there, so this is not a rare case. ABS_L_PS < ABS_S_PS: a bad table, reported on ordering_violation rather than clamped.
Synthesis implications. Two integer divisions by a runtime value, which is the whole cost and the reason this is configuration-time arithmetic. Chapter 13.2 §7 covered the options: firmware, a lookup table over supported periods, or a pipelined divider. The comparisons and saturation are trivial.
Failure modes. Truncating division instead of the ceiling: under-waits by one cycle at every frequency where the division is inexact, which is most but not all of them — so a single-frequency test cannot find it. Using >= for the governs flags: misreports the tie, which §6 showed is exactly where the real DDR4-3200 value sits, so this error would be visible in practice rather than theoretical. Baking the absolute terms in as localparams: wrong on a different page size. Passing a data-rate interval as tck_ps: every magnitude wrong by a factor of two, and undetectable from inside the block.
8. Four Assertions Worth Writing
Where these live. This block is combinational with no clk port, so the properties belong in a testbench or bind unit sampled on the environment's clock — Chapter 13.2 §9 developed what that costs and why it is acceptable for configuration-time arithmetic.
// ── Sampled on the ENVIRONMENT's clock: this block has none.
//
// ── P1. Each resolved magnitude covers its own cycle floor. The
// safety property: a resolver that under-reports produces a design
// that violates the contract everywhere at once.
property p_covers_floors;
@(posedge clk) disable iff (!rst_n)
!tck_invalid |-> ( ( (cycles_diff_group >= CYC_W'(FLOOR_S_NCK))
&& (cycles_same_group >= CYC_W'(FLOOR_L_NCK)) )
or overflow );
endproperty
a_covers_floors: assert property (p_covers_floors);
// ── P2. Each conversion is a genuine ceiling, checked against the
// DEFINITION rather than against the implementation's own formula.
// ceil(a/b) = c means c*b >= a and (c-1)*b < a. Re-deriving the
// RTL's expression would prove only that it equals itself.
// Catches truncation, round-to-nearest, and an off-by-one in the
// +b-1 term. Written for the _S class; the _L twin is identical.
property p_ceiling_is_a_ceiling_s;
@(posedge clk) disable iff (!rst_n)
(!tck_invalid && !overflow && (ABS_S_PS > 0) && diff_abs_governs) |->
( (32'(cycles_diff_group) * 32'(tck_ps) >= 32'(ABS_S_PS))
&& ((32'(cycles_diff_group) - 32'd1) * 32'(tck_ps) < 32'(ABS_S_PS)) );
endproperty
a_ceiling_is_a_ceiling_s: assert property (p_ceiling_is_a_ceiling_s);
// ── P3. The governs flags agree with the arithmetic, including the
// TIE. §6 showed the real DDR4-3200 figure lands exactly on the
// tie, so a >= / > confusion here is a bug that shows up on a real
// part rather than only in theory.
property p_governs_flags_consistent;
@(posedge clk) disable iff (!rst_n)
(!tck_invalid && !overflow) |->
( ( diff_abs_governs
? (cycles_diff_group > CYC_W'(FLOOR_S_NCK))
: (cycles_diff_group == CYC_W'(FLOOR_S_NCK)) )
&& ( same_abs_governs
? (cycles_same_group > CYC_W'(FLOOR_L_NCK))
: (cycles_same_group == CYC_W'(FLOOR_L_NCK)) ) );
endproperty
a_governs_flags_consistent: assert property (p_governs_flags_consistent);
// ── P4. The CONFIGURATION invariant: same-group must not resolve
// shorter than different-group, at any frequency. Not a property of
// the logic -- the logic works for any table -- but a mis-programmed
// table produces violations that look like logic bugs, and catching
// it where the configuration arrives is far cheaper. Chapters 14.3
// §7 and 14.6 §9 made the same argument.
property p_same_group_not_shorter;
@(posedge clk) disable iff (!rst_n)
!tck_invalid |-> !ordering_violation;
endproperty
a_same_group_not_shorter: assert property (p_same_group_not_shorter);What these prove. That both magnitudes cover their floors; that the conversions are genuine ceilings, checked against the mathematical definition; that the governing-term flags agree with the arithmetic including at the tie; and that the programmed table respects _L >= _S.
What these do not prove. That the programmed values are the right ones for the device — §4's figures are speed-grade and page-size specific, and no property can see that the table entry matches the part. That tck_ps is a CK period rather than a data-rate interval: the block cannot see what the number means, and Chapter 13.2 §9 established that no block-level property can catch a units error at its own boundary. And nothing about enforcement — these magnitudes feed bank_group_spacer, whose own properties cover whether the countdowns honour them.
Vacuity. P2 requires ABS_S_PS > 0 and diff_abs_governs, so it says nothing at frequencies below the crossover — which is most of the interesting range for a floor-governed parameter. Sweep tck_ps across the crossover and cover both sides, or P2 passes having checked nothing.
9. The Two Classes, Across Frequency
activate_spacing_resolver — two classes, two crossovers
10 cyclesThree observations.
The _S class crosses over and the _L class never does. With a 6.0 ns absolute term against a 4 nCK floor, the absolute term governs at every frequency in the sweep. The two classes are on opposite sides of the structure-versus-physics question at DDR4-1600 and the same side at DDR4-3200 — which is why the block resolves and reports them separately rather than assuming they behave alike.
The tie at DDR4-2400 reports floor-governed, per §7's strict comparison. §6 showed the real DDR4-3200 figure of 2.5 ns also lands on a tie, so this is a configuration a real part actually occupies.
The gap between the classes widens with frequency — 1 cycle at DDR4-1600, 4 cycles at DDR4-3200. So the throughput cost of concentrating activates into one bank group grows on faster parts, which makes Module 18's address mapping more important rather than less as speeds rise.
10. DV — Independent Reconstruction
Sweep, do not sample. The block is combinational, so a sweep costs nothing but loop iterations. The likeliest bug — a truncating division — is invisible at every frequency where the division happens to be exact, and §6's table contains two such points.
Search rather than recompute. A checker computing (abs + tck - 1) / tck proves the RTL contains that expression. A checker finding the smallest c with c * tck >= abs by counting upward proves it computes a ceiling. The second is slower and correct, and in a combinational sweep slowness is free — Chapter 13.2 §10's representation-inversion principle in miniature.
Hunt both crossovers deliberately. Each class has its own, at a different frequency. Test the two periods either side of each and the exact tie.
Resolve from the device's table, per page size. §4's page-size dependence is the tRRD-specific verification obligation: a checker programmed with the 1KB absolute term while the design is configured for a 2KB part agrees with nothing useful. The page size must come from the device configuration, not from a default.
TIMING VIOLATION
command : ACTIVATE, bank 9 (bank group 2)
issued at : cycle 204
resource : SHARED activation path
previous : ACTIVATE bank 1 (bank group 2), cycle 201
relationship : SAME bank group
selected : tRRD_L CONTROLLING
requirement : max(4 nCK, 6.0 ns / 0.625 ns = 10) = 10 cycles
governed by : absolute term
legal from : cycle 211
short by : 7 cycles
note : different bank group would have selected tRRD_S
= max(4, ceil(2.5/0.625) = 4) = 4 cycles, legal
at cycle 205Two lines earn their place here. The requirement line shows both terms and which governed, so a reader can check the resolution without leaving the report — and can see immediately whether a faster part would make it worse. The note gives Chapter 14.6 §10's counterfactual, which for activates is the difference between 10 cycles and 4.
11. Debugging
Symptom. Activates violate spacing, or activate throughput is below model.
| Candidate mechanism | Evidence | Discriminator |
|---|---|---|
| Per-bank state for a shared obligation | Single-bank passes; violations rise with bank parallelism | One-bank against all-bank traffic. Chapter 14.6 §11's discriminator, unchanged. |
_S selected where _L belongs | Violations only on same-bank-group activate pairs | The violating pairs' groups. §10's report names the selection. |
| Only the cycle floor enforced | Correct at low data rates; violations at high ones | §6's crossover. A design enforcing 4 nCK and ignoring the absolute term is right below the crossover and wrong above it — which means it passes on the slow part it was brought up on. |
| Only the absolute term enforced | Violations at low data rates | The mirror, and the counter-intuitive one: below the crossover the floor is the larger term, so ignoring it under-waits. |
| Wrong page size in the table | Requirement short by the 1KB-versus-2KB difference | §4. Check the configured page size against the part. |
| Truncating division | Off by one at frequencies where the division is inexact | §10's search-based check. |
| ns-for-nCK confusion | Every magnitude wrong by roughly 1/tCK | Compare the resolved value against §6's table by hand. |
| tFAW ignored | Violations only in bursts of four or more activates | Chapter 14.8. A different constraint class entirely. |
The discriminator unique to this chapter is which side of the crossover the failure appears on. A design enforcing only the cycle floor is correct below the crossover and wrong above; one enforcing only the absolute term is wrong below and correct above. So “it worked on the slower part” is diagnostic information rather than a puzzle — it says the floor was enforced and the absolute term was not, which is by far the more common omission because the floor is the simpler number to find.
Responsible layer. If both terms are resolved correctly and activate throughput is still short, look at whether activates are concentrating into one bank group — §9 showed that costs 4 cycles against 10 at DDR4-3200 — or at whether tFAW is the actual limiter, which the next chapter shows is common for activate-heavy traffic.
12. Common Misconceptions
“tRRD only matters when activating the same bank.” Tempting because the name pairs “row” with “row” and same-bank activation is the obvious conflict. Why it is wrong: the same-bank case is tRC's. tRRD is specifically the cross-bank obligation. Consequence: a controller that applies it per bank leaves cross-bank activates unconstrained — which is the traffic tRRD exists for. Replacement model: tRC for same bank, tRRD for different banks, at different scopes with very different magnitudes. Debugging clue: violations on activates to banks that had never been activated.
“If two banks are different, activating both is unconstrained.” Tempting because bank independence is DDR's selling point and six chapters of bank-local obligations reinforced it. Why it is wrong: §2 — activating a row engages shared resources, and the verified absolute-time component is the evidence. Consequence: back-to-back cross-bank activates violating spacing, with a rate that rises with parallelism. Replacement model: independent in state, contending in activation resources. Debugging clue: single-bank tests pass.
“If the nCK term passes, the absolute-time term can be ignored.” Tempting because the cycle floor is the easier number to find and enforce, and below the crossover it genuinely is the binding one. Why it is wrong: §6 — above the crossover the absolute term is larger, and it is larger on exactly the fast parts people care about. Consequence: a design correct at DDR4-2400 and violating at DDR4-3200, which is the worst possible distribution because bring-up often happens on the slower bin. Replacement model: resolve both terms and take the greater, every time. Debugging clue: “it worked on the slower part.”
“A timing table for one speed bin is universal.” Tempting because the parameter names and the cycle floors really are stable across a family. Why it is wrong: §4 verified the absolute term shrinking across grades — 3.3, 3.0, 2.5 ns — and varying with page size, 3.3 against 5.3 ns at one grade. Consequence: a controller configured from the wrong row of the table, short by the difference. Replacement model: a value needs its generation, speed grade and page size attached before it is a fact. Debugging clue: correct on one part number and wrong on another with identical nominal speed.
“_S and _L exist in every DDR generation.”
Tempting because the naming is everywhere in DDR4 material. Why it is wrong: §5 — DDR4-era naming for a DDR4 mechanism, and I could not confirm DDR5's. Consequence: a port assuming identical semantics. Replacement model: verify per generation. Debugging clue: a port that works except on one class of pattern.
“tFAW is just a longer tRRD.” Tempting because both constrain activates and tFAW's magnitude is larger. Why it is wrong: tRRD is pairwise — it relates a candidate to one prior activate. tFAW is a rolling window relating it to a history of several. Chapter 13.3 §2's class D against class A. Consequence: implementing tFAW as a single countdown, which cannot express a density limit — Chapter 14.8 is entirely about this. Replacement model: different constraint classes needing different state. Debugging clue: violations only in bursts of four or more activates, never in pairs.
13. Interview Reasoning
“What does tRRD constrain, and how is it different from tRC?” Both are activate-to-activate minimums, distinguished by scope: tRC is bank-local and governs recycling the same bank, while tRRD is shared and governs activating a different one. The magnitudes reflect that — tRC verified at 45.75 ns for a DDR4-3200 grade against tRRD_S at a few nanoseconds — which is the quantitative form of the argument for having many banks. The trap is applying tRRD per bank, which leaves the cross-bank traffic it exists for unconstrained.
“Why do activates to different banks contend at all?” Because an activate drives a wordline and starts sensing across a whole row, which engages circuitry the banks share. The strongest evidence is in the specification rather than in speculation about internals: the requirement has an absolute-time component, which is the signature of a physical cause, and it depends on page size — 3.3 ns at 1KB against 5.3 ns at 2KB for DDR4-2400. A purely structural requirement would not vary with how much array a row spans.
“tRRD_S is the greater of 4 nCK or 3.3 ns. Why both terms?” Because the two scale oppositely with frequency. The cycle floor is a structural requirement that stays 4 cycles at any clock; the absolute term is physical and costs more cycles as the clock rises. Specifying both and requiring the greater covers the whole operating range. And the verified figures show what the form is for: the absolute term shrinks across grades — 3.3 at DDR4-2400, 2.5 at DDR4-3200 — which keeps the resolved requirement near 4 cycles across the family instead of letting it grow.
“A design enforces only the 4 nCK floor. When does it fail?” Above the crossover, where the absolute term resolves larger than 4. At DDR4-2400 with 3.3 ns the two tie at 4, so the design is correct; at a grade where the absolute term resolves to 5 or 6 it under-waits. The uncomfortable part is the distribution: it passes on the slower bin, which is often where bring-up happens, and fails on the faster one. So “it worked on the slower part” is a diagnosis rather than a mystery.
“How does bank-group mapping affect activate throughput?” Same-group activate pairs pay the longer requirement and different-group pairs the shorter, so steering consecutive activates across groups issues them more often. With the educational same-group term in §9, the gap is 4 cycles against 10 at DDR4-3200 — and it widens with frequency, so address mapping matters more on faster parts, not less. That makes it a performance lever rather than a decoding detail.
“Why is tFAW not just a longer tRRD?” Different constraint classes. tRRD is pairwise: it relates the candidate to one prior activate, so one countdown expresses it. tFAW is a rolling window: it relates the candidate to a history of recent activates, and no single countdown can answer “how many happened in the last window.” The implementation consequence is that tFAW needs storage proportional to the event count, which is the next chapter.
14. Engineering Exercises
1. Resolve both terms. Using the verified DDR4-2400 1KB figure — the greater of 4 nCK or 3.3 ns — resolve tRRD_S at DDR4-1600, DDR4-2400 and DDR4-3200, and say which term governs at each.
Worked: at DDR4-1600, tCK is 1.25 ns, ceil(2.64) = 3, max(4, 3) = 4 — floor governs. At DDR4-2400, tCK is 0.8333, ceil(3.96) = 4, max(4, 4) = 4 — tie, reported as floor-governed. At DDR4-3200, tCK is 0.625, ceil(5.28) = 6, max(4, 6) = 6 — absolute governs. The crossover is at DDR4-2400.
2. Use the real per-grade value. Now redo DDR4-3200 with its actual verified absolute term of 2.5 ns instead of 3.3. What changes, and what does that tell you about how the table is constructed?
Worked: ceil(2.5 / 0.625) = 4, so max(4, 4) = 4 — back to the tie, and 2 cycles shorter than the fixed-3.3 sweep predicted. The table is constructed so the resolved requirement stays near the 4-cycle floor across the family. The fixed-term sweep of exercise 1 therefore over-estimates the real requirement at high speed, which is exactly why §6 labels it a teaching device.
3. Price the page size. At DDR4-2400, resolve tRRD_S for a 1KB part and a 2KB part. Express the difference as a percentage of activate spacing.
Worked: 1KB: max(4, ceil(3.3/0.8333) = 4) = 4 cycles. 2KB: max(4, ceil(5.3/0.8333) = 7) = 7 cycles. 75 percent longer, from a device property that appears nowhere in the parameter's name. A controller configured for the wrong page size is short by 3 cycles on every cross-group activate pair.
4. Find the one-sided design. A colleague enforces only the absolute term, ignoring the cycle floor. At which of exercise 1's three grades does that violate, and why is this error rarer in practice than the opposite one?
Worked: it violates at DDR4-1600, where the absolute term resolves to 3 and the floor requires 4. At the other two it is correct or conservative. It is rarer because the cycle floor is the more visible number in most documentation and tuning interfaces, so engineers are more likely to find the floor and miss the absolute term than the reverse — which is why §11 flags “worked on the slower part” as the common signature.
5. Compare the scopes. Construct the shortest activate sequence that violates tRRD but satisfies tRC, and one that violates tRC but satisfies tRRD.
Worked: tRRD only: ACTIVATE bank 0 at cycle 0, ACTIVATE bank 9 (different group) at cycle 1 — tRC does not apply since it is a different bank, and tRRD_S of 4 is violated. tRC only: ACTIVATE bank 0 at cycle 0, then PRECHARGE and ACTIVATE bank 0 again at cycle 20 with tRC of 74 — tRRD's 4 cycles are long satisfied and tRC is violated by 54. The pair makes the scope distinction concrete: neither obligation subsumes the other.
6. Sweep for the crossover. Write the loop that finds, for a given dual-term specification, the exact tck_ps at which the governing term changes. Then explain why §8's P2 proves nothing below that point.
7. Argue the reuse. §7 builds a resolver and reuses Chapter 4.5's bank_group_spacer for enforcement. Argue instead for one block doing both, then say what that costs in testability given that the resolver is combinational and the spacer is sequential.
15. Summary
tRRD constrains the next ACTIVATE to a different bank from any accepted ACTIVATE — shared scope, refined by bank group in DDR4, a minimum separation. It is the activate counterpart to Chapter 14.6's column spacing, and it removes the assumption that survived six chapters: two different banks does not mean unconstrained parallelism.
It is also the one parameter in this module with a fully verified value in full context: Micron's TN-40-03 specifies tRRD_S for DDR4-2400 as the greater of 4 nCK or 3.3 ns at 1KB page size, and 5.3 ns at 2KB — with corroborating figures of 3.0 ns at DDR4-2933 and 2.5 ns at DDR4-3200. Four things follow, and each is load-bearing: the max(nCK, ns) dual-term form is real; the cycle floor stays 4 across grades while the absolute term shrinks; the absolute term depends on page size, which is a device property and the best available evidence that the cause is physical; and a value quoted without its grade and page size is not a fact.
The dual-term form creates a crossover. Below it the obligation is structure-limited and the floor governs; above it the obligation is physics-limited and every clock increase costs cycles. The verified per-grade figures reveal what the form is for: the shrinking absolute term keeps the resolved requirement near 4 cycles across the family, which the fixed-term sweep of §6 deliberately does not show — and which makes the fixed-term sweep a teaching device rather than a description of a real part.
The crossover also gives this chapter a diagnostic no other chapter has: a design enforcing only the cycle floor is correct below the crossover and violating above, so “it worked on the slower part” identifies the bug rather than deepening the mystery. The mirror error, enforcing only the absolute term, fails at low data rates — the counter-intuitive direction.
Enforcement is reused: Chapter 4.5's bank_group_spacer holds the group-scoped countdowns. activate_spacing_resolver supplies its two magnitudes, resolves both dual-term specifications, reports which term governs each, and checks the _L >= _S configuration invariant. Its absolute terms are parameters precisely because §4 verified they depend on page size.
And _S / _L are labelled DDR4 throughout. §5 states that I could not confirm DDR5's naming or semantics — the fourth such gap in this curriculum, and by now a pattern worth trusting.
16. What Comes Next
tRRD relates a candidate ACTIVATE to one prior activate. Chapter 14.8 relates it to several.
tFAW is the module's only rolling-window constraint — Chapter 13.3 §2's class D, the one that is different in kind because legality depends on a history rather than on a single prior event. No countdown can express it, because no countdown can answer “how many activates happened in the last window.” It needs storage proportional to the event count, it is the one place in this module where a timestamp queue is the right structure, and it is where §12's last misconception — that tFAW is just a longer tRRD — gets taken apart properly.
Continue learning
Related tutorials
- Related topic
tCCD — CAS-to-CAS Delay
The first parameter that is not bank-local. Column spacing is constrained by resources every bank shares, and DDR4 splits it by bank group — so a per-bank state machine cannot enforce it.
- Related topic
DDR4 / DDR5 Bank-Group Concepts
The same-group penalty is not one number. It reaches twice for column commands, tracks that for activates on x8 parts, and on one verified x16 configuration disappears entirely.
- Related topic
DDR4
DDR4 is the generation where prefetch depth stops changing. With granularity already at a cache line, the rate had to come from overlapping independent accesses instead — which is what bank groups are, and why peak bandwidth became conditional on the access pattern.
- Related topic
Bank Groups
Not all bank pairs are equally independent. A bank group is the scope at which the internal column data path is shared, and the three-way classification of a request against its predecessor is the interface every later timing module consumes.
Standards & specifications
- Governing standard
- JEDEC JESD79 (DDR SDRAM)(opens JEDEC Solid State Technology Association in a new tab)
Defines the DDR SDRAM device itself — signals, command encoding, mode registers, timing parameters and the initialisation sequence — one document per generation. Memory-controller microarchitecture, address-mapping policy, PHY training algorithms and board-level design are not specified by it.
This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.
Where this fits
Part of the DDR curriculum.
