DDR · Module 19
PHY Calibration
Reset release is not readiness. A PHY becomes usable only after clocks settle, initialisation completes and calibration establishes settings that cannot be computed — some of which stop being correct while the system runs.
Four chapters have consumed signals that nothing has produced. Chapter 19.1's command stage refused traffic until phy_operational. 19.3 launched write data against a trained_offset and reported when trained_valid was low. 19.4 opened a gate at a position given by gate_offset and flagged an untrained gate_trained.
Every one of those was an opaque input. This chapter is where they come from, and the reason they exist at all:
A DDR PHY is not usable when reset is released. It becomes usable after a sequence of steps that establish values which cannot be calculated — and some of those values stop being correct while the system is running.
Both clauses matter. The first explains why bring-up is a sequence. The second explains why calibration is not a bring-up activity that finishes.
1. Five Events, Not One
The habit this chapter exists to break is treating “the PHY came out of reset” as a single event. It is at least five, they happen in order, and skipping the distinction is the direct cause of a failure class that only appears on cold boot.
1. RESET RELEASED rst_n goes high.
Logic state is defined. Nothing else is.
2. CLOCKS STABLE the PHY's clock resources have settled.
Before this, nothing clocked is meaningful.
3. INITIALISED the PHY's own configuration is applied and
the device has been brought through its
required power-up sequence.
4. CALIBRATED the settings that cannot be computed have
been established by measurement.
5. OPERATIONAL and only now may the controller issue
memory traffic.Each step depends on the one before it, and each takes a non-trivial and largely unpredictable amount of time. Clock resources take time to lock. Device power-up has device-specified requirements. Calibration takes as long as the search takes (Module 21).
2. What Calibration Actually Establishes
Chapter 19.3 §2 decomposed a launch offset into a programmed term and a measured one, and 19.4 §3 found the same decomposition on the receive side. Calibration is the process that produces every instance of the second term.
| Value | Consumed by | Why it cannot be computed |
|---|---|---|
| Write launch offset | 19.3's aligner | depends on the difference between two board paths |
| Receive gate position | 19.4's gate | depends on a round trip through the board |
| Per-lane skew compensation | both, per lane | lanes are routed differently (19.3 §5) |
| Sampling position within the data | Module 20's capture | depends on the received signal's shape |
| Reference level for the receiver | Module 20's capture | depends on electrical conditions (Module 22) |
The common property is the last column. Not one of these is a property of the design; every one is a property of this manufactured system — this silicon, this package, this board, at this temperature and voltage. A designer cannot know them, a datasheet cannot list them, and a simulation cannot produce them.
So they are found by trying. Something drives known patterns, observes what comes back, and selects settings that work. That is Module 21's subject in its entirety, and this chapter deliberately says nothing about how the search is conducted — only that it happens, that it takes time, and that until it finishes the consuming blocks have nothing meaningful to use.
3. Two Things Called Calibration
A terminology hazard flagged in 19.1 §7 and worth resolving fully here, because the two mechanisms are confused constantly and their failures look nothing alike.
| ZQ calibration | PHY calibration | |
|---|---|---|
| Which side | the DRAM device | the PHY, in the SoC |
| What it establishes | the device's own output-driver and termination characteristics | the PHY's timing settings: offsets, gate positions, sampling points |
| Invoked by | a command from the controller in DDR4; 7.7 §5 notes DDR5 changed this | the bring-up sequence and periodic triggers |
| Result visible to the controller? | no — 7.7 §3 is built on this | yes, as register state |
| Owned by | Chapter 7.7 | this chapter, plus Module 21 |
They can fail independently and the symptoms do not resemble each other. A device whose output driver is uncalibrated produces signals with the wrong electrical characteristics — a margin problem that worsens with rate and looks like Module 22's territory. A PHY whose timing settings are wrong misses beats or captures noise at specific positions — 19.4 §3's displacement and corruption signatures.
The practical rule: a failure that is electrical in character points at the device side; a failure that is positional in character points at the PHY side. Reaching for the wrong one sends a debug effort to the wrong die.
4. Once, and Then Continuously
The part that surprises people, and the reason the canonical description of this chapter says “at bring-up and continuously”.
Calibration is not a bring-up activity that completes. The physical quantities of §2 are not constants — they are functions of temperature and supply voltage, both of which move while a system runs. A setting that was optimal at cold idle can be marginal at sustained load.
So a real PHY has two calibration paths:
BRING-UP path runs once, from a known-nothing state
establishes every setting
takes as long as it takes
memory is UNUSABLE throughout
PERIODIC path runs repeatedly, from a known-good state
adjusts settings that have drifted
must be brief
memory is mostly usable around it5. The Lifecycle
Three features of this machine are the design.
OPERATIONAL is the only state in which traffic is permitted. Chapter 19.1's command stage gates on exactly this, and §1's failure is what happens when something else gates instead.
CALIBRATING has no known duration. The machine cannot predict when it will finish, because Module 21's search takes as long as the search takes. A lifecycle that waits a fixed number of cycles and then declares success is asserting something it does not know.
Failure returns to IN RESET rather than proceeding. A PHY that cannot establish usable settings must not present itself as operational — and §9's corner-case table treats a “calibrated but failed” state as the one outcome that must be impossible.
6. Readiness Over Time
EDUCATIONAL — phase boundaries show ordering only. Real clock-lock, initialisation and calibration intervals are generation- and implementation-specific and are far longer than any ten-cycle drawing can represent (§7).
From reset release to operational, and a later recalibration
10 cyclesThe gap between points 1 and 4 is the chapter. Reset is released at point 1 and the interface is unusable for the whole of that span — and in a real system that span is orders of magnitude longer than the drawing suggests, because clock lock and calibration are not cycle-scale activities.
Point 7 is the recalibration. phy_operational drops, cmd_accepted follows it down, and both come back. Note what does not drop: trained_valid stays high throughout, because the previous settings remain valid until new ones replace them. Dropping validity during a refresh would tell the consuming blocks they have nothing to use, when in fact they have something slightly stale — which is a strictly better position.
7. Why There Are No Real Numbers Here
An omission worth defending explicitly, because its absence is conspicuous.
Real initialisation sequences have specified timing. Devices require minimum intervals between power-supply stability, clock stability, reset deassertion and the first command; those intervals are device parameters and they are not small. Clock resources have lock times. Calibration takes as long as its search.
None of those numbers appears in this chapter, for three reasons.
They are generation-specific — the sequence and its constraints differ between DDR generations, and a number quoted without its generation is worse than no number.
They are device-specific — they come from a particular datasheet for a particular part.
And they are implementation-specific on the PHY side — clock lock time is a property of the PLL, and calibration duration is a property of Module 21's algorithm and the number of lanes it must sweep.
What transfers between systems is the ordering, not the magnitudes, and the ordering is what this chapter teaches. A reader who wants the magnitudes for a specific system will find them in that system's device datasheet and PHY documentation — which is exactly the discipline Chapter 18.4 established for address mapping, applied to a different question.
8. The Lifecycle Block
// ─────────────────────────────────────────────────────────────────────
// phy_calib_lifecycle
//
// CLASSIFICATION
// Synthesizable educational RTL. Sequential. One responsibility:
// sequence a PHY from reset to operational through its required
// steps, publish readiness, and manage periodic recalibration.
//
// It models ORDERING AND GATING. It does not perform calibration.
//
// WHAT IT DOES NOT MODEL
// - NO CALIBRATION ALGORITHM. calib_done and calib_failed are INPUTS
// from whatever runs the search -- firmware, a hardware engine, or
// the controller, and Chapter 19.1 §3 established that which one
// is implementation-dependent. Module 21 owns the algorithms
// entirely; this block never inspects a setting's value.
// - NO CLOCK GENERATION. clocks_stable is an input from a PLL or DLL
// resource; such structures are not expressible in portable RTL
// (Chapter 19.1 §5).
// - NO DEVICE INITIALISATION SEQUENCE. init_done is an input. The
// required order and intervals are generation- and device-specific
// (§7) and belong to the device documentation, not to this model.
// - NO ZQ CALIBRATION. That is device-side and Chapter 7.7 owns it
// (§3); nothing here is about it.
// - No real durations. Every wait here is "until the input says so",
// which is the only honest model of an unpredictable interval.
// ─────────────────────────────────────────────────────────────────────
module phy_calib_lifecycle #(
// Periodic recalibration interval, in cycles. A POLICY value: the
// right number depends on how fast settings drift in this system,
// which is a thermal and electrical property, not a logic one.
parameter int RECAL_INTERVAL = 4096,
// How long a recalibration pass is permitted to hold traffic off.
parameter int RECAL_CYCLES = 16,
parameter int IVL_W = (RECAL_INTERVAL <= 1) ? 1 : $clog2(RECAL_INTERVAL + 1),
parameter int RCL_W = (RECAL_CYCLES <= 1) ? 1 : $clog2(RECAL_CYCLES + 1)
) (
input logic clk,
input logic rst_n,
// ── Progress reports from the resources this block sequences. Each
// is "it has happened", never "it will happen in N cycles" (§7).
input logic clocks_stable,
input logic init_done,
input logic calib_done,
input logic calib_failed,
// ── Allows periodic recalibration to be disabled, which is useful
// in bring-up debug and is a legitimate configuration.
input logic recal_enable,
// ── THE output the rest of Module 19 gates on. Chapter 19.1's
// command stage consumes exactly this.
output logic phy_operational,
// ── Settings validity. Deliberately NOT the same signal as
// phy_operational: settings stay valid across a recalibration
// pass, because the previous values remain usable until new ones
// replace them (§6). Chapters 19.3 and 19.4 consume these.
output logic trained_valid,
// ── Observability.
output logic [2:0] lifecycle_state,
output logic recal_active,
output logic err_traffic_while_not_operational,
output logic err_calib_done_and_failed,
// ── From Chapter 19.1's command stage, for the error check only.
input logic ctrl_traffic_accepted
);
if (RECAL_INTERVAL < 1) $fatal(1, "phy_calib_lifecycle: RECAL_INTERVAL must be >= 1");
if (RECAL_CYCLES < 1) $fatal(1, "phy_calib_lifecycle: RECAL_CYCLES must be >= 1");
typedef enum logic [2:0] {
L_RESET = 3'd0,
L_CLK = 3'd1,
L_INIT = 3'd2,
L_CAL = 3'd3,
L_OPER = 3'd4,
L_RECAL = 3'd5
} life_e;
life_e state;
logic [IVL_W-1:0] ivl_cnt;
logic [RCL_W-1:0] rcl_cnt;
// Sticky: once settings have ever been established they remain
// usable until reset, including across a recalibration pass.
logic settings_established;
assign lifecycle_state = state;
assign phy_operational = (state == L_OPER);
assign recal_active = (state == L_RECAL);
assign trained_valid = settings_established;
// ── Traffic accepted outside OPERATIONAL is the §1 failure, caught
// at the moment it happens rather than as corruption later.
assign err_traffic_while_not_operational =
ctrl_traffic_accepted && !phy_operational;
// ── A calibrator reporting both outcomes is broken; proceeding on
// either interpretation would be a guess.
assign err_calib_done_and_failed = calib_done && calib_failed;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= L_RESET;
ivl_cnt <= '0;
rcl_cnt <= '0;
settings_established <= 1'b0;
end else begin
unique case (state)
// Reset is RELEASED here, not asserted. Arriving in this state
// with rst_n high means the machine is starting its sequence,
// or has returned after a calibration failure.
L_RESET: begin
settings_established <= 1'b0;
state <= L_CLK;
end
L_CLK:
if (clocks_stable) state <= L_INIT;
L_INIT:
if (init_done) state <= L_CAL;
L_CAL: begin
// Failure is checked FIRST. A calibrator asserting both is
// already broken, and treating that as success would present
// an unusable PHY as operational -- the one outcome §9 says
// must be impossible.
if (calib_failed) state <= L_RESET;
else if (calib_done) begin
settings_established <= 1'b1;
state <= L_OPER;
ivl_cnt <= '0;
end
end
L_OPER:
if (recal_enable && ivl_cnt >= IVL_W'(RECAL_INTERVAL - 1)) begin
state <= L_RECAL;
rcl_cnt <= '0;
end else if (!(&ivl_cnt)) begin
ivl_cnt <= ivl_cnt + IVL_W'(1);
end
L_RECAL: begin
// settings_established is deliberately NOT cleared here: the
// previous values stay usable while new ones are found (§6).
if (calib_failed) begin
state <= L_RESET;
end else if (rcl_cnt >= RCL_W'(RECAL_CYCLES - 1)) begin
state <= L_OPER;
ivl_cnt <= '0;
end else begin
rcl_cnt <= rcl_cnt + RCL_W'(1);
end
end
default: state <= L_RESET;
endcase
end
end
endmoduleThe bounded L_RECAL and the unbounded L_CAL are different on purpose. Bring-up calibration waits for calib_done with no timeout, because it genuinely does not know how long the search will take and inventing a deadline would mean declaring success or failure without evidence. Periodic recalibration is bounded by RECAL_CYCLES, because it is interrupting real traffic and §4 established that it must be brief — a periodic pass that could run indefinitely is a hang, not a calibration.
9. Corner Cases
| Situation | Correct behaviour | Failure if mishandled |
|---|---|---|
traffic offered before L_OPER | refused by 19.1's stage; error flagged | §1's cold-boot failure, in hardware |
calib_done and calib_failed together | failure wins; error flagged | an unusable PHY presented as operational |
calib_failed during bring-up | return to L_RESET, settings cleared | proceeding with settings that do not work |
calib_failed during recalibration | return to L_RESET | continuing on values known to be bad |
clocks_stable never asserts | machine waits in L_CLK | a timeout that declares readiness it cannot verify |
calib_done never asserts | machine waits in L_CAL | the same, at the more damaging step |
| recalibration while a write is in flight | settings stay valid; in-flight offset already loaded | a launch offset that shifts mid-transaction |
recal_enable low | stays in L_OPER indefinitely | drift accumulating with no correction |
RECAL_CYCLES = 1 | RCL_W guarded; one-cycle pass | zero-width counter |
reset during L_OPER | full sequence repeats; settings cleared | stale settings trusted after a reset |
ivl_cnt saturation with recal_enable low | interval counter saturates harmlessly | a wrap that triggers recalibration at a wrong time |
The two “never asserts” rows are deliberate design decisions, not oversights. A lifecycle that times out and proceeds is claiming knowledge it does not have: if calibration has not reported success, the settings are not established, and declaring operational anyway produces exactly the failure the machine exists to prevent. A hang in L_CAL is a visible, diagnosable condition; a false phy_operational is not. Where a timeout is genuinely wanted it belongs at system level, with a defined recovery, rather than as a silent promotion inside this block.
10. What the Assertions Prove
// ── P1. THE property of the chapter. Traffic is accepted only while
// operational -- §1's failure, caught at the moment of acceptance
// rather than as unexplained corruption several cycles later.
property p_no_traffic_before_operational;
@(posedge clk) disable iff (!rst_n)
ctrl_traffic_accepted |-> phy_operational;
endproperty
a_no_traffic_before_operational: assert property (p_no_traffic_before_operational);
// ── P2. Operational is reachable only through the full sequence. The
// ordering property: catches a machine that skips a step, which is
// the structural form of the same bug.
property p_operational_only_via_calibration;
@(posedge clk) disable iff (!rst_n)
$rose(phy_operational)
|-> $past(lifecycle_state == 3'd3 || lifecycle_state == 3'd5, 1);
endproperty
a_operational_only_via_calibration: assert property (p_operational_only_via_calibration);
// ── P3. A calibration failure never yields an operational PHY on the
// next cycle. The one outcome §9 says must be impossible.
property p_failure_never_operational;
@(posedge clk) disable iff (!rst_n)
(lifecycle_state == 3'd3 && calib_failed) |=> !phy_operational;
endproperty
a_failure_never_operational: assert property (p_failure_never_operational);
// ── P4. Settings survive a recalibration pass. §6: the previous
// values stay usable while new ones are found, and clearing
// validity here would tell 19.3 and 19.4 they have nothing to use
// when in fact they have something slightly stale.
property p_settings_survive_recal;
@(posedge clk) disable iff (!rst_n)
(recal_active && trained_valid && !calib_failed) |=> trained_valid;
endproperty
a_settings_survive_recal: assert property (p_settings_survive_recal);
// ── P5. Recalibration is bounded. An unbounded periodic pass is a
// hang that presents as a memory system which stops responding.
property p_recal_terminates;
@(posedge clk) disable iff (!rst_n)
$rose(recal_active) |-> ##[1:RECAL_CYCLES+1] !recal_active;
endproperty
a_recal_terminates: assert property (p_recal_terminates);
// ── Covers. Every one of these is a path a happy-path bring-up test
// never reaches, and P3 through P5 check nothing without them.
c_calib_failure: cover property (@(posedge clk) disable iff (!rst_n)
lifecycle_state == 3'd3 && calib_failed);
c_recal_pass: cover property (@(posedge clk) disable iff (!rst_n)
$rose(recal_active) ##[1:$] $fell(recal_active));
c_traffic_early: cover property (@(posedge clk) disable iff (!rst_n)
ctrl_traffic_accepted && !phy_operational);
c_full_sequence: cover property (@(posedge clk) disable iff (!rst_n)
lifecycle_state == 3'd1 ##[1:$] lifecycle_state == 3'd2
##[1:$] lifecycle_state == 3'd3 ##[1:$] lifecycle_state == 3'd4);What they prove. That readiness has a cause: traffic is gated on it, it is reachable only through the full sequence, a calibration failure cannot produce it, settings survive a refresh, and a periodic pass terminates.
What they do not prove — and on this block the limitation is categorical. Nothing here establishes that the settings calibration produced are good. calib_done is an input; this block trusts it completely and has no means not to. A calibrator that reports success having selected settings at the very edge of the margin satisfies every property above, and the resulting system works in the lab and fails in the field at temperature.
That gap is not closable in RTL, and recognising it is the point of the chapter's placement. Whether a trained value is good — whether it sits in the centre of a working range rather than at its edge — is measured, not asserted, and Module 21 is where measuring it properly is the subject. Module 28 is where the consequences of doing it badly are diagnosed.
Vacuity. c_full_sequence is the cover that matters most: without it, a test that never completes bring-up satisfies P2 and P3 trivially. P5's bounded window makes it genuinely falsifiable, unlike an ##[1:$] formulation which would be satisfied by any eventual exit.
11. DV — Checking a Sequence, Not a Datapath
There is no data here, so the independent model is a shadow sequencer: an enumeration of the five events of §1, advanced independently from observed inputs rather than from the RTL's state register.
Maintain a reference position in the sequence. On each observed input assertion, advance it if and only if the sequence permits. Then check three things the RTL never states: that the observed lifecycle_state matches the reference position, that phy_operational is high only at the final position, and that every transition to operational was preceded by an observed calib_done — reconstructed from the input stream, not read from the state.
LIFECYCLE ORDERING VIOLATION
cycle : 3,204
boot type : COLD (settings_established was 0)
observed input sequence : rst_n released @ 3,180
clocks_stable @ 3,186
init_done @ 3,191
calib_done @ never
RTL phy_operational : asserted @ 3,204
reference position : INIT_DONE (step 3 of 5)
diagnosis : the PHY declared itself operational without a
calibration completion. Every setting the aligner and
the gate will consume is whatever the registers held.
predicted symptom : first reads return displaced or corrupt data;
first writes land where nothing is sampling.
why it may look intermittent : on a WARM reset the registers
retain the previous boot's settings, so the same bug
produces a working interface. The fault is present in
both cases and visible only in one.
caught by : P1 if traffic is offered; P2 on the transition itselfThe why it may look intermittent block is the reason this report is worth building. The same defect produces a passing system and a failing one depending on boot type, and a report that does not say so invites the conclusion that cold boot has a different bug.
Directed cases worth running: a cold boot with each input withheld in turn, confirming the machine waits rather than proceeding; calib_done and calib_failed asserted together; a failure during L_RECAL; a reset landing in each state; recal_enable low across the interval boundary; and RECAL_CYCLES = 1.
12. Synthesis and What Is Missing
Cost. Three state bits, an interval counter sized by RECAL_INTERVAL, a short recalibration counter, and one sticky flag. For a 4096-cycle interval that is thirteen bits of counter — trivial, and instantiated once per PHY rather than per lane, unlike 19.3's aligner and 19.4's gate.
What a production lifecycle has that this does not:
- The calibration engine itself, or the interface to the firmware that is running it — and 19.1 §3 established that which of those it is varies by implementation.
- Per-lane calibration status, because lanes are trained independently and one can fail while others succeed.
- Retry and fallback. A real bring-up that fails calibration usually retries, often at a lower rate, before giving up. This block returns to reset and repeats, which is the simplest defensible behaviour and not the only one.
- Coordination with the controller's own maintenance. Chapter 17.3's refresh manager and a periodic recalibration both need the device quiet, and a real system arbitrates between them rather than letting them collide.
- Low-power state transitions, which interact with clock stability and can invalidate settings.
- Reporting of margin, not just success — knowing how much margin a calibration achieved is what turns a pass/fail into a health indicator.
13. Debugging
Symptom: works after a warm reset, fails from cold. §1. Check phy_operational's derivation before anything else — this signature is produced by an ordering assumption far more often than by a power or device problem, and it is the cheapest thing in the list to rule out. err_traffic_while_not_operational names it directly.
Symptom: the interface hangs during bring-up and never becomes ready. Read lifecycle_state. It is three bits and it says exactly which step did not complete: L_CLK means the clock resource never reported lock, L_INIT means the initialisation sequence did not finish, L_CAL means calibration never reported. Each points at a different subsystem, and §9 explains why the machine waits rather than timing out.
Symptom: works at bring-up, degrades after sustained load. Drift (§4). Check whether recal_enable is asserted and whether recalibration is actually running — recal_active should pulse at the configured interval. A system with periodic calibration disabled shows exactly this and looks like a thermal problem, which in a sense it is.
Symptom: one lane fails calibration and the rest pass. Per-lane physics or per-lane state (19.3 §5). Not this block, which has no per-lane status — §12 lists that as a production omission precisely because it is the first thing a real bring-up needs.
Symptom: intermittent failures that correlate with nothing obvious. Consider whether calibration succeeded marginally. §10 is explicit that nothing in RTL distinguishes a setting at the centre of its working range from one at the edge, and a marginal pass behaves exactly like a good one until conditions move. This is Module 21's centring problem and Module 28's diagnostic territory.
Symptom: transactions corrupt around a recalibration. Check that in-flight state is unaffected: 19.3 §9's aligner loads its offset at the command and 19.4 §9's gate does the same. A design that applies a new setting immediately rather than at the next transaction boundary produces corruption that correlates with the recalibration interval — which is a very distinctive period once you think to look for it.
14. Misconceptions
“PHY ready means reset is deasserted.” §1 — five events, not one. Consequence: traffic issued into an uncalibrated interface. Clue: phy_operational wired to rst_n, and a cold-boot-only failure.
“Training is optional tuning.” The values are not computable (19.3 §2); without them there is no correct offset or gate position to use. It is a prerequisite, not an optimisation. Clue: a bring-up plan that lists training as a performance step.
“Training happens once.” §4 — the physical quantities move with temperature and voltage. Clue: a design with no periodic path, degrading under sustained load.
“Calibration and ZQ calibration are the same thing.” §3 — different die, different state, different symptoms. Clue: a debug effort on the wrong side of the interface.
“This chapter explains how training works.” It explains when it runs and what depends on it. The algorithms are Module 21's, and treating a lifecycle diagram as an understanding of training is the trap this chapter is placed before that module to avoid. Clue: an answer about training that describes states rather than searches.
“If calibration reports success the settings are good.” §10 — a marginal pass satisfies every property. Clue: sign-off with no margin measurement.
“A timeout is a safe way to handle a calibration that does not complete.” §9 — proceeding without evidence produces a false readiness, which is strictly worse than a visible hang. Clue: a lifecycle that declares operational after a fixed count.
“Settings must be invalidated during recalibration.” §6 — the old values stay usable until new ones replace them. Invalidating them makes a brief refresh into a full outage. Clue: traffic stalling far longer than the recalibration window.
15. Interview Reasoning
“Why can't the controller issue traffic as soon as reset is released?” Because four more things must happen first, and the last of them establishes values that cannot be computed. The strong answer names the cold-boot-versus-warm-reset signature unprompted.
“Why does a PHY need calibration at all?” Because the timing it must meet depends on this board and this part, which no datasheet can state. Then the consequence: the value must be found by measurement, which takes time and must happen before traffic.
“Why is calibration not a one-time bring-up activity?” Because the quantities drift with temperature and voltage. Then the structural analogy: periodic recalibration is a maintenance obligation on the controller's time, like refresh.
“What is the difference between ZQ calibration and PHY calibration?” Different sides of the interface, different state, different failure character — electrical versus positional.
“Your lifecycle hangs in the calibrating state. Is that a bug?” It is a report. It says calibration never completed, which is diagnosable; the alternative — timing out and declaring readiness — hides the same fault behind data corruption.
“What can simulation prove about calibration?” The ordering and the gating. Not that the settings are good, because goodness is a margin measured on hardware. Volunteering the second half is the discriminator.
“Why do settings stay valid during a recalibration pass?” Because slightly stale values are strictly better than none, and invalidating them would turn a brief refresh into an outage.
16. Exercises
1. List the five events of §1 and, for each, name one thing that would go wrong if the controller began issuing traffic immediately after it.
2. A design asserts phy_operational 64 cycles after reset release. Give the test that passes, the test that fails, and explain why the passing one is the misleading result.
3. With RECAL_INTERVAL = 4096 and RECAL_CYCLES = 16, what fraction of time is traffic held off by recalibration? State the assumption your answer depends on.
4. calib_done and calib_failed assert together. Trace the FSM and say which state results and why the order of the checks in L_CAL matters.
5. Write the property asserting that trained_valid never rises without a preceding calib_done. Why is that stronger than P2?
6. A colleague clears settings_established on entry to L_RECAL. Describe what 19.3's aligner and 19.4's gate report, and what the system does for the duration of the pass.
7. All ten properties pass on a calibrator that selects settings at the extreme edge of the working range. Describe the field behaviour, and name the module that owns preventing it.
8. Explain why L_CAL is unbounded and L_RECAL is bounded, in terms of what each is interrupting.
17. Module 19, Complete
Five chapters, one boundary.
The PHY exists because some functions cannot be written in portable RTL. Chapter 19.1 drew the controller/PHY/DRAM split, marked the six functions whose ownership genuinely varies between implementations, and named the structures — delay elements, capture circuitry, clock resources — that are technology-specific rather than logical.
The width-versus-rate conversion is genuinely digital. 19.2 built both gearboxes, established that the transmit side can be stalled and the receive side cannot, and stopped at named abstractions in both directions.
Command and data take different paths. 19.3 decomposed the launch offset into a programmed term anyone can compute and a measured term nobody can — a decomposition that reappeared on the receive side and explains why every failure in this module has a population signature.
The strobe is authored on transmit and estimated on receive. 19.4 built the gate, showed the two ways to misplace it, and established that its correctness is a containment relationship against a window the PHY cannot see.
And none of it works until the sequence completes. This chapter supplied phy_operational, trained_valid and gate_trained, and explained why reset release is not readiness and why calibration does not finish.
The discipline every chapter repeated, because it is the one thing most likely to be misunderstood: every block here is genuinely correct and genuinely insufficient. A gearbox that orders beats perfectly, an aligner that counts cycles exactly, a gate that opens and closes on cue — all of it can be right while the interface does not function, because the quantity that decides is sub-cycle and no portable RTL contains a representation of it.
What Module 19 did not build is the rest: no capture, no training algorithms, no electrical analysis, no PLL, no delay line, no production PHY. Each chapter's limits section names its own omissions.
Module 20 opens the box marked CAPTURE — how DQ is actually sampled on DQS edges, and what makes a sampling point correct. Module 21 opens the search that produces every opaque value this module consumed. Module 22 explains why the signals look the way they do when they arrive.
Continue learning
Related tutorials
- Related topic
Row Opening
ACTIVATE transfers no data. It changes a bank from closed to holding one row, and it does so over an interval rather than instantly — which is why a bank has transitional states and why a controller must track them.
- Related topic
The Refresh Manager
Refresh due, refresh legal, refresh issued and refresh complete are four distinct events separated by many cycles. The manager turns an obligation into the drain, the gate and the request a scheduler consumes.
- Related topic
PHY Responsibilities
The controller decides which DDR operation should happen. The PHY makes it real at a pin boundary whose timing the controller cannot meet — and the line between them is not the same in any two implementations.
- Related topic
Serialisation
A controller runs wide and slow because that is what synthesisable logic can do; the pins run narrow and fast because that is what the bus is. The gearbox converts between them — and a correct gearbox proves nothing about sampling.
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.
