DDR · Module 34
“Training Happens Only Once”
Most training steps really do run once, and the chapter that says so opens by stating that some trained values stop being correct while the system is running. Six of eight values need re-establishing, and five are invalidated by a frequency change alone.
“Training runs at boot. Once the PHY is trained, it is trained.”
34.4 §24 named the change of object: three beliefs about numbers, one about a component's nature, and this one about a process's lifetime. DERIVED: a lifetime belief is refuted by neither arithmetic nor a census but by a state machine — the question is what states a trained value can be in, and how it leaves the one the belief thinks is terminal.
This belief is unusual in this module for a specific and uncomfortable reason: it is refuted in the second paragraph of the chapter that teaches it. CURRICULUM-DERIVED from 19.5 §2: “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.”
DERIVED: so this chapter is not supplying missing information. It is about why a reader who has that sentence still holds the belief — and the answer is that the belief is true of most of the values, most of the time, and the exceptions are invisible until a condition changes that nobody was watching.
1. The One-Sentence Correction
Training establishes values that are functions of temperature, supply voltage and frequency — so a trained value has a validity lifetime, not a completion, and the boot-time search is the first of an indefinite sequence whose later members are triggered by conditions rather than by a schedule.
CURRICULUM-DERIVED from 19.5 §4, which owns the one-time versus continuous split and states it without hedging: “Calibration is not a bring-up activity that completes.” The physical quantities “are not constants — they are functions of temperature and supply voltage, both of which move.”
2. What This Chapter Owns
| Ground | Owner |
|---|---|
| The PHY lifecycle; one-time versus continuous; when a value becomes or stops being valid | 19.5 |
| The recalibration pass's three requirements — brief, non-corrupting, schedulable | 19.5 §4, 19.5 §6 |
Every training algorithm, and the sequencer's state machine including RETRAIN HOLD | 21.5 |
| The dependency structure, and which steps repeat versus run once | 21.5 |
| Write levelling, read levelling, gate training, eye centring | 21.1–21.4 |
| Retention and its temperature dependence | 15.4 |
The five meanings of a calibration done flag; provenance and staleness | 28.4 |
| Reviewing which reset a trained register survives, and recalibration preconditions | 33.3 §9, 33.3 §10 |
| The eleven bitmap signatures when training reports failure | 28.1 |
| Why the belief survives 19.5 §2, and the lifetime census that dislodges it | this chapter |
Two boundaries, and the first is the tightest in this module.
With 19.5: that chapter owns the lifecycle, the split, and the recalibration pass's requirements. It is addressed to somebody designing the lifecycle. DERIVED: this chapter is addressed to somebody who has read it and still assumes a trained value is permanent — which is a different failure, and §8's census is the instrument that surfaces it because a count is harder to skim past than a sentence.
With 33.3 §10: that item reviews whether a recalibration's preconditions are enforced. DERIVED: it presumes a recalibration exists. This chapter is about the system that has none, so §10's trigger census is upstream of 33.3's precondition review.
3. Teaching-Model Boundary And Source Discipline
| Claim class | What it means here | Example below |
|---|---|---|
| Structural | a documented mechanism of this track | the one-time/continuous split; the RETRAIN HOLD state; the five done meanings |
| Curriculum-derived | follows from a cited chapter | every trigger, and the validity lifecycle's states |
| Derived | computed in this chapter from the models below | every count and drift figure in §19 |
| Illustrative | a chosen number that makes a mechanism visible | temperatures, drift rates, tap counts, intervals |
Every physical quantity here is ILLUSTRATIVE. CURRICULUM-DERIVED from 20.3's standing statement that sample quality is not digitally observable: a model in SystemVerilog cannot represent an eye or a volt, so every model below represents the digital belief a design holds about a physical value — a validity bit, a timestamp, a trigger mask. DERIVED: those are exactly what the misconception is about, which is why they are the right objects.
The drift rates are chosen, not derived. CURRICULUM-DERIVED from 21.4 and 20.5, which own eye width and the published window figures: a real drift-versus-temperature curve comes from characterisation, and this chapter derives none.
No external source was consulted and no network tool was used.
4. Why a Competent Engineer Believes It
| # | The true statement | What the belief does with it |
|---|---|---|
| 1 | Most training steps run once — write levelling, gate training | treats the majority as the whole |
| 2 | The boot sequence runs training once, and then boots | treats the caller's structure as the value's lifetime |
| 3 | At constant temperature, voltage and frequency, the values stay valid | treats the lab condition as the operating condition |
| 4 | A done flag asserts once and stays asserted | treats a monotonic flag as a statement about a non-monotonic value |
Reason 2 is the structural one and it is the most interesting, because the belief is reading a real fact off the wrong object. DERIVED: the boot sequence is one-shot, and the belief transfers that property to the values the sequence produced. CURRICULUM-DERIVED from 21.5, which owns the sequencer and whose state machine has a RETRAIN HOLD state distinct from IDLE — so the track's own sequencer is not one-shot, and the belief survives because a reader of the flow diagram sees a path from start to done and stops there.
Reason 4 is 28.4's territory and it is the cheapest to refute. CURRICULUM-DERIVED from 28.4 §2: a done flag can mean five different things, and the fifth “produces a system which boots, passes its own self-checks, and corrupts data hours later.” DERIVED: a flag that only ever rises cannot represent a value that can fall — which is 33.3 §7's item, and it is the same observation from the review side.
And reason 1 deserves its number, because the majority is real. DERIVED: of the training steps Module 21 builds, write levelling and gate training genuinely are one-time in most systems — so the belief is right about two of four searches, and §8 is the census that makes two of four visible instead of training.
5. The Region Where the Claim Is True
"TRAINING HAPPENS ONLY ONCE" HOLDS WHEN ALL FIVE HOLD:
1 temperature CONSTANT -> no drift in the eye
2 supply voltage CONSTANT -> no drift in the reference
3 frequency CONSTANT -> the trained set stays applicable
4 no power-state transitions -> nothing is powered down and back
5 no warm reset -> nothing clears a trained register
and then: the boot-time values remain correct indefinitely, and
the belief is exactly rightDERIVED: the region is non-empty and it is the bench. A board on a desk at room temperature, at one frequency, never suspended, reset only by power-cycling, satisfies all five for as long as anybody watches it.
CURRICULUM-DERIVED from 19.5 §4, whose sentence names exactly which two conditions fail in the field: the quantities “are functions of temperature and supply voltage, both of which move”. DERIVED: conditions 1 and 2 are the ones the specification's authors expected to fail, and conditions 3 through 5 are the ones a system integrator adds — DVFS, suspend-resume, and a warm reset path.
Condition 3 is the one most often overlooked, and it is not a drift. DERIVED: a frequency change does not invalidate a trained value by drift — it makes the value inapplicable, because the value was in units of a delay against a period that changed. CURRICULUM-DERIVED from 19.3 §2's decomposition into a programmed term and a measured term: the measured term is a physical time, and the count representing it is period-dependent.
6. The Boundary, Computed
| Exit | Condition | What becomes invalid | Owner |
|---|---|---|---|
| 1 | temperature crosses a drift threshold | the eye's centre; Vref | 19.5 §4, 21.4 |
| 2 | supply voltage moves | the reference level | 19.5 §4 |
| 3 | frequency changes | every count in units of cycles | 19.3 §2 |
| 4 | power-down exit | the DLL's lock; possibly the gate | 19.5 §2 |
| 5 | warm reset | whatever the reset domain clears | 33.3 §9 |
| 6 | the periodic interval elapses | ZQ and drift-tracked values | 7.7, 19.5 §4 |
Exit 3 is the one with the largest consequence and the least warning, so it gets the arithmetic. ILLUSTRATIVE: a trained flight time of 2.8 ns at 1.25 ns per cycle is 2.24 cycles, rounded to 2. At 0.625 ns per cycle the same 2.8 ns is 4.48 cycles, which is 4 — so the count changes and the physical quantity did not.
DERIVED: a design that keeps one trained set across a frequency change applies a count derived at the wrong period, and the error is proportional to the frequency ratio. CURRICULUM-DERIVED from 33.3 §6's calculated-versus-measured line: the trained value is the measured term, and converting it to cycles is the calculated step — so the conversion must be redone even when the measurement need not be.
And exit 5 is the one 33.3 §9 measures as a review finding, which makes it the cheapest of the six to check. CURRICULUM-DERIVED: that item's weak build passes every cold boot and fails after one warm reset, because the trained registers sat in the functional reset domain while the retrain trigger sat in the power-on domain.
7. What State Is a Trained Value In?
The diagram earns its place because the belief is a claim that one state is terminal, and a state machine is the only representation in which terminal is a visible property.
This is the value's lifecycle, not the sequencer's. 21.5 owns the sequencer's state machine, including its RETRAIN HOLD state; this is the object that machine produces.
The belief is the claim that VALID has no outgoing edges. It has four. DERIVED: two are drift-driven and internal to the PHY, one is a system action (a frequency change), and one is a reset-domain consequence — so the four edges belong to three different owners, which is why no single team notices all of them.
INAPPLICABLE is a separate state from STALE on purpose, and the distinction is the one §6's exit 3 turns on. DERIVED: a stale value was correct and drifted; an inapplicable value is still physically correct and its encoding no longer matches the period. A design that treats a frequency change as drift re-runs the full search where a re-conversion would have done, and one that treats it as nothing applies the wrong count.
8. The Lifetime Census
// ROBUST MODEL: every trained value carries a LIFETIME class, so
// "training" stops being one thing. 19.5 section 4's one-time versus
// continuous split, made a per-value property.
package value_lifetime_pkg;
typedef enum int {
L_ONE_TIME, // valid until a reset clears it
L_PERIODIC, // re-established on an interval
L_EVENT_DRIVEN, // re-established on a named condition
L_PER_FREQUENCY // one set per operating point
} lifetime_e;
typedef struct {
string name;
lifetime_e lifetime;
bit drifts_with_temp;
bit drifts_with_voltage;
bit period_dependent;
} tv_t;
// ILLUSTRATIVE assignment over the searches Module 21 builds plus the
// calibrations 19.5 and 7.7 own.
tv_t VALUES[] = '{
'{"write_level_delay", L_ONE_TIME, 1'b0, 1'b0, 1'b1},
'{"gate_offset", L_ONE_TIME, 1'b0, 1'b0, 1'b1},
'{"read_level_delay", L_PER_FREQUENCY, 1'b1, 1'b0, 1'b1},
'{"vref_host", L_PERIODIC, 1'b1, 1'b1, 1'b0},
'{"vref_device", L_PERIODIC, 1'b1, 1'b1, 1'b0},
'{"zq_drive_strength", L_PERIODIC, 1'b1, 1'b1, 1'b0},
'{"dll_lock", L_EVENT_DRIVEN, 1'b0, 1'b0, 1'b1},
'{"flight_offset", L_PER_FREQUENCY, 1'b1, 1'b0, 1'b1}
};
endpackage
module value_lifetime_census #(
parameter int NV = 8
)(
input logic clk,
input logic rst_n,
input logic audit,
output logic [3:0] one_time_count,
output logic [3:0] revisited_count,
output logic [3:0] temp_sensitive,
output logic [3:0] period_dependent_count,
output logic all_one_time,
output logic [7:0] revisited_share_pct
);
import value_lifetime_pkg::*;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
one_time_count <= '0; revisited_count <= '0; temp_sensitive <= '0;
period_dependent_count <= '0; all_one_time <= 1'b0;
revisited_share_pct <= '0;
end else if (audit) begin
automatic int ot = 0, rv = 0, ts = 0, pd = 0;
foreach (VALUES[i]) begin
if (VALUES[i].lifetime == L_ONE_TIME) ot++; else rv++;
if (VALUES[i].drifts_with_temp) ts++;
if (VALUES[i].period_dependent) pd++;
end
one_time_count <= 4'(ot);
revisited_count <= 4'(rv);
temp_sensitive <= 4'(ts);
period_dependent_count <= 4'(pd);
// The belief, as a predicate.
all_one_time <= (rv == 0);
revisited_share_pct <= 8'((rv * 100) / NV);
end
end
endmodule// INTENTIONALLY DEFECTIVE. WEAK MODEL: one lifetime for all of them.
//
// // "training" is a phase, so its outputs share its lifetime
// localparam lifetime_e TRAINING_LIFETIME = L_ONE_TIME;
// all_one_time <= 1'b1; // <-- the defect
// revisited_count <= '0;
//
// CONTRACT VIOLATED: 19.5 section 4's split. And the weak model is right
// about two of the eight values -- write levelling and gate training
// really are one-time.
//
// TRACE (ILLUSTRATIVE, the eight values above):
// robust: one_time 2, REVISITED 6, temp_sensitive 5,
// period_dependent 5, all_one_time 0,
// revisited_share 75%
// weak: one_time 8, revisited 0, all_one_time 1
//
// gap: six of eight values need re-establishing and the belief plans
// for none. And the split is not 50/50 in the belief's favour -- it
// is 75% against, which is why a census dislodges the belief where a
// sentence does not.
//
// The five period-dependent values are the sharpest sub-finding:
// they are not DRIFTING, they are ENCODED against a clock period, and
// a DVFS transition invalidates all five at once with no physical
// change whatsoever.75% is the number, and it is why this chapter exists despite 19.5 §2 already containing the correction. DERIVED: a sentence saying some values stop being correct is read as an exception; a census reporting six of eight is read as the rule.
And the five period-dependent values are the sub-finding worth carrying. DERIVED: they are invalidated by an event that changes no physical quantity at all — a frequency change — so they are outside the drift framing that 19.5 §4 supplies and outside the periodic framing too. CURRICULUM-DERIVED from 19.3 §2: the measured term is a physical time and the count is a conversion, so a DVFS transition is a re-conversion event, and §14 measures what happens when it is treated as neither.
9. A Value That Can Fall
// ROBUST MODEL: validity is a function of the CONDITIONS the value was
// measured under, so it can fall without anything failing. 19.5
// section 2's "stop being correct while the system is running".
module validity_tracking #(
parameter int TAP_W = 6,
parameter int TEMP_DELTA = 10, // ILLUSTRATIVE degrees before stale
parameter int STALE_TICKS = 512 // ILLUSTRATIVE
)(
input logic clk,
input logic rst_n,
input logic commit,
input logic [TAP_W-1:0] committed_tap,
input logic [7:0] temp_now,
input logic tick,
input logic freq_changed,
output logic [TAP_W-1:0] tap_in_use,
output logic valid,
output logic stale,
output logic inapplicable,
output logic [7:0] temp_at_commit,
output logic [15:0] age,
output logic [15:0] validity_falls,
output logic [15:0] used_while_invalid
);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tap_in_use <= '0; valid <= 1'b0; stale <= 1'b0;
inapplicable <= 1'b0; temp_at_commit <= '0; age <= '0;
validity_falls <= '0; used_while_invalid <= '0;
end else begin
if (commit) begin
tap_in_use <= committed_tap;
valid <= 1'b1;
stale <= 1'b0;
inapplicable <= 1'b0;
// The provenance that makes validity computable later --
// 28.4's "what a committed value was calibrated AGAINST".
temp_at_commit <= temp_now;
age <= '0;
end
if (valid) begin
// Drift: the condition moved away from the one measured at.
automatic logic [7:0] d = (temp_now > temp_at_commit)
? (temp_now - temp_at_commit)
: (temp_at_commit - temp_now);
if (d >= 8'(TEMP_DELTA)) begin
valid <= 1'b0; stale <= 1'b1;
validity_falls <= validity_falls + 1'b1;
end else if (tick && (age == 16'(STALE_TICKS))) begin
valid <= 1'b0; stale <= 1'b1;
validity_falls <= validity_falls + 1'b1;
end else if (tick) begin
age <= age + 1'b1;
end
// A frequency change makes it INAPPLICABLE, not stale: the
// physical measurement is still right and its encoding is not.
if (freq_changed) begin
valid <= 1'b0; inapplicable <= 1'b1;
validity_falls <= validity_falls + 1'b1;
end
end
// The escape counter: a consumer using the value while it is
// neither valid nor re-established.
if (!valid && (tap_in_use != '0) && !stale && !inapplicable)
used_while_invalid <= used_while_invalid + 1'b1;
end
end
endmodule// INTENTIONALLY DEFECTIVE. WEAK MODEL: validity is monotonic.
//
// if (commit) begin
// tap_in_use <= committed_tap;
// valid <= 1'b1; // and it never falls
// end
// // no temp_at_commit, no age, no freq_changed handling
//
// CONTRACT VIOLATED: 19.5 section 2 -- "some of those values stop being
// correct while the system is running" -- and 28.4 section 2's fifth case.
//
// WHY IT SURVIVES: it is correct for the whole of a bench session, and
// it is correct FOREVER for the two genuinely one-time values. A
// monotonic valid bit is also what a boot flow wants, because a boot
// flow asks "is it trained yet" and never asks "is it still".
//
// TRACE (ILLUSTRATIVE, a 90-minute run: 25C at boot, rising to 70C,
// one DVFS transition at minute 40):
// robust: commit at boot, temp_at_commit 25
// minute 18, temp 35: d = 10 -> valid 0, stale 1
// validity_falls 1, retrain
// minute 40, freq change: valid 0, inapplicable 1
// validity_falls 2, retrain for the bin
// minute 61, temp 60: d = 10 from the last commit -> stale
// validity_falls 3
// total: 3 falls, 3 retrains, used_while_invalid 0
// weak: valid 1 from boot to the end. 0 falls, 0 retrains.
// and the tap in use at minute 90 was measured at 25C
// against a period that changed at minute 40.
//
// gap: three invalidations in ninety minutes, none of them detected,
// and the final operating point is a value measured under two
// conditions that no longer hold.Three invalidations in ninety minutes is the measured refutation, and the run is not adversarial. DERIVED: a 45-degree rise over an hour and one DVFS transition describe a laptop opening a browser — so the belief's region is left by ordinary use, not by stress.
And used_while_invalid reading zero in both builds is the trap worth naming. DERIVED: the weak build never reports using an invalid value because it never has one — validity is monotonic, so the counter's antecedent cannot occur. CURRICULUM-DERIVED from 33.3 §7's item on a done flag's five meanings: a flag that cannot fall makes every downstream check vacuous, and the vacuity is invisible because the check passes.
10. The Trigger Census
§6 lists six exits. A design's retraining trigger set either contains all six or silently treats the missing ones as nothing happened.
// ROBUST MODEL: the trigger set is declared and audited against the
// exits, so a missing trigger is a finding rather than an absence.
module retrain_trigger_coverage #(
parameter int NTRIG = 6
)(
input logic clk,
input logic rst_n,
input logic audit,
input logic [5:0] triggers_implemented, // one bit per exit
// live events, to show which fire in practice
input logic [5:0] event_now,
output logic [3:0] implemented_count,
output logic [3:0] missing_count,
output logic [5:0] missing_mask,
output logic coverage_complete,
output logic [5:0] unhandled_events,
output logic [15:0] unhandled_event_count
);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
implemented_count <= '0; missing_count <= '0; missing_mask <= '0;
coverage_complete <= 1'b0; unhandled_events <= '0;
unhandled_event_count <= '0;
end else begin
if (audit) begin
implemented_count <= 4'($countones(triggers_implemented));
missing_count <= 4'(NTRIG - $countones(triggers_implemented));
missing_mask <= ~triggers_implemented & 6'h3F;
coverage_complete <= ($countones(triggers_implemented) == NTRIG);
end
// An event with no trigger is silently absorbed -- which is the
// whole mechanism by which the belief survives in a running
// system.
unhandled_events <= event_now & ~triggers_implemented;
if ((event_now & ~triggers_implemented) != '0)
unhandled_event_count <= unhandled_event_count
+ 16'($countones(event_now & ~triggers_implemented));
end
end
endmodule TRIGGER COVERAGE IN A TYPICAL DESIGN (ILLUSTRATIVE)
exit implemented? events in 90 min
1 temperature threshold no 2
2 voltage movement no 0
3 frequency change no 1
4 power-down exit YES 7
5 warm reset YES 1
6 periodic interval no 10
robust: implemented 2 of 6, missing 4,
missing_mask names temp, voltage, frequency, periodic
unhandled_event_count 13
weak: coverage_complete reported on a 2-trigger set, because the
set the design has is the set it declared
DERIVED: 13 events in 90 minutes were absorbed with no retraining.
And the two triggers that ARE implemented are the two that are
impossible to miss -- a power-down exit and a reset both have an
obvious hook, while a temperature threshold needs somebody to
decide to watch a sensor.The implemented pair being the obvious two is the finding, and it generalises beyond this belief. DERIVED: power-down exit and warm reset both arrive as events with an existing code path, and the four missing triggers all require somebody to create an observation — a sensor comparison, a voltage monitor, a DVFS hook, a timer. CURRICULUM-DERIVED from 33.6 §6's gate-criterion item: a criterion that requires a positive observation costs more than one that rides an existing event, and the cheap ones get built.
11. Per-Frequency Sets
§8 found five of eight values period-dependent and §6's exit 3 is the largest. This is the mechanism.
// ROBUST MODEL: one trained set PER operating point, because a count in
// cycles is meaningless at another period -- 19.3 section 2's decomposition.
module per_frequency_set #(
parameter int NBIN = 3,
parameter int TAP_W = 6
)(
input logic clk,
input logic rst_n,
input logic [1:0] bin_now,
input logic commit,
input logic [TAP_W-1:0] committed_tap,
input logic [15:0] period_x100, // ILLUSTRATIVE ps x100
output logic [TAP_W-1:0] tap_in_use,
output logic set_valid,
output logic [2:0] bins_trained,
output logic needs_training,
output logic [15:0] wrong_bin_uses,
output logic [TAP_W-1:0] would_be_tap // the correct tap here
);
logic [TAP_W-1:0] tap_of [0:NBIN-1];
logic val_of [0:NBIN-1];
logic [15:0] per_of [0:NBIN-1];
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tap_in_use <= '0; set_valid <= 1'b0; bins_trained <= '0;
needs_training <= 1'b1; wrong_bin_uses <= '0; would_be_tap <= '0;
for (int b = 0; b < NBIN; b++) begin
tap_of[b] <= '0; val_of[b] <= 1'b0; per_of[b] <= '0;
end
end else begin
if (commit) begin
tap_of[bin_now] <= committed_tap;
val_of[bin_now] <= 1'b1;
per_of[bin_now] <= period_x100;
end
// Selection is indexed by the CURRENT bin. A design with one set
// has no index, which is the defect.
tap_in_use <= tap_of[bin_now];
set_valid <= val_of[bin_now];
needs_training <= !val_of[bin_now];
bins_trained <= 3'($countones({val_of[2], val_of[1], val_of[0]}));
// The physical time is invariant; the COUNT is not. If a tap
// trained at another period were used here, this is what it
// would have to be -- and the difference is the error.
if (val_of[bin_now] && (per_of[bin_now] != '0))
would_be_tap <= TAP_W'((32'(tap_of[bin_now])
* 32'(per_of[bin_now])) / 32'(period_x100));
end
end
endmodule// INTENTIONALLY DEFECTIVE. WEAK MODEL: one set, no index.
//
// logic [TAP_W-1:0] the_tap; // <-- one value for all bins
// if (commit) the_tap <= committed_tap;
// tap_in_use <= the_tap;
// set_valid <= trained_once;
//
// CONTRACT VIOLATED: 19.3 section 2 -- the measured term is a physical time
// and the applied value is a count, so the conversion is
// period-dependent.
//
// WHY IT SURVIVES: on a system that never changes frequency it is
// identical to the robust build, and that includes every bench setup
// and most first bring-ups. DVFS is usually enabled late.
//
// TRACE (ILLUSTRATIVE, flight time 2.8 ns; three bins):
// bin 0 1.25 ns/cycle -> correct tap 2 (2.24 rounded)
// bin 1 0.833 ns/cycle -> correct tap 3 (3.36 rounded)
// bin 2 0.625 ns/cycle -> correct tap 4 (4.48 rounded)
//
// robust: trained in bin 0 -> bins_trained 1; entering bin 2 sets
// needs_training 1 and the search runs. bins_trained 2.
// wrong_bin_uses 0.
// weak: trained in bin 0 -> the_tap 2. Entering bin 2, tap_in_use
// is still 2 where 4 is correct: an error of 2 taps, which
// at 0.625 ns/cycle is 1.25 ns of misalignment.
// set_valid stays 1 and nothing reports anything.
//
// gap: a 2-tap error at the highest bin, silent, and it appears only
// after DVFS is enabled -- typically weeks after the PHY was
// declared working.The error's appearance weeks after the PHY was declared working is the expensive part. DERIVED: DVFS is usually enabled late in a programme, so the trained set is validated at one bin and the defect surfaces after that validation is considered complete — which is 33.6 §14's unlicensed assumption in a new place: the bring-up gate established this bin works and a later stage assumed the PHY works.
12. Re-Conversion Is Not Re-Search
§7 separated STALE from INAPPLICABLE and §11 measured the cost of ignoring the second. This is the cost of over-reacting to it, which is the mistake the correction invites.
CURRICULUM-DERIVED from 19.3 §2, which owns the decomposition of a PHY latency into a part known from the configuration and a part only knowable by measurement. DERIVED: a frequency change alters the configuration term and leaves the measured term untouched — so the correct response is to re-run the conversion, not the search.
// ROBUST MODEL: the measured physical quantity is stored, and the
// applied count is derived from it at the current period. A frequency
// change costs a division; only drift costs a search.
module reconversion_vs_research #(
parameter int TAP_W = 6,
parameter int PS_W = 16,
parameter int SEARCH_CYCLES = 4096 // ILLUSTRATIVE cost of a search
)(
input logic clk,
input logic rst_n,
input logic search_done,
input logic [PS_W-1:0] measured_ps, // the PHYSICAL quantity
input logic [PS_W-1:0] period_ps, // current, changes on DVFS
input logic freq_changed,
input logic drift_detected,
output logic [TAP_W-1:0] tap_in_use,
output logic have_measurement,
output logic search_requested,
output logic [15:0] searches_run,
output logic [15:0] reconversions,
output logic [31:0] cycles_spent_searching
);
logic [PS_W-1:0] held_ps;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
held_ps <= '0; tap_in_use <= '0; have_measurement <= 1'b0;
search_requested <= 1'b1; searches_run <= '0;
reconversions <= '0; cycles_spent_searching <= '0;
end else begin
search_requested <= 1'b0;
if (search_done) begin
// Store the PHYSICAL quantity, not the count. This one choice
// is the difference between the two builds.
held_ps <= measured_ps;
have_measurement <= 1'b1;
searches_run <= searches_run + 1'b1;
cycles_spent_searching <= cycles_spent_searching
+ 32'(SEARCH_CYCLES);
end
// A frequency change: re-derive the count. No search, no traffic
// interruption, a handful of cycles.
if (freq_changed && have_measurement) begin
reconversions <= reconversions + 1'b1;
end
// Drift: the MEASUREMENT is wrong, so a search is unavoidable.
if (drift_detected) begin
have_measurement <= 1'b0;
search_requested <= 1'b1;
end
// The applied count, always derived at the current period.
if (have_measurement && (period_ps != '0))
tap_in_use <= TAP_W'((32'(held_ps) + 32'(period_ps) - 32'd1)
/ 32'(period_ps));
end
end
endmodule// INTENTIONALLY DEFECTIVE, TWO WAYS. The correction invites an
// over-reaction, so both errors are shown.
//
// WEAK BUILD A -- store the COUNT, ignore the period:
// if (search_done) held_tap <= measured_tap; // a count, not a time
// tap_in_use <= held_tap; // applied at any period
// -> section 11's defect: the wrong count at the new bin, silently.
//
// WEAK BUILD B -- re-search on every frequency change:
// if (freq_changed) search_requested <= 1'b1; // <-- over-reaction
// -> correct values, and a full search at every DVFS transition.
//
// CONTRACT VIOLATED: 19.3 section 2's decomposition, in both directions --
// A treats the measured term as period-independent, B treats the
// configuration term as unmeasurable.
//
// WHY B SURVIVES REVIEW: it is CORRECT. Every applied value is right,
// every property about validity passes, and the only cost is time --
// 30.3 section 9's variety 8 again, in a PHY flow rather than a timing
// comparison.
//
// TRACE (ILLUSTRATIVE, 40 DVFS transitions and 3 drift events in an
// hour; SEARCH_CYCLES 4096):
// robust: searches_run 4 (1 boot + 3 drift), reconversions 40,
// cycles_spent_searching 16,384
// weak A: searches_run 4, reconversions 0,
// and 40 transitions applied a count from another period
// weak B: searches_run 44, reconversions 0,
// cycles_spent_searching 180,224 -- 11x the robust build
//
// gap: A is wrong 40 times; B is right and spends 164,000 extra
// cycles of interrupted traffic. DERIVED: the belief's correction
// has two failure modes and only one of them is a correctness bug.Weak build B is the more interesting of the two, because it is what an engineer who has just accepted the correction builds. DERIVED: it is functionally correct and costs 11× the search time, and every property in §15 about validity passes on it. CURRICULUM-DERIVED from 30.3 §9's variety 8: a design that is slower than required violates nothing, so B ships and is later diagnosed as DVFS transitions are expensive on this platform.
And the asymmetry between the two weak builds is the practical guidance. DERIVED: 4 searches against 44 is the difference between storing a picosecond figure and storing a tap index — one declaration. CURRICULUM-DERIVED from 33.3 §6's provenance census: the measured term must be stored in the units it was measured in, and converting on use rather than on commit is what makes a re-conversion possible at all.
13. Scheduling the Interruption
§14 row 5 says the cost is recurring rather than boot-time. 19.5 §4 states three requirements for the pass, and a design built on the belief has met none of them because it does not believe there is a pass.
CURRICULUM-DERIVED from 19.5 §4: a recalibration must be brief, must not corrupt in-flight transactions, and must be schedulable — “the same problem 17.3 solved for refresh, with the same shape.”
// ROBUST MODEL: recalibration as a schedulable obligation with the
// three requirements enforced -- the same shape 17.3 uses for refresh,
// as 19.5 section 4 says.
module recal_scheduling #(
parameter int MAX_PASS_CYCLES = 64, // ILLUSTRATIVE "brief"
parameter int INTERVAL = 4096, // ILLUSTRATIVE
parameter int MAX_DEFER = 4 // ILLUSTRATIVE headroom
)(
input logic clk,
input logic rst_n,
input logic tick,
input logic inflight_txn,
input logic bus_idle,
input logic pass_done,
output logic pass_start,
output logic pass_active,
output logic signed [7:0] recal_debt,
output logic [15:0] pass_cycles,
output logic brief_ok,
output logic noncorrupting_ok,
output logic schedulable_ok,
output logic [15:0] deferrals,
output logic [15:0] corrupted_txns
);
logic [15:0] ivl;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ivl <= '0; recal_debt <= '0; pass_start <= 1'b0;
pass_active <= 1'b0; pass_cycles <= '0;
brief_ok <= 1'b1; noncorrupting_ok <= 1'b1; schedulable_ok <= 1'b1;
deferrals <= '0; corrupted_txns <= '0;
end else begin
pass_start <= 1'b0;
if (tick) begin
if (ivl == INTERVAL[15:0]) begin
ivl <= '0;
recal_debt <= recal_debt + 8'sd1;
end else begin
ivl <= ivl + 1'b1;
end
end
// REQUIREMENT 3, schedulable: the pass waits for a window, and
// the wait is bounded so it cannot be deferred forever.
if ((recal_debt > 8'sd0) && !pass_active) begin
if (bus_idle && !inflight_txn) begin
pass_start <= 1'b1;
pass_active <= 1'b1;
pass_cycles <= '0;
end else if (recal_debt >= 8'sd(MAX_DEFER)) begin
// At the bound it goes regardless -- 17.3's
// illegal-versus-deprioritised line, reused.
pass_start <= 1'b1;
pass_active <= 1'b1;
pass_cycles <= '0;
// REQUIREMENT 2: starting with a transaction in flight is
// the corruption case, counted rather than assumed away.
if (inflight_txn) corrupted_txns <= corrupted_txns + 1'b1;
end else if (tick) begin
deferrals <= deferrals + 1'b1;
end
end
if (pass_active) begin
pass_cycles <= pass_cycles + 1'b1;
// REQUIREMENT 1, brief: a pass that overruns is a finding.
if (pass_cycles > 16'(MAX_PASS_CYCLES)) brief_ok <= 1'b0;
if (pass_done) begin
pass_active <= 1'b0;
recal_debt <= recal_debt - 8'sd1;
end
end
noncorrupting_ok <= (corrupted_txns == '0);
schedulable_ok <= (recal_debt <= 8'sd(MAX_DEFER));
end
end
endmodule THE THREE REQUIREMENTS, MEASURED (ILLUSTRATIVE, one hour,
INTERVAL 4096, 14 passes due)
design brief non-corrupting schedulable
------------------------------------------------------------
no recalibration -- -- --
(the belief: nothing to schedule; 0 of 3 met)
recalibrate immediately yes NO yes
(corrupted_txns 9 of 14 -- it starts mid-transaction)
recalibrate when idle yes yes NO
(deferrals unbounded; on a busy hour, 0 of 14 passes ran)
robust: idle, with a bound yes yes yes
(11 passes at idle, 3 forced at the bound, 1 corrupted)
DERIVED: the middle two designs each satisfy two requirements and
fail one, and they are the two an engineer writes first. Only the
bounded-deferral form satisfies all three, and it is exactly
17.3's refresh structure.The middle two rows are the finding: each is a natural first design and each fails one requirement. DERIVED: recalibrate immediately corrupts 9 of 14, and recalibrate when idle runs 0 of 14 on a busy hour — and the resolution is the bounded-deferral ledger 17.3 already built for refresh, which is why 19.5 §4 says the same problem, with the same shape.
The 9-of-14 corruption figure deserves one line, because it is the requirement people assume is free. DERIVED: do not corrupt in-flight transactions sounds like a property of the pass and is actually a property of when the pass starts — CURRICULUM-DERIVED from 19.5 §4, which cites 19.3 §9's aligner as the case that is unaffected by a later change because it loads its offset at the command. So some consumers are immune and some are not, and the pass has to know which — which is a per-consumer classification, exactly like 33.3 §10's precondition list.
And the first row is the belief. DERIVED: a design that believes training completes has nothing to schedule, so it satisfies zero of three requirements and reports no violation of any of them — there is no pass to be brief, nothing to corrupt, and no obligation to schedule. CURRICULUM-DERIVED from 34.4 §11's obligation-with-no-requester finding: this is the second such obligation in the curriculum, and a controller built on either belief has no type for it.
14. The Decision Built on the Belief
| Where it is applied | What it produces | Measured consequence |
|---|---|---|
| A boot flow | train, then boot | 6 of 8 values with no re-establishment path |
A valid flag | monotonic, set once | every downstream check vacuous (§9) |
| A trigger set | the two obvious events | 13 unhandled events in 90 minutes |
| A DVFS enablement plan | the PHY is already trained | 2-tap error at the top bin |
| A power budget | training costs boot time only | recalibration is recurring traffic interruption |
| A verification plan | train once, then test | 33.3 §10's precondition item unreachable |
Row 2 is the most damaging and the least visible, and it deserves the emphasis. DERIVED: a monotonic valid makes every consumer's check pass forever, so the design has the guard 33.3 §8 demands and the guard can never fire. CURRICULUM-DERIVED from 33.3 §7: a flag that cannot fall cannot represent a value that can — so the belief does not remove the safety check, it neuters it, which is strictly worse because the check's presence is evidence.
And row 5 is the one that surprises system architects. DERIVED: if training is one-time, its cost is boot time; if six of eight values are re-established periodically, its cost is a recurring traffic interruption — CURRICULUM-DERIVED from 19.5 §4's three requirements for a recalibration pass: it must be brief, must not corrupt in-flight transactions, and must be schedulable — “the same problem 17.3 solved for refresh, with the same shape.” A design built on the belief has no scheduler for it.
15. What the Assertions Prove
// ---- Section 8: the census. The belief is a predicate, and it is false.
property p_not_all_values_are_one_time;
@(posedge clk) disable iff (!rst_n)
audit |=> !all_one_time;
endproperty
assert property (p_not_all_values_are_one_time)
else $error("the census reports every trained value as one-time");
property p_census_partitions_the_values;
@(posedge clk) disable iff (!rst_n)
audit |=> ((one_time_count + revisited_count) == 4'(NV));
endproperty
assert property (p_census_partitions_the_values)
else $error("the lifetime classes do not partition the trained values");
// ---- Section 9: validity must be able to FALL -- 19.5 section 2.
property p_validity_falls_on_drift;
@(posedge clk) disable iff (!rst_n)
(valid && (temp_now > (temp_at_commit + 8'(TEMP_DELTA)))) |=> !valid;
endproperty
assert property (p_validity_falls_on_drift)
else $error("a trained value stayed valid past its drift threshold");
property p_frequency_change_makes_inapplicable;
@(posedge clk) disable iff (!rst_n)
(valid && freq_changed) |=> (inapplicable && !valid);
endproperty
assert property (p_frequency_change_makes_inapplicable)
else $error("a frequency change left the value valid");
// Stale and inapplicable are DIFFERENT states -- section 7's distinction.
property p_stale_and_inapplicable_are_exclusive;
@(posedge clk) disable iff (!rst_n) !(stale && inapplicable);
endproperty
assert property (p_stale_and_inapplicable_are_exclusive)
else $error("a value was reported both stale and inapplicable");
property p_never_used_while_invalid;
@(posedge clk) disable iff (!rst_n) used_while_invalid == '0;
endproperty
assert property (p_never_used_while_invalid)
else $error("a consumer used a value that was neither valid nor re-established");
// Two-sided -- 30.3 section 9's variety 8: a design that invalidates
// every cycle satisfies every property above and never operates.
property p_validity_survives_within_threshold;
@(posedge clk) disable iff (!rst_n)
(commit && (temp_now == temp_at_commit)) |=> valid;
endproperty
assert property (p_validity_survives_within_threshold)
else $error("a freshly committed value was invalidated at its own temperature");
// ---- Section 10: the trigger set, against section 6's six exits.
property p_trigger_coverage_is_complete;
@(posedge clk) disable iff (!rst_n)
(audit && coverage_complete) |=> (implemented_count == 4'(NTRIG));
endproperty
assert property (p_trigger_coverage_is_complete)
else $error("trigger coverage was called complete with an exit unhandled");
property p_no_event_is_absorbed;
@(posedge clk) disable iff (!rst_n) unhandled_events == '0;
endproperty
assert property (p_no_event_is_absorbed)
else $error("an invalidating event occurred with no retraining trigger");
property p_missing_mask_matches_the_count;
@(posedge clk) disable iff (!rst_n)
audit |=> (missing_count == 4'($countones(missing_mask)));
endproperty
assert property (p_missing_mask_matches_the_count)
else $error("the missing trigger count disagrees with the mask");
// ---- Section 11: per-frequency sets.
property p_set_is_indexed_by_bin;
@(posedge clk) disable iff (!rst_n)
set_valid |-> (tap_in_use == tap_of[bin_now]);
endproperty
assert property (p_set_is_indexed_by_bin)
else $error("the applied tap did not come from the current bin's set");
property p_untrained_bin_requests_training;
@(posedge clk) disable iff (!rst_n)
(!val_of[bin_now]) |=> needs_training;
endproperty
assert property (p_untrained_bin_requests_training)
else $error("an untrained operating point did not request training");
property p_no_wrong_bin_use;
@(posedge clk) disable iff (!rst_n) wrong_bin_uses == '0;
endproperty
assert property (p_no_wrong_bin_use)
else $error("a tap trained at another period was applied");
// ---- Section 12: re-conversion. The measured term is stored in
// physical units, so the count follows the period -- 19.3 section 2.
property p_tap_tracks_the_period;
@(posedge clk) disable iff (!rst_n)
(have_measurement && (period_ps != '0))
|=> (tap_in_use == TAP_W'((32'($past(held_ps))
+ 32'($past(period_ps)) - 32'd1)
/ 32'($past(period_ps))));
endproperty
assert property (p_tap_tracks_the_period)
else $error("the applied tap did not follow the current period");
property p_frequency_change_needs_no_search;
@(posedge clk) disable iff (!rst_n)
(freq_changed && have_measurement) |=> !search_requested;
endproperty
assert property (p_frequency_change_needs_no_search)
else $error("a frequency change triggered a full search");
property p_drift_does_need_a_search;
@(posedge clk) disable iff (!rst_n)
drift_detected |=> search_requested;
endproperty
assert property (p_drift_does_need_a_search)
else $error("drift did not request a new search");
// ---- Section 13: the three requirements -- 19.5 section 4.
property p_pass_is_brief;
@(posedge clk) disable iff (!rst_n) brief_ok;
endproperty
assert property (p_pass_is_brief)
else $error("a recalibration pass exceeded its brevity budget");
property p_pass_does_not_corrupt;
@(posedge clk) disable iff (!rst_n)
pass_start |-> (!inflight_txn || (recal_debt >= 8'sd(MAX_DEFER)));
endproperty
assert property (p_pass_does_not_corrupt)
else $error("a pass started mid-transaction with headroom remaining");
property p_pass_is_schedulable;
@(posedge clk) disable iff (!rst_n) schedulable_ok;
endproperty
assert property (p_pass_is_schedulable)
else $error("recalibration debt exceeded its deferral bound");
// And the two-sided partner: it must actually RUN, not merely defer.
property p_pass_runs_at_idle;
@(posedge clk) disable iff (!rst_n)
((recal_debt > 8'sd0) && bus_idle && !inflight_txn && !pass_active)
|=> pass_start;
endproperty
assert property (p_pass_runs_at_idle)
else $error("a due pass did not start in an idle window");
// ---- The CLAIM, as a conditional pair -- 34.1 section 1's required form.
property p_claim_holds_in_its_region;
@(posedge clk) disable iff (!rst_n)
(valid && (temp_now == temp_at_commit) && !freq_changed && !tick)
|=> valid;
endproperty
assert property (p_claim_holds_in_its_region)
else $error("with every condition constant the value still went invalid");
property p_claim_fails_outside_its_region;
@(posedge clk) disable iff (!rst_n)
(valid && freq_changed) |=> (validity_falls > $past(validity_falls));
endproperty
assert property (p_claim_fails_outside_its_region)
else $error("a frequency change did not invalidate anything");
// ---- COVERS. Each on the dimension the belief's failure scales with.
// The REGION: conditions constant, so the claim pair is not vacuous.
cover property (@(posedge clk) disable iff (!rst_n)
valid && (temp_now == temp_at_commit) && !freq_changed);
// A TEMPERATURE excursion past the threshold. The dimension is the
// ENVIRONMENT, and a bench at 25C never reaches it.
cover property (@(posedge clk) disable iff (!rst_n)
valid && (temp_now > (temp_at_commit + 8'(TEMP_DELTA))));
// A FREQUENCY change -- the dimension is the operating point, and a
// single-bin system never reaches it however long it runs.
cover property (@(posedge clk) disable iff (!rst_n) valid && freq_changed);
// Validity actually FALLING, so the properties about falling are not
// vacuous in a design where it never does.
cover property (@(posedge clk) disable iff (!rst_n) validity_falls > 16'd0);
// Both post-valid states, separately.
cover property (@(posedge clk) disable iff (!rst_n) stale);
cover property (@(posedge clk) disable iff (!rst_n) inapplicable);
// Section 10: an event with NO trigger -- the absorption mechanism.
cover property (@(posedge clk) disable iff (!rst_n) unhandled_events != '0);
// And complete coverage, so p_trigger_coverage_is_complete has a
// witness rather than being satisfied by never completing.
cover property (@(posedge clk) disable iff (!rst_n)
audit && coverage_complete);
// Section 11: a SECOND bin trained -- which requires a DVFS transition
// to occur at all.
cover property (@(posedge clk) disable iff (!rst_n) bins_trained >= 3'd2);
// And an untrained bin entered, so the request path is exercised.
cover property (@(posedge clk) disable iff (!rst_n)
needs_training && !set_valid);
// A census reporting a REVISITED majority -- section 8's 75%.
cover property (@(posedge clk) disable iff (!rst_n)
audit && (revisited_share_pct > 8'd50));
// Section 12: a RE-CONVERSION without a search -- the cheap path, which
// a design storing a tap index can never take.
cover property (@(posedge clk) disable iff (!rst_n)
freq_changed && have_measurement && !search_requested);
// And a search caused by DRIFT, so the two causes are separated.
cover property (@(posedge clk) disable iff (!rst_n)
drift_detected && search_requested);
// Section 13: a pass FORCED at the deferral bound -- the case the
// idle-only design never reaches and the belief has no pass for.
cover property (@(posedge clk) disable iff (!rst_n)
pass_start && (recal_debt >= 8'sd(MAX_DEFER)));
// And a pass starting in a genuine idle window.
cover property (@(posedge clk) disable iff (!rst_n)
pass_start && bus_idle && !inflight_txn);Two notes, and the first is this chapter's central property design.
p_not_all_values_are_one_time asserts the belief false as a property of the census, which is unusual and deliberate. DERIVED: every other chapter in this module asserts the claim true in its region and false outside it. Here the belief's predicate — every value is one-time — is false in every region, because two of eight being one-time is a fact about the value set rather than about conditions. CURRICULUM-DERIVED from 19.5 §4's split: the split is a property of the quantities, so no operating condition makes all eight one-time. The region in §5 makes the consequences invisible, not the classification wrong.
And p_never_used_while_invalid is the property the weak build satisfies vacuously, which §9 already measured. DERIVED: it reads zero in both builds and for opposite reasons — the robust build retrains before use, the weak build has no invalid state. CURRICULUM-DERIVED from 27.2: the cover on validity_falls > 0 is what separates the two, and without it the property is 33.4 §7's unprovable-but-passing case.
16. Mutation Testing
Baseline first: all twenty-three assertions pass and all fifteen covers are non-zero.
| # | Mutation | Killed by | Survived? |
|---|---|---|---|
| M1 | §8: every value set to L_ONE_TIME | p_not_all_values_are_one_time | killed |
| M2 | §8: revisited_count tied to zero | p_census_partitions_the_values | killed |
| M3 | §9: valid made monotonic | p_validity_falls_on_drift, by one cover | killed |
| M4 | §9: drop temp_at_commit | p_validity_falls_on_drift | killed |
| M5 | §9: treat freq_changed as drift | p_frequency_change_makes_inapplicable | killed |
| M6 | §9: set both stale and inapplicable | p_stale_and_inapplicable_are_exclusive | killed |
| M7 | §9: invalidate every cycle | p_validity_survives_within_threshold | killed |
| M8 | §10: coverage_complete tied high | p_trigger_coverage_is_complete | killed |
| M9 | §10: absorb events silently | p_no_event_is_absorbed, by one cover | killed |
| M10 | §10: missing_mask tied to zero | p_missing_mask_matches_the_count | killed |
| M11 | §11: one tap, no bin index | p_set_is_indexed_by_bin, by one cover | killed |
| M12 | §11: needs_training tied low | p_untrained_bin_requests_training | killed |
| M13 | §11: apply the nearest trained bin's tap | p_no_wrong_bin_use | killed |
| M14 | TEMP_DELTA raised to 200 | nothing | SURVIVES |
| M15 | STALE_TICKS raised to its maximum | nothing | SURVIVES |
| M16 | NBIN set to 1 | nothing | SURVIVES |
| M17 | the stimulus fixed at one temperature | nothing | SURVIVES |
| M18 | NTRIG reduced to 2 | nothing | SURVIVES |
| M19 | §12: store the tap index, not the picoseconds | p_tap_tracks_the_period, by one cover | killed |
| M20 | §12: re-search on every frequency change | p_frequency_change_needs_no_search | killed |
| M21 | §12: drift does not request a search | p_drift_does_need_a_search | killed |
| M22 | §13: start the pass regardless of in-flight | p_pass_does_not_corrupt | killed |
| M23 | §13: defer while busy, unbounded | p_pass_is_schedulable, by one cover | killed |
| M24 | §13: never start the pass | p_pass_runs_at_idle | killed |
| M25 | §13: MAX_PASS_CYCLES raised to its maximum | nothing | SURVIVES |
DERIVED: nineteen of twenty-five killed, six survived — and M18 is the one that is new to this module.
M25 is the sixth survivor and it is the brevity requirement's quantity. Raising MAX_PASS_CYCLES to its maximum makes brief_ok permanently true, so a pass of any length satisfies 19.5 §4's first requirement. DERIVED: and a long pass is exactly what brief was protecting against — the interruption whose whole cost is its duration. CURRICULUM-DERIVED from 33.4 §15's variety 12: the mechanism checks that brevity is tested and says nothing about the budget, and the budget's honest source is the deadline of whatever the pass interrupts — which is 33.5's per-class deadline, not a PHY parameter.
Reducing NTRIG to 2 makes coverage_complete true on a two-trigger design, and every property passes because each is written against NTRIG. DERIVED: that is §10's weak build reached by changing the denominator rather than the numerator — and it is the same shape as 34.4 §16's census defect, where the belief supplied its own denominator. CURRICULUM-DERIVED from 33.1 §5: a census's denominator must come from outside the design, and §6's six exits are this chapter's, derived from 19.5 §4 and 33.3 §9 rather than from the trigger set.
M14, M15, M16 and M17 reconstruct §5's region — the fifth consecutive chapter in this module with that result, and now unremarkable. A 200-degree drift threshold, an unreachable staleness age, one frequency bin, one temperature. DERIVED: each makes the belief true and kills nothing.
Three mutations are killed only by a cover, and M11's is the one with a schedule consequence. A single tap with no bin index is indistinguishable from the robust build until a second bin is entered, so the cover on bins_trained >= 2 is the only thing that reaches it. CURRICULUM-DERIVED from 31.2 §14: the dimension is the operating point, and DVFS being enabled late in a programme is precisely why this defect ships.
17. Baseline Defects Found Before Mutation
| Belief applied to | Caught by | At what cost |
|---|---|---|
| a lifetime assumption | p_not_all_values_are_one_time | nothing — classify the eight values |
a valid flag | p_validity_falls_on_drift | nothing — read the assignment |
| a trigger set | p_no_event_is_absorbed | nothing — count against six |
| a DVFS plan | p_set_is_indexed_by_bin | nothing — is the set an array? |
| a running system | p_never_used_while_invalid | a temperature excursion |
| a recalibration budget | — | nothing: §8's 75% is the budget |
DERIVED: five of six are found without running anything, and four of the five are structural — a classification, an assignment, a count, and whether a declaration is an array. That is the cheapest detection profile in this module, and it is because a lifetime belief leaves a structural fingerprint: a value with no invalidation path has no code to invalidate it.
One needs a stimulus, and the dimension belongs to the environment.
| Application | The stimulus | Why the usual test misses it |
|---|---|---|
| a running system | a temperature excursion or a DVFS transition | a bench runs at one temperature and one bin |
DERIVED: and both are cheap to add to a test plan and absent from most of them — CURRICULUM-DERIVED from 33.4 §6's configuration-reach item: the environment must be able to vary temperature and frequency, which is a testbench capability rather than a stimulus, and no amount of traffic substitutes for it.
18. Silicon Observability
| What silicon shows | What it says about the belief |
|---|---|
| errors appearing after a warm-up period, gone after a power cycle | §9 — drift, with no retraining |
| errors that start when DVFS is enabled | §11 — one set, several bins |
a trained flag that has never been observed low | §14 row 2 — monotonic validity |
| failures correlated with chassis temperature, not with load | §6 exit 1, and not a thermal throttling issue |
| a training-time counter that reads 1 for the part's lifetime | the belief, implemented |
| errors after suspend-resume only | §6 exit 4 — power-down exit |
Row 1 is the signature and it is nearly diagnostic on its own. DERIVED: errors that appear after a warm-up and vanish on a power cycle describe a value that drifted and was re-established by the reboot — and the power cycle's only relevant effect is that it re-runs training. CURRICULUM-DERIVED from 28.4 §2's fifth case: a system that “boots, passes its own self-checks, and corrupts data hours later” — this is that case's field signature.
Row 3 is the cheapest check in the chapter and it needs no equipment. DERIVED: ask whether anybody has ever seen the trained flag low after boot. If the answer is no, either the design is in §5's region or the flag cannot fall — and the two are distinguished by reading one assignment. CURRICULUM-DERIVED from 33.4 §10's positive-control matrix: a signal with no observed transition is either protecting something that never happens or is incapable of the transition, and only an injection separates them.
Row 4 is the one most often misattributed. DERIVED: temperature-correlated failures that are not load-correlated point at drift rather than at power — and the discriminator is one experiment: hold the load constant and change the chassis temperature. CURRICULUM-DERIVED from 33.7 §9's rate-consistency item: the hypothesis set for temperature-correlated corruption includes retention, drift, and thermal throttling, and a load-held temperature sweep partitions them.
19. Quantitative Reasoning
| Quantity | Truth | Under the belief | Gap | Provenance |
|---|---|---|---|---|
| trained values needing re-establishment | 6 of 8 | 0 of 8 | 75% | DERIVED, ILLUSTRATIVE set |
| genuinely one-time values | 2 of 8 | 8 of 8 | — | DERIVED |
| period-dependent values | 5 of 8 | 0 | all five silent | DERIVED |
| retraining triggers implemented | 2 of 6 | 2 of 6 | 4 missing | DERIVED |
| invalidating events in 90 min | 13 | 0 detected | 13 absorbed | DERIVED, ILLUSTRATIVE run |
| validity falls in 90 min | 3 | 0 | 3 | DERIVED |
| tap error at the top DVFS bin | 2 taps | 0 reported | 1.25 ns | DERIVED |
used_while_invalid | 0 | 0 | none — vacuously | DERIVED |
| recalibration cost | recurring | boot-time only | a scheduler | CURRICULUM-DERIVED, 19.5 §4 |
The eighth row is the one to dwell on, because it is the only row in this module where the belief and the truth agree and the agreement is worthless. DERIVED: used_while_invalid is zero in both builds — in one because the design retrains, in the other because there is no invalid state to be in. CURRICULUM-DERIVED from 33.4 §7: a property that passes with an unreached antecedent is unproven rather than proven, and this is the module's clearest instance of a belief producing one.
Sort by what kind of thing the belief gets wrong and this chapter adds a fourth kind to the module's collection.
| Kind | Rows | What the belief does |
|---|---|---|
| Classification | one-time count, period-dependent | assigns one lifetime to a set with four |
| Completeness | triggers, absorbed events | has 2 of 6 and reports complete |
| Vacuity | used_while_invalid | makes a correct check unfalsifiable |
| Category | recalibration cost | prices a recurring cost as a one-off |
DERIVED: the third row is new. 34.1 was wrong about magnitude, 34.2 silent, 34.3 an identification, 34.4 an expressibility gap. Here the belief leaves a correct guard in place and makes it unable to fire, which is the only one of the five that damages a design's verification rather than its function.
20. The Beliefs This One Generates
| Downstream belief | Why it follows | Where it is refuted |
|---|---|---|
“trained high means the PHY is good” | if training completes | §14 row 2; 28.4 §2 |
| “training costs boot time” | if it happens once | §14 row 5; 19.5 §4 |
| “DVFS is a clock-tree problem” | if trained values are frequency-independent | §11; 19.3 §2 |
| “a reboot fixing it means it was software” | if training is not a reboot effect | §18 row 1 |
| “temperature failures mean throttling” | if the PHY is temperature-independent | §18 row 4 |
The fourth row is the most expensive misdirection in this table. DERIVED: a power cycle re-runs training, so a reboot fixes it is evidence about training and is routinely read as evidence about software state. CURRICULUM-DERIVED from 33.7 §7's discriminating-power item: a reboot perturbs software state, hardware state and the trained set simultaneously, so it eliminates nothing — and it is the single most-performed experiment in computing.
And the third row reaches a different team entirely. DERIVED: DVFS enablement is usually owned by power management, and a trained-value dependency on frequency is invisible from there — which is 34.3 §9's compounding in a new form: two teams each correct about their own layer, and a dependency crossing between them that neither's specification mentions.
21. Common Wrong Answers
-
“Training runs once at boot.” The boot sequence runs once; the values have four lifetimes. CURRICULUM-DERIVED from 19.5 §4: “Calibration is not a bring-up activity that completes.”
-
“So nothing is one-time.” Inverted — §8: two of eight are. Write levelling and gate training genuinely complete. DERIVED: the correction is a census, not an inversion.
-
“
trainedis high, so the PHY is configured.” CURRICULUM-DERIVED from 28.4 §2: adoneflag means one of five things, and the worst “boots, passes its own self-checks, and corrupts data hours later.” -
“We have a
validgate on every consumer.” Can it fall? §9: a monotonicvalidmakes every such gate vacuous — the guard is present and unfalsifiable, which §19 calls the vacuity error. -
“Periodic recalibration is a ZQ thing.” §8: five of eight values drift with temperature and three are periodic. CURRICULUM-DERIVED from 19.5 §4: the quantities are functions of temperature and supply voltage, both of which move.
-
“We do not change frequency.” Then condition 3 holds and the belief is right about that exit. DERIVED: and §11's defect is invisible until DVFS is enabled, which happens late — so we do not change frequency is often we do not change frequency yet.
-
“A frequency change needs retraining, so we retrain on it.” Sometimes it needs only a re-conversion. DERIVED: §7 separates
STALEfromINAPPLICABLEbecause the physical measurement may still be right while its cycle count is not — and a full search where a division would do costs boot time at every transition. -
“The trained value is a physical time, so it is frequency-independent.” The value is; the register is not. CURRICULUM-DERIVED from 19.3 §2: a latency decomposes into a programmed term and a measured term, and the applied value is a count.
-
“We retrain on power-down exit and reset, which covers it.” §10: those are the two obvious exits, and four remain — temperature, voltage, frequency and the periodic interval. 13 unhandled events in 90 minutes.
-
“Our trigger coverage is complete.” Against what denominator? §16's M18: reducing
NTRIGto 2 makes a two-trigger design complete — CURRICULUM-DERIVED from 33.1 §5: the denominator must come from outside the design. -
“A reboot fixes it, so it is software.” A reboot re-runs training. CURRICULUM-DERIVED from 33.7 §7: it perturbs three things at once and therefore eliminates none of them.
-
“Temperature-correlated failures mean thermal throttling.” §18 row 4: hold the load constant and sweep the temperature. DERIVED: throttling is load-correlated and drift is not, and one experiment separates them.
-
“Recalibration would interrupt traffic, so we do not do it.” CURRICULUM-DERIVED from 19.5 §4: a recalibration pass must be brief, non-corrupting and schedulable — “the same problem 17.3 solved for refresh.” DERIVED: the requirement is a scheduling problem with a known shape, not a reason to skip it.
-
“Training cost is a boot-time number.” §14 row 5: with six of eight values re-established, it is recurring — and a design built on the belief has no scheduler for the recurrence.
-
“Our bench has run for a week without an error.” At one temperature, one voltage, one frequency, with no suspend and no warm reset. DERIVED: §5's five conditions, all satisfied, for a week.
-
“19.5 says some values stop being correct — I know that.” And §8 says six of eight. DERIVED: this chapter exists because some reads as an exception and 75% reads as the rule — the sentence and the census differ in effect, not in content.
-
“Then we should retrain continuously.” §15's
p_validity_survives_within_thresholdrejects that — a design that invalidates every cycle satisfies every falling-validity property and never operates. CURRICULUM-DERIVED from 30.3 §9's variety 8: the two-sided pair exists for exactly this over-correction. -
“
used_while_invalidreads zero, so we are safe.” It reads zero in the broken build too, and for the opposite reason. §19's eighth row — the only place in this module where the belief and the truth agree on a number and the agreement means nothing. -
“The five period-dependent values drift, so periodic retraining covers them.” They do not drift on a frequency change — they become inapplicable instantly. DERIVED: a periodic timer may not fire before the wrong count is applied, so the trigger has to be the transition rather than an interval.
-
“This is a PHY team problem.” §20 row 3: DVFS enablement is owned by power management, and the dependency crosses between the two teams — CURRICULUM-DERIVED from 34.3 §9's compounding: two correct specifications with an unmentioned dependency between them.
-
“Four mutations survived, so the property set is weak.” All five survivors move a quantity — a drift threshold, a staleness age, a bin count, a trigger count, a stimulus temperature. CURRICULUM-DERIVED from 33.4 §15's variety 12, for the fifth consecutive chapter.
-
“I would never assume a trained value is permanent.” The test is structural: does your
validbit have a falling assignment? DERIVED: §17 finds four of six applications of this belief by reading a declaration, and the fingerprint is an absence of code rather than a wrong value.
22. Self-Check
- Name the four lifetime classes a trained value can have, and give the split across §8's eight values.
- Which chapter's second paragraph refutes this belief, and what does it say?
- State the five conditions under which training happens only once is true, and say which two the specification's authors expected to fail.
- Why is
INAPPLICABLEa different state fromSTALE, and what does treating a frequency change as drift cost? - A
validbit is assigned only in acommitbranch. State the finding in one sentence, and say what it does to every downstream guard. - Six exits invalidate a trained value. Name them, and say which two a typical design implements and why those two.
- Flight time is 2.8 ns. Give the correct tap at 1.25 and at 0.625 ns per cycle, and the error a single-set design applies at the faster bin.
used_while_invalidreads zero. Give the two reasons that can be true, and the cover that distinguishes them.- A system fails after a warm-up and works after a power cycle. State the mechanism, and say why a reboot is a poor experiment.
- M18 reduced
NTRIGfrom 6 to 2. What did that make the instrument report, and which chapter's rule does the fix come from? - §19's table has a row the four preceding chapters do not. Name it, and say why it is the only error kind that damages verification rather than function.
- A colleague proposes retraining continuously. Give the property that rejects it and the variety it invokes.
23. The Residual Risk
What this chapter cannot settle.
It cannot supply the drift thresholds. §9's TEMP_DELTA is ILLUSTRATIVE and M14 raised it to 200 with nothing firing. CURRICULUM-DERIVED from 21.4 and 20.5: a real threshold comes from an eye-width-versus-temperature characterisation, and this chapter derives none — the fifth consecutive chapter whose survivor needs a measurement rather than a property.
It cannot tell you which values your PHY treats how. §8's assignment of eight values to four classes is ILLUSTRATIVE. CURRICULUM-DERIVED from 19.1 §3, whose ownership table has six implementation-dependent rows: DERIVED: a vendor PHY may handle drift internally and expose none of it, in which case several of §8's rows move to the IP's problem — and §10's trigger census then needs the IP's documentation rather than the design's code.
It cannot schedule the recalibration. §14 row 5 establishes that the cost is recurring and 19.5 §4 states the three requirements. DERIVED: how to make room for a brief, non-corrupting, schedulable interruption is 17.3's problem shape and 33.3 §10's review item, and this chapter only establishes that the problem exists.
It cannot tell you which consumers are immune to an interruption. §13's non-corruption requirement needs a per-consumer classification, and 19.5 §4 cites 19.3 §9's aligner as one immune case. DERIVED: the classification is a property of each consumer's own latching discipline, so it is design-specific and this chapter models the requirement rather than the list — the same shape as 33.3 §10's precondition item, one level down.
And it cannot distinguish a value the PHY re-establishes silently from one nobody re-establishes. DERIVED: a design with no retraining trigger and no failures may have a PHY doing it internally, or may be inside §5's region — and §10's census cannot tell those apart from the outside. CURRICULUM-DERIVED from 33.4 §13's VIP-observability item: what a supplied component does not report has to be established by experiment, and the experiment here is a temperature sweep.
24. Where This Goes
Five beliefs down: three about numbers, one about a component's nature, one about a process's lifetime.
Chapter 34.6 closes the module, and it changes the object once more. DERIVED: DDR5 is just faster DDR4 is a claim about a generation's relationship to its predecessor — which is neither a quantity, a structure nor a lifetime, but a claim about what changed.
And it inherits this chapter's sharpest sub-finding. DERIVED: §8 found five of eight trained values period-dependent — invalidated by a frequency change with no physical change at all. A generation change is a frequency change with everything else changed too, so every dependency this chapter found crossing a DVFS boundary crosses a generation boundary as well.
CURRICULUM-DERIVED from 4.6, whose framing the last chapter is built on: DDR5 transfers sixteen beats per burst and keeps granularity identical to DDR4's by halving the width the burst crosses — DERIVED: that is not a speed change, it is a structural change chosen to hold one quantity constant while a rate doubled, and a belief that reads it as a speed bump misses the reason the structure moved.
Continue learning
Related tutorials
- Related topic
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.
- Related topic
Write Leveling Algorithm
Chapter 20.4 built a probe that asks the device one yes-or-no question. Turning it into a search means sweeping a delay, distrusting any single answer near the boundary, confirming a transition, and keeping the candidate out of the production datapath.
- Related topic
Read Leveling
The read side has no phase comparator, only a correctness bit. That forces a two-edge search over a full sweep, an MPR stimulus whose format decides what can be trained at all, and per-bit adjustment to recover per-pin skew.
- Related topic
Gate Training
The DQS gate exists only inside the PHY, so JEDEC defines no procedure for it — only a preamble the PHY can find. The resulting search has a one-sided pass region whose safe side produces no observable at all.
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.
