Skip to content
VLSI Mentor

DDR · Module 10

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.

Chapter 10.1 left a transaction pending, waiting through an interval it knows nothing about. This chapter is that interval.

Chapter 6.5 already did the hardest part: it derived why a latency attached to the column command in the first place, what the interval is made of, and why the name survived the signal it was named after. None of that is repeated here.

What remains is the part that produces the most engineering errors:

What exactly does the number relate, in what units, and why is it not the thing people use it for?

CAS latency is probably the most quoted number in DDR and one of the least precisely understood. It is a relationship between two protocol events, counted in clock cycles, valid for one configuration — and treating it as a duration, as an array access time, or as memory latency each produces a different wrong answer.

1. Two Different Timing Questions

Before anything else, separate the two questions that both get called "DDR timing," because conflating them is the reason this chapter has a boundary at all.

QuestionAsksOwned by
Read latencywhen does data appear, relative to this command?this chapter
Timing legalitywhen may this command be issued, relative to other commands?Modules 13 and 14

They are not the same kind of claim. Read latency is a promise the device makes: issue a read now, and data appears at a defined offset. Timing legality is a constraint the controller must respect: do not issue this command until a minimum interval has elapsed since some other one.

One is an output of the protocol, the other an input to the scheduler. A controller can violate timing legality and produce undefined behaviour; it cannot "violate" read latency — it can only mispredict it and fail to capture what arrives.

This chapter is entirely about the first, and names no command-to-command parameter.

2. What the Number Relates

CAS latency relates the read command event to the first data of its return, measured in clock cycles, under one configuration.

Every clause of that does work, and the common definitions drop at least one.

"Relates two events." It is an offset between events, not a duration of a process. Nothing is "taking" CL cycles in the sense of being busy for them — the number says where the second event is relative to the first.

"The read command event." Chapter 6.1 and Chapter 7.1 §2 established that a command exists at a defined sampling event. The latency is counted from that event, not from when the controller decided to issue it.

"The first data of its return." Not all of it. A read returns several beats (Chapter 10.4); the latency locates the first. The rest follow at the transfer cadence, which is a different quantity entirely.

"In clock cycles." Not nanoseconds. §3 is about why that distinction is where most latency arithmetic goes wrong.

"Under one configuration." The value depends on the device, the operating speed, and the mode-register settings in force. A CL quoted without its operating point is not a fact about anything.

The family of terms

Datasheets do not use one number, and the relationships between them matter more than the values.

TermRelatesNotes
CL — CAS latencythe column command to first read datathe quoted number
AL — additive latencyan allowance to issue the column command earlierChapter 4.3 covered its introduction
RL — read latencythe total command-to-first-data offsetwhat a controller must actually predict
CWL — CAS write latencythe write-side analogueModule 11's, named here only for contrast

The structural relationship is that read latency is composed of the additive component and the column latency — datasheets express it as their sum. The controller must predict RL, not CL, and a controller that schedules against CL alone while additive latency is configured will expect data early by exactly the additive amount.

3. Units — Where the Arithmetic Goes Wrong

This section is short, mechanical, and prevents more errors than anything else in the chapter.

Four different quantities get called "speed" or "cycles," and they differ by factors of two.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   MT/s        transfers per second        the marketed number
   CK period   one clock cycle             what CL is counted in
   MHz         clock frequency             half the MT/s figure
   UI          one transfer interval       half a CK period

The factor of two is DDR itself. Module 4 established that a DDR interface performs two transfers per clock period. So:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   EDUCATIONAL WORKED EXAMPLE — assumptions stated, arithmetic derived.

   Given a part marketed at 3200 MT/s:

     transfers per second  =  3200 × 10⁶
     transfers per CK      =  2                    (DDR, Module 4)
     CK frequency          =  3200 / 2  =  1600 MHz
     CK period             =  1 / 1600 MHz  =  0.625 ns

   Given an EDUCATIONAL read latency of 20 CK cycles:

     latency in time       =  20 × 0.625 ns  =  12.5 ns

   The 20 is an EDUCATIONAL FIGURE, not a device value.
   The 0.625 ns follows from the marketed rate by derivation.

Three errors this prevents:

"DDR-3200 means a 3200 MHz clock." It does not. The clock is 1600 MHz; the 3200 counts transfers. An engineer who computes a CK period as 1/3200 MHz gets every latency wrong by a factor of two.

Comparing CL across speeds. A larger CL at a higher rate can be a shorter time. Comparing the cycle counts of two parts running at different rates compares nothing — §4 is about why that comparison is made constantly and is almost always meaningless.

Counting beats as cycles. A burst's beats arrive at the transfer cadence, not the clock cadence, so a burst of eight beats does not occupy eight clock cycles. Chapter 10.4 develops this, and it is a frequent off-by-two in trace analysis.

4. Why the Cycle Count Grew

A short historical section, because it explains a number that otherwise looks alarming.

Module 4 established the pattern across generations: the quoted CAS latency in cycles has grown substantially, while the physical interval it corresponds to has stayed roughly in the same range.

That is not a contradiction — it is the unit problem in §3 seen over time. The clock period shrank with each generation. An interval whose physical duration is set by the array and the output path therefore spans more cycles at each new rate, without getting any slower in absolute terms.

And it explains why the latency is a configurable setting rather than a fixed device property. A device that can run at several speeds must be told which latency to use, which is why it lives in a mode register — and why Chapter 7.6 called mode-register configuration a correctness concern rather than a tuning knob.

5. RTL — Carrying a Transaction Across the Latency

The engineering problem

Chapter 10.1 created a record at acceptance. Something must carry its identity across the interval and raise a signal when the return is due — without knowing anything about the device.

Why hardware needs it

A controller's only means of anticipating a return is to count. There is no signal from the device announcing that data is coming; the controller issued the command, knows the configured latency, and must predict.

Classification

SYNTHESIZABLE EDUCATIONAL CONTROLLER RTL. Layer C only.

What it models

A fixed-depth pipeline carrying a tag from read acceptance to an expected-return event, with occupancy visibility and collision reporting.

What it does NOT model

The device (nothing here does). Data, beats or the bus (Chapters 10.3, 10.4). Variable latency, mode-register changes, or retraining. Timing legality (Modules 13, 14). The PHY's latency contribution (Module 19). Reordering — returns are assumed to emerge in issue order, which §7 states as an explicit assumption rather than a universal rule.

Interface and parameter contract

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// read_return_pipeline
//
// Classification: SYNTHESIZABLE EDUCATIONAL CONTROLLER RTL.
//
// LATENCY_CYCLES IS AN EDUCATIONAL PIPELINE DEPTH. IT IS NOT A JEDEC
// CAS-LATENCY VALUE AND IS NOT DERIVED FROM ANY DEVICE. A real controller
// derives its depth from the device's configured read latency plus the
// PHY's own contribution (Module 19).
//
// MODELS: a fixed-depth pipeline carrying a transaction TAG from read
// acceptance to an expected-return event, with occupancy and collision
// reporting.
//
// IS NOT A DRAM MODEL. Nothing here represents an array, a column path or
// an output driver. It is the CONTROLLER'S EXPECTATION, and an expectation
// can be wrong -- which is the subject of Section 9.
//
// ORDERING ASSUMPTION: returns emerge in issue order. Stated, not assumed
// universal -- see Section 7.
//
// MODELS NO PHYSICAL OR ANALOG BEHAVIOUR.
// ─────────────────────────────────────────────────────────────────────────
module read_return_pipeline #(
  parameter int TAG_W          = 3,
  // EDUCATIONAL PIPELINE DEPTH. See the header.
  parameter int LATENCY_CYCLES = 4
) (
  input  logic                 clk,
  input  logic                 rst_n,

  // ── From Chapter 10.1's admission block.
  input  logic                 accept,
  input  logic [TAG_W-1:0]     accept_tag,

  // ── The expected-return event. NOT data, and not a claim that data has
  //    arrived -- only that the controller now expects it.
  output logic                 return_due,
  output logic [TAG_W-1:0]     return_tag,

  // ── Visibility. How many transactions are in flight in the interval.
  output logic                 occupied,
  // An accept while the first stage is already occupied. Only reachable
  // when a requester issues faster than the pipeline advances, which
  // Chapter 10.1's single-outstanding admission prevents -- reported here
  // because this block may be reused where it does not.
  output logic                 accept_collision
);

  if (TAG_W < 1) begin : g_tw
    initial $fatal(1, "read_return_pipeline: TAG_W must be >= 1");
  end
  if (LATENCY_CYCLES < 0) begin : g_lc
    initial $fatal(1, "read_return_pipeline: LATENCY_CYCLES must be >= 0");
  end

  // ── The degenerate depth. LATENCY_CYCLES == 0 means the return is
  //    expected in the same cycle as acceptance: a combinational pass.
  //    It is supported because it is the right way to express "no
  //    modelled latency" -- and because a zero-length unpacked array
  //    would be an illegal declaration, so the case must be structural.
  if (LATENCY_CYCLES == 0) begin : g_zero_depth
    assign return_due       = accept;
    assign return_tag       = accept_tag;
    assign occupied         = 1'b0;
    assign accept_collision = 1'b0;
  end else begin : g_pipe

    logic             vld_q [LATENCY_CYCLES];
    logic [TAG_W-1:0] tag_q [LATENCY_CYCLES];

    // A collision is reported BEFORE the shift, against the stage the new
    // entry is about to occupy.
    assign accept_collision = accept && vld_q[0];

    always_ff @(posedge clk) begin
      if (!rst_n) begin
        for (int i = 0; i < LATENCY_CYCLES; i++) begin
          vld_q[i] <= 1'b0;
          // Tags are not cleared: only the valid bit makes a stage
          // meaningful, and retaining the tag keeps the last-seen value
          // visible for debugging. Section 7's P4 covers the flush.
          tag_q[i] <= '0;
        end
      end else begin
        // Shift toward the output. Written highest-first so each stage
        // reads its predecessor's PRE-shift value -- with nonblocking
        // assignments the order is immaterial, and it is written this way
        // to read as a shift rather than to depend on ordering.
        for (int i = LATENCY_CYCLES - 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 return_due = vld_q[LATENCY_CYCLES-1];
    assign return_tag = tag_q[LATENCY_CYCLES-1];

    // Occupancy across every stage. A loop rather than a reduction,
    // because vld_q is an unpacked array and cannot be OR-reduced
    // directly.
    always_comb begin
      occupied = 1'b0;
      for (int i = 0; i < LATENCY_CYCLES; i++)
        if (vld_q[i]) occupied = 1'b1;
    end

  end

endmodule

State representation

LATENCY_CYCLES stages, each a valid bit and a tag. The valid bit is the transaction; the tag is its identity. Nothing else travels — no address, no data, no expectation of size. Those live in Chapter 10.1's record, indexed by the tag, which is the whole reason a tag exists.

Combinational behaviour

The output stage's valid and tag, a collision term, and an occupancy loop.

Sequential behaviour

A shift register, nonblocking throughout. With nonblocking assignments the loop order is immaterial — every right-hand side reads the pre-clock value — and the descending order is a readability choice, noted in the code so a reviewer does not look for a dependency that is not there.

Reset behaviour

Every valid bit clears; tags are left. The pipeline is fully flushed, so a reset during flight loses the in-flight expectations — which is correct behaviour and a real hazard: the device may still return data for a read issued before the reset, and the controller will no longer be expecting it. §9's phantom return, and Chapter 10.5's checker is where it is caught.

Cycle-by-cycle trace

LATENCY_CYCLES = 4, TAG_W = 3:

Cycleaccepttag invld_q[0..3] afterreturn_duereturn_tag
000 0 0 00
1101 0 0 00
200 1 0 00
300 0 1 00
400 0 0 10
500 0 0 010

Read cycle 5 carefully. return_due is high when the entry is in the last stage as seen at that cycle's sampling — that is, four cycles after the acceptance cycle. Which convention a design uses is the single most common off-by-one in this area, and §9 is about how to tell which one you have.

How to simulate, and expected output

Drive a single accept and confirm return_due exactly LATENCY_CYCLES cycles later with the same tag. Then:

LATENCY_CYCLES = 0return_due must equal accept combinationally, and occupied must stay low. This exercises the g_zero_depth arm, which no other configuration reaches.

LATENCY_CYCLES = 1 — the minimum registered depth, where vld_q[0] is also the output stage. This is the configuration most likely to break a hand-written shift loop, because the descending loop body never executes.

Back-to-back accepts on consecutive cycles must produce returns on consecutive cycles, in the same order, with tags preserved. This is the ordering assumption made visible.

Reset mid-flight must clear every stage and produce no further return_due.

accept while vld_q[0] is set must assert accept_collision — and note this cannot occur when Chapter 10.1's admission block is upstream, which is why the output exists for reuse rather than for that composition.

Expected waveform

§6, which shows both the single-read case and a back-to-back pair.

Synthesis implications

LATENCY_CYCLES × (1 + TAG_W) flops — at depth 4 and a 3-bit tag, 16. A read-latency pipeline is genuinely this cheap, which is worth knowing because the instinct is to implement it as a counter per transaction. A shift register costs less and makes the ordering assumption structural.

Corner cases

LATENCY_CYCLES == 0 is legal and structural. LATENCY_CYCLES == 1 is the minimum registered depth. Negative depth does not elaborate. TAG_W == 1 is legal. There is no maximum — a large depth costs flops linearly, and a real controller's depth is bounded by the configured latency, not by this block.

Failure modes and debugging clues

return_due arriving one cycle early or late is the off-by-one in §9, and the discriminator is whether LATENCY_CYCLES matches the configured read latency or the CAS latency alone — the difference is the additive component from §2. return_due never arriving means the pipeline was flushed by a reset, or accept never reached it. accept_collision asserting means a requester is issuing faster than the modelled latency permits with a single-entry-per-stage scheme.

Extension ideas

Carry a small expected-beat count alongside the tag and the block begins to describe the shape of the return, not just its timing — which is Chapter 10.4's. Making LATENCY_CYCLES a runtime register models a mode-register change, at the cost of needing the pipeline to be drained first, which is itself a good exercise.

Limitations

Fixed depth, known at elaboration. In-order returns, assumed. One entry per stage. It predicts; it does not observe — nothing here can tell whether data actually arrived, which is precisely the separation Chapter 10.5 exploits to detect a mispredicted latency.

6. Latency, in Cycles

read_return_pipeline — identity preserved across the interval

10 cycles
Ten cycles with an educational pipeline depth of four. A read is accepted at cycle one with tag zero, and the occupied output asserts. Four cycles later the return-due output asserts carrying tag zero. Two further reads are accepted on consecutive cycles five and six with tags one and two, and both are in flight simultaneously, which the occupied output shows. Their return-due events appear on consecutive cycles in the same order with tags one and two, demonstrating that the pipeline preserves both identity and issue order.L = 4 (educational)L = 4 (educational)accepted, tag 0accepted, tag 0return due, tag 0return due, tag 0two in flighttwo in flightreturns in orderreturns in orderCKacceptaccept_tag0000012222occupiedreturn_duereturn_tag0000000001t0t1t2t3t4t5t6t7t8t9
Figure 1 — Acceptance to expected return, and two reads in flight at once. EDUCATIONAL PIPELINE DEPTH — NOT A JEDEC CAS-LATENCY VALUE.

Cycles 1 to 5 are the whole mechanism. An acceptance enters the pipeline; four cycles later a return is expected, carrying the same tag. Nothing about the device is involved — this is the controller counting.

Cycles 5 and 6 accept two reads on consecutive cycles, and both are in flight at once. occupied stays high continuously from cycle 2 onward. Their returns emerge on consecutive cycles in the same order, tags 1 then 2, which is the in-order assumption made visible rather than assumed.

And return_due is not data. It is the controller saying I expect data now. Whether data actually appears is Chapter 10.3's, and the gap between expectation and observation is where every latency bug lives.

EDUCATIONAL PIPELINE DEPTH — NOT A JEDEC CAS-LATENCY VALUE. The depth of four is chosen to fit a readable waveform and corresponds to no device.

7. Four Assertions Worth Writing

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// NOTE THE GENERATE GUARD. $past(x, n) requires n >= 1, and ##n with n == 0
// collapses to the same cycle -- so P1 and P2 are not expressible at
// LATENCY_CYCLES == 0. That configuration is a combinational pass-through
// whose contract is the far simpler P0 below, and pretending one property
// covers both would produce an illegal $past in a legal configuration.
// ─────────────────────────────────────────────────────────────────────────
if (LATENCY_CYCLES == 0) begin : g_zero_asrt

  // P0 -- the degenerate depth is a wire. Trivial, and it is the whole
  // contract at that configuration.
  property p_zero_depth_is_passthrough;
    @(posedge clk) disable iff (!rst_n)
      (return_due == accept) && (!accept || (return_tag == accept_tag));
  endproperty
  assert property (p_zero_depth_is_passthrough);

end else begin : g_pipe_asrt

// P1 -- a return is expected only if a read was accepted exactly
// LATENCY_CYCLES cycles earlier, and the identity is preserved. This is
// the block's entire contract in one property, and it fails on any
// off-by-one in either direction.
property p_return_matches_acceptance;
  @(posedge clk) disable iff (!rst_n)
    return_due |-> $past(accept, LATENCY_CYCLES)
                   && (return_tag == $past(accept_tag, LATENCY_CYCLES));
endproperty
assert property (p_return_matches_acceptance);

// P2 -- no phantom returns. The converse direction: an acceptance must
// produce a return, so a dropped entry is caught as well as an invented
// one. Together with P1 this makes the pipeline a bijection between
// acceptances and expected returns.
property p_acceptance_produces_a_return;
  @(posedge clk) disable iff (!rst_n)
    accept |-> ##LATENCY_CYCLES (return_due && (return_tag == $past(accept_tag, LATENCY_CYCLES)));
endproperty
assert property (p_acceptance_produces_a_return);

// P3 -- occupancy is honest. If nothing is in flight, no return can be
// due; this catches an output stage that latches rather than shifting,
// which would republish a stale return every cycle.
property p_no_return_when_empty;
  @(posedge clk) disable iff (!rst_n)
    !occupied |-> !return_due;
endproperty
assert property (p_no_return_when_empty);

// P4 -- reset flushes. After a reset the pipeline must produce nothing
// until a new acceptance works through it. A pipeline that survives reset
// with stale entries produces returns for transactions the controller has
// already forgotten, which is the hardest class of phantom return to
// diagnose.
property p_reset_flushes_the_pipeline;
  @(posedge clk)
    $rose(rst_n) |-> !return_due;
endproperty
assert property (p_reset_flushes_the_pipeline);

end

What these prove. P0 covers the degenerate depth, where the block is a wire and the other four properties cannot be written at all. P1 and P2 together make the registered pipeline a bijection between acceptances and expected returns — nothing invented, nothing dropped, identity preserved. That pairing is worth more than either alone, because an off-by-one that shifts everything uniformly satisfies neither, while a dropped entry satisfies P1 and fails P2. P3 catches a latching output stage. P4 catches the stale-entry hazard across reset.

What these do not prove. Nothing here proves data actually returns, or returns on time — the block predicts and cannot observe, so every property is about its own arithmetic. Nothing proves LATENCY_CYCLES is the right value; a pipeline configured to the wrong depth satisfies all four properties perfectly and mispredicts every return, which is §9's central point and is only detectable by comparing against an observation. Nothing proves JEDEC timing compliance — no property in this module does, and Modules 13 and 14 are where that question is asked. And nothing proves the ordering assumption is valid for any system other than this pipeline.

8. DV — Checking a Latency You Configured

There is a trap here that catches otherwise careful verification environments, and it is worth stating plainly.

A monitor that predicts the return window using the same constant the controller was configured with cannot detect a wrong constant. Both are wrong together, the comparison passes, and the environment reports a clean latency check while every read arrives at a time nobody validated.

Three ways out, in increasing order of strength:

Derive the expectation from the configuration, not from the RTL parameter. The monitor should read the mode-register settings the device was actually programmed with — which Chapter 7.6 established is a real, observable configuration event — and compute its expectation from those. Now a controller programmed inconsistently with its own pipeline depth is detectable, which is the most common real version of this bug.

Measure rather than check. Record the observed offset from each read command to its first returned beat, and report the distribution. A latency checker with a configured expectation answers yes or no; a distribution shows you the value, and an unexpected value is visible without anyone having predicted it. A tight distribution at an unexpected offset is the clearest possible evidence of a misconfiguration.

Check the relationship, not the number. Some properties hold regardless of the value: every read produces exactly one first-beat event, the offsets are consistent across reads under a fixed configuration, and the offset changes only when the configuration changes. Those catch instability even when the absolute value is unknown, and they are the right properties for a bring-up environment where the correct value has not been established yet.

And separate the two failures. Data arrived at the wrong time and the wrong data arrived are independent, and a scoreboard that checks data at a predicted window conflates them: wrong-time data looks like missing data, and the actual data mismatch is never reached. Chapter 10.5 §8 builds the separation.

9. Debugging — The Data Is One Cycle Late

Symptom. Read data returns correctly but consistently one cycle later than the controller expects. Every read is affected identically. The data itself is correct.

This symptom is worth practising because "one cycle" has at least five unrelated causes, and the instinct — adjust the constant until it works — fixes the symptom and leaves four of them.

Candidate mechanisms.

  1. The pipeline depth was set from CL alone when the device has a non-zero additive latency configured, so the expectation is short by that amount. §2.
  2. An off-by-one in the pipeline's own convention: whether return_due asserts in the last stage or after it. §5's trace.
  3. The PHY contributes latency the controller's model does not account for. The device's read latency is not the whole command-to-captured-beat offset — Module 19 owns the PHY's share.
  4. The monitor's cycle definition differs from the design's — counting from the cycle the command was presented rather than the cycle it was sampled. Chapter 6.1.
  5. A mode-register setting differs from what the controller assumes — the device is running at a latency nobody configured deliberately. Chapter 7.6.

Evidence to collect. The measured offset from command to first beat, not the configured one. The device's programmed mode-register values, read back where the generation supports it. The controller's LATENCY_CYCLES and how it was derived. Whether the discrepancy is exactly one cycle or exactly the additive-latency setting. And whether the offset is constant across all reads — that single fact separates a systematic misconfiguration from an intermittent capture problem.

Discriminator.

  • Is the discrepancy exactly the configured additive latency? Mechanism 1, and it is the first thing to check because it is the most common and the arithmetic is decisive. A controller scheduling against CL where RL was required is short by exactly AL.
  • Is it exactly one cycle, always? Mechanism 2 or 4 — a convention mismatch. Distinguish them by where you measure: if the design and the monitor disagree, it is 4; if they agree with each other and both disagree with the device, it is 2.
  • Does the discrepancy change when the PHY is reconfigured or retrained? Mechanism 3, and it is not a controller bug — the model is missing a term that belongs to a different layer.
  • Read back the mode registers. If they differ from what the controller assumes, mechanism 5, and everything downstream was predicted from a fiction.
  • Is the offset constant? If it varies read to read, none of the above — that is a capture or association problem and belongs to Chapters 10.3 and 10.5.

Responsible layer. Mechanisms 1, 2 and 5 are layer C — the controller's model or its configuration. Mechanism 3 is layer B. Mechanism 4 is the verification environment, not the design, and it is worth checking early precisely because the instinct is to change the design.

Fix. Per mechanism — and never by tuning the constant until the test passes. A depth adjusted empirically to compensate for an unmodelled PHY term will break at a different speed grade, after retraining, or on the next device.

10. Common Misconceptions

"CAS latency is the time to access a column."

Why it is tempting: the name, and the fact that a column is involved.

Concrete failure: an engineer expects a faster array to reduce CL proportionally, and cannot explain why CL in cycles has risen across generations while devices got faster.

Correct model: it relates two protocol events in cycles. The interval is composed of several things (Chapter 6.5 §3) and its cycle count tracks the clock period as much as anything physical. §2 and §4.

Prevention: always state it as a relationship between events, never as a duration of an operation.

"CAS latency is total memory latency."

Why it is tempting: it is the memory number everyone quotes, so it feels like the memory latency.

Concrete failure: a system model that predicts load-to-use latency from CL and is wrong by a large factor, then "explains" the gap as measurement error.

Correct model: CL is one term among many. A CPU load also pays cache lookup, interconnect transit, controller queueing, any required row-state work (Module 9), the PHY's contribution, and the return path — and under load the queueing term can dominate all of them.

Prevention: draw the layered picture before quoting any number. If a latency budget has one term in it, it is wrong.

"DDR-3200 means a 3200 MHz clock."

Why it is tempting: the number is presented as a speed and looks like a frequency.

Concrete failure: every derived time is wrong by a factor of two — a CK period computed as 0.3125 ns instead of 0.625 ns, and every latency conversion built on it.

Correct model: 3200 MT/s, two transfers per CK, so a 1600 MHz clock. §3.

Prevention: write the units in the arithmetic. MT/s ÷ 2 = MHz is one line and it never fails.

"A lower CAS latency part is faster."

Why it is tempting: it is a latency, and lower latencies are better.

Concrete failure: parts are compared across different speed grades, where a higher CL at a higher rate is a shorter time — and the comparison recommends the slower part.

Correct model: CL is a cycle count; comparing counts at different clock periods compares nothing. And even at equal time, Chapter 6.5 and Module 9 both established that access pattern dominates.

Prevention: convert both to time using §3's derivation before comparing anything.

"A row hit means zero read latency."

Why it is tempting: Chapter 9.3 called a hit the best case, and "best" slides into "free."

Concrete failure: a performance model in which hits return immediately, which over-predicts throughput and cannot explain measurements.

Correct model: a hit removes a row-state transition. The read latency is entirely unaffected — it is the same interval whether the row was just opened or has been open for a thousand cycles.

Prevention: Chapter 9.3 §4's formulation — a hit is the absence of required row-state work, not the absence of an access.

"CAS latency and tRCD are the same thing."

Why it is tempting: both are latencies in the read path, both are quoted in the same list of part specifications, and both are counted in cycles.

Concrete failure: a latency budget that counts one interval twice, or one that omits the row-opening term entirely for accesses that needed an activate.

Correct model: they relate different pairs of events — one concerns the activate-to-column relationship and belongs to Modules 13 and 14; this chapter's concerns the column command to its data. A row hit pays only the second; a miss pays both.

Prevention: name the two events every latency relates. Two intervals with different endpoints are different intervals, whatever they are called.

"The RTL latency model is a DRAM device model."

Why it is tempting: it produces returns at the right time against a testbench.

Concrete failure: an engineer expects it to reveal a wrong latency configuration, and it cannot — it is the expectation, so it agrees with itself by construction. §8.

Correct model: layer C. It predicts; it does not observe.

Prevention: §8's three techniques, especially measuring the offset rather than checking it.

11. Interview Reasoning

"What does CAS latency actually relate?"

Two protocol events: the read command's sampling event and the first data of its return, counted in clock cycles, under one configuration. Every clause matters. It is an offset between events rather than the duration of an operation, so nothing is "busy" for CL cycles in any meaningful sense. It locates only the first beat — the rest follow at the transfer cadence. And it is configuration-dependent, so a CL quoted without its operating point and mode-register settings is not a fact about anything. What a controller actually has to predict is the read latency, which includes any configured additive component.

"Why isn't CAS latency total memory latency?"

Because it is one term in a chain and usually not the dominant one. A CPU load pays cache lookup, interconnect transit, controller queueing, any row-state work the access requires — an activate, or a precharge and an activate on a conflict — then this interval, then the burst, then the return path. Under load the queueing term routinely dominates all of the others. The practical test is that two systems with identical CL and different access patterns perform very differently, which is exactly Module 9's result: the work that matters is measured in row-state transitions, not in any latency figure.

"Why has CAS latency in cycles grown across generations?"

Mostly because the clock period shrank, not because devices got slower. The interval is set largely by physical processes — column selection, internal movement, output preparation — whose duration has stayed in a similar range, so the same interval spans more cycles at each higher rate. This is why a rising CL number is not evidence of a worse device, and why comparing CL between parts at different speed grades compares nothing at all. Convert both to time first, and even then the comparison is usually less informative than the access pattern.

"Why can a row hit still have non-zero read latency?"

Because a hit and the read latency answer different questions. A hit means the row-state transition that would otherwise be required is not required — no precharge, no activate. It says nothing about the interval between the column command and its data, which is the same whether the row was opened a moment ago or has been open for a thousand cycles. The column still has to be selected, the data still has to traverse the internal path, and the output still has to be prepared and launched.

"Your read data is consistently one cycle late. How do you approach it?"

By measuring the actual offset rather than adjusting the constant. The first check is whether the discrepancy equals the configured additive latency — a controller scheduling against CL where read latency was required is short by exactly that, and it is the most common cause. If it is exactly one cycle, it is a convention mismatch, and where you measure separates a design off-by-one from a monitor that counts from command presentation rather than command sampling. If it changes after retraining, the missing term belongs to the PHY and is not a controller bug at all. What I would not do is tune the depth until the test passes — that compensates for an unmodelled term and breaks at the next speed grade.

12. Engineering Exercise

1. A part is marketed at 4800 MT/s. Derive the CK frequency and the CK period, showing units.

2. With that period and an educational read latency of 24 CK cycles, what is the interval in nanoseconds?

3. Part A runs at 3200 MT/s with an educational CL of 22; part B at 4800 MT/s with an educational CL of 40. Which has the shorter column-command-to-first-data interval?

4. A controller sets LATENCY_CYCLES from the device's CL. The device has a non-zero additive latency configured. What does the controller observe, and by how much is it wrong?

5. With LATENCY_CYCLES = 1, walk the shift loop in §5 and confirm the block still works. Which line never executes?

6. A monitor and a controller both use the same LATENCY_CYCLES constant. Name the bug class this cannot detect and give a technique that can.

13. Summary

CAS latency relates two protocol events — the read command and its first data — in clock cycles, under one configuration. Not a duration, not an array access time, and not a property of a device independent of how it is programmed.

What a controller must predict is read latency, which includes any configured additive component. Scheduling against CL where read latency was required makes every read arrive late by exactly the additive amount — uniformly, reproducibly, and identifiably.

Units are where the arithmetic fails. MT/s ÷ 2 = MHz, because DDR performs two transfers per clock period. A part marketed at 3200 MT/s has a 1600 MHz clock and a 0.625 ns period, and getting this wrong scales every derived latency by two.

A rising CL across generations is mostly a rising clock frequency. The interval's physical duration stayed in a similar range while the period shrank, so the same interval spans more cycles. CL is therefore not a quality metric, and comparing counts across speed grades compares nothing.

A row hit does not reduce it. A hit removes row-state work; the column-command-to-data interval is unchanged.

And a model configured from the same constant as the design cannot check it. Derive the expectation from the programmed configuration, or measure the offset and report its distribution — because a latency checker that agrees with itself reports success regardless of the truth.

14. What Comes Next

The controller now expects data at a defined moment. Chapter 10.3 — Data Return is about what actually arrives, and about a boundary this chapter has been careful to gesture at without crossing.

During a read, the DRAM drives the bus. That is a reversal — for a write the controller's side drives — and it means the data arrives accompanied by a timing reference the device generated, not the controller's clock. Chapter 6.10 established what that strobe is; 10.3 establishes what it means for a read transaction.

It also draws the line this module depends on: below a certain point, capture is a PHY problem involving delay, alignment and training that ordinary controller RTL cannot and should not express. Above it, the controller receives already-captured digital beats. Getting that boundary right is most of what the chapter does, because the code people write when they get it wrong looks plausible and models nothing.


Return to CAS# for why the interval exists and what it is made of, The Read Command for the transaction waiting through it, DDR2 for the introduction of additive latency, Mode-Register Set for where the configuration lives, and Row Hits for the work a hit does and does not remove.

Continue learning

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.