DDR · Module 4
DDR2
A clock cycle has only two edges, so DDR2 raised bandwidth by deepening prefetch to 4n — making prefetch depth the frequency ratio between interface and core. Raising the rate on a multi-load bus then forced termination onto the die.
Chapter 4.2 ended on a structural wall. Transfers per clock cycle cannot exceed two, because a clock cycle has exactly two edges. So the term DDR1 unlocked is now itself exhausted, and bandwidth demand has not stopped growing.
What remains is the lever DDR1's 2n prefetch demonstrated but did not fully exploit. Prefetch decouples the array's access rate from the interface's word rate. DDR1 spent that decoupling on edges. DDR2 spends it on frequency: deepen the prefetch, and the interface clock can run faster than the array's access rate — which is a fundamentally different and much more scalable thing to have bought.
This chapter also confronts the first problem in this module that has nothing to do with the data path. Raising the signalling rate on a bus with several attached devices fails for electrical reasons, and the response — moving termination onto the die — is a change of a different kind from everything before it.
1. The Bottleneck, Stated as Arithmetic
Write out the three rates a DDR1 device runs at, and the wall is obvious.
DDR1:
array access rate = F accesses/s (each 2 words wide)
interface clock = F Hz
transfer rate = 2F transfers/s (2 per cycle)
To raise the transfer rate with a 2n prefetch, F must rise.
But F is ALSO the array's access rate -- so the array must speed up.
The array cannot speed up. (Chapter 3.5: sensing takes what it takes.)That coupling is the bottleneck. In DDR1, the interface clock and the array's access rate are the same number, so the interface cannot get faster without the array getting faster.
A 4n prefetch breaks the coupling:
DDR2 with a 4n prefetch:
array access rate = F accesses/s (each 4 words wide)
interface clock = 2F Hz <-- now INDEPENDENT of F
transfer rate = 4F transfers/s (2 per interface cycle)The array's access rate is unchanged. The interface clock is twice it. The transfer rate is four times it. The prefetch depth is what makes those three numbers different, and the ratio between the deepest and shallowest of them is exactly the prefetch depth.
2. Where the Rates Live
Read the figure right to left to see the design pressure. The market wants the rightmost number large. The leftmost number is fixed by physics that Module 3 established. The prefetch depth is the only thing standing between them, and its value is therefore set by the gap the designer needs to bridge — not chosen for its own sake.
And note which block is grey again. The array. Three generations in, and the array's access rate has barely moved. That is the central fact of DDR evolution: the interface has been pulled away from an array that stayed put, and every generation's features are consequences of the widening gap.
3. The Second Problem — A Bus With Several Devices On It
Everything so far treats the interface as a data-path problem. The other half of DDR2 is electrical, and it is the reason this module insists on separating the interface-and-PHY layer from the device-architecture layer.
A memory bus is not point-to-point. A controller drives a bus that several DRAM devices are attached to, across connectors and board traces. Every attachment is a discontinuity, and every discontinuity reflects.
At low signalling rates this is tolerable, because a reflection has time to bounce, decay and settle before the receiver samples. At high signalling rates it is not, for the same reason §4.2 gave about skew: the interval between transfers shrinks and the settling behaviour does not. Eventually the residue of the previous transfer is still present when the next one is sampled.
The classical fix is termination — a resistive load matched to the line's impedance, which absorbs the signal instead of reflecting it.
Before DDR2, termination for a memory bus lived on the motherboard: discrete resistor networks placed near the devices. That arrangement has three problems that get worse with rate.
It is in the wrong place. The optimal termination point is at the receiver, and a resistor on the board is some distance from the die's actual receiver — a stub whose length becomes electrically significant as rates rise.
It is always on. A fixed resistor terminates whether or not the device is the one being accessed, and whether the bus is being driven for a read or a write. Termination dissipates power continuously, and the right termination differs by direction and by which device is the target.
It cannot be changed. A board-level resistor is fixed at manufacture, so it cannot adapt to how many devices are populated, which one is being addressed, or which direction data is flowing.
DDR2's response is On-Die Termination — ODT. The termination resistance moves inside the DRAM device, placed at the receiver, and — this is the part that matters — it is controllable. A device can have its termination enabled or disabled, so the controller can terminate at the devices that should be terminating and leave the others unterminated.
4. The Generation, With Layers Labelled
| Property | DDR1 | DDR2 | Layer changed |
|---|---|---|---|
| Prefetch depth | 2n | 4n | Device architecture |
| Interface clock vs array access rate | equal | 2× | Consequence of prefetch |
| Transfers per interface clock cycle | 2 | 2 (unchanged) | — |
| Transfer rate vs array access rate | 2× | 4× | Consequence of prefetch |
| Termination | board-level, fixed | on-die, controllable (ODT) | External interface |
| Termination calibration | — | none | (closed in DDR3) |
| Supply voltage | 2.5 V | 1.8 V | Interface / device |
| Minimum access granularity | 2 words | 4 words | Consequence of prefetch |
| Array organisation | unchanged | unchanged | none |
The voltage reduction is causal, not cosmetic. Switching energy scales with the square of the voltage swing, and an interface performing twice as many transfers per second switches twice as often. Lowering the swing from 2.5 V to 1.8 V is how the rate increase was afforded. Every generation in this module lowers voltage for the same reason, and by 4.7 that pressure is the dominant design constraint rather than a supporting one.
One device-architecture feature is worth a mention in passing. DDR2 introduced a posted column command with an additive latency: the controller may issue the column command earlier than it otherwise could, and the device holds it internally for a specified number of cycles before acting. That is a scheduling capability — it lets the controller place commands on the bus more regularly rather than waiting — and it exists because command-bus scheduling becomes harder as the rate ratio widens. Modules 7 and 13 own the command and the timing parameter; it is named here only because it is an early instance of the same trend §3's callout described: the device gaining knobs whose scheduling is the controller's job.
5. RTL — The Prefetch Adaptation, Fully Parameterised
Problem
This is the module's flagship block, because it implements the mechanism the whole module turns on.
A burst of cmd_beats narrow beats must be produced from a stream of wide core words, where a core word is PREFETCH beats wide. The block must pull core words at the right rate — once per PREFETCH beats, not once per beat — emit beats in order, mark the burst boundaries, refuse a burst length that the prefetch organisation cannot express, and report a supply failure rather than emitting stale data.
Making the depth, the beat width and the burst length independent parameters is the point. Set PREFETCH = 2 and it is DDR1; 4 and it is this chapter; 8 and it is DDR3; 16 and it is DDR5. The generations in this module differ, in the data path, by this parameter — and being able to sweep it is worth more than four separate blocks.
Classification
SYNTHESIZABLE RTL. A width-and-rate adaptation with a burst sequencer: genuine digital logic of the kind a device's interface path and a controller's data path both contain.
What it does not model, deliberately. No DQS, no edge placement, no analog timing, no termination and no ODT. The double-edge behaviour is abstracted exactly as 4.2 §5 argued it must be — beats are successive cycles of one clock domain, because a negedge flop would represent none of the properties that make double-edge signalling hard. ODT is absent from this block entirely, and that is correct: termination is an analog property of a driver and receiver, and no register represents it.
Interface
cmd_valid with cmd_beats requests a burst. core_req asks for one wide word, which must be present on core_data that same cycle. beat_valid, beat_data, beat_index, beat_first and beat_last carry the burst. illegal_cmd and underrun report the two failure classes.
How to simulate it
vlog prefetch_serializer.sv tb_prefetch_serializer.sv then vsim -c tb_prefetch_serializer -do "run -all"; VCS vcs -sverilog prefetch_serializer.sv tb_prefetch_serializer.sv && ./simv; Xcelium xrun -sv prefetch_serializer.sv tb_prefetch_serializer.sv.
// ─────────────────────────────────────────────────────────────────────────
// PREFETCH SERIALIZER. Classification: SYNTHESIZABLE RTL.
//
// The central mechanism of DDR evolution, parameterised so the generations
// differ by a number rather than by a rewrite:
//
// PREFETCH = 2 -> DDR1 (interface clock = array access rate)
// PREFETCH = 4 -> DDR2 (interface clock = 2x array access rate)
// PREFETCH = 8 -> DDR3 (4x) -- and DDR4, which did NOT deepen
// PREFETCH = 16 -> DDR5 (8x)
//
// PREFETCH IS THE FREQUENCY RATIO between the interface and the core, and
// this block is where that ratio is spent: it pulls ONE core word per
// PREFETCH beats, which is the whole width-for-rate trade.
//
// WHAT THIS DOES NOT MODEL: DQS, clock edges, analog data timing, driver
// impedance, ODT or termination of any kind. Beats are successive cycles of
// ONE clock domain -- an honest abstraction of double-edge transfer, for the
// reasons given in Chapter 4.2 Section 5.
// ─────────────────────────────────────────────────────────────────────────
module prefetch_serializer #(
// Width of one external beat: the data-line width.
parameter int DQ_W = 8,
// Prefetch depth. Must be a power of two -- see the elaboration check,
// which explains why that is a real architectural constraint and not a
// convenience of this implementation.
parameter int PREFETCH = 4,
// Longest burst supported, in beats. Must itself be a multiple of
// PREFETCH: a burst that ends mid-word is not expressible.
parameter int MAX_BEATS = 8,
// DERIVED. The core word is PREFETCH beats wide. This single line IS the
// width-for-rate trade, stated as an elaboration fact.
parameter int CORE_W = DQ_W * PREFETCH,
parameter int PHASE_W = (PREFETCH <= 1) ? 1 : $clog2(PREFETCH),
parameter int BEAT_W = (MAX_BEATS <= 1) ? 1 : $clog2(MAX_BEATS)
) (
input logic clk,
input logic rst_n,
// ── Command side.
input logic cmd_valid,
// Beats requested. Legal values: a non-zero multiple of PREFETCH, not
// exceeding MAX_BEATS.
input logic [BEAT_W:0] cmd_beats,
output logic cmd_accept,
// ── Core side: wide, and pulled once per PREFETCH beats. A valid-on-
// request protocol -- core_data must be presented in the SAME cycle
// core_req is high. There is no queueing here, because the rate
// obligation is the thing being taught.
output logic core_req,
input logic core_valid,
input logic [CORE_W-1:0] core_data,
// ── Beat side: narrow, one beat per clock cycle of this domain.
output logic beat_valid,
output logic [DQ_W-1:0] beat_data,
output logic [BEAT_W-1:0] beat_index,
output logic beat_first,
output logic beat_last,
output logic busy,
// A command that cannot be honoured: zero length, over-length, not a
// multiple of PREFETCH, or arriving mid-burst. Reported, never repaired.
output logic illegal_cmd,
// core_req was high and core_valid was not. The burst aborts rather than
// emitting a stale beat.
output logic underrun
);
// ── COMPILE-TIME legality.
//
// PREFETCH must be a power of two. This is NOT an implementation
// convenience: the burst-length alignment check below is a bit test only
// because of it, and real prefetch depths are powers of two for the same
// structural reason -- the prefetch register is sliced by a binary phase
// index, and a non-power-of-two depth would make the slice arithmetic and
// the burst-order arithmetic both irregular.
if (PREFETCH < 1) begin : g_pf_min
initial $fatal(1, "prefetch_serializer: PREFETCH must be >= 1");
end
if ((PREFETCH & (PREFETCH - 1)) != 0) begin : g_pf_pow2
initial $fatal(1, "prefetch_serializer: PREFETCH must be a power of two");
end
if (DQ_W < 1) begin : g_dq_min
initial $fatal(1, "prefetch_serializer: DQ_W must be >= 1");
end
if (MAX_BEATS < PREFETCH) begin : g_mb_min
initial $fatal(1, "prefetch_serializer: MAX_BEATS must be >= PREFETCH");
end
if ((MAX_BEATS % PREFETCH) != 0) begin : g_mb_align
initial $fatal(1, "prefetch_serializer: MAX_BEATS must be a multiple of PREFETCH");
end
// ── State.
// `beats_left` counts beats still to emit INCLUDING the one being
// emitted this cycle, so `beats_left == 1` is the final beat.
logic [BEAT_W:0] beats_left;
logic [PHASE_W-1:0] phase_q;
logic [BEAT_W-1:0] index_q;
logic [CORE_W-1:0] word_q;
logic word_live;
assign busy = (beats_left != '0);
// ── Burst-length legality. The alignment test is a bit test because
// PREFETCH is a power of two. At PREFETCH == 1 every length is aligned,
// and the generate keeps that case from testing a meaningless bit.
logic beats_aligned;
if (PREFETCH == 1) begin : g_align_trivial
assign beats_aligned = 1'b1;
end else begin : g_align_check
assign beats_aligned = (cmd_beats[PHASE_W-1:0] == '0);
end
logic cmd_legal, start_pull, refill;
assign cmd_legal = cmd_valid
&& (cmd_beats != '0)
&& (cmd_beats <= (BEAT_W+1)'(MAX_BEATS))
&& beats_aligned;
// ── The rate relationship, in two signals.
// `start_pull` -- the first word of a burst.
// `refill` -- the final phase of the current word is being emitted
// and beats remain, so the next word is needed NOW.
// A word is pulled on exactly these cycles: ONCE PER PREFETCH BEATS.
logic phase_last;
assign phase_last = (phase_q == PHASE_W'(PREFETCH - 1));
assign start_pull = cmd_legal && !busy;
assign refill = word_live && phase_last && (beats_left > (BEAT_W+1)'(1));
assign core_req = start_pull || refill;
assign cmd_accept = start_pull && core_valid;
// ── Beat outputs. The phase index slices the held core word.
//
// SLICE ORDER IS A CONVENTION OF THIS BLOCK: phase 0 is the least
// significant DQ_W bits. Real burst ordering is a mode-register
// property with sequential and interleaved forms and depends on the
// starting column address -- Module 12 owns it, not this block.
assign beat_valid = word_live;
assign beat_data = word_q[phase_q*DQ_W +: DQ_W];
assign beat_index = index_q;
assign beat_first = word_live && (index_q == '0);
assign beat_last = word_live && (beats_left == (BEAT_W+1)'(1));
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
beats_left <= '0;
phase_q <= '0;
index_q <= '0;
word_q <= '0;
word_live <= 1'b0;
illegal_cmd <= 1'b0;
underrun <= 1'b0;
end else begin
illegal_cmd <= 1'b0;
underrun <= 1'b0;
if (core_req && !core_valid) begin
// ── Supply failure. Abort the burst rather than emit a beat sliced
// from a word that belongs to a completed transfer. A real
// interface committed to a burst CANNOT abort, which is exactly
// why the controller must guarantee supply -- and why this is
// surfaced rather than absorbed.
underrun <= 1'b1;
word_live <= 1'b0;
beats_left <= '0;
phase_q <= '0;
end else if (start_pull) begin
word_q <= core_data;
word_live <= 1'b1;
beats_left <= cmd_beats;
phase_q <= '0;
index_q <= '0;
end else if (word_live) begin
beats_left <= beats_left - (BEAT_W+1)'(1);
index_q <= index_q + 1'b1;
if (phase_last) begin
phase_q <= '0;
if (refill) begin
// Continue seamlessly with the next core word. word_live stays
// high: there is no gap between words in a burst.
word_q <= core_data;
end else begin
// Final beat of the final word: the burst is complete.
word_live <= 1'b0;
end
end else begin
phase_q <= phase_q + 1'b1;
end
end
// Report an unhonourable command. A start mid-burst is a requester
// error; queueing it would hide the fault.
if (cmd_valid && (!cmd_legal || busy)) begin
illegal_cmd <= 1'b1;
end
end
end
endmoduleCombinational logic
beats_aligned enforces that a burst cannot end mid-word — a real architectural constraint, not a simplification: a prefetch of four reads four words, and stopping after three would leave a word partially emitted with nothing to do with the rest. phase_last, start_pull and refill together express the rate relationship, and core_req is their disjunction. beat_data is the slice multiplexer whose ratio is the prefetch depth.
Sequential logic
Three counters with different jobs: beats_left tracks the burst, phase_q tracks position within a core word, index_q tracks position within the burst. The phase_last branch is where the interesting decision lives — finish, or take the next word and continue without a gap.
The branch order matters. The core_req && !core_valid test comes first, so a supply failure aborts before any state advances on stale data.
Cycle trace
DQ_W = 8, PREFETCH = 4, MAX_BEATS = 8. An 8-beat burst, so two core words A and B:
| Cycle | cmd_valid | core_req | phase_q | beats_left | beat_valid | beat_data | beat_last |
|---|---|---|---|---|---|---|---|
| 0 | 1 (8) | 1 (A) | 0 | 0 | 0 | — | 0 |
| 1 | 0 | 0 | 0 | 8 | 1 | A0 | 0 |
| 2 | 0 | 0 | 1 | 7 | 1 | A1 | 0 |
| 3 | 0 | 0 | 2 | 6 | 1 | A2 | 0 |
| 4 | 0 | 1 (B) | 3 | 5 | 1 | A3 | 0 |
| 5 | 0 | 0 | 0 | 4 | 1 | B0 | 0 |
| 6 | 0 | 0 | 1 | 3 | 1 | B1 | 0 |
| 7 | 0 | 0 | 2 | 2 | 1 | B2 | 0 |
| 8 | 0 | 0 | 3 | 1 | 1 | B3 | 1 |
| 9 | 0 | 0 | 0 | 0 | 0 | — | 0 |
Eight beats from two core pulls. core_req is high on exactly two of nine cycles. That 4:1 ratio is the prefetch depth, and it is the whole mechanism — the core side is idle for three of every four beat cycles, which is the headroom the interface spends on frequency.
Simulation
A directed test should sweep PREFETCH over 1, 2, 4, 8 and 16 and check, for each: cmd_beats beats per accepted command; one core_req per PREFETCH beats and no more; beats in slice order across word boundaries; beat_first and beat_last exactly at the boundaries; a misaligned or over-length or zero cmd_beats rejected with illegal_cmd and no beats; and a withheld word producing underrun with the burst aborting rather than continuing.
The sweep is the test that matters most, because the parameterisation is the block's reason for existing and a depth-specific bug will hide at the default.
Synthesis
A multiplexer whose width ratio is PREFETCH, three counters, a comparator and a wide register — small, and it maps well. PREFETCH being a power of two makes the slice select a clean shift and the alignment test a bit test.
The real device also contains everything this block excludes: the driver, the strobe generation, and the analog timing that launches these beats. This block is the digital core of an interface path, not an interface path.
Corner cases
PREFETCH == 1 degenerates to one beat per core word, which is SDR — and the generate guard keeps beats_aligned from testing a meaningless bit at that depth. MAX_BEATS == PREFETCH allows exactly one burst length. cmd_beats not a multiple of PREFETCH is rejected rather than rounded, because rounding would silently transfer a different amount than requested. A command arriving on the final beat is rejected, since busy is still high — back-to-back bursts need an accept-and-reload path, which is a deliberate omission noted in the limitations.
Verification
What DV must prove: the beat count; the pull rate — exactly one core_req per PREFETCH beats, which is the architectural claim; slice ordering across word boundaries; boundary flags; every illegal command reported and none acted on; an aborted burst emitting no beat after underrun; and all of it across the parameter sweep.
Debugging
If every fourth beat is wrong, look at the refill cycle: the new word must be captured on the same cycle the old word's last beat is emitted, and an off-by-one there emits the last beat of word N sliced from word N+1. If beats are right but grouped wrongly, check phase_q resetting on phase_last rather than wrapping a cycle later. If a burst is PREFETCH beats short, check refill's beats_left > 1 test — >= 1 would pull a word that is never used, and > PREFETCH would end one word early. If illegal_cmd never fires on a misaligned length, check that PHASE_W is wide enough for the alignment test at the configured depth.
Limitations
No back-to-back bursts without an idle cycle. No backpressure toward the beat side. No burst ordering modes — slice order is this block's convention. No ODT, no termination, no DQS, no analog anything — §3's electrical half of DDR2 is entirely absent from this block, and correctly so. No column address, no bank state, no row state: the block is told to emit beats and does, with no knowledge of whether the array could have supplied them.
6. Four Assertions Worth Writing
// VERIFICATION-ONLY, inside prefetch_serializer.
// P1 -- THE RATE PROPERTY. A core word is pulled at most once per PREFETCH
// beats. This is the chapter's architectural claim expressed as a checkable
// property, and it is the most valuable assertion in the block: a
// serialiser that pulled a word per beat would pass every count- and
// order-based check while having no prefetch at all.
property p_pull_rate;
@(posedge clk) disable iff (!rst_n)
(core_req && word_live) |-> phase_last;
endproperty
assert property (p_pull_rate);
// P2 -- burst length is exactly as commanded. Counted from the accept, and
// bounded: an unbounded eventuality here would pass a design that never
// finishes, for the reason Chapter 4.1 Section 6 set out.
property p_exact_burst;
logic [BEAT_W:0] n;
@(posedge clk) disable iff (!rst_n)
(cmd_accept, n = cmd_beats)
|=> ##[0:MAX_BEATS-1] (beat_last && (beats_left == (BEAT_W+1)'(1))
&& (index_q == BEAT_W'(n - (BEAT_W+1)'(1))));
endproperty
assert property (p_exact_burst);
// P3 -- ordering. The burst index advances by one per beat with no gap and
// no repeat, ACROSS core-word boundaries. The refill off-by-one from the
// debugging notes delivers the right count and the wrong data, so a
// count-based property cannot see it -- but a broken index can.
property p_index_walks;
@(posedge clk) disable iff (!rst_n)
(beat_valid && !beat_first) |-> (index_q == ($past(index_q) + 1'b1));
endproperty
assert property (p_index_walks);
// P4 -- a burst never ends mid-word. This is the architectural constraint
// beats_aligned enforces, stated independently of the check that enforces
// it: on the final beat the phase must be the last phase of a word.
property p_no_partial_word;
@(posedge clk) disable iff (!rst_n)
beat_last |-> phase_last;
endproperty
assert property (p_no_partial_word);
// P5 -- an aborted burst emits nothing further.
property p_underrun_aborts;
@(posedge clk) disable iff (!rst_n)
underrun |-> !beat_valid;
endproperty
assert property (p_underrun_aborts);P1 is the assertion to learn from. It does not restate the implementation; it states the design's reason for existing. A serialiser that pulled one core word per beat — no prefetch at all, just a wide bus being narrowed wastefully — would satisfy every count, order and boundary property in this list. Only P1 distinguishes a prefetch architecture from a non-prefetch one. When you write assertions, ask which one would fail if the design's central claim were false; if none would, the claim is unverified no matter how many assertions there are.
P4 is the architectural-constraint assertion. It restates §5's alignment rule as a property of the output, independent of the input check that produces it — so a bug in beats_aligned cannot hide behind the same logic that caused it.
What none of them prove. Nothing about data correctness, which needs a scoreboard. Nothing about the array actually having had the data. And nothing whatsoever about ODT, termination, reflections, settling or margin — §3's entire electrical half is outside what any assertion on this block can reach, and that boundary is the most important thing to keep straight when verifying a memory interface.
7. The Prefetch Ratio in Cycles
prefetch_serializer — an eight-beat burst at a prefetch depth of four
10 cyclesLook at core_req, not at the beats. It is high twice in nine cycles. Those two cycles are all the core-side activity an eight-beat burst requires, and the seven idle cycles are the headroom that lets the interface clock run above the array's access rate.
Compare with Figure 2 of 4.2, where a depth of two put the core side to work every other cycle. Doubling the depth halved the core-side duty cycle again. That is the quantity each generation buys, and following it is the cleanest way to see what deepening prefetch actually achieves.
What the figure claims: the pull ratio, the beat ordering across the word boundary, and the burst count. What it does not claim: any relationship to real edges or real time, and nothing at all about termination — §3's half of the chapter is not a waveform-visible phenomenon.
8. The New Costs, and the Next Bottleneck
Cost 1 — granularity doubled again. With a 4n prefetch, four words is the smallest readable quantity. Tracking the number:
minimum granularity = prefetch_depth × interface_width
DDR1: 2n × 8 bits = 2 bytes per device
DDR2: 4n × 8 bits = 4 bytes per device
... and on a 64-bit module:
DDR2: 4n × 64 bits = 32 bytes -- half a typical cache lineNote the second arithmetic. Devices are used in parallel to form a wider interface, so the granularity that a requester sees is prefetch_depth × module_width, not prefetch_depth × device_width. At DDR2 that is half a cache line — still comfortable. One more doubling and it is a whole one. That is 4.4, and the doubling after that is where the trend dies.
Cost 2 — the controller now manages the device's electrical state. ODT is a knob, and knobs need policy. Which device terminates, with what value, on which access, in which direction — all controller decisions, all affecting signal quality rather than functional correctness, and therefore all capable of producing a working-but-marginal system. This is a qualitatively new failure mode: a configuration that is functionally right and electrically wrong.
Cost 3 — termination is uncalibrated. DDR2's on-die resistance varies with process, voltage and temperature, so the realised termination is not the selected termination. At DDR2's rates the resulting variation is tolerable. At higher rates it is not.
And the next bottleneck is that third cost meeting a fourth doubling. Push the prefetch to 8n and the interface clock to four times the array's access rate, and two things break at once.
Uncalibrated termination stops being good enough, because the timing budget has shrunk again and termination variation eats margin directly.
And the bus topology itself becomes the limit. §3 said every attachment on a shared bus is a discontinuity. At DDR2's rates, careful routing and termination manage it. At the next generation's rates, the routing style itself has to change — and the change breaks an assumption so basic that it forces an entirely new category of mechanism: the controller having to measure its own connection to each device.
9. Common Misconceptions
"A deeper prefetch means the memory is faster."
Wrong mental model: prefetch depth is a speed rating.
Engineering action: comparing devices by prefetch depth; expecting a deeper prefetch to reduce latency; assuming a deeper prefetch is strictly better.
Observable failure / bad conclusion: inability to explain why DDR4 kept an 8n prefetch, and mis-prediction of performance on fine-grained scattered access, where a deeper prefetch is a net cost.
Correct model: prefetch depth is the frequency ratio between the interface and the core — depth = transfer_rate ÷ array_access_rate. It is headroom that allows a faster interface; it does not itself make anything faster, it does not reduce latency, and it raises minimum access granularity in direct proportion.
Prevention: ask what the array's access rate is. If it did not change, the prefetch did not make the memory faster — it made a faster interface possible.
"ODT is just a resistor that moved." Wrong mental model: ODT is a repackaging of board-level termination. Engineering action: treating termination as a static board property; not implementing per-access, per-device, per-direction termination policy in the controller; assuming a functionally correct configuration is electrically correct. Observable failure / bad conclusion: a system that works at reduced rate and is marginal at full rate, with no functional error to debug — exactly 4.2 §10's hardest symptom class. The engineer looks for logic bugs in a signal-integrity problem. Correct model: ODT is controllable termination placed at the receiver. The right termination depends on which device is targeted and in which direction, so ODT creates a per-access controller responsibility, not a board property. Prevention: ask who decides, per access, which devices terminate. If the answer is "nobody", the policy is missing.
"Prefetch and burst length are the same thing." Wrong mental model: the prefetch depth is the burst length. Engineering action: assuming a burst must be exactly the prefetch depth, or that any burst length is available. Observable failure / bad conclusion: confusion at DDR3's burst chop — which delivers fewer beats than the prefetch depth — and at DDR4's ability to transfer 8 beats while having 8n prefetch and bank groups. Also a controller that issues burst lengths the device cannot express. Correct model: prefetch depth is how many words one array access produces. Burst length is how many beats one command transfers. A burst is a multiple of the prefetch depth in the simple case — which is why §5's block rejects misaligned lengths — and later generations add mechanisms to transfer less than a full prefetch, at a cost in efficiency because the array read happened anyway. Prevention: ask which side of the prefetch register the number describes. Depth is internal; burst length is external.
"Lower voltage in each generation is just process improvement." Wrong mental model: voltage falls because manufacturing improves. Engineering action: treating the voltage row of a generation table as incidental; not connecting rate increases to power. Observable failure / bad conclusion: inability to explain why LPDDR diverged from the mainstream at all, since on this model it would just be the same parts at lower voltage. And power budgets that omit the rate-versus-swing trade entirely. Correct model: switching energy scales with the square of the voltage swing, and a faster interface switches more often per second. Lowering the swing is how each generation afforded its rate increase — it is causally tied to the rate, not parallel to it. Prevention: multiply the rate increase by the square of the voltage ratio and see whether the interface power stayed bounded. That is the calculation the generation actually made.
10. Debugging — One Device Position Fails and the Others Pass
Symptom. A multi-device memory configuration is functional when a single device is populated, and fails intermittently when fully populated — and the failures concentrate on particular device positions rather than being spread evenly.
Population-dependent, position-dependent failure is a strong signature, because very few mechanisms produce it. Almost nothing in the data path cares how many devices are attached.
Mechanism 1 — termination policy is wrong for the populated configuration. Inspect: the controller's ODT settings per access and per device position, against the number and arrangement of devices actually present. Expected evidence: settings that do not vary with target device or direction, or that were derived for a different population. Discriminator: it depends on population and it is configuration. This is the most likely cause and the cheapest to check, because it is a register-settings review rather than a measurement.
Mechanism 2 — the realised termination differs from the selected termination. Inspect: whether failures correlate with temperature or supply, and whether a different selected value improves them. Expected evidence: a margin that moves with operating conditions. Discriminator: it moves with temperature or voltage. This is DDR2's uncalibrated-termination cost from §8, and it is precisely the gap DDR3's calibration closes — on a DDR3-or-later system, a failure of this shape points instead at calibration having not run or having failed.
Mechanism 3 — reflections from the unterminated or badly terminated stubs. Inspect: whether the failing positions are the electrically most distant or most stub-loaded ones. Expected evidence: failures ranked by physical position on the bus. Discriminator: the position ordering. A policy error affects whichever positions the policy got wrong; a topology problem affects the electrically worst positions, and those are predictable from the layout rather than from the settings.
Mechanism 4 — the command bus, not the data bus. Inspect: whether failures are data corruption or command misinterpretation — a wrong address, an unexpected state. Expected evidence: accesses landing in the wrong place, or devices in unexpected states, rather than wrong data at the right address. Discriminator: is the data wrong, or is the access wrong? The command bus is shared by all devices while the data bus may be organised per device, so a shared-bus integrity problem often shows on the command path first — and this discrimination is frequently missed because both present as "errors".
Mechanism 5 — not electrical at all: a per-device configuration step was skipped. Inspect: whether every populated device received its full initialisation and mode configuration. Expected evidence: one position's configuration registers differing from the others. Discriminator: read back the per-device configuration. A device that was never configured behaves like one that is electrically marginal, and this is the mechanism to eliminate first because it is free to check and embarrassing to miss.
Discrimination, cheapest first. Read back every populated device's configuration — that eliminates mechanism 5 and often mechanism 1 in one pass. Then determine whether failures are wrong-data or wrong-access, which splits the data bus from the command bus. Then rank failing positions by physical layout, which splits policy from topology. Only then measure, and only then vary temperature.
The reasoning lesson. A symptom that depends on how many devices are attached is telling you the mechanism is in the shared environment, not in either endpoint. That single inference eliminates the entire data path — the serialiser of §5, the burst logic, the ordering — and points at termination, topology and the command bus. Engineers who begin by instrumenting the data path are not being careless; they are failing to use the most informative property the symptom has. Ask what the symptom depends on before asking what it looks like.
11. Interview Reasoning
"Why did DDR2 deepen the prefetch instead of transferring more per cycle?" Because a clock cycle has two edges and DDR1 already used both, so transfers-per-cycle was exhausted. The remaining lever is the frequency ratio between the interface and the core, which is exactly what prefetch depth is. A 4n prefetch means the array produces four words per access, so the interface clock can run at twice the array's access rate and still be fed — giving four times the array's access rate in transfers per second. The array's access rate did not change, which is the point: prefetch is how an interface is allowed to outrun an array that cannot speed up.
"What is the relationship between prefetch depth and access granularity?" Minimum granularity equals prefetch depth times interface width, because the array physically reads that many words per access — there is nothing smaller to return. On a single 8-bit device a 4n prefetch means four bytes, which is irrelevant. But devices operate in parallel to form a wider interface, so a requester sees depth times module width: 32 bytes on a 64-bit DDR2 module, half a typical cache line. That number doubles with each prefetch doubling, and when it reaches a full cache line, deepening further means transferring data nobody asked for.
"Why did termination have to move on-die?" Three reasons, all worsening with rate. Position: the optimal termination point is the receiver, and a board resistor sits at the end of a stub that becomes electrically significant as the transfer interval shrinks. Controllability: the correct termination depends on which device is targeted and in which direction, and a fixed resistor cannot express that. Power: a fixed resistor terminates continuously whether or not the device is involved. On-die termination fixes all three, and the controllability is the consequential part — it turns termination into a per-access controller decision.
"What did DDR2's ODT not solve?" Calibration. DDR2 offers selectable termination values, but the realised on-die resistance depends on process, voltage and temperature, so the selected value is not the value you get. At DDR2's rates the variation fits in the margin. At higher rates it does not, which is why DDR3 added calibration against an external precision reference. That is a good example of a generation's feature being the closing of the previous generation's known gap rather than a new idea.
"A memory system works with one device populated and fails with four. Where do you look?" The symptom depends on the shared environment, so the data path is eliminated immediately — a serialiser does not know how many devices are attached. First read back each populated device's configuration, because an unconfigured device mimics an electrically marginal one and it costs nothing to rule out. Then determine whether the failures are wrong data at the right address or accesses landing in the wrong place, because the command bus is shared by all devices while the data path may not be, so shared-bus problems often surface there first. Then rank the failing positions against the physical layout: if the electrically worst positions fail, it is topology and termination; if arbitrary positions fail, it is termination policy — which devices terminate, at what value, in which direction, per access.
12. Engineering Check
An educational DDR2-style device: 8 bits wide, 4n prefetch, array access rate 100 × 10⁶ accesses/s. Educational figures for clean arithmetic, not any real part.
1. What is the interface clock frequency and the transfer rate? The array supplies 100 × 10⁶ accesses/s × 4 words = 400 × 10⁶ words/s. The interface transfers 2 per clock cycle, so the interface clock is 200 × 10⁶ Hz = 200 MHz, and the transfer rate is 400 MT/s. Three different numbers — 100, 200, 400 — for one device, and naming which is which is the skill.
2. Peak bandwidth per device? 400 × 10⁶ transfers/s × 8 bits = 3.2 × 10⁹ bits/s = 400 MB/s.
3. Eight such devices form a 64-bit module. Bandwidth and granularity? Bandwidth is 400 MT/s × 64 bits = 25.6 × 10⁹ bits/s = 3.2 GB/s. Granularity is 4n × 64 bits = 32 bytes. Note that widening the module multiplied both — bandwidth beneficially, granularity as a cost. They are not independent, and that coupling is what eventually ends the prefetch trend.
4. The prefetch is deepened to 8n at the same array access rate. What are the three numbers? Array access rate stays 100 × 10⁶/s, now 8 words wide, giving 800 × 10⁶ words/s. Interface clock becomes 400 MHz, transfer rate 800 MT/s, module bandwidth 6.4 GB/s. The array did not change and the bandwidth doubled — which is precisely why this was the lever of choice for three generations.
5. What did question 4 cost? Granularity became 8n × 64 bits = 64 bytes, exactly one typical cache line. Every access now transfers a full line whether or not one was wanted. And the interface clock doubled, halving the transfer interval again — so termination variation, skew and settling all consume twice as much of the budget as before. Both costs land on the same generation, which is why 4.4 has to solve two things at once.
6. A proposal: 16n prefetch on the same 64-bit module. Why is this the end of the road? Granularity becomes 128 bytes — twice a typical cache line. Every access transfers a line that was wanted and a line that was not, spending interface time and switching energy on data that is discarded. The bandwidth number rises and the useful bandwidth does not. That is the wall, and 4.5 is the chapter about what to do instead: if depth cannot grow, the parallelism has to come from somewhere else in the device.
13. Summary
DDR1 exhausted transfers-per-cycle, because a clock cycle has two edges. DDR2's answer is to spend prefetch on frequency rather than on edges.
Prefetch depth is the frequency ratio between a device's interface and its core — depth = transfer_rate ÷ array_access_rate. A 4n prefetch means the array reads four words per access, so the interface clock can run at twice the array's access rate and the transfer rate at four times it, with no change to the array whatsoever. That reframing turns every generation's prefetch number from trivia into a statement about how far the interface has outrun the array.
The second half of DDR2 is electrical. A memory bus carries several attached devices, each attachment a discontinuity that reflects, and reflections that used to settle between transfers no longer do. On-Die Termination moves the terminating resistance inside the device, at the receiver — and makes it controllable, so the right termination can be applied per access, per device, per direction. That controllability is the consequential part: it is the first time a generation's feature makes the controller responsible for managing the device's electrical state, and that trend continues through every remaining chapter.
Lower voltage is causally tied to the rate increase, not parallel to it: switching energy scales with the square of the swing, and a faster interface switches more often.
Three costs carry forward. Granularity doubled to four words — 32 bytes on a 64-bit module, half a cache line, and doubling again next generation. A new failure mode appeared: configurations that are functionally correct and electrically marginal. And the on-die termination is uncalibrated, so its realised value drifts with process, voltage and temperature — a gap that fits inside DDR2's margin and will not fit inside the next generation's.
14. What Comes Next
Chapter 4.4 takes the prefetch to 8n and the interface clock to four times the array's access rate, and pays for it twice over.
Uncalibrated termination runs out, and the response is a calibration engine on the die working against an external precision reference — the first instance in this module of a device measuring itself.
And the bus routing has to change. Keeping a shared command and clock bus electrically clean at the new rate forces a routing style in which the clock reaches each device at a deliberately different time — which breaks the most basic assumption a synchronous interface has, that the clock arrives when you think it does. The response is that the controller must measure its own connection to each device before it can use it: training. Everything in Modules 19 to 21 descends from that one topology decision.
Return to DDR1 for prefetch and the source-synchronous strobe, SDR SDRAM for the rate vocabulary, or Sense Amplifiers for why the array's access rate is the fixed term in all of this arithmetic. The full path is on the DDR tutorials index.
Continue learning
Related tutorials
- Related topic
ODT — On-Die Termination Control
ODT is a control input selecting whether a device presents termination. Which device should terminate depends on which way data is flowing — and the one rule that never varies is that a driver must not terminate its own output.
- Related topic
Reflections
A reflection is energy that had nowhere to go. It returns after a round trip, so it corrupts a later bit than the one that caused it — and that single fact explains why a training sweep finds a narrow region.
- Related topic
DDR (DDR1)
Double data rate doubles transfer opportunities per clock cycle, not the clock. Two mechanisms make that survivable: a 2n prefetch so a slow array can feed a fast interface, and a source-synchronous DQS strobe so data carries its own timing.
- Related topic
Burst Reads
One read command returns several transfers because the array moves more data per access than the interface is wide. That makes beat counting a correctness obligation, not bookkeeping.
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.
