Skip to content
VLSI Mentor

DDR · Module 14

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.

Chapter 14.9 established CL as a fixed, programmed latency — two-sided, in cycles, governing data the device produces. CWL is its write-direction counterpart, and it is not simply a mirror:

With a read, the device produces the data and the controller receives it. With a write, the controller produces the data and the device receives it.

That inversion of agency changes who owes the obligation, which changes what can go wrong and who can detect it. And CWL carries a second job no other parameter in this module has: Chapter 14.5 showed it is a term in the projection that computes when write recovery begins, so an error in CWL moves a different parameter's deadline.

This is also the module's last chapter, so it closes with the synthesis work: the event-to-event matrix over all ten parameters, the cross-parameter consistency table, and the independent reference model that checks the whole set rather than one obligation at a time.

1. The Obligation, in Five Parts

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  PARAMETER          CWL   (CAS write latency)

  1 triggering event   a WRITE command accepted
  2 constrained event  the FIRST write data beat — launched BY THE
                       CONTROLLER
  3 resource           the data interface and the device's write path
  4 magnitude          in CK CYCLES — programmed, not physical
  5 sense              FIXED LATENCY  —  two-sided
  ─────────────────────────────────────────────────────────────────
  consequence        controller must launch first write data AT
                     write_cycle + CWL       — not at or after

Structurally identical to CL's five parts, with part 2's agency reversed. Everything interesting follows from that one word: launched.

The follow-up questions:

What re-arms it? Nothing in the minimum-separation sense; each accepted WRITE creates its own launch obligation, and several can be outstanding — a pipeline, as Chapter 14.9 §6 established for reads.

What can dominate it? Nothing. Like CL, it is not a lower bound and does not participate in Chapter 13.3 §3's maximum. It does not constrain whether the WRITE may issue — that is tRCD and tCCD.

Cycle or absolute-time component? Cycles, programmed, like CL.

Does generation matter? Not for the structure.

2. The Agency Inversion

Put the two latencies side by side, because the difference is entirely in who acts.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  READ  accepted ──── CL  ────▶  DEVICE drives data
                                 controller must be READY to capture

  WRITE accepted ──── CWL ────▶  CONTROLLER drives data
                                 device will be ready to capture

With CL, the controller is the recipient. The device commits; the controller must be ready. If the controller is not ready, it loses data that was correctly driven.

With CWL, the controller is the producer. The controller commits; the device will be ready at the configured offset. If the controller launches on the wrong cycle, the device captures the wrong thing — or captures nothing and leaves the intended location holding stale data.

Verified evidence for the class, the same as Chapter 14.9 §4's:

3. The PHY Boundary — Stated Sharply

This is the most easily crossed boundary in the module, and crossing it produces RTL that teaches a fiction.

What a controller owes. To present write data to its own interface such that it is launched at the configured offset from the accepted WRITE, measured in cycles.

What a controller does not own. How that data is physically driven onto the bus — the strobe, its preamble, its phase relationship to the data, the skew between lanes, the training that established any of it. Modules 19–21 own every part of that.

4. CWL Inside Another Parameter's Deadline

Chapter 14.5 built this and this chapter completes the loop from the other end.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  last_write_data_cycle  =  write_cmd_cycle  +  CWL  +  burst_cycles  −  1
  tWR deadline           =  last_write_data_cycle  +  resolved(tWR)

CWL appears in a deadline for a parameter that is not CWL. So consider a controller whose CWL is one cycle too large:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  the controller launches write data one cycle LATE
     → the device captures on the wrong cycle          (a CWL failure)

  AND the projected last-data cycle is one cycle late
     → the tWR deadline is one cycle late
     → precharge is held one cycle longer than needed  (a tWR slowdown)

One wrong number, two symptoms, in two different parameters' behaviour. And the two have opposite severities: the launch error corrupts data, while the deadline error merely costs a cycle. An engineer who finds the tWR slowdown first will be investigating the wrong parameter.

5. RTL — A Controller-Side Launch Obligation

Collision check. Chapter 14.9's read_latency_contract classifies observed read beats against expectations — the recipient side. Chapter 11.x's write_beat_sequencer and write_launch_pipeline own write-data sequencing. Chapter 14.5's twr_deadline_projector projects the recovery trigger. Chapter 6.5's cas_to_data_window models a column command's window.

What none of them does is track the controller's own launch obligation and report a mislaunch. read_latency_contract checks something the device owed; this checks something the design under test owes, which §2 argued is a different verification problem because there is no external authority to compare against.

The engineering problem. For each accepted WRITE, compute the cycle at which this controller must launch its first data beat, assert the launch on exactly that cycle, and report when a launch happens on any other cycle — in either direction.

Classification: controller-side sequential launch scheduling, with self-checking outputs. Counts cycles, compares cycle numbers.

What it does not model: any electrical behaviour. No strobe, no preamble, no phase, no skew, no training. §3.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────
//  write_launch_contract
//
//  CLASSIFICATION
//    Controller-side sequential launch scheduling with self-checking
//    outputs. Counts cycles and compares cycle numbers.
//
//  WHAT IT MODELS
//    §1's obligation, with the agency of §2:
//      trigger     = WRITE accepted on cycle N
//      constrained = the controller's OWN first write data beat,
//                    AT cycle N + CWL
//      sense       = FIXED LATENCY (class B) -- two-sided
//    pipelined, because several writes can be outstanding.
//    Also publishes the projected LAST data cycle, which is the input
//    Chapter 14.5's tWR projection needs -- §4.
//
//  WHAT IT DOES NOT MODEL
//    Any electrical or PHY behaviour. There is deliberately NO dqs,
//    NO preamble, NO phase, NO skew and NO training anywhere in this
//    block, because a controller-side block naming those would be
//    claiming to model what it cannot see (§3). It emits a launch
//    enable on a cycle. How the data physically reaches the device is
//    the PHY's contract, owned by Modules 19-21.
//
//  WHY SELF-CHECKING
//    §2: with CL the device is the authority and a controller compares
//    against it. With CWL the CONTROLLER is the authority, so there is
//    nothing external to compare against -- and a mislaunch corrupts
//    data the DEVICE stores, which the controller cannot observe. The
//    obligation must therefore be checked against an independently
//    computed expectation, which is what launch_early/launch_late are.
//
//  CONVENTION (Chapter 13.2 §6, as an equality per Chapter 14.9 §5)
//    WRITE accepted on cycle N with programmed CWL_CYCLES: the first
//    data beat must be launched ON cycle N + CWL_CYCLES, and the
//    remaining BURST_CYCLES-1 beats on the following cycles.
//
//  SIMULTANEITY
//    a WRITE accepted on the cycle a previous write's data launches
//        -> both handled; the pipeline holds several obligations.
//    two obligations due on the SAME cycle -> impossible if tCCD
//        (Chapter 14.6) is honoured, since two writes cannot be closer
//        than tCCD and share one CWL. REPORTED on due_collision.
//    reset -> all obligations abandoned. In-flight data belongs to
//        commands the controller no longer knows about.
// ─────────────────────────────────────────────────────────────────────
module write_launch_contract #(
  parameter int DEPTH        = 8,
  parameter int TS_W         = 12,
  parameter int BURST_CYCLES = 4,
  parameter int PTR_W = (DEPTH <= 1) ? 1 : $clog2(DEPTH),
  // Occupancy is a COUNT and can equal DEPTH.
  parameter int OCC_W = (DEPTH <= 1) ? 1 : $clog2(DEPTH + 1)
) (
  input  logic              clk,
  input  logic              rst_n,

  // ── The PROGRAMMED latency, in cycles. No conversion: §2 places CWL
  //    in CL's class, so there is no absolute-time term and nothing to
  //    resolve. A resolver here would invent a frequency dependence.
  input  logic [TS_W-1:0]   cwl_cycles,

  input  logic              write_accepted,

  // ── The controller's own data path reporting a first-beat launch.
  input  logic              launch_observed,

  output logic [TS_W-1:0]   now,

  // ── The obligation the controller owes next.
  output logic              launch_due_pending,
  output logic [TS_W-1:0]   launch_due_cycle,
  output logic [OCC_W-1:0]  outstanding,
  // High on exactly the cycle a launch is required. A data path may
  // use this directly as its launch enable, which is the point: the
  // obligation and the action come from one source.
  output logic              launch_now,

  // ── Two-sided self-check. Exactly one asserts when a launch is
  //    observed with an obligation pending.
  output logic              launch_on_time,
  output logic              launch_early,
  output logic              launch_late,
  output logic signed [TS_W-1:0] launch_error,
  // The due cycle passed with no launch. Distinct from late: a launch
  // that never happens leaves the device holding stale data, which is
  // a different failure from one on the wrong cycle.
  output logic              launch_missed,

  // ── §4: the projected LAST data cycle, which Chapter 14.5's tWR
  //    projection consumes. Published here because this block already
  //    holds CWL and the burst, so computing it elsewhere would
  //    duplicate the arithmetic and invite the two copies to drift.
  output logic [TS_W-1:0]   projected_last_data,
  output logic              projected_valid,

  output logic              due_collision,
  output logic              overflow
);

  if (DEPTH < 1) begin : g_depth
    initial $fatal(1, "write_launch_contract: DEPTH must be >= 1");
  end
  if (TS_W < 2) begin : g_ts
    initial $fatal(1, "write_launch_contract: TS_W must be >= 2");
  end
  if (BURST_CYCLES < 1) begin : g_burst
    initial $fatal(1, "write_launch_contract: BURST_CYCLES must be >= 1");
  end

  logic [TS_W-1:0]  due_ts [DEPTH];
  logic [PTR_W-1:0] head, tail;
  logic [OCC_W-1:0] occ;

  logic signed [TS_W-1:0] err;
  logic                   have_due;
  logic                   retire;

  always_comb begin
    have_due           = (occ != '0);
    launch_due_pending = have_due;
    launch_due_cycle   = have_due ? due_ts[tail] : '0;
    outstanding        = occ;

    // Wrap-tolerant signed error, per Chapter 13.3 §7.
    err          = have_due ? $signed(now - due_ts[tail]) : '0;
    launch_error = err;

    launch_now = have_due && (err == '0);

    launch_on_time = launch_observed && have_due && (err == '0);
    launch_early   = launch_observed && have_due && ($signed(err) < 0);
    launch_late    = launch_observed && have_due && ($signed(err) > 0);

    // Due cycle passed with nothing launched.
    launch_missed  = have_due && ($signed(err) > 0) && !launch_observed;

    // §4's projection, from the obligation this block already holds.
    // BURST_CYCLES is CYCLES, not transfers -- Chapter 14.5 §4 sizes
    // that confusion at four cycles for a burst of 8.
    projected_valid     = have_due;
    projected_last_data = have_due
                        ? (due_ts[tail] + TS_W'(BURST_CYCLES) - TS_W'(1))
                        : '0;

    overflow = write_accepted && (occ == OCC_W'(DEPTH));

    due_collision = (occ >= OCC_W'(2))
                 && (due_ts[tail] == due_ts[(tail + PTR_W'(1))]);

    // Retire once the obligation is discharged or demonstrably missed.
    // Retiring on a miss keeps one lost launch from misaligning every
    // later obligation -- Chapter 14.9 §7's argument, unchanged.
    retire = have_due && (launch_observed || ($signed(err) > 0));
  end

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      now  <= '0;
      head <= '0;
      tail <= '0;
      occ  <= '0;
      for (int unsigned i = 0; i < DEPTH; i++) begin
        due_ts[i] <= '0;
      end
    end else begin
      now <= now + 1'b1;

      if (write_accepted && (occ != OCC_W'(DEPTH))) begin
        due_ts[head] <= now + cwl_cycles;
        head         <= head + 1'b1;
      end

      if (retire) begin
        tail <= tail + 1'b1;
      end

      // Single occupancy update over all four combinations, so the
      // push and retire paths cannot disagree about occ.
      case ({ (write_accepted && (occ != OCC_W'(DEPTH))), retire })
        2'b10:   occ <= occ + OCC_W'(1);
        2'b01:   occ <= occ - OCC_W'(1);
        default: occ <= occ;
      endcase
    end
  end

endmodule

Interface contract. launch_now is intended to drive the data path's launch enable, so the obligation and the action share one source and cannot disagree — which is the structural answer to §2's “no external authority” problem. launch_observed then closes the loop from whatever the data path actually did. projected_last_data feeds Chapter 14.5's tWR projection from the block that already holds both terms, so the arithmetic exists once.

Parameter contract. DEPTH sized as Chapter 14.9 §7 argued — roughly ceil(CWL / tCCD) plus the burst. OCC_W is $clog2(DEPTH + 1) and PTR_W is $clog2(DEPTH), for the count-versus-index reason now stated in four chapters. BURST_CYCLES is documented as cycles, not transfers.

Corner cases. cwl_cycles == 0: the launch is due on the write cycle itself, arithmetically handled and not physically meaningful. DEPTH == 1: a second write while one is outstanding reports overflow. launch_observed with no obligation pending: no classification asserts, because all three require have_due — a spurious launch is not called early. Reset with obligations outstanding: abandoned.

Synthesis implications. DEPTH timestamp registers, two pointers, an occupancy counter, one subtractor, and an adder for the projection. launch_now is a zero-comparison on the subtraction result.

Failure modes. Gating launch_now on >= instead of == — converts a two-sided obligation into a one-sided one, launching continuously from the due cycle onward. Not driving the data path from launch_now but from a separate counter: the two drift and the self-check compares against the wrong thing. Using BURST_CYCLES as transfers: projected_last_data is late by the double-data-rate factor, moving tWR's deadline per §4. A resolver on cwl_cycles: invents a conversion.

6. The Launch Obligation, in Cycles

write_launch_contract — the controller owes the launch

10 cycles
Ten cycles with an educational write latency of three. Writes are accepted at cycles one and four, each creating a launch obligation at its own cycle plus three, giving due cycles of four and seven. The launch-now output rises on exactly cycle four and again on cycle seven, and the controller's data path launches on both, so both are classified on time with zero error. The projected last data cycle is published as the due cycle plus the burst minus one, giving five and eight, and that value is what the write-recovery projection consumes. Outstanding obligations reach two at cycle four when the second write is accepted on the same cycle the first launch is due, demonstrating that a retire and a push coincide.obligation pendingobligation pendinglaunching on schedulelaunching on schedulewrite@1 + CWL 3 = 4 — launch duewrite@1 + CWL 3 = 4 —launch duewrite@4 + 3 = 7 — launch duewrite@4 + 3 = 7 — launchdueproj last data 8 feeds tWRproj last data 8 feeds tWRCKnow0123456789write_accdue_cycle0044477777outstanding0011111100launch_nowlaunch_obson_timeproj last data0055588888t0t1t2t3t4t5t6t7t8t9

launch_now and launch_obs are identical here, which is what correct operation looks like when the data path is driven from the obligation. The value of the self-check is entirely in the cases where they differ — and §5's interface note explains why driving the data path from launch_now makes them agree by construction, leaving launch_observed to catch a data path that ignored it.

proj last data is the output that leaves this chapter. At cycle 5 it reads 8, and that number is what Chapter 14.5's projector needs to arm the tWR obligation. One parameter's output is another parameter's trigger — the only such coupling in the module.

7. Four Assertions Worth Writing

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── P1. The launch obligation is an EQUALITY, not a lower bound.
//    launch_now must assert on exactly the due cycle and nowhere else.
//    Catches gating on >=, which converts a two-sided obligation into
//    a one-sided one and launches continuously from the due cycle --
//    the §5 headline failure and the class error of Chapter 14.9 §3.
property p_launch_now_is_exact;
  @(posedge clk) disable iff (!rst_n)
    launch_due_pending |-> (launch_now == (now == launch_due_cycle));
endproperty
a_launch_now_is_exact: assert property (p_launch_now_is_exact);

// ── P2. The due cycle is write + CWL, with NO conversion. §2 places
//    CWL in CL's class -- a configured cycle count -- so a ceiling or
//    a resolver on this path would invent a frequency dependence.
property p_due_is_write_plus_cwl;
  @(posedge clk) disable iff (!rst_n)
    ( $past(write_accepted, 1) && ($past(outstanding, 1) == '0) )
      |-> (launch_due_cycle == ($past(now, 1) + $past(cwl_cycles, 1)));
endproperty
a_due_is_write_plus_cwl: assert property (p_due_is_write_plus_cwl);

// ── P3. The two-sided classification is well formed: exactly one of
//    on-time, early and late asserts on a classified launch. Catches
//    overlapping conditions, which would make a diagnostic report two
//    contradictory things -- worse than reporting nothing.
property p_classification_is_exclusive;
  @(posedge clk) disable iff (!rst_n)
    (launch_observed && launch_due_pending)
      |-> ($countones({launch_on_time, launch_early, launch_late}) == 1);
endproperty
a_classification_is_exclusive: assert property (p_classification_is_exclusive);

// ── P4. The projected last-data cycle -- the value Chapter 14.5's tWR
//    projection consumes -- is due + burst_cycles - 1. §4 showed a
//    wrong CWL moves tWR's deadline; this property makes sure the
//    block at least propagates it correctly, so a tWR shift can be
//    attributed to CWL rather than to this arithmetic.
property p_projection_feeds_twr_correctly;
  @(posedge clk) disable iff (!rst_n)
    projected_valid |->
      (projected_last_data == (launch_due_cycle + TS_W'(BURST_CYCLES)
                                                - TS_W'(1)));
endproperty
a_projection_feeds_twr_correctly:
  assert property (p_projection_feeds_twr_correctly);

// ── C1. A launch is observed ON TIME at least once. A classifier never
//    shown to fire is not known to work, and Chapter 14.9 §8 makes the
//    stronger point: an EARLY and a LATE launch should be injected
//    deliberately, because a design with no late detector passes every
//    test without ever testing the late direction.
c_launch_on_time: cover property (@(posedge clk) disable iff (!rst_n)
                                    launch_on_time);

What these prove. That the launch obligation is enforced as an equality — the structural signature of a class-B obligation; that the due cycle is write + CWL unconverted; that the classification is well formed; and that the value feeding tWR's projection is propagated correctly.

What these do not prove, and the first is the limitation §2 predicted. They cannot tell whether the programmed CWL matches the device's. The block launches on the cycle its own cwl_cycles dictates, and every property passes whether or not the device agrees — which is precisely the failure mode a controller-side authority creates. Only a mode-register readback settles it, which is a configuration check and not a timing one; §9 makes it a rule for the whole-set model.

They also do not prove the PHY delivers what was launched (§3 — a different contract entirely), nor that BURST_CYCLES is a cycle count rather than a transfer count, since P4's arithmetic is correct either way.

Vacuity. P2 requires an empty pipeline at the write; C1 requires an on-time launch. Cover both, and inject a deliberate early and late launch per Chapter 14.9 §8.

8. Cross-Parameter Consistency

Ten parameters, and a module with inconsistent definitions would be worse than no module. Here is the full set with the classification each chapter used, so any disagreement is visible in one place.

ParameterTriggerConstrained eventScopeClassUnit formGeneration
tRCDACT acceptedcolumn cmd, same bankbank-localmin separationns (verified)neutral
tRPPRE acceptedACT, same bankbank-localmin separationns (verified)neutral
tRASACT acceptedPRE, same bankbank-localmin separationns (inferred §15.3 §4)neutral
tRCACT acceptednext ACT, same bankbank-localmin separation, derivedns (verified)neutral
tWRlast write dataPRE, same bankbank-localmin separationnot verifiedneutral
tCCDcolumn cmd acceptednext column cmdshared / bank groupmin separationnCKDDR4 _S/_L
tRRDACT acceptednext ACT, diff bankshared / bank groupmin separationmax(nCK, ns) (verified)DDR4 _S/_L
tFAWaccumulation of ACTsnext ACTshared, rankrolling windownot verifiedcount of 4 verified
CLRD acceptedfirst data beat (device drives)data pathfixed latencynCK (verified)neutral
CWLWR acceptedfirst data beat (controller drives)data pathfixed latencynCKneutral

Three patterns are worth reading off that table.

Eight of ten are minimum separations. The module is overwhelmingly about one-sided obligations, which is why Chapter 14.9's two-sided arrival needed a whole section of re-orientation.

Only two triggers are not an accepted command. tWR's is a data event, requiring Chapter 14.5's projection, and tFAW's is an accumulation, requiring Chapter 14.8's history queue. Those two exceptions account for the module's two most distinctive RTL blocks.

Scope splits five bank-local, three shared, two data-path. And every shared one is where Chapter 13.3 §4's Bug 2 lives — fast and wrong, passing single-bank tests.

9. The Event-to-Event Matrix

The module's synthesis artefact: every populated edge, with its scope and class.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
                        ───────────── CONSTRAINED EVENT ─────────────
  PRIOR EVENT       ACTIVATE        column cmd      PRECHARGE    data
  ───────────────────────────────────────────────────────────────────
  ACTIVATE          tRC   (B,m)     tRCD  (B,m)     tRAS (B,m)     ·
   same bank
  ACTIVATE          tRRD  (G,m)          ·              ·          ·
   diff bank        tFAW  (R,w)
  ───────────────────────────────────────────────────────────────────
  column cmd             ·          tCCD  (G,m)         ·        CL  (D,f)
                                                                 CWL (D,f)
  ───────────────────────────────────────────────────────────────────
  PRECHARGE         tRP   (B,m)          ·              ·          ·
  ───────────────────────────────────────────────────────────────────
  last write data        ·               ·          tWR  (B,m)     ·

    SCOPE:  B bank-local   G bank group / shared   R rank-wide
            D data path
    CLASS:  m minimum separation   f fixed latency   w rolling window
    ·       no direct edge in this set

Four structural facts fall out of the matrix that no individual chapter could show.

One ACTIVATE populates three cells in its own row. Chapter 14.4 §1 said one accepted activate arms three obligations; here you can see them as three edges from one event.

The ACTIVATE column has four entries across two scopes. A candidate ACTIVATE is subject to tRC or tRP bank-locally, and tRRD and tFAW at coarser scopes. That is the most heavily constrained command in DDR, which is why Chapter 14.8 noted tFAW is often controlling for activate-heavy traffic.

The data column is the only one with fixed latencies, and it is the only column where the controller is not choosing to act.

The matrix is not symmetric and has empty cells. A PRECHARGE does not directly constrain a column command — it constrains an ACTIVATE, which then constrains the column command. Some relationships are compositions of edges rather than edges, which Chapter 13.3 §5 predicted and Chapter 14.4 worked through.

How a whole-set reference model checks every parameter at once rather than one obligation at a time. An observed command stream feeds an event classifier, which identifies each command and derives the data events that follow from the programmed latencies. The classifier updates a deadline set holding one entry per applicable obligation across all ten parameters. When a candidate command is observed, the reducer gathers every obligation applicable to that command by resource, takes the maximum of their deadlines, and identifies the controlling one. The verdict compares the observed issue cycle against that maximum and emits a report naming the controlling parameter, its source event and the shortfall, which is far more actionable than a bare timing error.Observed streamClassifierDeadline setReducerReportcommands + dataeventsarm per-parameterdeadlinescandidate commandapplicable, byresourcemax + controllingparamviolation with fullcontext

10. DV — A Whole-Set Reference Model

Every chapter has built a per-parameter checker. A real verification environment needs one model over all of them, and Chapter 13.4 §6's issue_timing_checker is its skeleton. Four design rules, each earned somewhere in the module.

Invert every representation. The designs in this module use per-bank countdowns (14.1, 14.2, 14.3), a shared countdown (14.6), a circular timestamp buffer (14.8) and expectation FIFOs (14.9, this chapter). The model should hold timestamps for everything and recompute from scratch, so it shares no bookkeeping with any of them.

Resolve every magnitude independently, from its own table entry. Not from the design's registers. Chapter 14.1 §10 made the general case; the module then produced three specific reasons it matters — tRP and tRCD coinciding at some grades so a shared register passes; tRAS obtained by subtraction so a wrong tRC propagates; and tRRD's page-size dependence so the wrong table row is silently plausible.

Derive data events rather than observing design signals. tWR's trigger and both latencies' data events must come from the model's own CWL + burst − 1 arithmetic (Chapter 14.5 §4), computed from independently sourced terms. A model reading the design's projection inherits its errors.

Report the applicable set, not just the violation. Every chapter's report converged on this shape, and the module's best examples are worth collecting: Chapter 14.4 §8 marks satisfied obligations so a reader sees nothing was overlooked; Chapter 14.6 §10 and 14.7 §11 add the counterfactual — this would have been legal in a different bank group; Chapter 14.8 §10 enumerates the window's contents, because a density violation has four source events and the oldest is the one that matters.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  TIMING VIOLATION
    command        : PRECHARGE, bank 2
    issued at      : cycle 4181
    applicable     : tWR  -> legal from 4186   CONTROLLING
                     tRAS -> legal from 4150   satisfied
    violated       : tWR
    trigger        : last write data, cycle 4171   (DERIVED)
      derivation   : WRITE @ 4154 + CWL 14 + burst 4 − 1 = 4171
      CWL source   : device mode register readback, not design register
    short by       : 5 cycles
    note           : tRAS was satisfied 31 cycles earlier; a design
                     checking only tRAS would have issued at 4150

The CWL source line is this chapter's contribution to the report format. §2 established that a wrong CWL moves tWR's deadline, so a model that took CWL from the design's register would compute the same wrong trigger and agree. Stating where the number came from makes the independence auditable rather than merely claimed.

11. Debugging

Symptom. Written data is wrong when read back later, or precharge timing after writes is off.

Candidate mechanismEvidenceDiscriminator
CWL wrong — controller and device disagreeWrite data corrupt and tWR deadline shifted, both by the same k§4's discriminator. Both symptoms shifted by the same amount implicates CWL as one root cause. Mode-register readback confirms.
tWR projection arithmetic wrongtWR deadline shifted; write data correct§4. Data fine plus deadline off means the projection, not CWL — Chapter 14.5 §4's − 1 or transfers-for-cycles.
Launch gated on >= not ==Data launched continuously from the due cycle§5's headline failure. Check whether launch_late can ever fire.
Data path not driven from launch_nowlaunch_now and launch_observed differ§5's interface note. Two sources drifting.
PHY untrained or mis-trainedCWL verified correct; data still corrupt§3. This block exonerates CWL and points at Modules 19–21 — a useful negative result.
BURST_CYCLES as transfersprojected_last_data late by the DDR factorCompare against due + burst_cycles − 1 by hand.
DEPTH undersizedFailures only under sustained write burstsoverflow. One dropped obligation misaligns all later ones.

The discriminator that defines this chapter is whether two symptoms moved together. CWL is the only parameter in the module that appears in another parameter's deadline, so a CWL error shows up twice — once as corruption and once as a tWR shift, both by the same k. Seeing both together identifies a single root cause where an engineer would otherwise chase two bugs.

And the second: whether CWL is provably correct. If it is, and data is still wrong, the honest conclusion is that the problem is not in this chapter's scope at all — it is the PHY, and §3 drew that boundary precisely so this conclusion can be reached cleanly rather than by exhaustion.

12. Common Misconceptions

“CWL tells the controller when a WRITE may issue.” Tempting because it is the write-side latency number, and the read-side symmetry with tRCD invites it. Why it is wrong: like CL, CWL governs data, not issue. Issue legality is tRCD, tCCD and bank state. Consequence: writes delayed by CWL for no reason — correct data, throughput short per write. Replacement model: issue obligations and latency obligations are different edges. Debugging clue: no data errors and write throughput short by a constant.

“CWL is CL for writes, so the same reasoning applies.” Tempting because the five-part forms are structurally identical. Why it is wrong: §2's agency inversion. With CL the controller receives and the device is the authority; with CWL the controller produces and is the authority. So a CWL failure corrupts data the device stores, which the controller cannot observe — it surfaces on a later read of a different transaction. Consequence: a verification environment that checks CL properly and assumes CWL is symmetric has no independent check on the write direction. Replacement model: same class, opposite agency, different detectability. Debugging clue: write corruption discovered far from its cause.

“A wrong CWL only affects write data.” Tempting because CWL is the write-data latency and that is where it acts. Why it is wrong: §4 — CWL is a term in tWR's projected trigger, so a wrong CWL also moves the write-recovery deadline. One wrong number, two parameters' behaviour. Consequence: an engineer investigating a tWR timing shift looks at tWR and finds nothing wrong with it. Replacement model: CWL is the module's only parameter that feeds another's deadline. Debugging clue: a tWR shift and a data corruption of the same magnitude.

“The controller's RTL should model the strobe to get CWL right.” Tempting because write data really does need a strobe with a real phase relationship. Why it is wrong: §3 — CWL is a cycle count; the electrical relationship is the PHY's contract, established by training and owned by Modules 19–21. Consequence: controller RTL naming signals it cannot observe, which misleads every later reader and makes the two independent requirements harder to debug separately. Replacement model: two requirements, one digital and one electrical, both necessary. Debugging clue: a proposed fix that requires the controller to know about skew.

“CWL needs an ns-to-cycle conversion.” Tempting because four parameters in the module do. Why it is wrong: §2 places CWL in CL's class — a configured pipeline depth in cycles, verified for CL from the datasheet's own headings. Consequence: a design resolving it invents a frequency dependence and gets a different CWL per speed grade. Replacement model: configured depths do not resolve. Debugging clue: the configured CWL varying across grades when the table does not.

“A checker that copies the RTL's timing counters is independent verification.” Tempting because it agrees with the design, which looks like passing. Why it is wrong: agreement is the problem — a checker sharing the design's representation, magnitudes, or derived events shares its bugs and reports success on a broken design. §10's four rules are the module's accumulated answer. Consequence: a verification asset that provides confidence without checking, which is worse than no checker because the team stops looking. Replacement model: invert the representation, resolve magnitudes from the table, derive data events independently. Debugging clue: a checker that has never disagreed with its design over a long programme.

13. Interview Reasoning

“What does CWL constrain, and how does it differ from CL?” Both are fixed programmed latencies in cycles — two-sided, so being late fails as surely as being early. The difference is agency: with CL the device drives data and the controller must be ready to capture; with CWL the controller drives data and the device will be ready. That inversion matters for detectability — a CL failure corrupts data the controller reads and its own checkers can see it, while a CWL failure corrupts what the device stores and only surfaces on a later read of a different transaction.

“Does CWL tell the controller when a WRITE may issue?” No — issue legality is tRCD, column spacing and bank state. CWL governs when the data must be launched after the write has already been accepted. Putting it in the issue conjunction delays every write by CWL for no reason: correct data, throughput short by a constant, and no error to point at.

“Why is write recovery measured from the write data rather than the WRITE command, and what does CWL have to do with it?” Because the interval protects data being driven into the cells, which cannot start before the data arrives. CWL is how you find that cycle: the last write data is write_cmd + CWL + burst_cycles − 1, so CWL is a term in tWR's deadline. That gives CWL a property no other parameter in the set has — a wrong CWL produces both a data corruption and a tWR timing shift, by the same amount, which is a useful single-root-cause signature.

“Your write data is corrupt and precharges after writes are one cycle late. One bug or two?” Almost certainly one: a CWL that is one cycle too large. It mislaunches the data and, because CWL feeds tWR's projection, it also pushes the recovery deadline out by one. The check is whether both shifts are the same magnitude — if they are, fix CWL and both resolve. If the data were correct and only the deadline were off, the projection arithmetic would be the suspect instead, typically the − 1 or using burst transfers where burst cycles belong.

“Should controller RTL model the write strobe to implement CWL?” No. CWL is a cycle count, and the electrical relationship between data and strobe is the PHY's contract, established by training. A controller-side block naming a strobe is claiming to model what it cannot observe. The practical argument is that these are two independent requirements — correct CWL with an untrained PHY still fails, and a perfect PHY cannot rescue a wrong CWL — so keeping them separate is what makes either debuggable.

“How would you verify all ten of these parameters together rather than one at a time?” One model over the whole set, following four rules the module accumulated: hold timestamps for everything and recompute from scratch, since the designs use countdowns, a shared counter, a circular buffer and FIFOs; resolve every magnitude from its own table entry rather than from the design's registers, because tRP and tRCD coincide at some grades, tRAS is often obtained by subtraction, and tRRD depends on page size; derive data events from independently sourced CWL and burst rather than reading the design's projection; and report the whole applicable set with the controlling parameter marked, plus a counterfactual where scope selection was involved.

“Give me the most heavily constrained command in DDR and why.” ACTIVATE. It is subject to tRC or tRP bank-locally, tRRD at bank-group scope, and tFAW rank-wide as a rolling window — four obligations across three scopes and two constraint classes. That is why activate-heavy traffic so often finds tFAW controlling, and why the activate column of the event-to-event matrix is the fullest.

14. Engineering Exercises

1. Compute launch cycles and the tWR trigger. A WRITE is accepted at cycle 500 with CWL of 14 and a burst of 8 transfers. Give the first data cycle, the last data cycle, and the projected tWR trigger.

Worked: 8 transfers occupy 4 clock cycles. First data launch at 500 + 14 = 514. Last data at 500 + 14 + 4 − 1 = 517. That last figure is the tWR trigger, and Chapter 14.5 adds the resolved tWR to it.

2. Propagate a CWL error. Repeat exercise 1 with CWL mistakenly set to 15. Give the launch cycle, the projected trigger, and both resulting symptoms.

Worked: launch at 515 — one cycle late, so the device captures the wrong cycle, giving data corruption. Projected trigger at 518 instead of 517, so the tWR deadline is one cycle late and precharge is held one cycle longer than needed — a slowdown. One wrong number, two symptoms, both shifted by 1.

3. Distinguish two root causes. Design A has CWL one too large. Design B has the correct CWL but omits the − 1 in the projection. Both show a tWR deadline one cycle late. Give the one observation that separates them.

Worked: whether the write data is correct. Design A also mislaunches, so data is corrupt. Design B launches correctly and only the deadline moves. Data correct plus deadline late isolates the projection; both wrong isolates CWL.

4. Classify all ten. Without looking at §8, write each of the module's ten parameters' trigger, scope and class. Then check. Which did you get wrong, and is the error in the trigger, the scope or the class?

Worked guidance: the two most commonly missed triggers are tWR's — a data event, not the command — and tFAW's, which is an accumulation rather than any single event. The most commonly missed scopes are tCCD's and tRRD's, which are shared rather than bank-local. And the most commonly missed classes are CL's and CWL's, which are fixed latencies rather than minimum separations. Those six are the module's six hardest facts, and they are hard for a reason — each is the exception to a pattern the other parameters establish.

5. Read the matrix. Using §9's matrix, list every obligation applicable to a candidate ACTIVATE to bank 5 given that bank 5 was precharged recently and other banks have been active. Then say which you would expect to control for activate-heavy traffic.

Worked: tRP from bank 5's precharge (bank-local); tRC from bank 5's previous activate (bank-local); tRRD from the most recent activate to any bank, with the magnitude selected by bank-group relationship; and tFAW from the rolling window. Four obligations, three scopes. For activate-heavy traffic tFAW is the most likely to control, because it is the only one that tightens as the rate of activates rises rather than depending on a single prior event.

6. Find the dependent-checker bug. A verification model reads CWL from the design's configuration register to derive the tWR trigger. Construct the scenario in which the model and the design are both wrong and agree, and give the fix.

Worked: the controller is programmed with CWL 15 while the device holds 14. The design launches at write + 15 and projects the trigger from 15; the model reads 15 and projects the same. They agree, and both are wrong by one — the device captured at write + 14. Every check passes and the data is corrupt. The fix is §10's rule: the model takes CWL from a mode-register readback of the device, not from the design's register, so the disagreement surfaces.

7. Justify the boundary. §3 forbids naming electrical signals in this block. Argue that a controller-side CWL model should include a preamble parameter, then rebut using the two-independent-requirements argument.

15. Summary

CWL is CL's write-direction counterpart — a fixed, programmed latency in cycles, two-sided, with the same five-part shape and one word changed: the controller launches the data rather than receiving it.

That agency inversion has three consequences. A CWL failure corrupts data the device stores, which the controller cannot observe, so it surfaces on a later read of a different transaction. The obligation is owed by the design under test, so there is no external authority to compare against and a verification environment must reconstruct the expected launch cycle independently. And CWL is a term in tWR's projected trigger, so a wrong CWL moves a different parameter's deadline — the only such coupling in the module, and it yields a single-root-cause signature: corruption and a tWR shift of the same magnitude.

The PHY boundary is the sharpest in the module. CWL is a cycle count; the strobe, its preamble, its phase and the training that established them are the PHY's contract, owned by Modules 19–21. write_launch_contract has no strobe, no preamble and no skew anywhere in it — and the practical payoff is that a verified-correct CWL exonerates this layer and points cleanly at the PHY, rather than leaving the two tangled.

The module's synthesis: eight of ten parameters are minimum separations; only two triggers are not an accepted command — tWR's data event and tFAW's accumulation, which account for the module's two most distinctive RTL blocks; and scope splits five bank-local, three shared, two data-path, with every shared one being where Chapter 13.3 §4's fast-and-wrong bug lives.

The event-to-event matrix shows what no single chapter could: one ACTIVATE populating three cells in its own row; the ACTIVATE column carrying four obligations across three scopes, making it the most heavily constrained command in DDR; the data column as the only one with fixed latencies and the only one where the controller is not choosing to act; and empty cells that are compositions rather than edges — a PRECHARGE constrains an ACTIVATE, which then constrains the column command.

And the whole-set reference model rests on four rules the module earned chapter by chapter: invert every representation; resolve every magnitude from its own table entry, because tRP and tRCD coincide at some grades, tRAS is often obtained by subtraction, and tRRD depends on page size; derive data events independently; and report the applicable set with the controlling parameter marked and a counterfactual where scope was selected.

16. Module 14 in One Chain

Module 13 built a timing engine and left it empty. This module filled it.

Every parameter is an edge with five parts — a triggering event, a constrained event, a resource, a magnitude and a sense — and the recurring grammar was the point rather than the parameters. By this chapter, a parameter you have never met should be a four-question classification: what triggers it, what does it constrain, what resource owns it, and is it a minimum, a latency, an occupancy or a window?

The units carry the classification. Micron's verified speed-bin heading — Data Rate (MT/s) | CL | tRCD (ns) | tRP (ns) | tRC (ns) — says it in one line: physical requirements in absolute time, configured pipeline depths in cycles. Physical requirements cost more cycles at a faster clock; configured depths cost the same cycles and less time. That single distinction predicted why tRRD carries a dual-term specification, why tCCD does not resolve, and why a CL of 22 can be faster than a CL of 14.

Scope determines applicability, and getting it wrong has two opposite failures. Bank-local held globally is safe and slow and invisible; shared held per bank is fast and wrong and fails more the better the design does its job.

Composition is a maximum, never a sum. Chapter 14.4 §5's trace showed tRAS satisfied while a precharge was illegal, and tRC satisfied while an activate was illegal — and changing one WRITE to a READ moved two verdicts by four cycles. Memorising definitions would have answered none of those six candidates.

And the honest gaps are part of the result. Five DDR5 questions this curriculum could not close from public material — interleaved burst, activate-to-column separation, column spacing, activate spacing and the activate window — plus tWR's and tFAW's unit forms and CWL's values. DDR4 is publicly documented and DDR5 largely is not, so a DDR4 timing table carried into DDR5 deserves more scepticism than it usually gets. _S and _L are DDR4-era names for a DDR4 mechanism, and this module labelled them as such every time.

Module 15 takes up refresh — the obligation that is neither a separation nor a latency but a deadline the controller owes the device, and the first in this curriculum where failing to act, rather than acting too soon, is the violation.

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.