DDR · Module 4
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.
Chapter 4.1 ended with an equation and one untouched term.
peak_bandwidth = ( clock_frequency × transfers_per_cycle ) × width
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^^^
constrained by = 1 for SDR constrained by
array access time NOBODY HAD TOUCHED IT pins, traces,
and bus settling drivers, energyThis chapter pulls that term from one to two. That is the whole of what "double data rate" means, and the rest of the chapter is about what it cost — because doubling transfer opportunities creates two problems that neither the clock nor the array can solve, and the two mechanisms invented to solve them are still present in every DDR generation shipping today.
1. What DDR Doubles, Stated Precisely
A DDR interface performs a data transfer on both the rising and the falling edge of the clock. Two transfer opportunities per clock cycle instead of one.
That is the entire mechanism. Everything else in this chapter follows from it.
So the arithmetic becomes:
transfer_rate = clock_frequency × 2 [MT/s from MHz]
A device whose clock runs at F MHz performs 2F MT/s per data line.And this is where Chapter 4.1 §3's vocabulary earns its keep. A part described by its clock frequency and the same part described by its transfer rate produce two different numbers, and both are in circulation — which is why the field settled on quoting DDR parts in MT/s, and why quoting one in MHz is ambiguous unless you say which quantity you mean.
2. The First Problem — The Array Cannot Keep Up
Doubling transfer opportunities does not double the array's ability to supply data. It never could.
The mismatch is worth stating as a rate comparison. Suppose the interface must emit two data words per clock cycle. Can the array produce two words per clock cycle? Module 3 says no, emphatically: a column access reaches into sense amplifiers that are holding a sensed row, and the internal circuitry that does so operates on a timescale set by the array, not by the interface.
The response is to decouple the two rates by changing the width at which the array is read.
Instead of reading one word per internal access and emitting it in one transfer, the device reads two words per internal access and emits them as two consecutive transfers. The array works at half the rate but twice the width; the interface works at twice the rate but the original width. The product — words per second — matches.
This is prefetch, and the "n" notation names the depth: DDR1 uses a 2n prefetch.
The greyed array block is the point. Nothing inside it changed. The cell, the sensing, the restoration and the row state are exactly as Module 3 left them. Prefetch is a device-architecture change that lets an unchanged array serve a faster interface — and that layer separation is why this module labels every feature.
3. The Second Problem — Timing the Data
The other consequence of doubling transfer opportunities is harder, and its solution is the more far-reaching of the two.
Halving the interval between transfers halves the time available for everything the interface must do in that interval: drive a level onto a line, let it travel and settle, and sample it correctly. The board did not get shorter and the drivers did not get faster. Only the budget shrank.
Now consider how an SDR interface times its data: the shared clock, distributed from the controller to the device. For that to work, the clock's arrival at the sampling point must be known relative to the data's arrival at the sampling point — and those two signals travel different paths, through different drivers, over different traces, into different receivers. The difference between them is skew, and skew does not shrink because the transfer interval did.
When skew becomes a significant fraction of the interval between transfers, a separately distributed clock can no longer reliably time the data. That is not a design flaw to be engineered away; it is arithmetic. A fixed skew against a halving budget eventually wins.
The response is to stop timing data with the clock, and instead send a timing signal alongside the data itself.
That signal is DQS — the data strobe. It is driven by whichever side is driving the data, travels with the data, and is used by the receiving side to capture it. Because strobe and data traverse nearly the same path through nearly the same circuitry, the skew between them is far smaller and far better controlled than the skew between data and a separately distributed clock.
Two properties of DQS are worth naming now, because they matter in every later chapter and their reasons are already available.
It is bidirectional. Reads are driven by the device, writes by the controller. Source-synchronous means the driver supplies the strobe, so DQS is driven by the device on a read and by the controller on a write — which makes it a bidirectional signal with a turnaround, and turnaround costs cycles. Module 12 develops the bus-turnaround cost.
It is a strobe, not a clock. It toggles when data is moving and is otherwise not driven. That is a genuinely different kind of signal from a free-running clock, and it is why a receiver cannot simply lock to it indefinitely — a point that becomes central when Modules 19 to 21 cover PHY training.
And one thing this chapter deliberately does not do: model any of DQS's analog behaviour. Its edge placement relative to data, its centring, its jitter and the margin it leaves are analog timing properties of the PHY, and §5's RTL says so explicitly rather than pretending a register can represent them.
4. The Generation in One Table
Stated as engineering facts, with the layer each one changed:
| Property | SDR baseline | DDR1 | Layer changed |
|---|---|---|---|
| Transfers per clock cycle | 1 | 2 (both edges) | External interface |
| Prefetch depth | 1n | 2n | Device architecture |
| Data timing reference | shared clock | DQS strobe (source-synchronous) | External interface |
| Supply voltage | — | 2.5 V | Interface / device |
| Minimum access granularity | 1 word | 2 words | Consequence of prefetch |
| Array organisation | — | unchanged | none |
The last row is the row that matters most. DDR1's changes are interface and device-architecture changes. The array physics of Modules 2 and 3 are untouched, and they remain untouched through every generation in this module. Every DDR generation is, at bottom, a new way to talk to substantially the same kind of array — which is exactly why Chapter 1.7's argument about DRAM's durability held for decades.
The voltage reduction deserves one sentence of causality, because a voltage row in a generation table is the most common place this module could degenerate into trivia. Switching a signal line dissipates energy that scales with the square of the voltage swing, and an interface performing twice as many transfers per second switches twice as often. Lower voltage is not a separate feature; it is how the interface afforded the higher rate without the power growing proportionally. Chapter 1.6 §5's energy-per-bit framing is the same argument, and 4.7 is the chapter where that constraint becomes the dominant one.
5. RTL — Modelling the Rate Relationship
Problem
A device's core produces PREFETCH words per core-clock cycle, and its interface must emit them as PREFETCH consecutive beats within that same cycle. The rate relationship between the two — and the ordering discipline it requires — is genuine digital logic. The analog launching of those beats is not.
This block models the former and explicitly refuses the latter.
Classification
EDUCATIONAL DIGITAL MODEL. It represents the rate arithmetic of a double-data-rate interface using a single clock domain and a phase index, so the relationship is visible in simulation.
It is not a PHY and must not be read as one. A real DDR interface launches beats relative to DQS edges using analog-timed circuitry — delay elements, duty-cycle correction, phase interpolation, and per-bit deskew. None of that is representable in RTL, and this module does not attempt it. The reason for the substitution is simple and worth internalising: a negedge-triggered flop in a simulator captures none of the properties that make double-edge signalling hard — the halved settling budget, the skew, the jitter, the margin. Writing one would produce code that looks like DDR and teaches nothing about it.
What the model does teach, and what a PHY model could not teach more clearly: that the interface consumes words at PREFETCH times the rate the core supplies them, and that ordering across the phase boundary is a correctness requirement.
Interface
core_valid with core_data supplies one wide word per core cycle. beat_valid, beat_data and beat_phase emit the narrow beats. underrun reports the interface needing a beat the core did not supply.
How to simulate it
vlog ddr_rate_model.sv tb_ddr_rate_model.sv then vsim -c tb_ddr_rate_model -do "run -all"; VCS vcs -sverilog ddr_rate_model.sv tb_ddr_rate_model.sv && ./simv; Xcelium xrun -sv ddr_rate_model.sv tb_ddr_rate_model.sv.
// ─────────────────────────────────────────────────────────────────────────
// DDR RATE MODEL. Classification: EDUCATIONAL DIGITAL MODEL.
//
// WHAT THIS MODELS: the rate relationship between a core that supplies
// PREFETCH words per core cycle and an interface that emits PREFETCH beats
// per core cycle, plus the ordering discipline that relationship requires.
//
// WHAT THIS DOES NOT MODEL, AND CANNOT:
// * DQS edge placement, centring, jitter or duty cycle
// * the analog timing margin of a double-edge interface
// * driver impedance, slew rate, termination or settling
// * any per-bit deskew or training
// All of those are ANALOG PROPERTIES OF THE PHY. A negedge-triggered flop
// would represent none of them while appearing to; the phase index below is
// an honest abstraction instead of a dishonest one.
//
// The real interface emits beat_phase 0 and 1 on opposite clock edges. Here
// they are successive values of a phase counter in ONE clock domain, so the
// ARITHMETIC and the ORDERING are simulable and the analog is absent rather
// than faked.
// ─────────────────────────────────────────────────────────────────────────
module ddr_rate_model #(
// Beats emitted per core cycle. 2 is DDR1's 2n prefetch; later chapters
// raise it, which is the point of making it a parameter.
parameter int PREFETCH = 2,
// Width of ONE external beat, i.e. the data-line width.
parameter int BEAT_W = 8,
// DERIVED. The core word is PREFETCH beats wide -- this is the
// width-for-rate trade of Section 2, expressed as an elaboration fact.
parameter int CORE_W = PREFETCH * BEAT_W,
parameter int PHASE_W = (PREFETCH <= 1) ? 1 : $clog2(PREFETCH)
) (
input logic clk,
input logic rst_n,
// Core side: wide and slow. One word per core cycle when valid.
input logic core_valid,
input logic [CORE_W-1:0] core_data,
// Interface side: narrow and fast. PREFETCH beats per core cycle.
output logic beat_valid,
output logic [BEAT_W-1:0] beat_data,
output logic [PHASE_W-1:0] beat_phase,
// The interface reached a beat the core had not supplied a word for.
// On real hardware this is a scheduling failure upstream, and reporting
// it is more useful than emitting a stale beat.
output logic underrun
);
// ── COMPILE-TIME legality.
if (PREFETCH < 1) begin : g_bad_pf
initial $fatal(1, "ddr_rate_model: PREFETCH must be >= 1");
end
if (BEAT_W < 1) begin : g_bad_bw
initial $fatal(1, "ddr_rate_model: BEAT_W must be >= 1");
end
logic [CORE_W-1:0] word_q;
logic word_live;
logic [PHASE_W-1:0] phase_q;
// ── Beat selection. The core word is sliced into PREFETCH beats and the
// phase index chooses one. Ordering is LOW SLICE FIRST: the beat at
// phase 0 is the least significant BEAT_W bits.
//
// THIS ORDERING IS A CONVENTION OF THIS MODEL, not a statement about
// any device's burst ordering. Real burst order is a mode-register
// property with sequential and interleaved forms, and it depends on the
// starting column address -- Module 12's subject, not this model's.
always_comb begin
beat_data = word_q[phase_q*BEAT_W +: BEAT_W];
end
assign beat_valid = word_live;
assign beat_phase = phase_q;
// The last phase of a word: the cycle on which a fresh core word must
// already be available if the stream is to continue without a gap.
logic phase_last;
assign phase_last = (phase_q == PHASE_W'(PREFETCH - 1));
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
word_q <= '0;
word_live <= 1'b0;
phase_q <= '0;
underrun <= 1'b0;
end else begin
underrun <= 1'b0;
if (!word_live) begin
// Idle: accept a word and start emitting from phase 0.
if (core_valid) begin
word_q <= core_data;
word_live <= 1'b1;
phase_q <= '0;
end
end else if (phase_last) begin
// Final beat of the current word is being emitted THIS cycle. To
// continue seamlessly the next word must be presented now.
phase_q <= '0;
if (core_valid) begin
word_q <= core_data;
word_live <= 1'b1;
end else begin
// No word: stop cleanly rather than re-emit stale data. A real
// interface committed to a burst cannot stop -- which is exactly
// why the controller must guarantee supply, and why this is
// reported rather than absorbed.
word_live <= 1'b0;
underrun <= 1'b1;
end
end else begin
// Mid-word: advance the phase. The core supplies nothing during
// these cycles, which IS the rate relationship being modelled.
phase_q <= phase_q + 1'b1;
end
end
end
endmoduleCombinational logic
beat_data slices the held core word by the phase index — a multiplexer whose width ratio is the prefetch depth. phase_last identifies the cycle on which a replacement word must already be present, which is the model's expression of the supply obligation.
Sequential logic
word_q holds the wide word for its full emission period. phase_q walks the beats. word_live gates everything. The interesting line is the phase_last branch: it must both finish the current word and accept the next in the same cycle, or a gap appears.
Cycle trace
PREFETCH = 2, BEAT_W = 8, so CORE_W = 16. The core presents 0xBBAA then 0xDDCC, with a gap after:
| Cycle | core_valid | core_data | phase_q | beat_valid | beat_data | underrun |
|---|---|---|---|---|---|---|
| 0 | 1 | BBAA | 0 | 0 | — | 0 |
| 1 | 1 | DDCC | 0 | 1 | AA | 0 |
| 2 | 0 | — | 1 | 1 | BB | 0 |
| 3 | 0 | — | 0 | 1 | CC | 0 |
| 4 | 0 | — | 1 | 1 | DD | 0 |
| 5 | 0 | — | 0 | 0 | — | 1 |
Two beats per core cycle, four beats from two core words. The core supplied data on two cycles; the interface emitted on four. That two-to-one ratio is the whole of what double data rate does, and the underrun at cycle 5 is the obligation it creates: the core must keep up, and there is no mechanism by which the interface can wait.
Simulation
A directed test should present a stream of core words and check PREFETCH beats per word, in slice order, with the phase index cycling; then withhold a word and confirm underrun asserts exactly once rather than the previous word being re-emitted.
Synthesis
The logic is synthesizable — a register, a multiplexer and a counter — but synthesising it would not produce a DDR interface. It produces a single-clock-domain serialiser. The real function requires PHY circuitry outside RTL's expressive range, and that gap is the point of the classification.
Corner cases
PREFETCH == 1 degenerates to a pass-through, one beat per core cycle — which is SDR, and the model reproducing 4.1 at that parameter value is a useful self-check. PREFETCH == 1 also gives PHASE_W == 1 through the guard rather than $clog2(1) == 0. A core_valid presented mid-word is ignored, not queued, so an upstream block must present the next word on the phase_last cycle.
Verification
What DV must prove: exactly PREFETCH beats per accepted core word; beats in slice order with the phase index matching; no beat emitted without a word behind it; a withheld word producing exactly one underrun and no stale beat; and the degenerate PREFETCH == 1 case behaving as a pass-through.
Debugging
If every second beat is wrong, check the slice direction — word_q[phase_q*BEAT_W +: BEAT_W] against a descending alternative — because a reversed slice produces beats that are individually valid and collectively transposed, which a per-beat check will not catch. If beats repeat, check that phase_q resets on the phase_last cycle rather than wrapping a cycle later. If underrun never fires, check that the phase_last branch tests core_valid rather than assuming supply.
Limitations
It is not a PHY, and the header says so at length. No DQS, no edges, no analog timing, no margin, no training, no skew. No backpressure toward the core. No burst ordering modes — the slice order is this model's convention, and Module 12 owns the real thing. And the phase index is a stand-in for opposite clock edges, which is the deliberate abstraction that keeps the model honest.
6. Three Assertions Worth Writing
// VERIFICATION-ONLY, inside ddr_rate_model.
// P1 -- a beat is emitted only while a word is live. Forbids the stale-beat
// failure that `underrun` exists to prevent: emitting from a register whose
// contents belong to a completed word.
property p_beat_needs_word;
@(posedge clk) disable iff (!rst_n)
beat_valid |-> word_live;
endproperty
assert property (p_beat_needs_word);
// P2 -- the phase advances by one per beat and wraps only at the last.
// This is the ORDERING property, and it is separate from any count: the
// reversed-slice and late-wrap bugs in the debugging notes both deliver the
// right NUMBER of beats.
property p_phase_walks;
@(posedge clk) disable iff (!rst_n)
(beat_valid && $past(beat_valid) && !$past(phase_last))
|-> (phase_q == ($past(phase_q) + 1'b1));
endproperty
assert property (p_phase_walks);
property p_phase_wraps_only_at_last;
@(posedge clk) disable iff (!rst_n)
(beat_valid && $past(beat_valid) && (phase_q == '0))
|-> $past(phase_last);
endproperty
assert property (p_phase_wraps_only_at_last);
// P3 -- THE RATE RELATIONSHIP ITSELF. The held core word changes only at a
// word boundary, so one word feeds PREFETCH beats. This encodes the
// CHAPTER'S CLAIM rather than a local invariant, and it is what
// distinguishes a genuine prefetch model from a pass-through that consumes
// a word per beat.
property p_word_changes_only_at_boundary;
@(posedge clk) disable iff (!rst_n)
(word_live && $past(word_live) && (word_q != $past(word_q)))
|-> $past(phase_last);
endproperty
assert property (p_word_changes_only_at_boundary);
// KNOWN INCOMPLETENESS, and it is worth stating rather than hiding: the
// antecedent is DATA-DEPENDENT. Two consecutive core words carrying
// identical values do not trigger it, so the property cannot see a
// mis-timed refill between them. A data-dependent antecedent is a common
// and easily-missed weakness -- the fix is a constrained-random stimulus
// that never presents equal consecutive words, not a stronger property.
// P4 -- underrun implies the stream stopped, never that it continued with
// stale data. Makes "report, never repair" checkable.
property p_underrun_stops_cleanly;
@(posedge clk) disable iff (!rst_n)
underrun |-> !beat_valid;
endproperty
assert property (p_underrun_stops_cleanly);What these prove. P1 and P4 together forbid stale beats. P2 is the ordering half that a count-based check misses.
P3 is the one to notice, for two reasons. It asserts the rate relationship — the property the chapter is about — rather than a local implementation invariant, and assertions that encode the design's claim are worth more than assertions that restate its code. But it also carries a data-dependent antecedent: it fires only when the held word's value changes, so two consecutive words with identical contents slip past it.
That weakness is worth more attention than the property. A data-dependent antecedent produces an assertion that passes not because the design is right but because the stimulus never distinguished the cases — and it reports coverage it does not have. The remedy is in the testbench, not the property: constrain the stimulus so consecutive core words are never equal. When an assertion's antecedent depends on data, its strength depends on the stimulus, and the two must be reviewed together.
What none of them prove, and this is the important limitation. Nothing here says anything about the real interface's correctness, because the real interface's difficulty is analog: whether the strobe is centred in the data window, whether the margin survives jitter and skew, whether the eye is open. No assertion on this model can address any of that. Verifying a DDR interface's timing is a PHY and signal-integrity activity using analog and mixed-signal methods, and treating simulable assertions as coverage of it is the single most dangerous abstraction error in this domain.
7. The Rate Relationship in Cycles
ddr_rate_model — two core words become four beats, then an underrun
10 cyclesCycles 0 and 1 — two core words. The core is active on two cycles only. That is all the supply this burst gets.
Cycles 1 to 4 — four beats. Two phase bands, two beats each. The phase index alternates 0, 1, 0, 1 — and in a real device those alternating phases are the rising and falling edges of one clock cycle, which is what the model abstracts.
Cycle 5 — the obligation made visible. No third word arrived, so underrun asserts and the stream stops. A real interface mid-burst cannot stop, which is precisely why the controller must guarantee supply — and why Module 17's controller is built around committed transfers.
What this figure claims and does not claim. It claims the rate ratio, the ordering, and the supply obligation. It claims nothing about when within a cycle a beat is launched, because that is the analog question §6 said assertions cannot reach.
8. The New Cost, and the Next Bottleneck
DDR1 bought a doubling of transfer rate at no cost in pins and no change to the array. Three costs came with it, and one of them sets up the next chapter.
Cost 1 — the timing budget halved, permanently. Every subsequent generation inherits a data path whose transfer interval is half a clock period, and every subsequent generation must find more margin in it. The source-synchronous strobe bought margin once. It cannot be re-bought.
Cost 2 — access granularity doubled. A 2n prefetch means two words is the smallest readable quantity. At this depth it is harmless. It does not stay harmless, and tracking it is how you predict the whole rest of the module:
minimum access granularity = prefetch_depth × interface_width
DDR1: 2n × 8 bits = 2 bytes -- trivially small
DDR3: 8n × 8 bits = 8 bytes -- still under a cache line
DDR4: 8n × 64 bits = 64 bytes -- EXACTLY one typical cache lineThat last line is the whole reason 4.5 exists. Once granularity reaches the size of the thing the requester actually wants, deepening prefetch stops helping and starts wasting — and a different lever has to be found. Watch this number across the next three chapters; it is the module's most predictive quantity.
Cost 3 — the interface, command path and array now run at three different rates. Data at 2F, commands at F, the array slower still. Every DDR device since has this internal rate hierarchy, and most of the complexity in Modules 13 and 14's timing parameters exists to manage the boundaries between those rates.
And the next bottleneck. The same pressure that produced DDR1 did not stop. Bandwidth demand kept growing, the clock was still constrained by array access and bus settling, and width was still expensive. But now there is a second lever alongside transfers-per-cycle — one the 2n prefetch just demonstrated works.
Transfers per cycle cannot go past two, because a clock cycle has exactly two edges. So the lever that remains is prefetch depth: read more words per array access, and let the interface run faster still against the same internal access rate. Chapter 4.3 does exactly that — and adds a second change, because raising the rate on a bus with multiple attached loads breaks in a way that has nothing to do with prefetch.
9. Common Misconceptions
"DDR doubles the clock frequency." Wrong mental model: DDR is a clock change. Engineering action: assuming everything in the device runs at the doubled rate; budgeting the command path and internal logic at twice the frequency; reading a device's MT/s figure as a clock frequency. Observable failure / bad conclusion: a factor-of-two error in the opposite direction from 4.1 §9's — over-budgeting the command path and mis-deriving cycle counts for every timing parameter in Modules 13 and 14. The engineer also cannot explain why prefetch is needed at all, since a genuinely doubled clock would need no rate adaptation. Correct model: the clock frequency is unchanged. Transfer opportunities per clock cycle went from one to two, on the data lines only. The command path still moves one command per cycle and the array is unchanged. Prevention: the existence of prefetch is the proof. If the clock had doubled, nothing would need a width-for-rate trade.
"Prefetch is a cache, or a prediction."
Wrong mental model: the device fetches data it guesses will be needed.
Engineering action: reasoning about prefetch hit rates; expecting locality to affect whether prefetch "works"; expecting a deeper prefetch to be strictly better.
Observable failure / bad conclusion: complete inability to explain 4.5 — why DDR4 stopped deepening prefetch — because on a cache model, deeper is always better. Also mis-modelling access granularity, which is the cost that actually decides the question.
Correct model: prefetch is a rate adaptation, an arithmetic trade of internal width for external rate: internal_width × internal_rate = external_width × external_rate. It predicts nothing and stores nothing for later. Its cost is a minimum access granularity equal to depth × width.
Prevention: ask what happens when the requester wants less than the prefetch depth. On a cache model, nothing. In reality, the excess is transferred and discarded — which is the cost that stops the trend.
"DQS is just another clock." Wrong mental model: DQS is a second clock signal. Engineering action: treating it as free-running; expecting a receiver to lock to it continuously; ignoring the turnaround between read and write direction. Observable failure / bad conclusion: mis-modelling bus turnaround cost in a controller, and complete confusion when Modules 19 to 21 cover training — a free-running clock would not need per-direction, per-rank training. Correct model: DQS is a source-synchronous strobe. It is driven by whichever side drives the data, it toggles only when data moves, it is otherwise not driven, and it therefore has a direction and a turnaround. Prevention: ask who drives it. A clock has one driver; DQS has two, at different times.
"Prefetch makes the memory faster." Wrong mental model: prefetch is a performance feature. Engineering action: expecting a deeper prefetch to reduce latency, or to improve performance on access patterns that do not use the whole prefetched quantity. Observable failure / bad conclusion: predicting a benefit from DDR4 deepening its prefetch — which it did not do, for exactly this reason. And mis-predicting performance on fine-grained scattered access, where deeper prefetch is a cost, not a benefit. Correct model: prefetch makes the interface able to run faster than the array. It changes neither the array's access time nor the latency to the first beat. It is what makes a higher external rate possible; it does not itself make anything faster. Prevention: separate "what rate can the interface sustain" from "how long until the first beat arrives" from "how much of what was transferred was wanted". Prefetch affects the first, never the second, and harms the third.
10. Debugging — Data Is Correct at Low Rate and Corrupt at High Rate
Symptom. A DDR interface is functionally correct at a reduced transfer rate. At the intended rate, data is intermittently corrupt — not absent, not all-wrong, but wrong in a rate-dependent, pattern-dependent way.
Rate-dependent corruption is the signature of a margin problem rather than a logic problem, and the first job is to decide which layer owns it. This is the most important discrimination in DDR debug, and getting it wrong wastes weeks.
Mechanism 1 — the strobe is not centred in the data window. Inspect: the PHY's read and write timing calibration results, and the margin reported at the current rate. Expected evidence: margin collapsing as the rate rises, with a systematic offset between the strobe's sampling point and the centre of the data window. Discriminator: it scales with rate and it is analog. Corruption that disappears at a lower rate and returns at a higher one, with no change in any logic, is a timing-margin mechanism. This is the most likely cause and is the subject of Modules 19 to 21.
Mechanism 2 — per-bit skew across the data lines. Inspect: which bit lanes corrupt. Expected evidence: errors concentrated in particular lanes rather than spread uniformly. Discriminator: the lane distribution. A shared timing problem affects all lanes similarly; per-lane skew affects the lanes with the worst path. Correlating failing lanes against physical trace lengths often settles it in one look.
Mechanism 3 — beat ordering, not beat corruption. Inspect: whether the bytes are individually correct but in the wrong order within a burst. Expected evidence: every byte present, positions transposed — the reversed-slice bug §5's debugging notes describe. Discriminator: is any byte value wrong, or only its position? This is crucial, because ordering is a logic bug that will never be fixed by timing work. It can look rate-dependent if it only manifests in a faster access path.
Mechanism 4 — the supply cannot keep up. Inspect: the underrun condition §5 models — whether the data path can present words at the rate the interface consumes them. Expected evidence: corruption correlated with burst position, typically the later beats, and correlated with contention upstream. Discriminator: burst position. A margin problem is roughly uniform across a burst; a supply problem concentrates at the end of one.
Mechanism 5 — signal integrity on a loaded bus. Inspect: the number of attached loads and the termination arrangement, and whether corruption depends on how many devices are present. Expected evidence: corruption that changes with population. Discriminator: does changing the load change the symptom? This mechanism is the reason 4.3 exists, and it is the one that a single-device test bench will never reproduce.
Discrimination, cheapest first. Check ordering first: read a known pattern and ask whether any byte value is wrong or only its position. That single check separates a logic bug from every timing mechanism, costs nothing, and is skipped surprisingly often. Then check the lane distribution, which splits shared timing from per-lane skew. Then correlate against burst position, which splits margin from supply. Only then engage with analog margin and calibration.
The reasoning lesson. Rate-dependent corruption invites you to assume an analog cause, and that assumption is right often enough to be dangerous. An ordering bug, a supply bug and a margin problem can all present as "works slow, fails fast" — but they live in different layers and only one of them responds to calibration. Establish which layer owns the symptom before engaging with the hardest one, because the analog layer is where the expensive equipment and the long weeks are, and arriving there with a logic bug in hand is the classic way to lose a schedule.
11. Interview Reasoning
"What does double data rate double?"
Transfer opportunities per clock cycle, on the data lines — one per clock edge instead of one per cycle. Not the clock frequency: the command path still moves one command per cycle and the array is unchanged. The proof that the clock did not double is that prefetch exists at all; a genuinely doubled clock would need no width-for-rate adaptation to feed it. The arithmetic is transfer_rate = clock_frequency × 2, which is why DDR parts are quoted in MT/s rather than MHz.
"Why does DDR need prefetch?"
Because the array cannot supply data at the rate the interface consumes it, and no interface decision changes that — sensing takes the time regeneration takes. Prefetch resolves the mismatch by trading internal width for external rate: the array reads two words per internal access and the interface emits them as two consecutive transfers, so 2 words × F accesses/s balances 1 word × 2F transfers/s. It is a rate adaptation, not a cache and not a prediction, and its cost is that two words becomes the minimum readable quantity.
"Why is a strobe better than a clock for timing data?" Because of which skew the timing budget has to absorb. A distributed clock and the data it times travel different paths through different drivers and receivers, so the budget must absorb the full skew between those paths — and that skew does not shrink when the transfer interval halves. A strobe driven by the same side that drives the data, over nearly the same path, leaves only the much smaller strobe-to-data skew in the budget. That is source-synchronous timing, and every DDR generation since uses it.
"What is the cost of a deeper prefetch?" Access granularity. Minimum granularity is prefetch depth times interface width, so a deeper prefetch means a larger smallest-possible access. At DDR1's 2n it is two words and irrelevant. By DDR4 it is 64 bytes on a 64-bit interface — exactly one typical cache line — at which point deepening further would transfer twice what the requester wanted, spending time and energy on data that is discarded. That is why prefetch depth stopped growing at DDR4 and a different lever was used instead.
"A DDR interface works at half rate and fails at full rate. Where do you look first?" Not at the analog layer, even though that is where the cause usually is. First read back a known pattern and ask whether any byte value is wrong or whether the bytes are all present in the wrong order — because an ordering bug is a logic bug that presents identically and will never respond to calibration. Then check whether errors cluster in particular lanes, which separates shared timing from per-lane skew, and whether they cluster at the end of bursts, which separates margin from a supply shortfall. Those three checks are free and they determine which layer owns the problem; only then is it worth engaging with calibration and margin, which is where the time and equipment go.
12. Engineering Check
An educational DDR interface is clocked at 100 MHz, is 8 bits wide, and uses a 2n prefetch. Educational figures for clean arithmetic, not any real part.
1. What is the transfer rate per data line? 100 × 10⁶ cycles/s × 2 transfers/cycle = 200 × 10⁶ transfers/s = 200 MT/s. Note that the MHz and MT/s numbers now differ, which is the coincidence 4.1 warned would end.
2. Peak bandwidth? 200 × 10⁶ transfers/s × 8 bits = 1.6 × 10⁹ bits/s = 200 MB/s.
3. Compare with an SDR interface at the same clock and width. SDR gives 100 MT/s and 100 MB/s. DDR gives twice the bandwidth at the same clock frequency and the same pin count — which is the entire commercial argument, and why the transition happened.
4. How many words per second must the array supply, and how wide is each internal access? The interface consumes 200 × 10⁶ 8-bit words per second. With a 2n prefetch the array performs 100 × 10⁶ accesses per second, each 16 bits wide. The array's access rate equals the clock frequency, not the transfer rate — that is what prefetch bought, and it is the number to hold onto.
5. What is the minimum access granularity, and is it a problem here? 2 × 8 bits = 2 bytes. Not a problem: a requester almost always wants at least that. But note the formula, because §8 showed it reaching a cache line by DDR4 — and at that point it becomes the constraint that ends the trend.
6. A proposal: keep 100 MHz and 8 bits, but use a 4n prefetch with four transfers per clock cycle. What breaks? The prefetch is fine — the array would read 32 bits per access at 50 × 10⁶ accesses per second, and the arithmetic balances. What breaks is "four transfers per clock cycle": a clock cycle has two edges. There is no third or fourth edge to transfer on. So a 4n prefetch cannot be spent on more transfers per cycle; it must be spent on a higher clock frequency for the interface than the array's access rate — which is precisely what 4.3 does, and why the generations after DDR1 raise the interface clock while the array's access rate barely moves.
13. Summary
DDR doubles transfer opportunities per clock cycle — one per clock edge — on the data lines only. It does not double the clock. The command path still moves one command per cycle, the array is unchanged, and the proof that the clock did not double is that prefetch had to be invented to feed the interface.
Two mechanisms make the doubling survivable, and both persist in every DDR generation since.
A 2n prefetch resolves the rate mismatch between a slow array and a fast interface by trading internal width for external rate: internal_width × internal_rate = external_width × external_rate. It is a rate adaptation, not a cache and not a prediction. Its cost is a minimum access granularity of prefetch_depth × interface_width.
A source-synchronous strobe (DQS) resolves the timing problem. Halving the transfer interval does not halve the skew between a separately distributed clock and the data it times, so eventually that skew consumes the budget. Sending a strobe with the data leaves only the much smaller strobe-to-data skew to absorb. DQS is driven by whichever side drives the data, so it is bidirectional and has a turnaround — a strobe, not a clock.
The costs set up the rest of the module. The transfer interval is now permanently half a clock period, so every later generation must find margin in a budget that was already halved. Access granularity has started growing and will eventually reach the size of a cache line. And the device now runs at three different rates internally — data, commands, array — which is where most of the timing complexity of later modules comes from.
And the next bottleneck is structural. Transfers per cycle cannot exceed two, because a clock cycle has two edges. The lever that remains is prefetch depth, which lets the interface clock run faster than the array's access rate.
14. What Comes Next
Chapter 4.3 deepens the prefetch to 4n and raises the interface clock above the array's access rate — the first generation in which the interface and the core are genuinely decoupled in frequency, not merely in width. Its RTL is this module's flagship: a fully parameterised prefetch adaptation whose depth, core width and interface width are independent, so the trade becomes something you can vary and observe rather than read about.
It also confronts a problem that has nothing to do with prefetch. Raising the signalling rate on a bus with multiple attached devices fails for reasons of reflection and settling rather than of logic or of rate arithmetic — and the response, moving termination onto the die itself, is the first time in this module that a generation's defining feature is about the electrical environment rather than the data path.
Return to SDR SDRAM for the baseline and the rate vocabulary, Sense Amplifiers for why the array's access time is what it is, or Memory Matrices and Hierarchy for the device this interface fronts. The full path is on the DDR tutorials index.
Continue learning
Related tutorials
- Related topic
DQS — The Data Strobe
DQS carries the data's own timing reference along the same path as the data. It is directional, it is not free-running, and the strobe window is wider than the data window — three facts that make it nothing like CK.
- Related topic
Data Return
During a read the DRAM drives the bus and supplies the timing reference. Controller RTL never sees that — it receives already-captured beats from a boundary it must not cross.
- Related topic
Source-Synchronous Interfaces
Sending a strobe with the data does not remove timing uncertainty. It replaces an unanswerable question about absolute arrival with a bounded one about relative arrival — and that residual budget is what the rest of the module spends.
- Related topic
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.
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.
