Skip to content
VLSI Mentor

DDR · Module 19

Timing Alignment

A write command and its data leave the PHY on different paths and must arrive in a defined relationship. The device specifies the relationship; the PHY absorbs the difference between the paths.

Chapter 19.2 built two gearboxes and left a question open on purpose. A write gearbox emits beats as fast as its consumer takes them — but nothing in it decides when the first beat should leave.

That decision is this chapter's subject, and it exists because of a structural fact Chapter 19.1 §4 established:

A command and the data that belongs to it leave the PHY on different paths. The device specifies the relationship it expects between them. The PHY is responsible for producing that relationship despite the two paths not being identical.

Both halves matter. The relationship is not the PHY's to choose — it comes from the device and the mode registers the controller programmed. What the PHY owns is the compensation that makes the specified relationship actually occur at the device's pins.

1. Two Paths, One Deadline

Follow a write from the moment Chapter 17.1's commit point fires.

The command goes out on the command/address path: through launch logic, through CA output cells, across the board, into the device's command inputs. The data goes out on the data path: through 19.2's gearbox, through DQ output cells, across a different set of board traces, into the device's DQ inputs.

Those are different journeys. They traverse different logic, different I/O cells, and different board traces of different lengths. There is no reason for them to take the same time, and in general they do not.

Meanwhile the device has a rule. Chapter 14.10 established it: after a write command, the device expects its data a defined number of cycles later — CWL, a value programmed into a mode register. The device is not negotiating. It samples when its own internal counting says to sample, and data that arrives at a different time is data it does not correctly receive.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  what the device requires            what the PHY must arrange

  WR command at its pins              command leaves PHY at time T_cmd
         |                            data leaves PHY at time T_data
         | CWL cycles                 the two paths differ by some
         v                            amount the PHY alone can know
  data expected at its pins           so T_data is NOT simply T_cmd + CWL

2. The Offset Has Two Parts

The single most useful idea in this chapter is that the launch offset is a sum of two terms of completely different character.

TermWhere it comes fromKnown when?Changes with
Architecturalmode-register latency: CWL for writes, CL for reads (14.9, 14.10)design / configuration time — it is a programmed numberspeed bin, mode-register settings
Physicalthe difference between the two paths: silicon, package, board, temperatureonly by measurement, after the system existsboard revision, part, temperature, voltage

The architectural term is arithmetic. Look up the programmed CWL, count cycles, done. Any competent engineer can compute it from a datasheet and a mode-register setting.

The physical term is not computable at all. It is not a number anybody can derive; it is a number somebody has to find, on this board, by trying values and observing which ones work. That process is Module 21's subject and this chapter does not touch it.

3. The Same Structure, Mirrored

The write and read alignment problems drawn as two sequences against the same actors. On a write, the controller commits a write command, the PHY launches it on the command and address path, and separately launches the write data on the data path at an offset which is the programmed write latency plus a trained compensation term; both arrive at the DRAM, which samples the data at the interval its mode register specifies. On a read, the controller commits a read command, the PHY launches it, the DRAM responds after the programmed read latency by driving data and a strobe back, and the PHY must open its receive path at the right moment, which requires the same two-part offset applied in the receive direction. The symmetry is that both directions need a programmed term the controller knows and a measured term only the PHY can hold.Alignment on a write and on a readControllerPHYDRAMcommit WR + writedatacommand on the CApathdata at CWL +trained offsetsamples where CWLsayscommit RDcommand on the CApathdata + strobe afterCLreceive path open atCL + trainedassembled read word

Read the two halves against each other. The write problem is “launch the data so it arrives when the device expects it.” The read problem is “be ready to receive when the device sends it.” Same structure, opposite direction, and both decompose into a programmed term plus a measured one.

One asymmetry is worth naming because it shapes 19.4. On a write the PHY controls when data leaves, which is an action. On a read the PHY controls when it listens, which is a window — and a window has two edges to get right rather than one instant. That is why the receive side needs a gate and the transmit side does not.

4. What the PHY Does Not Get to Decide

A boundary worth stating sharply, because it is the one most often blurred in conversation.

The PHY does not choose CWL or CL. Those are device parameters selected from the speed bin (Chapter 14.9) and written into a mode register by the initialisation sequence. The controller's timing model is built on them (11.4). The PHY consumes them.

The PHY does not decide when a command issues. Chapter 17.1's commit point did that, subject to every legality rule in Modules 13 and 14.

What the PHY decides is narrow and specific: the offset between launching the command and launching the data, such that the device's rule is satisfied at the device's pins. That is a single scheduling relationship inside the PHY, and §6's block implements exactly it and nothing else.

5. Why the Alignment Is Per Lane

One structural point that 19.5 depends on.

The data path is not one path. It is a set of byte lanes (19.2 §3), each with its own DQ pins, its own strobe, and — critically — its own board traces. Those traces are not the same length, and they are not routed identically.

So the physical term of §2 is not one number for the interface. It is one number per lane, and a PHY that holds a single global compensation value can align the average lane and misalign the others.

This has a direct diagnostic consequence and it recurs throughout the module: a fault affecting one lane and sparing the others is per-lane state or per-lane physics. It is essentially never a controller problem, because the controller does not know lanes exist, and it is essentially never a gearbox problem, because a gearbox slices a word uniformly across all lanes (19.2 §14).

The block below is written for one lane, with the lane index as a parameter, precisely so that this structure is visible rather than assumed.

6. The Launch Aligner

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────
// phy_launch_aligner
//
// CLASSIFICATION
//   Synthesizable educational RTL. Sequential. One responsibility:
//   given a committed column command, assert the data-launch trigger
//   the correct number of cycles later, where "correct" is the sum of
//   a programmed latency and an opaque trained compensation.
//
//   It models ORDERING and OFFSET ACCOUNTING in cycles. It does not
//   model sub-cycle timing, which is the whole of the hard part and is
//   not expressible here (§10).
//
// WHAT IT DOES NOT MODEL
//   - No sub-cycle or fractional delay. The trained term here shifts
//     the launch by whole cycles. A real PHY's compensation is largely
//     SUB-CYCLE, implemented in delay elements that portable RTL
//     cannot express (Chapter 19.1 §5). This block accounts for the
//     integer part and names the rest as out of scope.
//   - No training. trained_offset is an INPUT and an opaque value;
//     Module 21 owns how it is found and Chapter 19.5 owns where it
//     is stored and when it is valid.
//   - It does not CHOOSE cwl_cycles. That is a mode-register value the
//     controller programmed (Chapter 14.10) and is an input here.
//   - No command legality, no scheduling (Modules 13, 14, 17).
//   - No strobe generation (Chapter 19.4), no capture (Module 20), no
//     electrical behaviour (Module 22).
// ─────────────────────────────────────────────────────────────────────
module phy_launch_aligner #(
  // Largest total offset this block can represent, in cycles.
  parameter int MAX_OFFSET = 32,
  // Which byte lane this instance serves. Present so that the per-lane
  // structure of §5 is explicit at the interface rather than implied.
  parameter int LANE_ID    = 0,
  parameter int OFF_W = (MAX_OFFSET <= 1) ? 1 : $clog2(MAX_OFFSET + 1)
) (
  input  logic              clk,
  input  logic              rst_n,

  // ── From Chapter 17.1's commit: a column WRITE has been issued.
  //    One pulse per command.
  input  logic              wr_cmd_committed,

  // ── The two terms of §2, kept as separate inputs so that they
  //    remain separately observable -- which is what makes §13's
  //    population discriminator usable in hardware, not just on paper.
  input  logic [OFF_W-1:0]  cwl_cycles,      // programmed, from the MR
  input  logic [OFF_W-1:0]  trained_offset,  // measured, opaque here

  // ── From Chapter 19.5: the trained value is meaningful.
  input  logic              trained_valid,

  // ── To Chapter 19.2's write gearbox: begin launching this word.
  output logic              data_launch,

  // ── Observability.
  output logic [OFF_W-1:0]  total_offset,
  output logic              counting,
  output logic              err_launch_untrained,
  output logic              err_offset_overflow,
  output logic              err_command_while_counting
);

  if (MAX_OFFSET < 1) $fatal(1, "phy_launch_aligner: MAX_OFFSET must be >= 1");

  // ── The sum, computed one bit wider than the counter so that it
  //    cannot itself wrap, then SATURATED against MAX_OFFSET rather
  //    than truncated into it. A truncated offset launches data early
  //    and presents as a capture fault, which sends the investigation
  //    to entirely the wrong layer (§13).
  logic [OFF_W:0] sum;
  assign sum = {1'b0, cwl_cycles} + {1'b0, trained_offset};

  assign err_offset_overflow = sum > (OFF_W+1)'(MAX_OFFSET);
  assign total_offset        = err_offset_overflow ? OFF_W'(MAX_OFFSET)
                                                   : OFF_W'(sum);

  logic [OFF_W-1:0] cnt;
  logic             armed;

  assign counting    = armed;
  assign data_launch = armed && (cnt == OFF_W'(0));

  // ── Launching against an unestablished trained value is a bring-up
  //    error: the offset is arbitrary, so the data lands nowhere in
  //    particular. Surfaced rather than launched quietly (§13).
  assign err_launch_untrained = wr_cmd_committed && !trained_valid;

  // ── A second command while one is still counting means the write
  //    spacing upstream is tighter than this single-slot aligner can
  //    track. Real PHYs pipeline several; §12 states the limitation.
  assign err_command_while_counting = wr_cmd_committed && armed;

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      cnt   <= '0;
      armed <= 1'b0;
    end else begin
      // ── Fire first, then arm. A command arriving on the same cycle
      //    a launch fires must start a fresh count rather than be
      //    absorbed into the one that is ending.
      if (armed && cnt != OFF_W'(0)) cnt <= cnt - OFF_W'(1);
      else if (armed)                armed <= 1'b0;

      if (wr_cmd_committed) begin
        // total_offset == 0 would mean launching in the same cycle as
        // the command, which no real configuration does; the count
        // still handles it by firing on the next cycle.
        cnt   <= total_offset;
        armed <= 1'b1;
      end
    end
  end

endmodule

A note on what the counter is really doing. It is counting cycles, and cycles are the coarse part of the problem. The hard part of alignment is the fraction of a cycle — placing a launch edge somewhere inside a bit period — and no counter can do that. §10's assertion review is explicit that this block's correctness is necessary and nowhere near sufficient.

7. Launching a Write, Cycle by Cycle

EDUCATIONAL — cycle numbers show ordering only. cwl_cycles and trained_offset are shown as small integers so the accounting is traceable; neither is a device figure and the real compensation is largely sub-cycle (§6).

cwl_cycles = 5, trained_offset = 2, so total_offset = 7.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  cyc  wr_commit  trained_valid  armed  cnt  data_launch  note
  ───  ─────────  ─────────────  ─────  ───  ───────────  ───────────────────
   3       0            1          0     0        0
   4       1            1          0     0        0       command committed
   5       0            1          1     7        0       counting
   6       0            1          1     6        0
   7       0            1          1     5        0
   8       0            1          1     4        0
   9       0            1          1     3        0
  10       0            1          1     2        0
  11       0            1          1     1        0
  12       0            1          1     0        1       <-- data_launch
  13       0            1          0     0        0       gearbox now emitting

Cycle 4 arms; cycle 12 launches — eight cycles later for an offset of seven, because the count is loaded on the cycle after the command and decrements to zero. That off-by-one is exactly the kind of thing §11's independent model exists to check, and exactly the kind of thing that is invisible in review and obvious in a trace.

Now the same configuration with the trained value not yet established:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   4       1            0          0     0        0       err_launch_untrained

The command is committed and the aligner reports that it has been asked to launch against a value that means nothing. Nothing stops it — the block is not a safety interlock — but the error is visible, and §13's cold-boot symptom is exactly this condition going unreported.

8. Both Paths, End to End

§7 traced the aligner alone. This traces the whole chain — every block Module 19 has built, in one run, in each direction. It is the clearest single answer to “what does a PHY actually do,” and it is worth reading slowly because each row belongs to a different chapter.

EDUCATIONAL — cycle numbers show ordering only. The offsets are small integers so the chain is traceable; none is a device figure, and the compensation that decides success is sub-cycle (§7's callout).

The write direction. cwl_cycles = 5, trained_offset = 2, four beats. Blocks: 19.1's command stage, this chapter's aligner, 19.2's write gearbox, 19.4's strobe generation.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  cyc  event                                    block        signal
  ───  ──────────────────────────────────────   ──────────   ─────────────────
   0   controller commits WR; PHY accepts it    19.1 stage   ctrl_cmd_ready=1
                                                             -> held=1
   0   aligner arms on the same commit          19.3         armed=1, cnt=7
   1   command offered on the CA path           19.1 stage   cmd_launch=1
   2   CA path takes the command                19.1 stage   launch_taken=1
                                                             -> held=0
   3   ...aligner counting...                   19.3         cnt=5
   8   count reaches zero                       19.3         data_launch=1
   9   first beat leaves the gearbox            19.2         beat A0, first=1
   9   strobe generation begins alongside       19.4         PHY drives DQS
  10   second beat                              19.2         beat A1
  11   third beat                               19.2         beat A2
  12   final beat                               19.2         beat A3, last=1
  12   strobe generation ends                   19.4         PHY releases DQS

Four distinct acceptance events, and conflating any two of them is a bug. The controller's request was accepted at cycle 0. The command was taken by the CA path at cycle 2. The data launch began at cycle 8. The burst completed at cycle 12. None of these is the transaction's completion, which Chapter 17.5 §8 owns and which for a write is a protocol question rather than a PHY one.

Note that the command leaves at cycle 2 and the data at cycle 9. That seven-cycle separation is the entire subject of this chapter, and it is not slack — it is the interval the device requires, plus the compensation the board demands.

The read direction. cl_cycles = 6, gate_offset = 2, LEAD_CYCLES = 1, TRAIL_CYCLES = 1, four beats. Blocks: 19.1's stage, 19.4's gate, the abstract capture block, 19.2's read assembler.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  cyc  event                                    block        signal
  ───  ──────────────────────────────────────   ──────────   ─────────────────
   0   controller commits RD; PHY accepts       19.1 stage   held=1
   0   gate controller arms                     19.4         G_WAIT, cnt=6
   2   CA path takes the command                19.1 stage   launch_taken=1
   7   gate opens -- BEFORE anything arrives    19.4         gate_open=1
   8   strobe becomes active at the pins        device       (the estimate
                                                             was correct)
   8   first beat captured                      MODULE 20    captured_first=1
   9   second beat captured                     MODULE 20    captured_valid
  10   third beat captured                      MODULE 20    captured_valid
  11   final beat captured                      MODULE 20    captured_valid
  11   assembler completes the word             19.2         word_valid=1
  13   gate closes                              19.4         gate_open=0
  ...  controller accepts the word              19.2         word_ready=1

The two directions are not mirror images, and this trace shows why better than prose can. On the write, every cycle in the table was chosen by the PHY — the launch, the beats, the strobe. On the read, the PHY chose exactly one thing, cycle 7, and everything else was the device's. That asymmetry is 19.4 §1 against 19.4 §2, and it is the reason the receive side carries all of the module's difficulty.

9. What the Assertions Prove

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── P1. A launch happens exactly total_offset+1 cycles after a
//    command. The integer accounting property, stated as a delay so it
//    checks the INTERVAL rather than merely that a launch eventually
//    occurred.
property p_launch_at_offset;
  @(posedge clk) disable iff (!rst_n)
    (wr_cmd_committed && !armed)
      |-> ##1 (counting [*1:$]) ##0 data_launch;
endproperty
a_launch_at_offset: assert property (p_launch_at_offset);

// ── P2. One launch per command. Catches a counter that reloads or an
//    armed flag that fails to clear -- both of which produce a second
//    data burst the device is not expecting, which corrupts whatever
//    it does expect next.
property p_one_launch_per_command;
  @(posedge clk) disable iff (!rst_n)
    data_launch |=> (!data_launch until_with wr_cmd_committed);
endproperty
a_one_launch_per_command: assert property (p_one_launch_per_command);

// ── P3. No launch without a command. The converse, and the property
//    that catches a spurious arm out of reset.
property p_no_launch_without_command;
  @(posedge clk) disable iff (!rst_n)
    data_launch |-> $past(armed, 1);
endproperty
a_no_launch_without_command: assert property (p_no_launch_without_command);

// ── P4. The offset is the sum of the two terms, saturated rather than
//    wrapped. An offset that wraps produces a launch far too early --
//    which presents as a capture failure and sends the investigation
//    to entirely the wrong layer (§13).
property p_offset_is_sum_or_saturated;
  @(posedge clk) disable iff (!rst_n)
    total_offset == ((cwl_cycles + trained_offset > OFF_W'(MAX_OFFSET))
                     ? OFF_W'(MAX_OFFSET)
                     : cwl_cycles + trained_offset);
endproperty
a_offset_is_sum_or_saturated: assert property (p_offset_is_sum_or_saturated);

// ── P5. Launching against an unestablished trained value is reported.
//    Not forbidden -- this block does not police bring-up order -- but
//    never silent.
property p_untrained_launch_reported;
  @(posedge clk) disable iff (!rst_n)
    (wr_cmd_committed && !trained_valid) |-> err_launch_untrained;
endproperty
a_untrained_launch_reported: assert property (p_untrained_launch_reported);

// ── Covers.
c_untrained_command: cover property (@(posedge clk) disable iff (!rst_n)
                       wr_cmd_committed && !trained_valid);
c_offset_saturates:  cover property (@(posedge clk) disable iff (!rst_n)
                       err_offset_overflow);
c_command_collision: cover property (@(posedge clk) disable iff (!rst_n)
                       wr_cmd_committed && counting);

What they prove. That the integer offset accounting is correct: one launch per command, at the summed offset, never without a command, with overflow saturated and bring-up-order violations reported.

What they do not prove — and here the gap is larger than anywhere else in this module. These properties are entirely blind to the quantity that actually determines whether a write works. The compensation that matters is sub-cycle, and this model contains no sub-cycle representation, so no property written against it can be sensitive to the error it is supposed to prevent. P1 passes identically whether the trained value is correct or wildly wrong, because both are integers and the block counts both faithfully.

That is not a weakness in the properties. It is the boundary of what RTL verification can reach on this problem, and stating it is more useful than any additional property would be. The sub-cycle term is verified by measurement on real hardware with real trained settings, which is Module 21's domain and, when it goes wrong, Module 28's.

Vacuity. P2 uses until_with, which is satisfied trivially if wr_cmd_committed never recurs — so a single-command test proves nothing. c_command_collision and a multi-command stimulus are what make it real.

10. Corner Cases

SituationCorrect behaviourFailure if mishandled
trained_valid low at a commandlaunch proceeds; error reportedsilent launch against a meaningless offset
cwl_cycles + trained_offset > MAX_OFFSETsaturates; overflow flaggedwraps to a tiny offset — data launched far too early
command while countingreported; count restartstwo writes collapsed into one launch
total_offset = 0launches the cycle after the commanda launch in the same cycle, which no device expects
MAX_OFFSET = 1OFF_W guarded to 1zero-width counter
reset while countingarmed clears; no launcha launch with no command behind it
trained_offset changes while countingthe loaded count is unaffectedan offset that shifts mid-flight
back-to-back commands at exactly the offseteach launches onceone launch absorbed by the previous count

The row about trained_offset changing mid-count is worth a note. This block loads the sum once, at the command, and a later change does not disturb an in-flight count. That is the conservative choice and it matters during 19.5's periodic recalibration, when settings genuinely do change while traffic is running.

11. DV — Checking the Interval, Not the Counter

The reference model must not re-implement the countdown, because a countdown is precisely what an off-by-one lives in.

Model it as a queue of expected launch cycles: on each observed wr_cmd_committed, compute cycle + total_offset + 1 arithmetically and push it. On each observed data_launch, pop and compare against the current cycle. At end of test, assert the queue is empty — an unmatched entry is a command whose data never launched, which is a far worse condition than a mistimed one.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  LAUNCH INTERVAL MISMATCH
    command index      : 12
    committed at cycle : 4,081
    cwl_cycles         : 5
    trained_offset     : 2
    total_offset       : 7
    expected launch    : cycle 4,089   (commit + offset + 1)
    observed launch    : cycle 4,088
    error              : one cycle EARLY

    diagnosis : the count is loaded and decremented in the same cycle,
                so the interval is offset rather than offset+1.
    population check : does this affect every unit, or only some?
                every unit  -> integer accounting, i.e. this bug
                some units  -> not this; the trained term differs per
                               board and this report would not be
                               reproducible across them (§2)
    NOT indicated by this report : anything about whether offset 7 is
                the RIGHT value. The block counted faithfully to a
                number somebody else supplied.

The last two blocks are what make the report usable. The population check turns the report into the §2 discriminator, and the final line prevents the most likely misreading — that a correct interval means a correct alignment.

Directed cases worth running: MAX_OFFSET = 1; trained_offset = 0, which is the pure-architectural case and should still work; an offset that saturates; commands spaced exactly at the offset, one apart, and colliding; trained_valid toggling around a command; and a reset landing mid-count.

12. Synthesis and What Is Missing

Cost. One OFF_W-wide down-counter, an armed flag, and an adder one bit wider than the counter. For MAX_OFFSET = 32 that is six bits of counter and a seven-bit adder — negligible, and instantiated once per lane (§5), which is where the multiplier is.

What a production aligner has that this does not:

  • Sub-cycle delay, which is the part that matters and is a technology-specific cell rather than logic (19.1 §5).
  • Pipelining. This block tracks one outstanding command; a real PHY must track several, because Chapter 14.6's column spacing permits commands closer together than the latency. err_command_while_counting marks exactly this limitation rather than hiding it.
  • A read-side counterpart. The read direction needs the mirrored structure of §3, and its output is a window rather than an instant — which is 19.4's gate.
  • Per-lane deskew beyond a whole-cycle offset.
  • Recalibration-safe updates, so settings can change without disturbing traffic in flight.

13. Debugging

Symptom: every write fails, on every board, from the first one. The architectural term. Check the programmed CWL against the mode register actually written and against the speed bin in use. §2's population test points here immediately, and this is the cheap case — it is a configuration bug and it is the same on every unit.

Symptom: writes fail on some boards and not others, or above a certain rate. The physical term. Not a CWL problem, and not an RTL problem. This is trained-value territory: 19.5 for whether the value was established, Module 21 for whether the algorithm found a good one.

Symptom: writes fail after a cold boot and pass after a warm reset. Check err_launch_untrained. Traffic issued before the trained value is established produces exactly this signature, because a warm reset typically preserves the setting while a cold boot must re-establish it. Chapter 19.1 §10's cycles 0–1 are the same lesson at the command interface.

Symptom: one lane fails and the others pass. §5. Per-lane trained state or per-lane board physics. Not the controller, and not the gearbox — a gearbox error would affect all lanes identically.

Symptom: data lands earlier than the configuration calls for. Check err_offset_overflow before investigating anything physical. When the two terms sum past MAX_OFFSET the block saturates, so the launch is early by exactly the excess — an arithmetic condition that presents as mistiming. It is worth ruling out first because it costs one signal read, and because the fix is a parameter rather than a board.

Symptom: occasional writes corrupt the write that follows them. Check err_command_while_counting. A single-slot aligner meeting back-to-back column commands cannot track both, and the second launch is lost or merged — which corrupts the following transaction rather than the one that caused it, making the trace misleading.

14. Misconceptions

“The PHY decides the write latency.” CWL is a mode-register value from the speed bin (14.10). The PHY consumes it. Clue: a proposal to fix a timing failure by changing a PHY setting when the mode register is wrong.

“Alignment is just counting cycles.” §7's callout — the cycle count is the part RTL can do, and the part that matters is sub-cycle. Clue: an alignment design with no adjustable delay element in it anywhere.

“A correct launch interval means correct alignment.” §9 — the properties pass identically on a right and a wrong trained value. Clue: sign-off on alignment from simulation.

“The controller can compensate for path differences.” It has neither the information nor the mechanism (§1). It can change command spacing; it cannot move a launch within a cycle. Clue: a request to the controller team to fix a bring-up timing failure.

“One offset works for the whole interface.” §5 — lanes have different traces, so the physical term is per lane. Clue: a single global compensation register on a multi-lane interface.

“Read alignment and write alignment are the same problem.” Mirrored, not identical: a write launches at an instant, a read must open a window with two edges (19.4). Clue: a receive path designed as a delayed launch.

“If the trained value is wrong the RTL will catch it.” §9 — nothing in the model is sensitive to it. Clue: a verification plan with no post-silicon margin step.

“Training is optional tuning.” The physical term is not computable (§2); without it there is no correct offset to use. It is not an optimisation, it is a prerequisite. Clue: a bring-up plan that treats training as a performance step.

15. Interview Reasoning

“Why does the PHY need to align command and data at all?” Because they travel different paths with different delays, and the device applies a fixed rule at its pins. The strong answer names why the controller cannot do it — the information is only available at the PHY.

“What are the two parts of the launch offset?” A programmed latency and a measured compensation. The discriminating follow-up is how their failures differ: one is universal and systematic, the other is per-unit and conditional.

“Every board fails writes identically. Where do you look?” The architectural term — CWL and the mode register. Not training, because a trained-value problem would not reproduce identically everywhere.

“Why is the compensation per lane?” Different board traces per lane. Then the diagnostic consequence: a single-lane failure is per-lane state or physics, never the controller.

“What can you verify about alignment in simulation?” The integer accounting. What can you not? The sub-cycle term, which is the one that decides whether it works — and volunteering that is the answer that distinguishes understanding from recall.

“Why must PHY readiness gate traffic?” Because before training completes there is no correct offset to launch against, so the launch lands arbitrarily. That is 19.5's subject and the reason readiness is not reset release.

16. Exercises

1. With cwl_cycles = 9 and trained_offset = 3, at which cycle does data_launch fire for a command committed at cycle 100? Show the count.

2. MAX_OFFSET = 8, cwl_cycles = 6, trained_offset = 5. Give OFF_W, show that the sum cannot wrap as written, state what total_offset reads and which error asserts — then say how many cycles early the data launches compared with the offset the two terms actually called for.

3. Classify each as architectural or physical: a mode register programmed with the wrong CAS write latency; a board whose DQ traces are 4 mm longer than its CA traces; a speed-bin change; a unit that fails above 40 °C.

4. Construct a command sequence that sets err_command_while_counting. What is the minimum spacing that avoids it, in terms of total_offset?

5. Write the read-side counterpart of P1. Which output does it assert about, and why is it a window rather than a pulse?

6. P1 passes on a design whose trained offset is completely wrong. Write the check that would catch that, and say why it cannot be an RTL assertion.

7. A colleague makes trained_offset take effect immediately rather than at command load. Give the traffic pattern during recalibration that breaks, and the symptom.

8. Explain why a one-lane-only failure exonerates both the controller and the write gearbox, referring to what each of them does uniformly.

17. Where This Goes

The offset is accounted for, in cycles, and the chapter has been explicit that cycles are the easy part.

Two things are still missing from the transmit side and one from the receive side. On a write, the data the gearbox launches must be accompanied by a strobe the PHY generates, in a defined relationship to the data — because the device captures against that strobe, not against a clock. On a read, the PHY must decide when to listen, which §3 showed is a window rather than an instant.

Chapter 19.4 owns both: strobe generation on the transmit side, and the receive gate on the other. 19.5 then closes the module by explaining where trained_offset and trained_valid come from, and why phy_operational has been gating everything since 19.1.

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.