DDR · Module 11
Write Latency (CWL)
A read latency is a promise the device makes and a controller can mispredict. A write latency is a requirement the controller must meet — and a promise can be mispredicted while a deadline can only be missed.
Chapter 11.1 left a controller holding a payload it owes, with no idea when to deliver it. This chapter is that relationship.
The obvious framing is that this is the write-side CAS latency, and the obvious framing is wrong in a way that matters:
Why must write data have a defined launch relationship to its command at all — and what kind of obligation is that relationship?
A read latency is a promise. The device commits to producing data at a defined offset; a controller that mispredicts it looks in the wrong place and misses something that still exists.
A write latency is a deadline. The device commits to sampling at a defined offset, and the controller must have data there. A promise can be mispredicted. A deadline can only be missed.
1. Why a Relationship Must Exist
Derive it before naming anything, because the derivation makes the rest inevitable.
The device must sample the write data. It has no other way to receive it: the data arrives on DQ, accompanied by a strobe, and the device captures it into the column path of the open row.
So the device must know when to sample. It cannot wait indefinitely — the bus is shared, other commands are in flight, and a device listening forever would have no way to distinguish this write's data from anything else that appears on DQ.
And nothing tells it. There is no handshake. The controller does not signal "data starts now" and the device does not signal "I am ready." Chapter 10.3 §1 made the same observation about the read direction's bus handover: the transition is scheduled, independently, by both ends.
Therefore both ends must derive the same moment from something they already share — and what they share is the command event and the configuration.
the device samples at: command event + configured offset
the controller launches at: command event + configured offset
Nothing coordinates these. They agree because they were
configured to agree, and for no other reason.2. A Promise Versus a Requirement
The read and write intervals look symmetric and behave completely differently. This is the distinction the chapter is built around.
| Read latency | Write latency | |
|---|---|---|
| Who commits | the device | the controller |
| What is committed | data will appear at this offset | data will be present at this offset |
| Controller's role | predict, and look there | meet the deadline |
| If the controller is wrong | it looks in the wrong window and misses data that still exists | the device samples whatever is on the bus |
| Recoverable? | yes — re-read | no — a location has been overwritten |
| Detectable by the controller? | yes, as missing data | no, by itself |
Read the last two rows together, because they compound. A mistimed read produces an absence the controller can see. A mistimed write produces a plausible, silent, permanent corruption of a real location — and the controller has no local evidence that anything went wrong. It issued a command, it drove data, nothing reported an error.
This is why write levelling exists. Chapter 4.4 established that from DDR3 onward interface timing is measured rather than designed; the write direction's version of that measurement exists precisely because the controller must land data inside a window it cannot observe. Module 21 owns it, and it is named here only so that the reason for it is understood: it is the calibration of a deadline.
3. What CWL Relates
CAS write latency relates the write command event to the first data the controller must present, measured in clock cycles, under one configuration.
The clauses do the same work as Chapter 10.2 §2's, with one word changed and it is the important one: must present, not will appear.
"The write command event." The sampling event — Chapter 6.1 and Chapter 7.1 §2 — not when the controller decided to issue.
"The first data." Not all of it. The rest follows at the transfer cadence, which is Chapter 11.3's.
"In clock cycles." Chapter 10.2 §3's unit discipline applies unchanged and is not repeated here. The one thing worth restating: MT/s ÷ 2 = MHz, because a DDR interface performs two transfers per clock period, and getting that wrong scales every derived figure by two.
"Under one configuration." Device, speed grade, and mode-register settings.
The family, and how it composes
| Term | Relates |
|---|---|
| CWL | the write command to the first write data the controller must present |
| AL — additive latency | an allowance to issue the column command earlier (Chapter 4.3) |
| WL — write latency | the total command-to-first-data offset the controller must meet |
| CL / RL | the read-side counterparts, Chapter 10.2's |
Datasheets express the total as the sum of the additive component and CWL, exactly as the read side sums it with CL. A controller must meet WL, not CWL — and one configured against CWL alone while additive latency is in force presents its data early by exactly the additive amount.
4. Three Intervals That Get Confused
A write involves three distinct intervals, and the module's worst errors come from treating any two as one.
Interval one — write latency. Command event to first data. The controller owes a deadline. This chapter.
Interval two — the burst. First beat to last. The controller owes the bus, continuously, for the duration. Chapter 11.3.
Interval three — write recovery. End of data to the point the bank may be closed. The device owes internal work, and the controller owes only patience. Chapter 11.4.
5. RTL — Carrying a Payload to Its Deadline
The engineering problem
Carry a transaction's identity from acceptance to the cycle its data must be launched — and report when the deadline arrived and the payload was not ready, because a missed write deadline has no other symptom.
Why hardware needs it
The controller has no signal telling it when to drive. It counts. And unlike the read side, it cannot simply be late — so the model must be able to say that it was.
Classification
SYNTHESIZABLE EDUCATIONAL CONTROLLER RTL.
What it models
A fixed-depth pipeline carrying a transaction tag from write acceptance to its launch deadline, with occupancy visibility, collision reporting, and detection of a deadline reached while the payload was not ready.
What it does NOT model
The device. Data or beats (Chapter 11.3). Recovery (Chapter 11.4). Variable latency or mode-register changes. Timing legality (Modules 13, 14). The PHY's latency contribution or write levelling (Modules 19 to 21). Reordering — launches are assumed to emerge in issue order, stated in §7 rather than assumed universal.
Interface and parameter contract
// ─────────────────────────────────────────────────────────────────────────
// write_launch_pipeline
//
// Classification: SYNTHESIZABLE EDUCATIONAL CONTROLLER RTL.
//
// LAUNCH_EVENTS IS AN EDUCATIONAL DIGITAL PIPELINE DEPTH. IT IS NOT A
// JEDEC CWL VALUE. A real controller derives its depth from the configured
// WRITE LATENCY plus the PHY's contribution (Module 19) -- the depth a
// controller uses and the number in a datasheet are different quantities.
//
// MODELS: a fixed-depth pipeline carrying a transaction TAG from write
// acceptance to its LAUNCH DEADLINE, with occupancy, collision reporting,
// and detection of a deadline reached with no payload ready.
//
// RELATION TO CHAPTER 10.2: read_return_pipeline PREDICTS an event the
// DEVICE produces. This SCHEDULES an event the CONTROLLER must produce.
// Hence launch_missed, which has no read-side counterpart: a prediction
// cannot be missed, a deadline can.
//
// CARRIES A TAG, NOT DATA. The payload stays where Chapter 11.1's record
// left it; Chapter 11.3 delivers it.
//
// ORDERING ASSUMPTION: launches emerge in issue order. Stated, not
// assumed universal -- see Section 7.
//
// MODELS NO PHYSICAL OR ANALOG BEHAVIOUR.
// ─────────────────────────────────────────────────────────────────────────
module write_launch_pipeline #(
parameter int TAG_W = 3,
// EDUCATIONAL PIPELINE DEPTH. See the header.
parameter int LAUNCH_EVENTS = 4
) (
input logic clk,
input logic rst_n,
// ── From Chapter 11.1's admission.
input logic accept,
input logic [TAG_W-1:0] accept_tag,
// ── Whether the payload source can supply data this cycle. An INPUT:
// this block schedules the deadline and does not own the buffer.
input logic payload_ready,
// ── The deadline. NOT data, and not a claim that anything was driven --
// only that this is the cycle the device will be sampling.
output logic launch_due,
output logic [TAG_W-1:0] launch_tag,
// ── THE WRITE-SPECIFIC OUTPUT. The deadline arrived and no payload was
// available. On real hardware nothing objects: the device samples
// whatever the bus carries. This makes the failure visible at the one
// place it is still local.
output logic launch_missed,
output logic occupied,
// An accept while the first stage is occupied. Chapter 11.1's
// single-outstanding admission prevents it; reported for reuse.
output logic accept_collision
);
if (TAG_W < 1) begin : g_tw
initial $fatal(1, "write_launch_pipeline: TAG_W must be >= 1");
end
if (LAUNCH_EVENTS < 0) begin : g_le
initial $fatal(1, "write_launch_pipeline: LAUNCH_EVENTS must be >= 0");
end
// ── Degenerate depth: the deadline is the acceptance cycle itself. A
// zero-length unpacked array would be an illegal declaration, so the
// case must be structural rather than a runtime special case.
if (LAUNCH_EVENTS == 0) begin : g_zero_depth
assign launch_due = accept;
assign launch_tag = accept_tag;
assign occupied = 1'b0;
assign accept_collision = 1'b0;
assign launch_missed = accept && !payload_ready;
end else begin : g_pipe
logic vld_q [LAUNCH_EVENTS];
logic [TAG_W-1:0] tag_q [LAUNCH_EVENTS];
assign accept_collision = accept && vld_q[0];
always_ff @(posedge clk) begin
if (!rst_n) begin
for (int i = 0; i < LAUNCH_EVENTS; i++) begin
vld_q[i] <= 1'b0;
// Tags are not cleared: only the valid bit makes a stage
// meaningful, and the retained tag stays visible for debugging.
tag_q[i] <= '0;
end
end else begin
// Shift toward the output. With nonblocking assignments every
// right-hand side reads the pre-clock value, so the loop order is
// immaterial -- it is written descending to read as a shift.
for (int i = LAUNCH_EVENTS - 1; i > 0; i--) begin
vld_q[i] <= vld_q[i-1];
tag_q[i] <= tag_q[i-1];
end
vld_q[0] <= accept;
tag_q[0] <= accept_tag;
end
end
assign launch_due = vld_q[LAUNCH_EVENTS-1];
assign launch_tag = tag_q[LAUNCH_EVENTS-1];
// The deadline arrived and nothing was ready to meet it.
assign launch_missed = launch_due && !payload_ready;
// A loop rather than a reduction: vld_q is unpacked and cannot be
// OR-reduced directly.
always_comb begin
occupied = 1'b0;
for (int i = 0; i < LAUNCH_EVENTS; i++)
if (vld_q[i]) occupied = 1'b1;
end
end
endmoduleState representation
LAUNCH_EVENTS stages, each a valid bit and a tag. Nothing else travels — the payload, the column and the bank stay in Chapter 11.1's record, indexed by the tag, which is why a tag exists.
Combinational behaviour
The output stage's valid and tag, the collision term, the missed-deadline term, and an occupancy loop.
Sequential behaviour and reset
A shift register, nonblocking throughout. Reset flushes every valid bit, which loses in-flight deadlines — and that is a genuine hazard with no read-side equivalent: the device may still be about to sample for a command issued before the reset, and the controller will no longer drive. §9's mechanism 5, and Chapter 11.1 §5's reset note.
Cycle-by-cycle trace
LAUNCH_EVENTS = 4, with the payload ready on time and then late:
| Cycle | accept | payload_ready | launch_due | launch_tag | launch_missed |
|---|---|---|---|---|---|
| 1 | 1 (tag 0) | 1 | 0 | — | 0 |
| 5 | 0 | 1 | 1 | 0 | 0 |
| 6 | 1 (tag 1) | 1 | 0 | — | 0 |
| 10 | 0 | 0 | 1 | 1 | 1 |
Cycle 10 is why this block differs from its read-side twin. The deadline arrived, the payload was not there, and the block says so. On hardware the device samples regardless, and this output is the last place the failure is still local to the controller.
How to simulate, and expected output
Drive a single accept and confirm launch_due exactly LAUNCH_EVENTS cycles later with the same tag. Then:
LAUNCH_EVENTS = 0 — launch_due equals accept combinationally, and launch_missed asserts if the payload is not ready in that same cycle. This exercises the g_zero_depth arm, which no other configuration reaches.
LAUNCH_EVENTS = 1 — the minimum registered depth, where stage 0 is also the output stage. The descending loop body never executes, and the block must still work.
payload_ready low at the deadline must assert launch_missed — and this should be a directed test, because random stimulus with a always-ready payload never produces it, and it is the chapter's central failure.
Back-to-back accepts must produce launches on consecutive cycles in the same order with tags preserved.
Reset mid-flight must clear every stage and produce no further launch_due.
Expected waveform
§6, which shows a met deadline and a missed one.
Synthesis implications
LAUNCH_EVENTS × (1 + TAG_W) flops — 16 at depth 4 with a 3-bit tag. Identical cost to the read-side pipeline, which is worth noticing: the two obligations are structurally the same shape and completely different in consequence.
Corner cases
LAUNCH_EVENTS == 0 is legal and structural. LAUNCH_EVENTS == 1 is the minimum registered depth. Negative depth does not elaborate. TAG_W == 1 is legal. payload_ready low with no deadline due is not an error and produces nothing — the payload only has to be there when it is needed.
Failure modes and debugging clues
launch_missed asserting means the payload path cannot keep up with the configured depth — either the buffer is too shallow or the depth is too short for the source. launch_due one cycle early or late is §9's off-by-one. launch_due never arriving means a reset flushed the pipeline or accept never reached it.
Extension ideas
Carrying a small expected-beat count alongside the tag connects this block to Chapter 11.3 directly. Making payload_ready a per-tag lookup rather than a single signal is what multiple outstanding writes require, and it is where the payload buffer's cost becomes explicit.
Limitations
Fixed depth, known at elaboration. In-order launches, assumed. One entry per stage. It schedules; it does not drive — nothing here puts anything on a bus, and whether the launch actually happened is Chapter 11.3's.
6. The Launch, in Cycles
write_launch_pipeline — a deadline, not a prediction
10 cyclesCycles 1 to 5 are the mechanism. An acceptance enters the pipeline; four cycles later the deadline arrives with the same tag, the payload is ready, and the launch is met.
Cycle 9 is the state that has no read-side equivalent. payload_ready has fallen while a transaction is still in flight. Tag 1's deadline is one cycle away and there is nothing to send.
On hardware, nothing stops at that point. The device samples at the cycle it was configured to sample; the bus carries whatever it carries. launch_missed is the last moment at which the failure is visible to the controller — after it, the only evidence is corrupted memory at a location that may not be read for a long time.
occupied stays high from cycle 2 onward, showing both transactions in flight across the overlap, and launches emerge in issue order.
EDUCATIONAL PIPELINE DEPTH — NOT A JEDEC CWL VALUE. The depth of four fits a readable waveform and corresponds to no device.
7. Four Assertions Worth Writing
// ─────────────────────────────────────────────────────────────────────────
// The generate guard exists because $past(x, n) requires n >= 1 and ##n
// with n == 0 collapses to the same cycle -- so P1 and P2 are not
// expressible at LAUNCH_EVENTS == 0, which is a legal configuration whose
// contract is the simpler P0.
// ─────────────────────────────────────────────────────────────────────────
if (LAUNCH_EVENTS == 0) begin : g_zero_asrt
property p_zero_depth_is_passthrough;
@(posedge clk) disable iff (!rst_n)
(launch_due == accept) && (!accept || (launch_tag == accept_tag));
endproperty
assert property (p_zero_depth_is_passthrough);
end else begin : g_pipe_asrt
// P1 -- a deadline arrives only if a write was accepted exactly
// LAUNCH_EVENTS cycles earlier, with identity preserved. The block's
// contract in one property; it fails on any off-by-one in either
// direction, which is Section 9's central symptom.
property p_launch_matches_acceptance;
@(posedge clk) disable iff (!rst_n)
launch_due |-> $past(accept, LAUNCH_EVENTS)
&& (launch_tag == $past(accept_tag, LAUNCH_EVENTS));
endproperty
assert property (p_launch_matches_acceptance);
// P2 -- and the converse: every acceptance produces a deadline. Together
// with P1 the pipeline is a bijection between acceptances and launches,
// so a dropped entry is caught as well as an invented one. A DROPPED
// DEADLINE IS THE WORSE FAILURE on the write side: the device samples at
// a cycle the controller has forgotten about.
property p_acceptance_produces_a_launch;
@(posedge clk) disable iff (!rst_n)
accept |-> ##LAUNCH_EVENTS (launch_due
&& (launch_tag == $past(accept_tag, LAUNCH_EVENTS)));
endproperty
assert property (p_acceptance_produces_a_launch);
// P3 -- a missed deadline is reported exactly when it occurs. Both
// directions, because under-reporting hides the chapter's central failure
// and over-reporting trains an engineer to ignore the output.
property p_missed_reported_exactly;
@(posedge clk) disable iff (!rst_n)
launch_missed == (launch_due && !payload_ready);
endproperty
assert property (p_missed_reported_exactly);
// P4 -- reset flushes. A pipeline surviving reset with stale entries
// would drive data for a transaction the controller has forgotten, at a
// cycle nothing is expecting it.
property p_reset_flushes_the_pipeline;
@(posedge clk)
$rose(rst_n) |-> !launch_due;
endproperty
assert property (p_reset_flushes_the_pipeline);
endWhat these prove. P1 and P2 make the pipeline a bijection between acceptances and deadlines — and on the write side the dropped direction is the dangerous one, because a forgotten deadline means the device samples and the controller does not drive. P3 is the property with no read-side counterpart, and it makes the chapter's central failure observable at the one point it is still local. P4 covers the stale-entry hazard across reset.
What these do not prove. Nothing here proves data was actually driven — this block schedules and does not drive, so launch_due with payload_ready high means only that a payload could have been supplied. Chapter 11.3 owns whether it was. Nothing proves LAUNCH_EVENTS is the right value: a pipeline configured to the wrong depth satisfies all four properties perfectly and lands every write in the wrong cycle, which is §8's central point. Nothing proves JEDEC timing compliance (Modules 13 and 14). Nothing proves anything about recovery (Chapter 11.4). And nothing proves anything physical — no property here concerns a bus, a strobe, a driver or a voltage.
8. DV — Checking a Deadline You Set
Chapter 10.2 §8 established that a monitor configured from the design's own constant cannot detect a wrong constant. That applies here and is worse, for a reason specific to the write direction.
On the read side, a wrong latency eventually announces itself. The controller looks in the wrong window and data appears to be missing, and a missing read is a loud, immediate, investigated failure.
On the write side, a wrong latency announces nothing. The controller drives data at the wrong cycle, the device samples at the right one, and the result is a corrupted location that may not be read for a long time — or ever. There is no stall, no timeout, no error. The system runs.
So the write direction needs the measurement discipline more, not less:
Measure the offset from the command event to the first driven beat, and report the distribution. Not a check against a constant — the value itself. A tight distribution at an unexpected offset is the only cheap evidence of a misconfiguration, and it requires no prediction to see.
Derive the monitor's expectation from the programmed mode registers, not from the RTL parameter, so an inconsistently configured controller is detectable. Chapter 7.6 established that configuration is observable and is a correctness concern.
Treat launch_missed as a first-class error. It is the one write failure that is still local to the controller when it happens. Everything after it is archaeology.
And check the relationship as well as the value. Every accepted write should produce exactly one launch; the offsets should be identical across writes under a fixed configuration; and the offset should change only when the configuration changes. Those hold even during bring-up when the correct value has not been established, and they catch instability that an absolute check cannot.
9. Debugging — Write Data Lands One Cycle Off
Symptom. Writes complete without error. Reading back the written locations returns wrong data — often data that looks like a neighbouring beat, or like a previous write's content. No error is reported anywhere.
The absence of an error is the diagnostic. A read that lands in the wrong window produces missing data; a write that lands in the wrong cycle produces nothing but wrong memory, which is why this symptom is discovered by a data check rather than by a protocol check.
Candidate mechanisms.
- The pipeline depth was configured from CWL alone while the device has a non-zero additive latency in force, so data is presented early by exactly that amount. §3.
- The depth was configured from CL rather than CWL — they are separate values and need not be equal. §3's callout.
- An off-by-one in the pipeline's convention: whether
launch_dueasserts in the last stage or after it. §5's trace. - The PHY contributes latency the controller's model does not account for — and on the write side this is what write levelling exists to calibrate. Modules 19 and 21.
- A mode-register setting differs from what the controller assumes. Chapter 7.6.
Evidence to collect. The measured offset from the command event to the first driven beat — not the configured one. The programmed mode-register values, read back where the generation permits. The controller's LAUNCH_EVENTS and how it was derived. Whether the discrepancy is exactly one cycle or exactly the additive-latency setting or exactly the difference between CL and CWL. And whether the offset is constant across all writes.
Discriminator.
- Does the discrepancy equal the configured additive latency? Mechanism 1, and the arithmetic is decisive. Check it first.
- Does it equal
CL − CWL? Mechanism 2, and this is the check people skip because the two numbers are adjacent in every part listing and are assumed equal. - Exactly one cycle, always? Mechanism 3 — a convention mismatch. Distinguish design from monitor by where you measure: if the two disagree with each other it is the monitor; if they agree and both disagree with the device it is the design.
- Does the discrepancy change after retraining, or with temperature? Mechanism 4, and it is not a controller bug — the model is missing a term belonging to another layer. This is the write-levelling case.
- Read back the mode registers. Different from what the controller assumes is mechanism 5, and everything downstream was computed from a fiction.
- Is the offset constant? Varying write to write is none of the above — that is a payload-availability or ownership problem and belongs to Chapter 11.3.
Responsible layer. Mechanisms 1, 2, 3 and 5 are the controller's model or its configuration. Mechanism 4 is the PHY, and the write-levelling connection is the tell. None of them is a data-path fault, which is counter-intuitive given that the symptom is wrong data.
Fix. Per mechanism — and never by tuning the depth until the data checks pass. A depth adjusted empirically to absorb an unmodelled PHY term will break at a different speed grade, after retraining, or on the next device — and its failure mode is silent corruption, not a stall.
10. Common Misconceptions
"CWL and CL mean the same thing."
Why it is tempting: they sit adjacent in every part listing, are quoted in the same units, and relate structurally similar intervals.
Concrete failure: the launch pipeline is configured from CL, write data lands CL − CWL cycles away from where the device samples, and every write silently corrupts its location while all commands remain legal.
Correct model: separate configured values that need not be equal, relating different directions with different obligations. §2 and §3.
Prevention: read both from the device's documentation for the configuration in force, and check that the difference between measured read and write offsets is what the configuration predicts.
"CWL is total write latency."
Why it is tempting: it is the write number everyone quotes.
Concrete failure: a system model predicting store completion from CWL, wrong by a large factor, with the gap explained away as measurement error.
Correct model: one term among many — queueing, the address path, any required row-state work (Module 9), the PHY's contribution, the burst, and the recovery that follows. §4.
Prevention: the three-interval picture in §4. A write "latency" with one term in it is not a budget.
"CWL and tWR are the same thing."
Why it is tempting: both are write-side intervals quoted in cycles, and both are somewhere between the command and being finished.
Concrete failure: a controller that treats the launch offset as the whole obligation closes the row when the burst ends — which is Chapter 11.4's corruption case, and it is the module's most damaging single confusion.
Correct model: different endpoints, different owners, opposite ends of the transaction. §4's three intervals: the controller owes the first, drives through the second, and waits out the third.
Prevention: name the two events every interval relates before using it. Chapter 10.2 §10 made the same recommendation for CL and tRCD.
"The write latency is how long the write takes."
Why it is tempting: it is called a latency and latencies are durations.
Concrete failure: an engineer expects a lower CWL device to complete writes sooner and cannot explain why the row still cannot be closed any earlier.
Correct model: it is an agreement about when data must be present, not a measure of how long anything takes. §1. The part that resembles "how long the write takes" is the recovery interval, and that is a different number with a different owner.
Prevention: §1's derivation — two machines with no handshake agreeing on a cycle.
"A waveform with four cycles proves a four-cycle JEDEC parameter."
Why it is tempting: the number is visible and concrete.
Concrete failure: an educational figure is quoted in a review as a device value and a schedule is built on it.
Correct model: every waveform in this module is labelled educational. Real values come from the device's documentation for its configuration.
Prevention: treat any number in a tutorial waveform as illustrative — including all of this chapter's.
"Normal controller RTL generates the physical strobe."
Why it is tempting: for a write the controller is the source of DQS, so generating it feels like controller work.
Concrete failure: RTL like always_ff @(posedge clk) dqs <= ~dqs; presented as a DDR strobe generator. It is not, and it teaches a model that has to be unlearned: the strobe's phase relative to the data it times must be established and maintained against the channel, which is what write levelling calibrates.
Correct model: the controller supplies digital beats to the PHY across a boundary; the PHY produces the electrical strobe and data. Chapter 10.3 §3 drew that boundary for the read direction and it holds unchanged here.
Prevention: if controller RTL references DQS, the boundary has been crossed.
11. Interview Reasoning
"Why does write latency exist at all?"
Because the device must sample the write data, must know when to sample, and nothing tells it. There is no handshake in either direction on a DDR interface — the controller does not signal that data is starting and the device does not signal readiness. So both ends must derive the same moment from something they already share, which is the command event plus the configured offset. The write latency is an agreement about when, not a measure of how long anything takes, and its entire correctness rests on both ends having been configured consistently.
"Why is CWL not just the write-side CAS latency?"
Because the obligation runs the other way. A read latency is a promise: the device commits to producing data at an offset, and a controller that mispredicts it misses data that still exists and can simply re-read. A write latency is a deadline: the device commits to sampling at an offset, and the controller must have data there. A promise can be mispredicted and recovered from; a deadline can only be missed — and missing it means the device samples whatever the bus carries and commits it into a real location, with no stall, no timeout and no error anywhere. CWL and CL are also separate configured values that need not be equal, which is a specific and silent source of error.
"Why is a one-cycle write-latency error harder to find than a one-cycle read-latency error?"
Because it does not announce itself. A read looking in the wrong window appears to be missing data, which stalls a requester and gets investigated immediately. A write landing in the wrong cycle produces nothing but wrong memory — the command was legal, the data was driven, nothing reported an error, and the corruption is at a location that may not be read for a long time. It is found by a data check rather than a protocol check, which is much later and much further from the cause. That asymmetry is the reason to measure the write offset and report its distribution rather than checking it against a constant.
"How do you distinguish a write-latency misconfiguration from a PHY problem?"
By whether the discrepancy moves. A configuration error is fixed and reproducible, and its magnitude is usually diagnostic — equal to the configured additive latency means the controller used CWL where write latency was required; equal to CL − CWL means it used the read number. A discrepancy that changes after retraining or with temperature belongs to the PHY, and on the write side that is specifically what write levelling calibrates: landing the data inside a window the controller cannot observe. The fix differs completely — one is a constant, the other is a calibration — and tuning the constant to absorb a PHY term produces a design that works on one board.
"What would you never do when write data lands a cycle off?"
Adjust the pipeline depth until the data checks pass. That compensates for an unmodelled term rather than identifying it, and on the write side the consequence of getting it wrong later is silent corruption rather than a visible stall — so the empirical fix removes the symptom and leaves a design that fails at the next speed grade, after the next retraining, or on the next device, with no stall to warn anyone.
12. Engineering Exercise
LAUNCH_EVENTS = 6, TAG_W = 3, a part marketed at 3200 MT/s.
1. Using Chapter 10.2 §3's derivation, give the CK period, then express 6 educational cycles in nanoseconds.
2. A controller sets its depth from CL where the device's write path requires CWL, and CL − CWL = 2. Describe precisely what happens on the bus and in memory.
3. The same controller instead sets its depth from CWL while a non-zero additive latency is configured. In which direction is the data wrong, and by how much?
4. payload_ready falls one cycle before a deadline. Which outputs assert, and what happens on real hardware?
5. With LAUNCH_EVENTS = 1, walk the shift loop and confirm the block works. Which line never executes?
6. Name the three intervals of §4, their endpoints, and who owes each.
13. Summary
The write latency exists because two machines with no handshake must agree on a cycle. The device samples at a configured offset; the controller must have data there; nothing coordinates them. They agree because they were configured to agree, and for no other reason.
A read latency is a promise; a write latency is a deadline. The device commits to producing in one direction and to sampling in the other. A promise can be mispredicted and recovered from. A deadline can only be missed — and missing it means the device commits whatever the bus carried into a real location.
Reads fail loudly, writes fail silently. A mistimed read looks like missing data and is investigated at once. A mistimed write produces no stall, no timeout and no error — only wrong memory, discovered much later by a data check.
CWL is not CL. Separate configured values that need not be equal, and assuming they are lands every write CL − CWL cycles from where the device samples.
Three intervals, three owners. Write latency — the controller owes a deadline. The burst — the controller owes the bus. Recovery — the device owes internal work. Confusing the first with the third closes rows too early and corrupts data.
And because the failure is silent, measure rather than check. Report the distribution of observed command-to-first-beat offsets; a tight distribution at an unexpected value is the only cheap evidence there is, and it requires no prediction to see.
14. What Comes Next
The deadline is scheduled and the payload is waiting. Chapter 11.3 — Burst Writes is the delivery.
One write command consumes several beats, for the same architectural reason a read produces several — Chapter 10.4 derived it from the mismatch between internal access width and interface width, and the derivation is unchanged. What changes is who has to sustain it.
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 does not pause. The bus is owned for the duration, the strobe is sourced for the duration, and a gap in the middle is not a delay but a hole in the data.
And that chapter ends where this module's most important distinction begins: the last beat leaves the controller, and the write is not finished.
Return to CAS Latency for the read-side counterpart and the unit discipline this chapter uses, CAS# for why a column-command latency exists at all, The Write Command for the payload this chapter schedules, DDR2 for additive latency, and Mode-Register Set for where the configuration both ends rely on actually lives.
Continue learning
Related tutorials
- Related topic
The Refresh Requirement
Leakage produces a rule about the passage of time rather than about any operation. What the maintenance operation actually does, why it costs device availability, and how a digital design tracks a deadline, arbitrates it against traffic, and proves it never silently drops the obligation.
- Related topic
CAS Latency (CL)
CAS latency relates two protocol events, in clock cycles, under one configuration. It is not the time to access a column, not total memory latency, and not a duration.
- Related topic
Device Physics Behind Timing
The array's processes take absolute time and know nothing about any clock. A controller counts cycles. Converting between them is where a physical duration becomes a digital obligation — and where the same device needs more cycles the faster you run it.
- Related topic
CWL — CAS Write Latency
CWL inverts CL's agency: the controller produces the data, so the obligation is on the controller to launch it at the configured offset — and it is the term that sets when write recovery begins.
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.
