DDR · Module 10
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.
Beats have been arriving in fours throughout Chapter 10.3 without explanation. This chapter explains them.
One read command produces several transfers. Not one, and not a number the controller chooses per access. The reason is structural, and it is the last piece the read transaction needs:
Why does a single command return multiple beats — and what does a controller have to do about it?
The second half is where the engineering is. Counting returned beats is not bookkeeping. A burst that delivers too few beats leaves a transaction that never completes; one that delivers too many corrupts the transaction after it. Both are silent at every other layer.
1. Why One Command Is Not One Transfer
Start with the mismatch. Two numbers govern a column access, and they are not equal:
How much data the array moves per access. Module 3 established that a column access selects from a row already resolved in the sense amplifiers, and that the internal path is wide — far wider than the pins.
How much data the interface moves per transfer. The device has a fixed number of DQ pins, and a transfer moves that many bits.
The first is much larger than the second, and the ratio is not accidental. Module 4 traced why: each generation raised the interface rate faster than the array could be made faster, and the gap was closed by moving more data per internal access — fetching several interface-widths at once and delivering them over successive transfers.
So a single column access produces more data than one transfer can carry, and the interface delivers it over several. That is the burst, and it is a consequence of the architecture rather than a protocol convenience.
2. The Relationship, and Its Generation-Specific Values
The structural relationship, which holds in every generation:
beats per read = data moved per internal access
────────────────────────────────
data moved per transferThat ratio is what Module 4 calls the prefetch depth, and the number of beats follows from it directly.
The values are generation-specific. Module 4 established these, and they are quoted rather than re-derived:
| Generation | Prefetch | Interface used | Beats | Bytes per access |
|---|---|---|---|---|
| DDR3 | 8n | 64-bit module | 8 | 64 |
| DDR4 | 8n | 64-bit module | 8 | 64 |
| DDR5 | 16n | 32-bit sub-channel | 16 | 64 |
Two things about that table are worth dwelling on.
DDR4 kept DDR3's prefetch depth, breaking a three-generation pattern of doubling — Chapter 4.5 covered why, and the short version is that doubling again would have taken access granularity past a typical cache line.
DDR5 doubled the prefetch and halved the channel width simultaneously, so the bytes per access stayed at 64. Chapter 4.7 derived this: two independent 32-bit sub-channels, each with its own command bus, each delivering 16 beats of 32 bits. The beat count doubled and the granularity did not, which is the entire point of the sub-channel split.
3. What a Controller Must Do About It
The consequence for a read transaction is narrower than it first appears, and it is worth stating exactly.
The controller must know how many beats to expect, and it must count them.
Knowing comes from configuration — the generation, the device, and the mode-register settings, the same source as the latency in Chapter 10.2. It is not discovered from the return.
Counting is the obligation, and it exists because a transaction completes on its final beat. Get the count wrong and one of two things happens:
expected more than arrive → the transaction never completes.
The requester waits forever, and the
next return is mis-attributed to it.
expected fewer than arrive → the transaction completes early, and
the surplus beats become phantoms
(Chapter 10.3) or corrupt the NEXT
transaction.Both failures are silent everywhere else. The commands were correct, the addresses were correct, the data on the bus was correct, and the capture was correct. The only component that can detect either is the one counting, which is why this chapter's block exists and why its assertions are worth more than they look.
4. RTL — Collecting and Validating a Burst
The engineering problem
Receive beats from Chapter 10.3's boundary, count them against the configured expectation, complete the transaction on the final beat, and report every way the burst can be malformed rather than absorbing it.
Why hardware needs it
Transaction completion has to happen somewhere, and it has to happen on evidence. A controller that completes on a timer rather than on a counted final beat cannot distinguish a slow return from a short one.
Classification
SYNTHESIZABLE EDUCATIONAL CONTROLLER RTL. Layer C, above Chapter 10.3's boundary.
What it models
Beat counting against a configured expectation, transaction completion on a validated final beat, and classification of four distinct malformations.
What it does NOT model
Capture (Modules 19 to 21). The boundary (Chapter 10.3). Latency or arrival time (Chapter 10.2) — a burst that arrives at entirely the wrong time but with the right beats passes every check here. Data correctness — it stores no data and compares nothing. Burst ordering, length selection or efficiency (Module 12). Multiple outstanding reads.
Interface and parameter contract
// ─────────────────────────────────────────────────────────────────────────
// read_beat_collector
//
// Classification: SYNTHESIZABLE EDUCATIONAL CONTROLLER RTL.
//
// MODELS: beat counting against a configured expectation, transaction
// completion on a validated final beat, and classification of the four
// ways a burst can be malformed.
//
// IS A BEAT SINK, NOT A SOURCE. Chapter 4.1's sdr_burst_engine PRODUCES a
// beat sequence; this RECEIVES one it did not produce and checks it. A
// block that did both would validate its own output.
//
// DOES NOT SELECT A BURST LENGTH. Chapter 4.4's burst_length_select
// chooses full versus chopped and measures waste. This block is TOLD how
// many beats to expect and has no opinion about the choice (Module 12).
//
// DOES NOT ORDER BEATS OR INTERPRET ADDRESSES (Module 12). It counts; it
// does not know what any beat contains.
//
// DOES NOT CHECK ARRIVAL TIME. A burst arriving at entirely the wrong
// moment with the right beats passes every check here (Chapter 10.2).
//
// MODELS NO PHYSICAL OR ANALOG BEHAVIOUR. It sits above Chapter 10.3's
// boundary and never sees DQ or DQS.
// ─────────────────────────────────────────────────────────────────────────
module read_beat_collector #(
parameter int TAG_W = 3,
// Beats expected per read. A CONFIGURED value, from the generation and
// the mode-register settings in force -- not a property of "DDR", and
// not discoverable from the return (Section 2).
parameter int BEATS_PER_READ = 8,
// DERIVED. Wide enough to hold BEATS_PER_READ ITSELF, hence the +1: the
// counter must represent the completed count, not just the indices.
parameter int CNT_W = (BEATS_PER_READ <= 1) ? 1 : $clog2(BEATS_PER_READ + 1)
) (
input logic clk,
input logic rst_n,
// ── From Chapter 10.3's boundary. Already associated with a tag.
input logic rd_valid,
input logic rd_first,
input logic rd_last,
input logic [TAG_W-1:0] rd_tag,
output logic burst_active,
// Beats received so far in the current burst.
output logic [CNT_W-1:0] beat_count,
// ── Completion. THE event a transaction retires on.
output logic burst_complete,
output logic [TAG_W-1:0] complete_tag,
// ── The four malformations, reported separately because they have
// different causes and different fixes. A single "burst error" would
// be diagnostically useless.
// last asserted before the expected count was reached.
output logic err_early_last,
// a beat arrived after the expected count was already reached.
output logic err_overrun,
// a beat arrived with no burst active and without first.
output logic err_no_first,
// first arrived while a burst was already active.
output logic err_restart
);
if (TAG_W < 1) begin : g_tw
initial $fatal(1, "read_beat_collector: TAG_W must be >= 1");
end
// A zero-beat burst is not a short burst -- it is a read that returns
// nothing, which is not a burst at all. Rejected structurally rather
// than treated as a degenerate case.
if (BEATS_PER_READ < 1) begin : g_bpr
initial $fatal(1, "read_beat_collector: BEATS_PER_READ must be >= 1");
end
logic [CNT_W-1:0] cnt_q;
logic active_q;
logic [TAG_W-1:0] tag_q;
// ── Is this beat the one that should carry last? Compared against the
// count INCLUDING this beat, which is why the counter is sized to
// hold BEATS_PER_READ itself.
logic [CNT_W-1:0] cnt_with_this;
logic at_expected_last;
always_comb begin
cnt_with_this = cnt_q + CNT_W'(1);
at_expected_last = (cnt_with_this == CNT_W'(BEATS_PER_READ));
end
// ── Malformation detection. Combinational, so each is reported in the
// cycle of the offending beat rather than a cycle later.
assign err_no_first = rd_valid && !active_q && !rd_first;
assign err_restart = rd_valid && active_q && rd_first;
assign err_overrun = rd_valid && active_q && (cnt_q >= CNT_W'(BEATS_PER_READ));
assign err_early_last = rd_valid && rd_last && !at_expected_last
&& (active_q || rd_first);
// ── Completion requires BOTH the flag and the count. Either alone is a
// malformation, and requiring both is what makes a short or long
// burst detectable instead of silently accepted.
assign burst_complete = rd_valid && rd_last && at_expected_last
&& (active_q || rd_first);
assign complete_tag = active_q ? tag_q : rd_tag;
assign burst_active = active_q;
assign beat_count = cnt_q;
always_ff @(posedge clk) begin
if (!rst_n) begin
cnt_q <= '0;
active_q <= 1'b0;
tag_q <= '0;
end else if (rd_valid) begin
if (rd_first && !active_q) begin
// Start. The tag is captured here and held for the whole burst,
// so a tag that changes mid-return (Chapter 10.3's P3) cannot
// split one transaction across two completions.
active_q <= 1'b1;
tag_q <= rd_tag;
cnt_q <= CNT_W'(1);
if (at_expected_last && rd_last) begin
// A single-beat burst: BEATS_PER_READ == 1, first and last on
// the same beat. Completes immediately.
active_q <= 1'b0;
cnt_q <= '0;
end
end else if (active_q) begin
if (rd_last && at_expected_last) begin
active_q <= 1'b0;
cnt_q <= '0;
end else if (cnt_q < CNT_W'(BEATS_PER_READ)) begin
cnt_q <= cnt_with_this;
end
// An overrun beat does NOT advance the counter. It is reported and
// ignored, so one malformed burst cannot corrupt the count for the
// next one.
end
// A beat with no active burst and no first is reported by
// err_no_first and changes nothing -- deliberately, so a stray beat
// cannot start a phantom burst.
end
end
endmoduleState representation and transitions
A count, an active flag, and the burst's tag. Three states in effect:
idle --rd_valid & rd_first--> collecting(1)
collecting(n) --beat, n < N--> collecting(n+1)
collecting(N) --rd_last--> idle, burst_completeThe tag is captured at the first beat and held, which is a small decision with a real consequence: Chapter 10.3's P3 forbids the tag changing mid-burst, and this block additionally does not depend on it staying constant — it uses its own captured copy. Two components defending the same property independently is appropriate here, because the failure is silent.
Combinational behaviour
The next-count arithmetic, the expected-last comparison, four malformation terms, and the completion term. burst_complete requires both rd_last and the count, which is the design: either alone would accept a malformed burst.
Sequential behaviour and reset
Nonblocking only. Reset returns to idle with a zero count — so a reset mid-burst abandons the transaction, and the remaining beats then produce err_no_first on each. That is correct and diagnostic: a run of err_no_first immediately after a reset is exactly what an abandoned in-flight burst looks like, and it pairs with Chapter 10.3's phantom-beat signature from the same cause.
Cycle-by-cycle trace
BEATS_PER_READ = 4, TAG_W = 3, tag 2:
| Cycle | rd_valid | first | last | beat_count after | active | complete | Error |
|---|---|---|---|---|---|---|---|
| 0 | 0 | — | — | 0 | 0 | 0 | — |
| 1 | 1 | 1 | 0 | 1 | 1 | 0 | — |
| 2 | 1 | 0 | 0 | 2 | 1 | 0 | — |
| 3 | 1 | 0 | 0 | 3 | 1 | 0 | — |
| 4 | 1 | 0 | 1 | 0 | 0 | 1 | — |
| 5 | 1 | 0 | 0 | 0 | 0 | 0 | no_first |
Cycle 4 is the completion, and it required both the flag and a count of four. Cycle 5 is a stray beat — no burst is active and it does not carry first, so it is reported and changes nothing. It cannot start a phantom burst, which is the point of requiring first.
How to simulate, and expected output
Drive the trace, then each malformation deliberately:
Early last — assert rd_last on beat 2 of 4. err_early_last must assert and burst_complete must not. This is the short-burst case and it is the one most likely to be silently accepted by a naive collector that completes on the flag alone.
Overrun — send a fifth beat after four. err_overrun must assert and the count must not advance.
Missing first — a beat while idle without first. err_no_first, no state change.
Restart — first while a burst is active. err_restart, and note that the current burst is not abandoned, which is a stated choice: abandoning on a suspicious signal would discard a burst that may be fine.
BEATS_PER_READ = 1 — first and last on one beat must complete immediately with no intermediate active state. This exercises the single-beat path inside the start branch, which no other configuration reaches.
Reset mid-burst — confirm idle, zero count, and err_no_first on the remaining beats.
Expected waveform
§5, which shows a clean burst followed by a malformed one.
Synthesis implications
A CNT_W counter, a TAG_W register, one flag, and a handful of comparators — at eight beats and a 3-bit tag, about eight flops. Trivial, and it is the only thing standing between a short burst and a transaction that hangs forever.
Corner cases
BEATS_PER_READ == 1 is legal and handled in the start branch. BEATS_PER_READ == 0 does not elaborate — a read returning nothing is not a degenerate burst, it is a different failure, and treating it as a parameter value would make "no data" a configuration rather than a bug. CNT_W is sized with +1 so the counter can represent the completed count and not merely the indices — the classic off-by-one in this kind of block, and the reason a burst of eight needs four counter bits rather than three. TAG_W == 1 is legal.
Failure modes and debugging clues
burst_complete never asserting with beats arriving means BEATS_PER_READ exceeds what the device actually returns — check the configuration against the mode registers, not against the tutorial. err_overrun in a steady stream means the opposite. err_no_first immediately after a reset is expected, not a defect. err_early_last means the device or the PHY is flagging the last beat at the wrong position, which is a boundary or a configuration problem rather than a counting one.
Extension ideas
Storing the beats rather than only counting them turns this into a reassembly buffer, and the natural width is BEATS_PER_READ × DATA_W — at which point the block delivers one wide word per read instead of a beat stream, which many controllers prefer. Supporting several outstanding bursts requires a count per tag, which is Chapter 10.5's.
Limitations
One burst at a time. It stores no data, so it can say a burst was well-formed and nothing about whether it was correct. It cannot check arrival time. And it trusts BEATS_PER_READ: a collector configured with the wrong expectation reports errors on perfectly good bursts, which is why §9's first check is the configuration.
5. A Burst, in Cycles
read_beat_collector — completion requires the flag and the count
10 cyclesThe first burst completes because both conditions held: the final beat carried last and it was the fourth beat.
The second burst is the instructive one. rd_last arrives on the second beat. A collector that completed on the flag alone would retire the transaction here, hand the requester two beats' worth of a four-beat read, and free the record — after which the real remaining beats, if they arrive, become phantoms at Chapter 10.3's boundary.
Instead err_early_last asserts and burst_complete stays low. The transaction remains outstanding, which is uncomfortable and correct: the controller does not have the data it was asked for, and pretending otherwise converts a detectable fault into silent corruption.
EDUCATIONAL — NOT TO SCALE, NOT JEDEC TIMING. The one-beat-per-cycle cadence is a drawing convenience; §6 is about why it is not the real cadence.
6. Beats Are Not Clock Cycles
A short section that prevents a specific, common off-by-two in trace reading — and it is Chapter 10.2 §3's unit discipline applied to the burst.
A DDR interface performs two transfers per clock period. Module 4 established this and it is the D in DDR. So:
EDUCATIONAL ARITHMETIC — the relationship, not a device figure.
beats in a burst = N
transfers per CK period = 2
CK periods occupied = N / 2
A burst of 8 beats occupies 4 clock periods of transfer opportunity.
A burst of 16 beats occupies 8.Three consequences.
A waveform drawn with one beat per cycle — including §5's — is a readability convention, not the cadence. Drawing beats at the real rate makes a burst half as wide and much harder to annotate, which is why almost every teaching waveform does this. It is also why almost every reader of such a waveform ends up with a factor of two in the wrong place.
Comparing a burst's duration against a latency requires converting one of them. The latency is in clock cycles; the burst is in transfers. Adding them directly is wrong by a factor of two on the burst term.
And the beat count did not change between DDR4 and DDR5 for the reason people assume. DDR5's 16 beats against DDR4's 8 is not twice the data — §2's table shows both delivering 64 bytes, because the sub-channel is half as wide. Twice the beats, half the width, same granularity.
7. Five Assertions Worth Writing
// P1 -- completion requires BOTH the flag and the count. The chapter's
// central contract: a collector that completes on rd_last alone accepts a
// short burst and hands the requester incomplete data, and every other
// layer reports success.
property p_complete_requires_flag_and_count;
@(posedge clk) disable iff (!rst_n)
burst_complete |-> rd_valid && rd_last
&& (beat_count == CNT_W'(BEATS_PER_READ - 1));
endproperty
assert property (p_complete_requires_flag_and_count);
// P2 -- the count never exceeds the expectation. An overrun beat is
// reported and ignored, so one malformed burst cannot corrupt the count
// for the next -- which is what makes a single fault a single fault.
property p_count_never_exceeds_expected;
@(posedge clk) disable iff (!rst_n)
beat_count <= CNT_W'(BEATS_PER_READ);
endproperty
assert property (p_count_never_exceeds_expected);
// P3 -- no beat is accepted outside an active burst. A stray beat cannot
// start a phantom burst, because starting requires rd_first.
property p_no_collection_without_start;
@(posedge clk) disable iff (!rst_n)
(rd_valid && !burst_active && !rd_first) |=> (beat_count == '0)
&& !burst_active;
endproperty
assert property (p_no_collection_without_start);
// P4 -- every malformation is reported. Together with P1 this makes the
// block total: a beat either advances a well-formed burst, completes one,
// or raises exactly one error.
property p_malformations_are_reported;
@(posedge clk) disable iff (!rst_n)
(rd_valid && !burst_complete && !(burst_active || rd_first))
|-> err_no_first;
endproperty
assert property (p_malformations_are_reported);
// P5 -- the tag held for a completion is the tag captured at the first
// beat, not whatever arrived with the last one. This is what stops a
// mid-burst tag change splitting one transaction across two records --
// and it defends the property independently of Chapter 10.3's P3, because
// the failure is silent in both places.
property p_completion_tag_is_the_start_tag;
@(posedge clk) disable iff (!rst_n)
(burst_complete && $past(burst_active))
|-> (complete_tag == $past(complete_tag));
endproperty
assert property (p_completion_tag_is_the_start_tag);What these prove. P1 is the chapter's contract and the one that catches a short burst. P2 bounds the counter and confines a fault to one burst. P3 stops a stray beat manufacturing a transaction. P4 makes the block total — every beat is accounted for. P5 protects the association across the burst, independently of the boundary's own guarantee.
What these do not prove. Nothing here says the data is correct — the block stores no data and compares nothing; that needs a reference model. Nothing says the burst arrived at the right time: a burst delivered at entirely the wrong moment with the right beats and the right flags passes all five, and detecting that requires Chapter 10.2's prediction compared against an observation, which is Chapter 10.5's. Nothing says BEATS_PER_READ is right — a collector configured with the wrong expectation satisfies every property while rejecting perfectly good bursts, which is §9's first check. And nothing proves anything about ordering: the block does not know what any beat contains, so a correctly counted burst in the wrong order is invisible to it, and that is Module 12's.
8. DV — The Four Ways a Burst Goes Wrong
The four error outputs are not a defensive-coding habit; they are four genuinely different faults with different owners.
| Malformation | Likely cause | Owner |
|---|---|---|
| Early last | wrong burst configuration, or a boundary flagging the wrong beat | configuration, or Chapter 10.3 |
| Overrun | expectation configured shorter than the device returns | configuration |
| No first | reset mid-burst, or a phantom return | Chapter 10.2, Chapter 10.3 |
| Restart | a return overlapping another, or a lost last | association, Chapter 10.5 |
A single "burst error" signal collapses that table, and the collapse is expensive: three of the four causes are configuration or upstream-layer problems, and one is a controller defect. Reporting them separately routes the investigation in one glance.
Three further requirements for a read environment:
Count beats independently in the monitor. A monitor that trusts the collector's burst_complete is trusting the component under test to report its own failure. Maintain a separate count from the observed boundary signals and compare — which is the same argument Chapter 9.2 made about two row-context models.
Cover the malformations deliberately. Random stimulus produces well-formed bursts, so a regression with no injected short burst has never exercised P1 — the property that catches the most dangerous fault in this chapter. Error injection here is cheap: suppress a beat, or move a flag.
Check completion count against command count. Over a run, every accepted read should produce exactly one burst_complete. A shortfall means transactions are hanging; a surplus means something is completing twice. This one comparison catches more read-path bugs than any per-beat check, and it needs no per-transaction instrumentation.
9. Debugging — First Beat Correct, Remaining Beats Shifted
Symptom. The first beat of every read carries correct data. Subsequent beats are wrong — frequently they look like data belonging one position earlier or later in the burst, or like the previous read's tail.
Candidate mechanisms.
BEATS_PER_READdoes not match the device's configured burst length, so the collector's notion of where the burst ends is wrong and the next burst's beats are folded into the current one.- The boundary is flagging
firston the wrong beat, so the collection starts one position off and everything after it is shifted. - The PHY's captured beats are themselves misaligned — the capture is off by one transfer position, which is a Module 20 problem and not a counting one.
- Two reads' returns overlap and are being attributed to one transaction —
err_restartis the tell. - The data is correct and the reassembly order above this block is wrong, which is an ordering question and Module 12's.
Evidence to collect. BEATS_PER_READ against the device's programmed mode-register settings — not against what the design's documentation claims. The four error outputs across the failing window. beat_count at each beat. Whether the first beat is correct for every read or only the first read after idle. And whether the shift is consistent in direction and magnitude.
Discriminator.
- Check the configuration first. If
BEATS_PER_READdisagrees with the programmed burst length, mechanism 1, and everything else is a symptom. This is a one-line check and it is the most common cause, so doing it first is not laziness. - Is
err_overrunorerr_early_lastasserting? Either confirms a count mismatch and distinguishes the direction: overrun means the expectation is too short, early-last too long. - Is the first beat correct for every read, or only the first after an idle period? Correct for every read points at a per-burst positional error — mechanisms 1 or 2. Correct only after idle suggests the previous burst is bleeding into the next, which is mechanism 1 or 4.
- Is
err_restartasserting? Mechanism 4 — returns are overlapping, and with one outstanding read that should be impossible, so the association or the admission is at fault. - If the count and the flags are all correct and the data is still shifted, the beats arrived in the order the device sent them and something above reassembled them wrongly — mechanism 5, and Module 12 owns burst ordering. Or the capture itself is misaligned — mechanism 3, and the tell is that the error moves with temperature or after retraining, which a logical fault never does.
Responsible layer. Mechanisms 1 and 4 are layer C. Mechanism 2 is the boundary. Mechanism 3 is below the boundary and goes elsewhere entirely. Mechanism 5 is layer C but a different chapter's subject. The configuration check separates the most likely cause from all the others in one step.
Fix. Per mechanism, and add the completion-count-against-command-count comparison from §8 to the standard report, because it turns "the data looks shifted" into "eleven reads completed for twelve commands" — a far more actionable statement.
10. Common Misconceptions
"One READ command returns one beat."
Why it is tempting: one command, one access, one result feels natural, and every other addressed read the learner has met works that way.
Concrete failure: a controller that retires the transaction on the first beat and drops the rest, or a monitor that expects a single data event and reports every read as having extra data.
Correct model: one command returns as many beats as the prefetch depth implies. §1 and §2.
Prevention: build the collector before the completion logic. A model that counts cannot express "one beat."
"Every DDR generation uses the same burst length."
Why it is tempting: BL8 is quoted so often it reads like a constant of the technology.
Concrete failure: a controller configured for 8 beats against a device returning 16. The first eight beats complete a transaction and the remaining eight become phantoms or corrupt the next read — which is §9's mechanism 1 and is the most common real version of this.
Correct model: generation- and configuration-specific. §2's table, and Module 12 for the full picture.
Prevention: take the number from the programmed mode registers, never from a default.
"BL4, BL8 and BL16 are universal DDR choices."
Why it is tempting: they appear together in summaries as though they were a menu.
Concrete failure: a verification environment parameterised over all three against a generation that does not offer all three, producing configurations that cannot exist and failures that mean nothing.
Correct model: which lengths exist, which are fixed and which are selectable is generation-specific, and Module 12 owns it. This chapter states only what Module 4 verified.
Prevention: scope every burst-length claim to a generation, or do not make it.
"A burst of 8 beats takes 8 clock cycles."
Why it is tempting: teaching waveforms — including §5's — draw one beat per cycle, and the convention is invisible once you are used to it.
Concrete failure: a latency budget that double-counts the burst term, or a trace analysis that looks for the final beat twice as far out as it is.
Correct model: two transfers per clock period, so 8 beats occupy 4 periods. §6.
Prevention: write the units. beats ÷ 2 = CK periods is one line.
"A waveform drawn with four cycles proves a four-cycle JEDEC latency."
Why it is tempting: the waveform is concrete and the number is right there.
Concrete failure: an educational figure is quoted in a design review as a device parameter, and a schedule is built on it.
Correct model: every waveform in this module is labelled educational and not to scale. The real values come from the device's documentation for its configuration, as Chapter 10.2 §2 said.
Prevention: treat any number in a tutorial waveform as illustrative until confirmed against a datasheet — including the ones in this module.
"Burst chop makes small accesses efficient."
Why it is tempting: it transfers fewer beats, so it looks like a saving.
Concrete failure: a performance model that assumes a chopped burst costs half as much everywhere, and cannot explain measurements.
Correct model: Chapter 4.4 §5 established it precisely: chopping halves interface waste and leaves the array's work untouched, because the array performed the full access regardless. It is mitigation, not a solution.
Prevention: separate array work from interface work in any efficiency argument.
11. Interview Reasoning
"Why does one READ command produce a burst?"
Because the array moves far more data per internal access than the interface can carry in one transfer, so the interface delivers what one access produced over several transfer opportunities. The ratio is the prefetch depth, and it exists because each generation raised the interface rate faster than the array could be made faster — closing the gap by fetching more per access rather than by accessing more often. The usual framing, that bursts amortise command overhead, describes a real benefit but reverses the causation: the burst is a consequence of the width mismatch, and the amortisation is what makes it tolerable.
"Does every DDR generation return the same number of beats?"
No. DDR3 and DDR4 both use an 8n prefetch and return 8 beats on a 64-bit module; DDR5 uses a 16n prefetch and returns 16 beats on a 32-bit sub-channel. The point people miss is that DDR5's doubling did not double the data: half the width times twice the beats leaves access granularity at 64 bytes, which was the objective — the granularity is pinned near a cache line and the sub-channel split is what allowed the beat count to rise without it. A controller configured for the wrong beat count is one of the most common real read-path failures, because the first beats look perfectly correct.
"What state does a controller need to track during a burst?"
How many beats it expects, how many it has received, and which transaction they belong to. Completion has to be on evidence — a counted final beat — rather than on a timer, because a timer cannot distinguish a slow return from a short one. And the count needs one more bit than the indices do, since it must represent the completed total rather than the largest index, which is the standard off-by-one in this kind of block.
"What would cause a correct first beat and shifted later beats?"
Most likely a burst-length mismatch: the collector's expectation differs from the device's configured burst, so the boundary between one burst and the next is in the wrong place and the tail of each folds into the head of the next. The first beat is correct because the burst starts correctly. The check is the programmed mode-register setting against the controller's parameter, and it takes one step. The alternatives are a first flag on the wrong beat, a capture misaligned by a transfer position — which is below the boundary and identifiable because it moves with temperature or retraining — or a reassembly-order error above, which is a different module's subject.
"Why is a short burst more dangerous than a long one?"
Because a collector that completes on the last-beat flag alone will accept it. The transaction retires with incomplete data, the requester is handed a partial result as though it were whole, and the record is freed — after which the real remaining beats arrive with nothing outstanding and become phantoms. Every other layer reports success: the command was right, the address was right, the captured data was right. Requiring both the flag and the count is what converts silent corruption into a reported error, and it is one comparator.
12. Engineering Exercise
BEATS_PER_READ = 8, TAG_W = 3.
1. How many clock periods of transfer opportunity does one burst occupy? Show the reasoning.
2. How wide must beat_count be, and why is $clog2(8) the wrong answer?
3. A device is configured for 16 beats and the collector for 8. Trace what happens across two consecutive reads.
4. Beat 3 of 8 carries rd_last. Which outputs assert, and what is the state of the transaction afterwards?
5. With BEATS_PER_READ = 1, walk the start branch and confirm the burst completes correctly.
6. A run reports 4,096 read commands and 4,090 burst_complete events. What are the two likeliest causes and how do you separate them?
13. Summary
One read command returns several beats because the array moves more data per access than the interface carries per transfer. The ratio is the prefetch depth. The command-overhead amortisation is a benefit of that arrangement, not its cause.
The values are generation-specific. DDR3 and DDR4 return 8 beats on a 64-bit module; DDR5 returns 16 on a 32-bit sub-channel — twice the beats, half the width, the same 64 bytes. Which burst lengths exist and which are selectable belongs to Module 12 and to the device's own documentation.
Counting is a correctness obligation. Expect more beats than arrive and the transaction hangs; expect fewer and it completes on partial data while the surplus corrupts the next one. Both are silent at every other layer — correct commands, correct addresses, correct capture.
So completion requires the flag and the count. A collector that retires on the last-beat flag alone accepts a short burst and reports success, which is the most dangerous failure in the chapter and is prevented by one comparator.
Four malformations, reported separately. Early last, overrun, a beat with no start, and a restart — three of which are configuration or upstream problems and one a controller defect. A single "burst error" signal makes that distinction unavailable exactly when it is needed.
And beats are not clock cycles. Two transfers per clock period, so eight beats occupy four periods. Every teaching waveform in this module draws one beat per cycle for readability, including this chapter's — and that convention is where a factor of two enters most trace analysis.
14. What Comes Next
Every piece now exists separately: a transaction created at acceptance, a predicted return, a boundary that delivers beats and refuses phantoms, and a collector that validates the burst.
Chapter 10.5 — Read Timing Analysis puts them together and asks the question none of them can answer alone:
Given a trace, how do you reason from a command to its returned data without confusing the timing domains it crosses?
Because a read spans three of them — the command interface, the source-synchronous return, and the controller's own clock — and the most common analysis errors are not arithmetic but attribution: measuring from the wrong event, comparing a cycle count against a transfer count, or assigning a fault to the layer that reported it rather than the one that caused it.
That chapter builds the end-to-end tracker, the verification-only checker that watches it, and the methodology for reading a real trace — including what to establish about the device's configuration before any number on a waveform means anything at all.
Return to Data Return for the boundary these beats arrive through, CAS Latency for when the first one is due, DDR3 for burst chop and what it does not save, DDR4 and DDR5 for the prefetch evolution behind the beat counts, and SDR SDRAM for the burst engine that generates beats rather than collecting them.
Continue learning
Related tutorials
- Related topic
Burst Writes
A read's controller receives beats as they arrive. A write's controller must produce every beat on consecutive transfer opportunities, without interruption, because the device is sampling on a schedule and will not wait.
- Related topic
Burst Length
Burst length counts transfer positions. It is not a byte count, not a bus width, not a cache line, and not a number of clock cycles — and it is not a free menu you pick from.
- Related topic
SDR SDRAM
Making DRAM synchronous replaced an analog timing negotiation with a clocked contract, which is what made pipelining and counted bursts possible. It also fixes the vocabulary the rest of the curriculum depends on: clock frequency, transfer rate, data rate and bandwidth are four different quantities.
- 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.
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.
