DDR · Module 10
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.
Chapter 10.1 created a transaction. Chapter 10.2 taught the controller when to expect its data. Neither said what actually arrives, or from where.
This chapter does, and it turns on a reversal that is easy to state and easy to model wrongly:
During a read, the DRAM drives the data bus — and supplies the timing reference that goes with it.
That is the opposite of a write, and it has two consequences that shape everything downstream. The data is accompanied by a strobe the device generated, not the controller's clock. And capturing data against a strobe that arrived from the far end of a channel is a specialised problem that ordinary controller RTL cannot express.
So the chapter's question is really two:
Who drives what during a read — and where does controller RTL stop?
The second question matters more than it sounds. The code people write when they misplace that boundary compiles, simulates, and models nothing.
1. The Reversal
Chapter 6.9 established that DQ is bidirectional and that exactly one side may drive it at a time. This chapter applies that to a transaction, where it produces a sequence worth stating carefully:
at the command: the controller's side drives the command/address
interface. The DRAM drives nothing.
during the gap: nobody drives the data bus. The transaction exists
only in the controller's record.
at the return: THE DRAM drives DQ, and drives DQS with it.
The controller's side must not be driving.
after the burst: the DRAM stops driving. Ownership is available again.Two things about that sequence are worth dwelling on.
The direction of the command and the direction of the data are opposite. A read is a request sent one way and satisfied the other. That is unremarkable until you notice that the bus has to change hands in between, and that the change is not signalled — it is scheduled, by both ends independently, from a latency they each derived from the configuration. Chapter 6.9's contention output exists because that scheduling can be wrong.
The strobe travels with the data, so it changes hands too. Chapter 6.10 established that the strobe's ownership follows the data's direction exactly — a strobe with a different owner from the data it times would not be source-synchronous at all. For a read, both come from the device.
2. Why the Reference Comes From the Far End
Chapter 6.10 derived the existence of a strobe. This section adds the one thing a read transaction needs from it, and no more.
The problem is that the data and any clock-based reference take different paths. The command travelled to the device; the data travels back. Package, board and channel delays apply to each, and they are not the same and not perfectly known. A receiver timing the returned data against its own clock would be timing it against a reference that never experienced the return path.
A source-synchronous strobe removes the question. It is launched by the same device, from the same output circuitry, at the same time as the data, and travels the same path. Whatever delay the data experienced on the way back, the strobe experienced too — so their relationship survives the journey even though neither one's relationship to the receiver's clock does.
That is the entire reason a read's timing reference comes from the far end, and it is enough for this chapter.
What it is not enough for is actually capturing the data, which needs the strobe positioned correctly relative to the data it times, and that positioning is neither free nor fixed. It depends on the device, the channel, the temperature and the voltage, and it is established and maintained by mechanisms that Module 20 and Module 21 own. This chapter stops at "a returned strobe makes capture possible."
3. Where Controller RTL Stops
Here is the boundary, and it is the most practically important content in the chapter.
Below the boundary the problem is electrical and temporal: a strobe arriving with an unknown phase relative to anything the receiver knows, data that must be sampled in a window narrower than a clock period, a channel whose delays drift with temperature and voltage, and a mechanism to discover and track the right sampling position. None of that is expressible in ordinary synchronous RTL, and the attempt is the subject of §10's central misconception.
Above the boundary the problem is digital and architectural: beats arrive on a synchronous interface with a valid signal, and they must be attributed to a transaction, counted, and completed.
The boundary itself is an interface that presents already-captured beats, synchronous to the controller's clock domain, with no strobe and no analog content. That is what controller RTL consumes, and it is all it consumes.
4. RTL — The PHY Boundary
The engineering problem
Accept already-captured beats from a PHY and attach them to the transaction they belong to — while rejecting beats that correspond to no outstanding read.
Why hardware needs it
The PHY delivers a transfer; the controller needs a transaction. Nothing on the interface carries a transaction identity, so something must add it, and something must notice when beats arrive that nobody asked for.
Classification
SYNTHESIZABLE DIGITAL CONTROLLER/PHY-BOUNDARY MODEL. Entirely above the boundary.
What it models
Association of captured beats with one outstanding read; addition of the transaction tag at the boundary; and detection of beats that correspond to no pending read.
What it does NOT model
Capture (Modules 19 to 21). Bus ownership (Chapter 6.9) or the strobe window (Chapter 6.10). Beat counting against an expected burst length — Chapter 10.4 owns that, and this block passes first and last through without checking them. Latency prediction (Chapter 10.2). Error correction, CRC or poisoning. Multiple outstanding reads — one at a time, as in Chapter 10.1.
Interface and parameter contract
// ─────────────────────────────────────────────────────────────────────────
// phy_read_boundary
//
// Classification: SYNTHESIZABLE DIGITAL CONTROLLER/PHY-BOUNDARY MODEL.
//
// EVERYTHING BELOW THIS INTERFACE IS NOT MODELLED HERE: DQS capture,
// sampling-phase selection, delay adjustment, deskew, gating, levelling
// and calibration are Modules 19-21's. phy_rd_valid and phy_rd_data are
// consumed as ALREADY-CAPTURED DIGITAL VALUES in the controller's clock
// domain.
//
// MODELS: association of captured beats with one outstanding read, the
// addition of a transaction TAG the PHY never carried, and detection of
// beats corresponding to no pending read.
//
// RELATION TO EXISTING BLOCKS: Chapter 6.9's dq_bus_ownership models the
// bidirectional bus and contention; Chapter 6.10's dqs_ownership_window
// models the strobe's phases. BOTH SIT BELOW THIS BLOCK, which would be
// their consumer. Neither is reimplemented.
//
// DOES NOT COUNT BEATS against an expected burst length -- Chapter 10.4
// owns that. first/last are passed through unchecked.
//
// MODELS NO PHYSICAL OR ANALOG BEHAVIOUR.
// ─────────────────────────────────────────────────────────────────────────
module phy_read_boundary #(
parameter int DATA_W = 32,
parameter int TAG_W = 3
) (
input logic clk,
input logic rst_n,
// ── FROM THE PHY. Synchronous, already captured. No strobe appears in
// this interface, and that absence is the design.
input logic phy_rd_valid,
input logic [DATA_W-1:0] phy_rd_data,
input logic phy_rd_first,
input logic phy_rd_last,
// ── The controller's outstanding transaction, from Chapter 10.1.
input logic pending,
input logic [TAG_W-1:0] pending_tag,
// ── TO THE CONTROLLER. Same beats, plus an identity.
output logic rd_valid,
output logic [DATA_W-1:0] rd_data,
output logic rd_first,
output logic rd_last,
// THE TAG IS ADDED HERE. It did not cross the interface and does not
// exist below this block -- see Section 6.
output logic [TAG_W-1:0] rd_tag,
// ── A beat arrived with no outstanding read. Reported, never silently
// consumed: a phantom beat that is dropped without evidence is the
// hardest read failure there is to diagnose.
output logic unexpected_beat
);
if (DATA_W < 1) begin : g_dw
initial $fatal(1, "phy_read_boundary: DATA_W must be >= 1");
end
if (TAG_W < 1) begin : g_tw
initial $fatal(1, "phy_read_boundary: TAG_W must be >= 1");
end
// ── Association. Combinational: the beat is presented in the cycle the
// PHY presents it, with the identity of whatever is outstanding.
// Registering it would delay data for no reason and would associate
// against a record that may have retired in the meantime.
assign rd_valid = phy_rd_valid && pending;
assign rd_data = phy_rd_data;
assign rd_first = phy_rd_valid && pending && phy_rd_first;
assign rd_last = phy_rd_valid && pending && phy_rd_last;
assign rd_tag = pending_tag;
// ── The phantom. A beat with nothing outstanding means the controller's
// model and the device disagree about whether a read is in flight --
// a mispredicted latency, a reset that flushed an expectation the
// device still intends to satisfy (Chapter 10.2 Section 5), or a
// return for a transaction already retired.
assign unexpected_beat = phy_rd_valid && !pending;
endmoduleState representation
None. The block is a function of the PHY interface and the controller's outstanding record. That is deliberate: a boundary adapter that held state would be a second place where a transaction's progress lives, and Chapter 9.2 established what happens when two models of one fact can disagree. Beat progress belongs to Chapter 10.4's collector, in one place.
Combinational behaviour
Four gated passthroughs, a tag attachment, and one error term. rd_data is passed through ungated — the data lines carry whatever the PHY captured regardless, and gating them would suggest a validity the data itself does not have. rd_valid is the only thing that says the data means anything, which is the usual convention and is worth being explicit about.
Sequential behaviour and reset
Neither. The reset behaviour that matters is upstream: pending is cleared by reset in Chapter 10.1, so a reset during a return makes every subsequent beat of that burst an unexpected_beat. That is correct and it is diagnostic — a burst of phantom beats immediately after a reset is exactly what a reset during an in-flight read looks like.
Cycle-by-cycle trace
DATA_W = 32, TAG_W = 3, one read outstanding with tag 2, a four-beat return:
| Cycle | phy_rd_valid | first | last | pending | rd_valid | rd_tag | unexpected_beat |
|---|---|---|---|---|---|---|---|
| 0 | 0 | — | — | 1 | 0 | 2 | 0 |
| 1 | 1 | 1 | 0 | 1 | 1 | 2 | 0 |
| 2 | 1 | 0 | 0 | 1 | 1 | 2 | 0 |
| 3 | 1 | 0 | 0 | 1 | 1 | 2 | 0 |
| 4 | 1 | 0 | 1 | 1 | 1 | 2 | 0 |
| 5 | 0 | — | — | 0 | 0 | — | 0 |
| 6 | 1 | 1 | 0 | 0 | 0 | — | 1 |
Cycle 6 is the one to study. A beat arrives with nothing outstanding. rd_valid stays low — the controller is not handed data it cannot attribute — and unexpected_beat asserts. The beat is refused and reported, not dropped, which is the difference between a diagnosable failure and a mysterious one.
How to simulate, and expected output
Drive the trace and check all six outputs. Then:
Beats with pending low must produce unexpected_beat and no rd_valid — the phantom case, and it should be a directed test rather than something a random stimulus happens to produce.
pending deasserting mid-burst must convert the remaining beats to phantoms. This is the reset-during-read case and it is worth constructing deliberately, because it is how a real reset interacts with an in-flight return.
phy_rd_valid low with pending high must produce nothing at all — waiting is not an error.
first and last on the same beat — a single-beat return — must pass through with both set. This block does not police burst length, so it must not object.
Tag stability across a burst — rd_tag must be identical on every beat of one return, which follows from pending_tag being stable (Chapter 10.1's P3) and is worth checking at this boundary too.
Expected waveform
§5, which shows the ownership reversal alongside the beats.
Synthesis implications
A handful of AND gates. The block costs essentially nothing, which is appropriate — its value is architectural, not computational. It names a boundary and attaches an identity.
Corner cases
DATA_W == 1 and TAG_W == 1 are legal. A beat that is both first and last is a legal single-beat return here. Simultaneous pending deassertion and a valid beat resolves to unexpected_beat, because pending is the current value — and that is the conservative choice: refusing a beat that might have been legitimate is recoverable, while accepting one that was not corrupts a transaction.
Failure modes and debugging clues
unexpected_beat firing in bursts points at a latency misprediction or a reset during flight — §9 and Chapter 10.2 §9. rd_valid never asserting while phy_rd_valid toggles means pending is not reaching this block, which is a wiring or a retirement problem rather than a data problem. rd_tag changing during a burst means the upstream record is mutating, which Chapter 10.1's P3 forbids.
Extension ideas
With several outstanding reads, pending_tag becomes a lookup rather than a single value, and the association stops being trivial — which is Chapter 10.5's subject. Adding a phy_rd_error input, where the established PHY interface provides one, lets a poisoned beat be marked rather than silently trusted.
Limitations
One outstanding read. No beat counting — a return with the wrong number of beats passes through here unremarked, by design, because Chapter 10.4 owns that check. It cannot tell a correctly captured beat from an incorrectly captured one: if the PHY captured the wrong value, this block forwards it faithfully, and detecting that is a data-correctness question that needs a reference model.
5. Return, in Cycles
phy_read_boundary — the device drives, the controller receives
10 cyclesThe bus owner row is the chapter. At cycle 1 the controller's side is driving the command interface and nothing is driving the data bus. From cycle 4 the DRAM drives it, along with the strobe. Afterwards it is released.
Nobody signalled the handover. Both ends scheduled it independently, from a latency each derived from the configuration. Chapter 6.9 built contention detection precisely because that independent scheduling can be wrong.
Cycles 1 to 4 are the interval Chapter 10.2 owns, and it is worth seeing what is on the data bus during it: nothing. The transaction exists entirely in the pending flag.
Cycle 9 is a phantom. A beat arrives with nothing outstanding — the controller's model and the device disagree about whether a read is in flight. It is refused and reported, and a burst of these immediately after a reset is the signature of a reset during an in-flight return.
EDUCATIONAL — NOT TO SCALE, NOT JEDEC TIMING. The three-cycle gap and the four-beat cadence are chosen for readability and correspond to no device.
6. The Tag Is Added Here
A short section on a point that is easy to skip and important to get right.
No transaction identity crosses the DDR interface. Not in the command, not in the data, not in the strobe. The device receives a command and produces a burst; it has no notion of a requester, a tag, or which of several outstanding operations it is serving.
So the tag in §4 is attached, not recovered. The block reads the controller's outstanding record and stamps its identity onto beats that carry none. With one outstanding read that attachment is trivially correct — there is only one candidate.
With several outstanding reads it is the entire problem, and the only thing that makes it solvable is the ordering assumption: if returns emerge in the order the reads were issued, the oldest outstanding record owns the next return. That assumption is a design choice, stated in Chapter 10.2 §7, and Chapter 10.5 is where the association is built on it.
7. Four Assertions Worth Writing
// P1 -- data reaches the controller only when a read is outstanding. The
// safety property of the boundary: it forbids the controller being handed
// data it cannot attribute to anything.
property p_valid_requires_pending;
@(posedge clk) disable iff (!rst_n)
rd_valid |-> (phy_rd_valid && pending);
endproperty
assert property (p_valid_requires_pending);
// P2 -- and the converse: every captured beat is either delivered or
// reported. Nothing is silently dropped, which is what makes a phantom
// return diagnosable rather than mysterious.
property p_every_beat_is_delivered_or_reported;
@(posedge clk) disable iff (!rst_n)
phy_rd_valid |-> (rd_valid ^ unexpected_beat);
endproperty
assert property (p_every_beat_is_delivered_or_reported);
// P3 -- the tag is stable across a burst. A tag that changed mid-return
// would split one transaction's data across two records, and the failure
// is silent: both halves look like well-formed partial transactions.
property p_tag_stable_within_burst;
@(posedge clk) disable iff (!rst_n)
(rd_valid && !rd_last && $past(rd_valid) && !$past(rd_last))
|-> (rd_tag == $past(rd_tag));
endproperty
assert property (p_tag_stable_within_burst);
// P4 -- the controller-facing qualifiers never outlive their beat. first
// and last are meaningless without valid, and a consumer that latched
// last while valid was low would complete a transaction on no data at all.
property p_qualifiers_require_valid;
@(posedge clk) disable iff (!rst_n)
(rd_first || rd_last) |-> rd_valid;
endproperty
assert property (p_qualifiers_require_valid);What these prove. P1 and P2 together make the boundary total: every beat the PHY presents is accounted for exactly once, as a delivery or as a reported phantom, and neither can happen without the other's absence. That pairing is the property worth having — P1 alone permits silently dropping beats. P3 protects the association across a burst. P4 stops a consumer completing on a qualifier without data.
What these do not prove. Nothing here proves the data is correct. The block forwards whatever the PHY captured; if capture produced the wrong value, every property above passes and the data is wrong. Detecting that needs a reference model and is a different kind of check entirely — §8 separates them. Nothing proves the beat arrived at the right time: this block has no notion of an expected window, and Chapter 10.2's prediction is not an input here. Nothing proves the burst has the right number of beats — Chapter 10.4 owns that, and this block deliberately passes first and last through unchecked. And nothing proves anything below the boundary: no property here concerns a strobe, a sampling phase, a delay or a channel, and the block contains no representation of any of them.
8. DV — Three Independent Checks
This chapter makes a separation that a read verification environment depends on, and that a single scoreboard tends to collapse.
A read can fail in three independent ways, and a check that conflates them cannot localise any of them:
| Failure | Question | What detects it |
|---|---|---|
| Ownership / transfer | did the bus change hands correctly and did a transfer happen? | Chapter 6.9's contention, and beat activity at all |
| Timing | did the beats arrive when expected? | measured offset vs Chapter 10.2's prediction |
| Data | were the values correct? | comparison against a reference memory |
These are genuinely independent. Data can be correct and arrive at the wrong time. Data can arrive at exactly the right time and be wrong. The bus can change hands correctly and carry nothing. A scoreboard that samples data only inside a predicted window fails all three the same way — as "missing data" — and the actual data comparison is never even reached.
Which gives three practical requirements:
Sample beats on the PHY interface's own valid, not on a predicted window. Then wrong-time data is observed rather than missed, and the timing check becomes a comparison between two observations rather than a filter that discards evidence.
Record the arrival offset for every beat, even when it matches. Chapter 10.2 §8 argued for distributions over checks; this is where the measurement is taken.
Check unexpected_beat as a first-class error, not as a warning. A phantom beat means the controller's model and the device have diverged about whether a read is in flight — and a model that has diverged once will keep diverging. It is an early, loud symptom of a latency or reset problem that otherwise surfaces much later as data corruption.
9. Debugging — DQ Toggles and the Controller Sees Nothing
Symptom. Probing shows the data bus is active in the expected region after a read command. The controller reports no data returned and the transaction never completes.
This symptom is valuable because it has already localised itself across the boundary, and the discipline is to notice that before doing anything else: the device produced a transfer. The read command was accepted, the row was open, the device did its part. Everything upstream of the bus is exonerated — which eliminates the entire command path, the row state and the address map in one observation.
Candidate mechanisms.
- The PHY is not presenting
phy_rd_valid— capture is failing, so the transfer happened on the channel and produced no digital beats. Modules 19 to 21. - The PHY is presenting beats and
pendingis low, so they are being refused as phantoms. The controller's expectation closed early, or a reset flushed it. pendingnever asserted — the read was never admitted, and the bus activity belongs to some other transaction. Chapter 10.1.- Beats are being delivered and the beat count is wrong, so the transaction never sees its
lastand never completes. Chapter 10.4. - The transfer on the bus is not this read's — another requester, another rank, or a write.
Evidence to collect. phy_rd_valid at the boundary, which is the single most decisive signal and the one a probe on the bus cannot substitute for. pending and unexpected_beat across the window. Whether the bus activity's timing matches the predicted return window. And whether a reset occurred at any point since the read was accepted.
Discriminator.
- Is
phy_rd_validasserting at all? This splits the problem in one signal. No means capture is failing and the fault is below the boundary — Modules 19 to 21, and no amount of controller debugging will help. Yes means the transfer was captured and the fault is above. - If beats are arriving, is
unexpected_beatasserting? Mechanism 2. The beats are being refused, so the question becomes whypendingis low — and the next check is whether a reset occurred, since Chapter 10.2 §5 established that a reset flushes expectations the device may still intend to satisfy. - Did
pendingever assert for this read? Mechanism 3, and the bus activity belongs to something else. Chapter 10.1 §9 covers it. - Are beats delivered but no
rd_last? Mechanism 4 — the transaction is stuck waiting for a final beat that never came, or came with the flag unset. - Does the bus activity's timing match the prediction? A large mismatch suggests mechanism 5 — the transfer is somebody else's — and comparing the observed offset against the predicted one distinguishes it from a latency misprediction, which would be a small, consistent offset.
Responsible layer. Mechanism 1 is layer B and below, and it goes to different people with different instruments. Mechanisms 2, 3 and 4 are layer C. Mechanism 5 is a system-level attribution question. The single phy_rd_valid observation is what routes the problem, which is the practical value of having a named boundary at all.
Fix. Per mechanism — and in every case, instrument the boundary. A design that cannot show whether beats crossed it forces every read failure to be debugged as though it might be anything.
10. Common Misconceptions
"The controller drives DQS during reads."
Why it is tempting: the controller drives it for writes, and it drives the clock always, so it feels like the master of all timing.
Concrete failure: an engineer looks for the controller's strobe generation logic in the read path and cannot find it — or worse, a design attempts to drive it and contends with the device.
Correct model: the strobe's ownership follows the data's direction. For a read, both come from the device. §1, and Chapter 6.10.
Prevention: ask who launched the data. The strobe has the same answer, always.
"The controller samples DQ with CK in ordinary RTL."
Why it is tempting: it is how every other synchronous interface works, and it is the code an RTL engineer's instincts produce.
Concrete failure: a design that works in a zero-delay simulation and cannot work on hardware, because the returned data's phase relative to the controller's clock is unknown and varies with the channel, temperature and voltage.
Correct model: capture happens in the PHY against the returned strobe, using mechanisms Modules 19 to 21 own. The controller receives already-captured beats. §3.
Prevention: if controller RTL references DQ or DQS directly, the boundary has been crossed.
"DQS is just another clock."
Why it is tempting: it toggles, it times data, and it is drawn like a clock.
Concrete failure: a model treating it as free-running, which cannot explain the preamble, the postamble, or why it is not driven between transfers — all of which Chapter 6.10 established.
Correct model: a strobe that exists only around a transfer, is sourced by whoever drives the data, and has no fixed relationship to the receiver's clock. §2.
Prevention: Chapter 6.10's window model, where strobe-active and data-valid are deliberately separate outputs.
"The PHY decides which address to read."
Why it is tempting: the PHY is closest to the device, so it feels like where the access happens.
Concrete failure: a debug plan that looks in the PHY for an addressing bug, or a verification environment that expects the PHY interface to carry addresses.
Correct model: the PHY moves transfers. It has no notion of an address or a transaction — the command carrying the address went out earlier, and the tag is added above. §6.
Prevention: the three-layer table in Chapter 10.1 §6.
"Correct DQ values prove the read timing is correct."
Why it is tempting: the data came back right, so everything upstream must have worked.
Concrete failure: a design whose capture happens to work at one speed, one temperature and one device, with no margin — and fails on the next board, with correct-looking data on the one that passed.
Correct model: correctness and timing are independent, §8. Correct values sampled with no margin are correct values that will stop being correct.
Prevention: measure the arrival offset even when the data matches, and treat margin as a separate question from correctness.
"Correct read timing proves the returned data is correct."
Why it is tempting: it is the converse of the last one and feels equally reasonable.
Concrete failure: a timing checker passes while the device returns data from the wrong column — a perfectly timed return of the wrong location.
Correct model: timing says when, a reference model says what. §8's three checks.
Prevention: keep the timing check and the data check as separate checks with separate reports.
11. Interview Reasoning
"Who drives DQ and DQS during a read?"
The DRAM, both of them. A read is a request sent one way and satisfied the other, so the bus changes hands between the command and the data — and nothing signals the handover. Both ends schedule it independently from the configured latency, which is why bus contention is a real failure mode and why a controller's model of read latency has consequences beyond predicting when to look. The strobe's ownership follows the data's exactly, because a strobe owned by a different side from the data it times would not be source-synchronous at all.
"Why is DQS needed if CK already exists?"
Because the clock never travelled the return path. The command went to the device and the data came back, through package and board delays that are neither identical nor precisely known, so the receiver's clock has no reliable relationship to the returned data. A strobe launched by the same device, from the same output circuitry, at the same moment, through the same path, does — whatever delay the data suffered, the strobe suffered too, so their relationship survives the journey even though neither one's relationship to the receiver's clock does. That is the whole argument for source-synchronous return.
"Why shouldn't ordinary controller RTL sample DQ directly?"
Because the returned strobe's phase relative to the receiver is unknown and drifts with temperature, voltage and the specific channel, and the sampling window is a fraction of a clock period. That is not a problem a fabric flip-flop solves — it needs adjustable delay, a mechanism to find the right sampling position, and a mechanism to track it as conditions change. So capture belongs in the PHY, and the controller consumes already-captured beats on a synchronous interface. The practical tell is simple: if controller RTL references DQ or DQS, the boundary has been crossed, and the code will simulate perfectly and not work.
"A read command went out, the data bus is clearly active, and the controller reports nothing. Where do you look?"
At the PHY's captured-beat valid, because that one signal routes the entire problem across the boundary. If beats are not being presented, the transfer happened on the channel and capture failed — that is a PHY question, with different tools and usually different people, and no amount of controller debugging touches it. If beats are being presented and refused, the controller has no outstanding read at that moment, so the question becomes why: a mispredicted latency window, a reset that flushed the expectation while the device still intended to satisfy it, or a transaction already retired. The bus probe alone cannot distinguish these; the boundary signal can.
"How does a returned beat get associated with a request?"
By something above the interface attaching an identity the interface never carried. No tag crosses a DDR bus — the device receives a command and produces a burst, with no notion of a requester or of which outstanding operation it is serving. With one read outstanding the attachment is trivial. With several, it rests entirely on an ordering assumption: if returns emerge in issue order, the oldest outstanding record owns the next return. That assumption is a design choice, and a verification monitor must apply the same rule the controller does — if the two differ, both will attribute beats confidently and to different transactions.
12. Engineering Exercise
DATA_W = 32, TAG_W = 3.
1. For each event, name the owner of the data bus: read command issued; the latency interval; first returned beat; after the final beat.
2. A colleague writes always_ff @(posedge dqs) captured <= dq; in the memory controller. Give two independent reasons it is wrong.
3. phy_rd_valid is high, pending is low. What are the outputs, and name three causes.
4. A burst's four beats arrive and rd_tag reads 2, 2, 3, 3. What has happened and what does it break downstream?
5. Which of these does this block detect: wrong data values, wrong beat count, a beat with no outstanding read, a beat one cycle late? For each undetected one, name the owner.
6. A monitor samples data only inside the predicted return window. Give the symptom when the latency is misconfigured by one cycle.
13. Summary
During a read the DRAM drives the data bus and the strobe. That is the reverse of a write, the handover is scheduled independently by both ends rather than signalled, and the strobe's ownership follows the data's exactly.
The timing reference comes from the far end because the clock never made the journey. A strobe launched with the data, from the same circuitry, through the same path, keeps its relationship to that data regardless of what the channel did — which the receiver's clock cannot.
Capture belongs to the PHY, and controller RTL stops above it. Below the boundary: unknown phase, sub-period sampling windows, drift, and the mechanisms that find and track the right sampling position. Above it: digital beats on a synchronous interface. If controller RTL references DQ or DQS, the boundary has been crossed — and the resulting code simulates perfectly and cannot work.
No transaction identity crosses the interface. The tag is attached at the boundary from the controller's own record; the device has no notion of a requester. With one read outstanding that is trivial, and with several it rests entirely on the ordering assumption.
A beat with nothing outstanding is refused and reported, never dropped. It means the controller's model and the device have diverged about whether a read is in flight, and it is an early, loud symptom of a problem that otherwise appears much later as corruption.
And a read fails in three independent ways — transfer, timing, and data. A scoreboard that samples only inside a predicted window collapses all three into "missing data" and never reaches the comparison that would have identified which.
14. What Comes Next
Beats have been arriving in fours throughout this chapter without explanation. Chapter 10.4 — Burst Reads explains why.
One read command produces several transfers, and the reason is architectural rather than conventional: the array moves far more data per access than the interface is wide, so the interface spends several transfer opportunities delivering what one internal access produced. Module 4 derived that relationship as prefetch; 10.4 connects it to what a controller must actually do about it.
Which is mostly counting — and counting correctly, because a burst that delivers the wrong number of beats is a transaction that never completes or one that completes on somebody else's data. Module 12 owns burst lengths, ordering and efficiency; 10.4 takes only what a read transaction requires.
Return to The DQ Bus for ownership and contention, DQS for the strobe and its window, CAS Latency for the prediction that decides when to expect this, The Read Command for the record the tag comes from, and CK / CK# for the clock that times commands and not returned data.
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
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
DQ — The Data Bus
Saying DQ is bidirectional says almost nothing. What matters is who drives these wires right now, how ownership changes, and what guarantees both sides never drive at once — which is a state machine, not a property.
- 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.
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.
