DDR · Module 34
“DDR5 Is Just Faster DDR4”
The last of six, and the last chapter of the DDR track. DDR5 doubled the beats and halved the width each burst crosses, so access granularity is exactly unchanged — the structure moved in order to hold one number still, and zero of seventeen controller obligations are untouched.
“DDR5 is DDR4 at a higher data rate. Same commands, same concepts, faster pins.”
34.5 §24 named the last change of object: this belief is 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 the claim's first clause is true. DDR5 is faster. DERIVED: what the belief gets wrong is the direction of causation — it reads the speed as the change and the rest as consequences, and the arithmetic runs the other way.
CURRICULUM-DERIVED from 4.6, which states the whole of it in two lines:
16 beats x 64 bits = 128 bytes -- twice a cache line. Fatal.
16 beats x 32 bits = 64 bytes -- a cache line. UNCHANGED.DERIVED: the structure moved in order to hold one number still. Doubling the beats would have doubled the access size, which is unacceptable — so the width the burst crosses was halved, and a 64-bit channel became two independent 32-bit sub-channels. The speed is what the structure bought; the structure is not what the speed cost.
1. The One-Sentence Correction
DDR5 doubled the beats per burst and halved the width each burst crosses, so access granularity is exactly unchanged and the per-pin rate doubles — and the consequence is two independent sub-channels with their own command paths, their own bank hierarchies and their own mode-register spaces, which is a controller that has two of everything rather than one that runs faster.
CURRICULUM-DERIVED from 4.6, which owns the derivation and records that the arithmetic is exact rather than approximate: doubling the beats and halving the width cancel precisely.
2. What This Chapter Owns
| Ground | Owner |
|---|---|
| The generational derivation, and the exact cancellation | 4.6 |
The DDR5 command and address interface; CS_n inside the command code; sub-channel contents; the per-sub-channel mode-register space and its controller hazard | 25.2 |
| DDR5 bank-group enhancements | 25.1 |
| On-DIMM PMIC and power delivery | 25.3 |
On-die ECC, CRC in both directions and ALERT_n, directed refresh management, DFE | 25.4 |
| The five-level hierarchy and the quantitative same-group penalty | 16.4 |
| The generational sequence from SDR to DDR5 | Module 4 |
| The thirteen controller obligations the destructive-read property creates | 31.1 §5, 34.4 §8 |
| Trained values that are period-dependent | 34.5 §8 |
| Why the belief inverts the causation, and the obligation delta it hides | this chapter |
One boundary needs care, because 4.6 already contains the derivation.
4.6 owns the two-line arithmetic and the sub-channel split it forces, addressed to somebody learning what DDR5 is. DERIVED: this chapter is addressed to somebody who has read that and still plans a DDR5 controller as a DDR4 controller at a higher clock — and §10's obligation delta is the instrument, because a delta is what an engineer porting a design needs and a description is not.
And 25.4 owns the four new capabilities and their interaction. DERIVED: this chapter counts how many of them add a controller obligation rather than a device feature, which is the question a port has to answer and which 25.4 has no reason to pose.
3. Teaching-Model Boundary And Source Discipline
| Claim class | What it means here | Example below |
|---|---|---|
| Structural | a documented mechanism, or an arithmetic identity | the 16×32 = 8×64 cancellation; the four DDR5 capabilities; two sub-channels |
| Curriculum-derived | follows from a cited chapter of this track | the obligation set, the same-group penalty, the mode-register hazard |
| Derived | computed in this chapter from the models below | every count and delta in §19 |
| Illustrative | a chosen number that makes a mechanism visible | rates, bank counts, queue depths, error rates |
The cancellation is STRUCTURAL and exact. CURRICULUM-DERIVED from 4.6: 16 × 32 bits = 64 bytes = 8 × 64 bits, and the chapter records that the cancellation is “exact rather than approximate.” DERIVED: every argument below rests on that identity and not on any rate.
The four capabilities are STRUCTURAL and are 25.4's. DERIVED: this chapter does not re-derive on-die ECC, CRC, directed refresh management or DFE — it classifies each as adding a device feature, a controller obligation, or both.
No external source was consulted and no network tool was used. Where a DDR5 figure is used it is ILLUSTRATIVE and labelled; the verified device figures in this track belong to the chapters that verified them.
4. Why a Competent Engineer Believes It
| # | The true statement | What the belief does with it |
|---|---|---|
| 1 | DDR5 is faster — the per-pin rate doubled | treats the headline consequence as the change |
| 2 | The command set and concepts carry over almost entirely | treats programming-model continuity as architectural continuity |
| 3 | The generation names are a sequence | treats a sequence of names as a sequence of speed bumps |
| 4 | Access granularity is unchanged at 64 bytes | treats an invariant as evidence that nothing moved |
Reason 4 is the sharpest and it is the one that makes this belief different from the five before it. DERIVED: granularity being unchanged is not a sign that the structure held — it is the thing the structural change was performed to achieve. CURRICULUM-DERIVED from 4.6: 16 beats across 64 bits would be 128 bytes, twice a cache line — “Fatal” — so the width had to halve.
DERIVED: the belief reads the invariant as evidence of continuity, and the invariant is evidence of a deliberate structural intervention. That is a genuinely difficult inference to make from the outside, because a successful invariant looks exactly like nothing having happened.
Reason 2 is true to an extent that is worth quantifying rather than dismissing. DERIVED: activate, precharge, read, write, refresh and the timing parameters all carry over, so a DDR4 mental model answers most questions about DDR5 correctly — and §10 measures how many of 34.4 §8's thirteen obligations are unchanged, which is most of them. The belief is not wrong about the overlap; it is wrong about the residue.
5. The Region Where the Claim Is True
"DDR5 IS JUST FASTER DDR4" HOLDS AT EXACTLY ONE LEVEL:
1 the COMMAND SEMANTICS layer -- what ACT, PRE, RD, WR, REF mean
2 the TIMING PARAMETER layer -- tRCD, tRP, tRAS still govern
3 the ACCESS GRANULARITY layer -- 64 bytes, unchanged by design
and then: a DDR4 mental model answers the question correctly, and
the belief is a useful abstraction
IT FAILS AT:
4 the CHANNEL ORGANISATION layer -- two sub-channels, not one
5 the COMMAND PATH layer -- two-cycle framing, CS_n inside
6 the CONFIGURATION layer -- per-sub-channel mode registers
7 the RELIABILITY layer -- on-die ECC, CRC, ALERT_n
8 the POWER layer -- on-DIMM PMIC
9 the REFRESH layer -- directed refresh managementDERIVED: the belief is true at three layers and false at six, and the three it is true at are the three a software or firmware engineer works in. That is why the belief is stable in some roles and untenable in others — and it explains the recurring experience of a driver porting cleanly while a controller does not.
CURRICULUM-DERIVED from 25.2, which owns layers 5 and 6 and identifies the per-sub-channel command bus as “the load-bearing one” of the duplicated resources: a shared command bus would mean “one stream serving two data paths” — DERIVED: so layer 4's split is not a packaging choice, it is what makes the beat doubling usable.
6. The Boundary, Computed
The cancellation, stated once, because every other number in this chapter follows from it.
DDR4: BL8 x 64 bits = 8 x 8 bytes = 64 bytes (STRUCTURAL)
DDR5: BL16 x 32 bits = 16 x 4 bytes = 64 bytes (STRUCTURAL)
granularity ratio: 64 / 64 = 1.000 EXACTLY
beats per burst ratio: 16 / 8 = 2.000
width per burst ratio: 32 / 64 = 0.500
product of the last two: = 1.000 <- the cancellation
and the consequence:
command paths per 64-bit channel DDR4: 1 DDR5: 2
bank hierarchies per channel DDR4: 1 DDR5: 2
mode-register spaces per channel DDR4: 1 DDR5: 2| Layer | DDR4 | DDR5 | Owner |
|---|---|---|---|
| Access granularity | 64 B | 64 B | 4.6 |
| Beats per burst | 8 | 16 | 4.6 |
| Width per burst | 64 b | 32 b | 4.6 |
| Command paths per channel | 1 | 2 | 25.2 |
| Mode-register spaces | 1 | 2 | 25.2 |
| Command framing | 1 cycle | 1 or 2 | 25.2 |
| Power delivery | board | on-DIMM PMIC | 25.3 |
| Device-level ECC | none | on-die | 25.4 |
| Write CRC | optional | both directions + ALERT_n | 25.4 |
| Refresh control | REF | + directed refresh management | 25.4 |
DERIVED: one row is unchanged, three are arithmetic consequences of the cancellation, and six are new mechanisms. The belief's claim is that the first row's invariance characterises the table, and it characterises one row of ten.
7. The Layers at Which It Differs
The diagram earns its place because the belief is a claim about which layers moved, and a layer stack is the only representation in which that is a readable property.
Read the stack as three bands: three green, two brand, four amber-and-red. DERIVED: the belief is a correct description of the green band, and every layer a controller designer touches is in the other two. CURRICULUM-DERIVED from 25.2: the duplication is not symmetric decoration — the command bus is the load-bearing duplicated resource, so the amber band is where the doubled beat count is actually paid for.
8. The Cancellation, Modelled
// ROBUST MODEL: granularity is DERIVED from beats and width, so the
// invariant is visible as a computed equality rather than asserted.
// 4.6's exact cancellation, made structural.
module granularity_invariant #(
parameter int D4_BEATS = 8,
parameter int D4_BITS = 64,
parameter int D5_BEATS = 16,
parameter int D5_BITS = 32
)(
input logic clk,
input logic rst_n,
input logic evaluate,
output logic [15:0] d4_bytes,
output logic [15:0] d5_bytes,
output logic granularity_held,
output logic [15:0] beats_ratio_x100,
output logic [15:0] width_ratio_x100,
output logic [15:0] product_x100,
output logic cancellation_exact,
output logic [15:0] naive_d5_bytes // what NOT halving would give
);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
d4_bytes <= '0; d5_bytes <= '0; granularity_held <= 1'b0;
beats_ratio_x100 <= '0; width_ratio_x100 <= '0;
product_x100 <= '0; cancellation_exact <= 1'b0;
naive_d5_bytes <= '0;
end else if (evaluate) begin
d4_bytes <= 16'((D4_BEATS * D4_BITS) / 8);
d5_bytes <= 16'((D5_BEATS * D5_BITS) / 8);
// The counterfactual 4.6 calls "Fatal": double the beats and keep
// the width.
naive_d5_bytes <= 16'((D5_BEATS * D4_BITS) / 8);
beats_ratio_x100 <= 16'((D5_BEATS * 100) / D4_BEATS);
width_ratio_x100 <= 16'((D5_BITS * 100) / D4_BITS);
product_x100 <= 16'(((D5_BEATS * 100) / D4_BEATS)
* ((D5_BITS * 100) / D4_BITS) / 100);
granularity_held <= (((D4_BEATS * D4_BITS) / 8)
== ((D5_BEATS * D5_BITS) / 8));
// Exact, not approximate -- 4.6's word, as a check.
cancellation_exact <= ((((D5_BEATS * 100) / D4_BEATS)
* ((D5_BITS * 100) / D4_BITS)) == 10000);
end
end
endmodule// INTENTIONALLY DEFECTIVE. WEAK MODEL: granularity is a constant.
//
// localparam int ACCESS_BYTES = 64; // "it is 64 bytes"
// d4_bytes <= 16'(ACCESS_BYTES);
// d5_bytes <= 16'(ACCESS_BYTES);
// granularity_held <= 1'b1; // <-- the defect
//
// CONTRACT VIOLATED: none numerically -- 64 bytes IS the answer for both
// generations. The defect is that it is stored rather than derived, so
// the model cannot show WHY it is the same, and it reports the same
// answer for a hypothetical DDR5 that did not halve the width.
//
// WHY IT SURVIVES: it is right about the only number the belief's
// holder ever checks, and it is right for both generations.
//
// TRACE (ILLUSTRATIVE, and the third row is the point):
// as specified: D5_BEATS 16, D5_BITS 32
// robust: d4 64, d5 64, granularity_held 1,
// beats 200%, width 50%, product 100%,
// cancellation_exact 1, naive_d5_bytes 128
// weak: d4 64, d5 64, granularity_held 1 SAME ANSWER
//
// counterfactual: D5_BEATS 16, D5_BITS 64 (the "Fatal" case)
// robust: d5 128, granularity_held 0, product 200%,
// cancellation_exact 0
// weak: d5 64, granularity_held 1 -- WRONG, and confidently
//
// gap: the weak model cannot represent the design decision at all.
// It agrees on the specified case and is wrong on the counterfactual,
// which is the case that explains WHY the sub-channels exist.
// DERIVED: a model that stores an invariant cannot show that it was
// achieved, and the belief is exactly that model in a person's head.The counterfactual row is the finding, and it is the cleanest demonstration in this module that a right answer can come from a model that cannot reason. DERIVED: both models say 64 bytes for the specified case; only one says 128 for the case where the width is not halved — and 128 is the number that explains the sub-channels.
CURRICULUM-DERIVED from 34.1 §8's rebuild test, which this generalises: a number that does not move when its inputs move was remembered rather than derived. DERIVED: here the number is correct and remembered, and the cost of remembering it is that the architectural reason is unavailable.
9. Two of Everything
// ROBUST MODEL: a controller with two sub-channels has two of each
// duplicated resource, and the per-sub-channel mode-register space is
// the hazard 25.2 names.
module subchannel_independence #(
parameter int NSUB = 2,
parameter int NBANK = 16,
parameter int MR_N = 8
)(
input logic clk,
input logic rst_n,
// one command request per sub-channel, independently
input logic [NSUB-1:0] cmd_req,
input logic [3:0] cmd_bank [0:NSUB-1],
// a mode-register write, targeted at ONE sub-channel
input logic mr_write,
input logic mr_sub,
input logic [2:0] mr_index,
input logic [7:0] mr_value,
output logic [NSUB-1:0] cmd_issue,
output logic [15:0] issued [0:NSUB-1],
output logic [7:0] mr [0:NSUB-1][0:MR_N-1],
output logic subchannels_independent,
output logic [15:0] mr_divergence,
output logic [15:0] shared_path_stalls
);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cmd_issue <= '0; subchannels_independent <= 1'b1;
mr_divergence <= '0; shared_path_stalls <= '0;
for (int s = 0; s < NSUB; s++) begin
issued[s] <= '0;
for (int i = 0; i < MR_N; i++) mr[s][i] <= '0;
end
end else begin
// TWO command paths: both sub-channels may issue in the same
// cycle. 25.2 calls the command bus the load-bearing duplicate.
for (int s = 0; s < NSUB; s++) begin
cmd_issue[s] <= cmd_req[s];
if (cmd_req[s]) issued[s] <= issued[s] + 1'b1;
end
// TWO mode-register spaces. A write targets one sub-channel, and
// the other is UNAFFECTED -- which is the hazard: configuration
// is no longer a per-channel property.
if (mr_write) begin
mr[mr_sub][mr_index] <= mr_value;
// Divergence is a legitimate state and must be VISIBLE, because
// a controller that assumes symmetry will read one and apply
// its value to both.
if (mr[mr_sub ^ 1'b1][mr_index] != mr_value)
mr_divergence <= mr_divergence + 1'b1;
end
subchannels_independent <= 1'b1;
end
end
endmodule// INTENTIONALLY DEFECTIVE. WEAK MODEL: one command path, one MR space.
// This is a DDR4 controller at a DDR5 rate -- the belief, ported.
//
// // one command bus serving both data paths
// logic issue_any;
// assign issue_any = |cmd_req; // <-- one path
// ...
// logic [7:0] mr_shared [0:MR_N-1]; // <-- one MR space
// if (mr_write) mr_shared[mr_index] <= mr_value;
//
// CONTRACT VIOLATED: 25.2 -- the per-sub-channel command bus is "the
// load-bearing one", and a shared bus means "one stream serving two
// data paths". And the per-sub-channel mode-register space is a
// command-path concern rather than a configuration detail.
//
// WHY IT SURVIVES: with traffic to one sub-channel it is identical to
// the robust build, and a first bring-up populates one sub-channel.
// It also passes every protocol check -- each command it issues is
// well-formed and legal.
//
// TRACE (ILLUSTRATIVE, 64 cycles, both sub-channels demanding):
// robust: issued[0] 41, issued[1] 39, total 80,
// shared_path_stalls 0
// weak: one bus, so at most one command per cycle:
// total 44, shared_path_stalls 36
// -> 45% of the demand unserved, and the DATA paths are idle
// while the single command path saturates
//
// and the mode-register half:
// write MR[3] = 0x20 to sub-channel 0 only
// robust: mr[0][3] 0x20, mr[1][3] 0x00, mr_divergence 1
// weak: mr_shared[3] 0x20 -- applied to BOTH, silently
// -> sub-channel 1 now runs a configuration nobody programmed for
// it, and no check fires because the write succeeded
//
// gap: 45% of the command demand unservable, and a configuration
// write that lands on a sub-channel it was not addressed to.
// DERIVED: the first is a performance ceiling that reads as "DDR5 is
// not as fast as claimed"; the second is a correctness bug that
// looks like a device problem.The 45% figure is the belief's cost stated as a performance ceiling, and it is the most likely way this belief is first noticed. DERIVED: a shared command path halves the achievable command rate while both data paths sit idle, so the symptom is DDR5 is not delivering its promised bandwidth — which sends the investigation to 34.3's territory, where it will find a real ratio and the wrong cause.
And the mode-register half is the worse of the two. CURRICULUM-DERIVED from 25.2, which makes the per-sub-channel mode-register space “a command-path concern rather than a configuration detail”: DERIVED: a controller that treats configuration as per-channel writes one sub-channel's value into both, and the write succeeds — so there is no error to observe, only a sub-channel operating under a configuration nobody chose for it.
10. The Obligation Delta
34.4 §8 established thirteen controller obligations from the destructive-read property. A port needs to know which of the thirteen change and which are added — which is a delta rather than a description.
// ROBUST MODEL: the delta, per obligation, across a generation.
package obligation_delta_pkg;
typedef enum int {
D_UNCHANGED, // same mechanism, possibly different values
D_DUPLICATED, // now one instance per sub-channel
D_ADDED, // did not exist in DDR4
D_RESHAPED // same purpose, different mechanism
} delta_e;
typedef struct { string name; delta_e delta; } od_t;
// ILLUSTRATIVE mapping of 34.4 section 8's thirteen plus DDR5's additions.
od_t DELTA[] = '{
'{"activate", D_DUPLICATED},
'{"precharge", D_DUPLICATED},
'{"restore_tras", D_DUPLICATED},
'{"trcd", D_DUPLICATED},
'{"trp", D_DUPLICATED},
'{"trrd_faw", D_DUPLICATED},
'{"turnaround", D_DUPLICATED},
'{"tccd", D_RESHAPED}, // same-group penalty, 16.4
'{"refresh", D_RESHAPED}, // + directed refresh mgmt, 25.4
'{"bank_state", D_DUPLICATED},
'{"address_map", D_RESHAPED}, // a sub-channel bit appears
'{"policy", D_DUPLICATED},
'{"arbitration", D_DUPLICATED},
'{"crc_alert", D_ADDED}, // 25.4
'{"ecc_transparency", D_ADDED}, // 25.4
'{"mr_per_subchannel", D_ADDED}, // 25.2
'{"two_cycle_framing", D_ADDED} // 25.2
};
endpackage
module obligation_delta #(
parameter int ND = 17
)(
input logic clk,
input logic rst_n,
input logic audit,
output logic [4:0] unchanged_count,
output logic [4:0] duplicated_count,
output logic [4:0] added_count,
output logic [4:0] reshaped_count,
output logic [4:0] port_work_items,
output logic port_is_a_reclock,
output logic [7:0] touched_share_pct
);
import obligation_delta_pkg::*;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
unchanged_count <= '0; duplicated_count <= '0; added_count <= '0;
reshaped_count <= '0; port_work_items <= '0;
port_is_a_reclock <= 1'b0; touched_share_pct <= '0;
end else if (audit) begin
automatic int u = 0, d = 0, a = 0, r = 0;
foreach (DELTA[i])
case (DELTA[i].delta)
D_UNCHANGED: u++;
D_DUPLICATED: d++;
D_ADDED: a++;
default: r++;
endcase
unchanged_count <= 5'(u);
duplicated_count <= 5'(d);
added_count <= 5'(a);
reshaped_count <= 5'(r);
// Everything except UNCHANGED is work. The belief's claim is that
// this number is zero.
port_work_items <= 5'(d + a + r);
port_is_a_reclock <= ((d + a + r) == 0);
touched_share_pct <= 8'(((d + a + r) * 100) / ND);
end
end
endmodule THE DELTA, COUNTED (ILLUSTRATIVE mapping, 17 obligations)
UNCHANGED 0 -- not one obligation is untouched
DUPLICATED 9 -- one instance per sub-channel
RESHAPED 4 -- tCCD, refresh, address map
ADDED 4 -- CRC/ALERT_n, ECC transparency,
per-sub-channel MR, two-cycle framing
port work items 17 of 17 touched share 100%
port_is_a_reclock 0
DERIVED: zero obligations are unchanged. Nine are duplicated, which
is the cheapest kind of work and the most voluminous; four are
reshaped, which needs re-derivation; four are new, which needs
design.Zero unchanged is the number, and it needs the qualification that makes it honest. DERIVED: duplicated is the cheapest category — the mechanism is identical and there are two of it — so nine of the seventeen are a parameterisation rather than a redesign. The belief is nearest to right about those nine and wrong about all seventeen, and a schedule that prices zero work items is wrong by seventeen.
And the nine duplications carry a trap that the word cheap conceals. DERIVED: duplicating a mechanism is cheap only if the two instances are genuinely independent, and §9 shows that the mode-register space is where they are not treated as such. CURRICULUM-DERIVED from 25.2, which makes the per-sub-channel mode-register space a command-path concern: so the cheapest category contains the chapter's silent correctness bug, and the expensive categories contain only work.
And the four reshaped ones are where a port goes wrong quietly. CURRICULUM-DERIVED from 16.4, which owns the quantitative same-group penalty and records that it reaches 2× for column commands and on one verified x16 configuration disappears entirely: DERIVED: a tCCD handler ported unchanged applies a DDR4 penalty structure to a DDR5 hierarchy, and the error is configuration-dependent — which is 31.1 §14's variety 10 arriving across a generation boundary.
11. Two-Cycle Framing, and CS_n Inside the Command
§6's command-framing row and §13's rank 3 are the same mechanism, and it is the one place where a DDR4-shaped controller emits something the device cannot parse.
CURRICULUM-DERIVED from 25.2, which owns the DDR5 command and address interface — its width, its one- and two-cycle framing, and CS_n's role inside the command code rather than as an external select.
// ROBUST MODEL: a command is framed over one or two cycles, and CS_n
// participates in the command code -- 25.2's interface, consumed.
module command_framing #(
parameter int CA_W = 7 // ILLUSTRATIVE command/address width
)(
input logic clk,
input logic rst_n,
input logic cmd_valid,
input logic [3:0] cmd_op, // which command
input logic [CA_W-1:0] ca_first,
input logic [CA_W-1:0] ca_second,
input logic cs_n_field, // part of the code, not a select
output logic ca_drive,
output logic [CA_W-1:0] ca_out,
output logic frame_active,
output logic [1:0] frame_cycles,
output logic [15:0] frames_complete,
output logic [15:0] frames_truncated,
output logic cs_is_in_the_code
);
// STRUCTURAL: which operations need two cycles is a property of the
// command encoding. ILLUSTRATIVE assignment over four opcodes.
function automatic logic needs_two(logic [3:0] op);
return (op == 4'd0) // ACT -- row address does not fit in one
|| (op == 4'd5); // MRW -- register index plus value
endfunction
logic in_second;
logic [3:0] held_op;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ca_drive <= 1'b0; ca_out <= '0; frame_active <= 1'b0;
frame_cycles <= '0; frames_complete <= '0; frames_truncated <= '0;
in_second <= 1'b0; held_op <= '0; cs_is_in_the_code <= 1'b1;
end else begin
ca_drive <= 1'b0;
if (cmd_valid && !in_second) begin
ca_drive <= 1'b1;
// CS_n is a FIELD of the code. A controller that drives it as a
// separate select has a bit missing from every command.
ca_out <= {ca_first[CA_W-1:1], cs_n_field};
held_op <= cmd_op;
frame_active <= 1'b1;
if (needs_two(cmd_op)) begin
in_second <= 1'b1;
frame_cycles <= 2'd2;
end else begin
frame_cycles <= 2'd1;
frames_complete <= frames_complete + 1'b1;
frame_active <= 1'b0;
end
end else if (in_second) begin
ca_drive <= 1'b1;
ca_out <= ca_second;
in_second <= 1'b0;
frame_active <= 1'b0;
frames_complete <= frames_complete + 1'b1;
end
// A new command arriving mid-frame truncates the one in flight.
if (cmd_valid && in_second)
frames_truncated <= frames_truncated + 1'b1;
end
end
endmodule// INTENTIONALLY DEFECTIVE. WEAK MODEL: every command is one cycle, and
// CS_n is a separate select. This is the DDR4 interface, ported.
//
// if (cmd_valid) begin
// ca_drive <= 1'b1;
// ca_out <= ca_first; // <-- one cycle, always
// cs_n_out <= cs_n_field; // <-- a separate pin
// frames_complete <= frames_complete + 1'b1;
// end
//
// CONTRACT VIOLATED: 25.2 -- the framing is one OR two cycles, and CS_n
// is inside the command code.
//
// WHY IT SURVIVES: the one-cycle commands -- reads, writes, precharge,
// refresh -- are framed correctly, and they are the overwhelming
// majority of traffic. Only ACT and MRW are mis-framed, and MRW happens
// at boot.
//
// TRACE (ILLUSTRATIVE, 1000 commands: 620 RD/WR, 250 ACT, 120 PRE,
// 10 MRW):
// robust: frames_complete 1000, frames_truncated 0,
// frame_cycles 2 on 260 of them
// weak: frames_complete 1000 by its own count, and 260 commands
// carried only their first cycle -- every ACT lost its row
// address extension and every MRW lost its value
//
// gap: 260 of 1000 commands malformed, and the 620 column commands
// are all correct. A design that issues reads and writes to an
// already-open row works perfectly -- which is section 5's condition
// 3 and 34.1 section 6's row-hit region, arriving from a third
// direction.The 620 correct column commands are why this defect is survivable long enough to ship. DERIVED: a test that opens a row once and then reads it repeatedly exercises one malformed ACT and 620 correct RDs — and the single ACT may well succeed, because a truncated row address that happens to select the intended row is indistinguishable from a correct one.
And the CS_n half is the subtler error. CURRICULUM-DERIVED from 25.2: CS_n is inside the command code, so a controller driving it as an external select leaves that bit position unspecified in every command it sends — a systematic one-bit corruption of the command encoding, which is not a timing problem and not a data problem.
12. The Reliability Obligations
§7's stack has a reliability layer and §13's ranks 4 and 6 sit in it. 25.4 owns the four capabilities; this models the two that add a controller obligation rather than a device feature.
// ROBUST MODEL: ALERT_n and ECC transparency as controller obligations.
// 25.4 owns the mechanisms; this owns whether the controller has a
// place for them.
module reliability_obligations (
input logic clk,
input logic rst_n,
input logic alert_n, // device asserts low
input logic wr_crc_enabled,
input logic txn_in_flight,
// on-die ECC reporting, if the device exposes it
input logic ecc_corrected,
input logic [7:0] ecc_corrected_count,
output logic alert_handled,
output logic replay_requested,
output logic [15:0] alerts_seen,
output logic [15:0] alerts_unhandled,
output logic [15:0] corrected_logged,
output logic fault_structure_visible,
output logic obligations_present
);
logic alert_n_q;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
alert_n_q <= 1'b1; alert_handled <= 1'b0; replay_requested <= 1'b0;
alerts_seen <= '0; alerts_unhandled <= '0; corrected_logged <= '0;
fault_structure_visible <= 1'b0; obligations_present <= 1'b1;
end else begin
alert_n_q <= alert_n;
alert_handled <= 1'b0;
replay_requested <= 1'b0;
// ALERT_n is a DEVICE-ORIGINATED signal -- like refresh in
// 34.4 section 11, nothing requested it, and a controller with no
// input for it simply does not see it.
if (alert_n_q && !alert_n) begin
alerts_seen <= alerts_seen + 1'b1;
if (wr_crc_enabled) begin
alert_handled <= 1'b1;
// The obligation: a CRC error means the write must be
// replayed. 25.4's ALERT_n semantics.
replay_requested <= 1'b1;
end else begin
alerts_unhandled <= alerts_unhandled + 1'b1;
end
end
// ECC transparency: the corrected count is logged, and the
// controller records that the OBSERVED structure is post-
// correction -- 28.5 section 12's visibility problem, as a flag.
if (ecc_corrected) begin
corrected_logged <= corrected_logged + 16'(ecc_corrected_count);
// False, deliberately: on-die correction means the fault
// structure is NOT visible, and asserting otherwise is the
// error 28.5 section 12 warns about.
fault_structure_visible <= 1'b0;
end
end
end
endmodule// INTENTIONALLY DEFECTIVE. WEAK MODEL: neither obligation exists.
//
// // a DDR4 controller has no ALERT_n input and no ECC reporting
// // port. The signals are simply not connected.
// // alert_n -- not in the port list
// // ecc_corrected -- not in the port list
// obligations_present <= 1'b1; // <-- nothing to be absent
//
// CONTRACT VIOLATED: 25.4's ALERT_n semantics and its separate
// ECC-transparency obligation.
//
// WHY IT SURVIVES: an unconnected input is not an error, and a device
// that never asserts ALERT_n is indistinguishable from a controller
// that cannot see it. CRC errors are rare by design.
//
// TRACE (ILLUSTRATIVE, 24 hours, 3 CRC errors, 41 corrected ECC events):
// robust: alerts_seen 3, alert_handled 3, replay_requested 3,
// alerts_unhandled 0, corrected_logged 41,
// fault_structure_visible 0
// weak: the signals are unconnected. 3 write errors are never
// replayed and never reported; 41 corrections are invisible.
// No counter reads anything, because no counter exists.
//
// gap: three unreplayed writes in a day -- silent data corruption
// with a device-side mechanism that detected it and a controller
// that could not hear the report. DERIVED: this is the only defect
// in this module where the DEVICE detected the problem and the
// belief discarded the notification.That last line is the sharpest thing in this chapter. DERIVED: on-die CRC detected the error, the device asserted ALERT_n, and the controller had no port for it — so the generation shipped a detection mechanism and the belief threw away its output.
CURRICULUM-DERIVED from 34.4 §11's obligation-with-no-requester finding, which this is the third instance of: refresh, recalibration, and now ALERT_n. DERIVED: all three are device- or physics-originated obligations with no request to arbitrate, and all three are invisible to a controller shaped around requests — which is why 34.4's belief and this one compose so badly.
And fault_structure_visible being deliberately false is the honest modelling choice. CURRICULUM-DERIVED from 28.5 §12's ECC visibility problem: on-die correction means the observed structure is not the fault structure, so a controller that logs corrected counts has a rate and not a pattern — and 28.5's eleven signatures are pattern-based.
13. Where the Belief Breaks First
| Rank | The exit | Why it comes first | What it produces |
|---|---|---|---|
| 1 | both sub-channels demanding | the second sub-channel is populated | §9's 45% unserved |
| 2 | a per-sub-channel configuration write | the first mode-register programming | a value on the wrong sub-channel |
| 3 | two-cycle command framing | any DDR5 command that needs it | a malformed command |
| 4 | ALERT_n asserting | the first CRC error | an unhandled device signal |
| 5 | directed refresh management | a row-hammer mitigation policy | an unimplemented obligation |
| 6 | on-die ECC transparency | the first corrected error | a corruption investigation with no visibility |
DERIVED: rank 1 arrives at the first integration and rank 2 at the first boot, so this belief has the earliest failure of any in this module. CURRICULUM-DERIVED from 25.2: the sub-channels each have their own command path and their own bank hierarchy, so populating the device means exercising both.
Rank 6 is the subtlest and it connects to a documented hazard. CURRICULUM-DERIVED from 25.4, which lists on-die ECC (bounded fault) and ECC transparency and error scrub as separate bullets, and from 28.5 §12's ECC visibility problem: DERIVED: on-die correction means the observed error structure is not the fault structure, so a DDR5 corruption investigation using DDR4 reasoning draws conclusions from a corrected signal.
14. The Decision Built on the Belief
| Where it is applied | What it produces | Measured consequence |
|---|---|---|
| A port schedule | re-time the DDR4 controller | 17 of 17 obligations touched |
| A command-path design | one bus at a higher clock | 45% of demand unservable (§9) |
| A configuration flow | per-channel mode registers | a write on the wrong sub-channel |
| A bandwidth expectation | twice DDR4 | the rate doubled; §6's other nine rows |
A tCCD handler | the DDR4 penalty structure | 2× error, configuration-dependent |
| A corruption investigation | DDR4 error reasoning | on-die ECC changed the observable |
Row 1 is the decision the belief actually drives, and it is the one with the largest number attached. DERIVED: re-time the DDR4 controller prices zero work items and the delta is seventeen — nine parameterisations, four re-derivations and four new designs. CURRICULUM-DERIVED from 34.4 §14's first row, which made the same point one module earlier: an estimate is correct for what it priced, and the error is in the scope.
And row 6 is the one that costs a silicon debug rather than a schedule. CURRICULUM-DERIVED from 28.5 §12's ECC visibility problem: the observed structure is not the fault structure, so a bit-pattern analysis that would have been correct on DDR4 is analysing a post-correction signal. DERIVED: and this is 33.7 §6's hypothesis-set item — the true cause is not in the live set because the observable no longer distinguishes it.
15. What the Assertions Prove
// ---- Section 8: the cancellation must be DERIVED, so the counterfactual
// is representable -- 4.6's exact arithmetic.
property p_granularity_is_derived;
@(posedge clk) disable iff (!rst_n)
evaluate |=> (d5_bytes == 16'(($past(D5_BEATS) * $past(D5_BITS)) / 8));
endproperty
assert property (p_granularity_is_derived)
else $error("the DDR5 access size was not computed from beats and width");
property p_cancellation_is_exact;
@(posedge clk) disable iff (!rst_n)
(evaluate && granularity_held) |=> cancellation_exact;
endproperty
assert property (p_cancellation_is_exact)
else $error("granularity held without the ratios cancelling exactly");
// The counterfactual must be visible: not halving the width gives 128.
property p_naive_case_doubles;
@(posedge clk) disable iff (!rst_n)
evaluate |=> (naive_d5_bytes == (d4_bytes * 16'd2));
endproperty
assert property (p_naive_case_doubles)
else $error("the un-halved counterfactual did not double the access size");
// ---- Section 9: two of everything -- 25.2.
property p_both_subchannels_may_issue;
@(posedge clk) disable iff (!rst_n)
(cmd_req == {NSUB{1'b1}}) |=> (cmd_issue == {NSUB{1'b1}});
endproperty
assert property (p_both_subchannels_may_issue)
else $error("a shared command path prevented concurrent sub-channel issue");
property p_no_shared_path_stall;
@(posedge clk) disable iff (!rst_n) shared_path_stalls == '0;
endproperty
assert property (p_no_shared_path_stall)
else $error("a command was stalled by a shared path that should be duplicated");
property p_mr_write_targets_one_subchannel;
@(posedge clk) disable iff (!rst_n)
(mr_write) |=> $stable(mr[$past(mr_sub) ^ 1'b1][$past(mr_index)]);
endproperty
assert property (p_mr_write_targets_one_subchannel)
else $error("a mode-register write changed the other sub-channel");
property p_divergence_is_permitted_and_counted;
@(posedge clk) disable iff (!rst_n)
(mr_write && (mr[mr_sub ^ 1'b1][mr_index] != mr_value))
|=> (mr_divergence != '0);
endproperty
assert property (p_divergence_is_permitted_and_counted)
else $error("sub-channel configuration divergence was not counted");
// ---- Section 10: the delta.
property p_delta_partitions_the_obligations;
@(posedge clk) disable iff (!rst_n)
audit |=> ((unchanged_count + duplicated_count
+ added_count + reshaped_count) == 5'(ND));
endproperty
assert property (p_delta_partitions_the_obligations)
else $error("the delta classes do not partition the obligation set");
property p_port_is_not_a_reclock;
@(posedge clk) disable iff (!rst_n)
audit |=> !port_is_a_reclock;
endproperty
assert property (p_port_is_not_a_reclock)
else $error("the delta reports a generation port as a pure re-clock");
property p_work_items_exclude_unchanged;
@(posedge clk) disable iff (!rst_n)
audit |=> (port_work_items == (duplicated_count + added_count
+ reshaped_count));
endproperty
assert property (p_work_items_exclude_unchanged)
else $error("the work-item count does not match the non-unchanged classes");
// ---- Section 11: command framing -- 25.2's one- and two-cycle interface.
property p_two_cycle_commands_get_two_cycles;
@(posedge clk) disable iff (!rst_n)
(cmd_valid && !in_second && needs_two(cmd_op)) |=> frame_active;
endproperty
assert property (p_two_cycle_commands_get_two_cycles)
else $error("a two-cycle command was framed in one cycle");
property p_frame_completes_before_the_next;
@(posedge clk) disable iff (!rst_n) frames_truncated == '0;
endproperty
assert property (p_frame_completes_before_the_next)
else $error("a command frame was truncated by the next command");
property p_cs_is_a_field_not_a_pin;
@(posedge clk) disable iff (!rst_n)
(ca_drive && !in_second) |-> (ca_out[0] == $past(cs_n_field));
endproperty
assert property (p_cs_is_a_field_not_a_pin)
else $error("CS_n was not carried inside the command code");
// Two-sided: one-cycle commands must NOT be stretched -- a controller
// that frames everything over two cycles halves its command rate,
// which is 30.3 section 9's variety 8 in the framing layer.
property p_one_cycle_commands_stay_one;
@(posedge clk) disable iff (!rst_n)
(cmd_valid && !in_second && !needs_two(cmd_op)) |=> !frame_active;
endproperty
assert property (p_one_cycle_commands_stay_one)
else $error("a one-cycle command occupied two frame cycles");
// ---- Section 12: the reliability obligations -- 25.4.
property p_alert_is_handled;
@(posedge clk) disable iff (!rst_n)
($fell(alert_n) && wr_crc_enabled) |=> (alert_handled && replay_requested);
endproperty
assert property (p_alert_is_handled)
else $error("ALERT_n asserted with CRC enabled and no replay was requested");
property p_no_unhandled_alert;
@(posedge clk) disable iff (!rst_n)
wr_crc_enabled |-> (alerts_unhandled == '0);
endproperty
assert property (p_no_unhandled_alert)
else $error("a CRC alert was seen and not handled");
// The honest negative: on-die correction means the fault structure is
// NOT visible -- 28.5 section 12. Asserting otherwise is the error.
property p_fault_structure_is_not_claimed_visible;
@(posedge clk) disable iff (!rst_n)
ecc_corrected |=> !fault_structure_visible;
endproperty
assert property (p_fault_structure_is_not_claimed_visible)
else $error("the controller claimed pre-correction fault visibility");
// ---- The CLAIM, as a conditional pair -- 34.1 section 1's required form.
// The belief is TRUE at the granularity and semantics layers.
property p_claim_holds_at_the_granularity_layer;
@(posedge clk) disable iff (!rst_n)
evaluate |=> (d5_bytes == d4_bytes);
endproperty
assert property (p_claim_holds_at_the_granularity_layer)
else $error("access granularity changed between the generations");
property p_claim_fails_at_the_command_path_layer;
@(posedge clk) disable iff (!rst_n)
(cmd_req == {NSUB{1'b1}}) |=> ($countones(cmd_issue) == NSUB);
endproperty
assert property (p_claim_fails_at_the_command_path_layer)
else $error("concurrent demand on both sub-channels was not concurrently served");
// ---- COVERS. Each on the dimension the belief's failure scales with.
// The granularity equality, so the claim's true half is exercised.
cover property (@(posedge clk) disable iff (!rst_n)
evaluate && (d5_bytes == d4_bytes));
// The COUNTERFACTUAL evaluated -- the case that explains the
// sub-channels, and one a fixed-parameter model cannot reach.
cover property (@(posedge clk) disable iff (!rst_n)
evaluate && (naive_d5_bytes == 16'd128));
// BOTH sub-channels demanding in one cycle. The dimension is the
// sub-channel POPULATION, and a single-sub-channel bring-up never
// reaches it -- 31.2 section 14's coverage-dimension rule.
cover property (@(posedge clk) disable iff (!rst_n)
cmd_req == {NSUB{1'b1}});
// Both issuing in one cycle, which a shared path makes impossible.
cover property (@(posedge clk) disable iff (!rst_n)
cmd_issue == {NSUB{1'b1}});
// A mode-register write to EACH sub-channel, so the targeting is
// exercised in both directions.
cover property (@(posedge clk) disable iff (!rst_n)
mr_write && (mr_sub == 1'b0));
cover property (@(posedge clk) disable iff (!rst_n)
mr_write && (mr_sub == 1'b1));
// Configuration DIVERGENCE -- a legitimate state the belief treats as
// impossible.
cover property (@(posedge clk) disable iff (!rst_n) mr_divergence != '0);
// Section 10: the delta audited, with ADDED obligations present.
cover property (@(posedge clk) disable iff (!rst_n)
audit && (added_count >= 5'd4));
// And with DUPLICATED the largest class, which is the honest shape.
cover property (@(posedge clk) disable iff (!rst_n)
audit && (duplicated_count > added_count));
// Zero unchanged -- section 10's headline.
cover property (@(posedge clk) disable iff (!rst_n)
audit && (unchanged_count == '0));
// A shared-path stall, so p_no_shared_path_stall is not vacuous in a
// testbench that never demands both at once.
cover property (@(posedge clk) disable iff (!rst_n) shared_path_stalls != '0);
// Section 11: a TWO-CYCLE command framed. The dimension is the command
// MIX, and a column-only stimulus never reaches it.
cover property (@(posedge clk) disable iff (!rst_n)
cmd_valid && needs_two(cmd_op));
// And a one-cycle command, so the two-sided pair is exercised.
cover property (@(posedge clk) disable iff (!rst_n)
cmd_valid && !needs_two(cmd_op));
// Section 12: ALERT_n actually asserting -- rare by design, and the
// dimension is the error RATE rather than the traffic.
cover property (@(posedge clk) disable iff (!rst_n) $fell(alert_n));
// A corrected ECC event logged, so the transparency obligation is
// exercised rather than argued.
cover property (@(posedge clk) disable iff (!rst_n) ecc_corrected);Two notes, and the first is the module's last instance of a pattern it has used six times.
p_claim_holds_at_the_granularity_layer asserts the belief true — and here the region is a layer rather than an operating condition. DERIVED: in the five preceding chapters the belief's region was a set of conditions that a system could leave. Here it is a level of abstraction, and nothing a system does changes which level a question is asked at. CURRICULUM-DERIVED from 34.1 §1's anatomy: the region is still non-empty and still stated as a conjunction — it is just a conjunction over layers, which is why §5 lists three that hold and six that do not.
And p_divergence_is_permitted_and_counted permits a state the belief treats as impossible. DERIVED: two sub-channels with different mode-register contents is legal and normal, so a property forbidding divergence would encode the belief. CURRICULUM-DERIVED from 34.4 §15's expansion property, which had the same shape: the second time in this module that the honest property permits what the misconception forbids.
16. Mutation Testing
Baseline first: all nineteen assertions pass and all fifteen covers are non-zero.
| # | Mutation | Killed by | Survived? |
|---|---|---|---|
| M1 | §8: store 64 as a constant | p_granularity_is_derived | killed |
| M2 | §8: drop the counterfactual output | p_naive_case_doubles | killed |
| M3 | §8: cancellation_exact tied high | p_cancellation_is_exact | killed* |
| M4 | §9: one shared command path | p_both_subchannels_may_issue, by one cover | killed |
| M5 | §9: one shared mode-register space | p_mr_write_targets_one_subchannel | killed |
| M6 | §9: mirror every MR write to both | p_mr_write_targets_one_subchannel | killed |
| M7 | §9: forbid divergence | p_divergence_is_permitted_and_counted, by one cover | killed |
| M8 | §9: drop shared_path_stalls | p_no_shared_path_stall | killed |
| M9 | §10: classify everything D_UNCHANGED | p_port_is_not_a_reclock | killed |
| M10 | §10: exclude D_RESHAPED from work items | p_work_items_exclude_unchanged | killed |
| M11 | §10: ND reduced to 13 | nothing | SURVIVES |
| M12 | NSUB set to 1 | nothing | SURVIVES |
| M13 | the stimulus restricted to one sub-channel | nothing | SURVIVES |
| M14 | §11: frame every command in one cycle | p_two_cycle_commands_get_two_cycles, by one cover | killed |
| M15 | §11: drive CS_n as a separate pin | p_cs_is_a_field_not_a_pin | killed |
| M16 | §11: frame every command over two cycles | p_one_cycle_commands_stay_one | killed |
| M17 | §12: ignore ALERT_n | p_alert_is_handled, by one cover | killed |
| M18 | §12: claim pre-correction visibility | p_fault_structure_is_not_claimed_visible | killed |
| M19 | §8: D5_BITS set to 64 with D5_BEATS 8 | nothing | SURVIVES |
DERIVED: fifteen of nineteen killed, four survived — and M11 is the module's third instance of a census supplying its own denominator.
Reducing ND to 13 makes the delta partition a thirteen-item set, dropping the four D_ADDED obligations entirely — and p_delta_partitions_the_obligations passes because it is written against ND. DERIVED: so the four capabilities 25.4 and 25.2 add are silently outside the audit, which is the belief's exact shape: the DDR4 obligation list, applied to DDR5. CURRICULUM-DERIVED from 33.1 §5: the denominator must come from outside the design, and finding this failure in 34.4 §16, 34.5 §16 and here makes it three chapters in a row.
M12, M13 and M19 reconstruct the region, for the sixth and last time in this module. One sub-channel; a single-sub-channel stimulus; and DDR5 parameters set to DDR4's, which makes the belief true by construction. DERIVED: M19 is the neatest statement of the whole module — set the parameters so the generations are identical and the belief is correct, and no property can object.
Three mutations are killed only by a cover, and M4's carries the schedule lesson. A shared command path is indistinguishable from two paths until both sub-channels demand in the same cycle, so the cover on cmd_req == '1 is the only thing that reaches it. CURRICULUM-DERIVED from 31.2 §14: the dimension is the sub-channel population, and a bring-up that populates one never arrives.
17. Baseline Defects Found Before Mutation
| Belief applied to | Caught by | At what cost |
|---|---|---|
| a stored granularity | p_granularity_is_derived | nothing — is 64 a constant or an expression? |
| a command-path design | p_both_subchannels_may_issue | both sub-channels in the testbench |
| a configuration flow | p_mr_write_targets_one_subchannel | nothing — is the MR array indexed by sub-channel? |
| a port schedule | p_port_is_not_a_reclock | nothing — classify seventeen obligations |
| a work-item estimate | p_work_items_exclude_unchanged | nothing — read the delta |
| a symmetry assumption | p_divergence_is_permitted_and_counted | a write to one sub-channel |
DERIVED: four of six are found without running anything, and three of those four are answered by reading a declaration — whether 64 is a constant, whether the mode-register array has a sub-channel index, whether the obligation list has seventeen entries. That is the same structural fingerprint 34.5 §17 found: a belief about structure leaves its trace in a declaration.
Two need a stimulus and both need the same one.
| Application | The stimulus | Why the usual test misses it |
|---|---|---|
| a command-path design | both sub-channels demanding | a first bring-up populates one |
| a symmetry assumption | a write to one sub-channel only | a symmetric configuration flow writes both |
DERIVED: and the second is the harder of the two to add, because writing both sub-channels identically is the natural thing to do — so the test that would reveal the shared mode-register space is one a correct-looking configuration flow never performs. CURRICULUM-DERIVED from 33.4 §6's configuration-reach item: the dimension belongs to the environment's model, and here the model is the configuration sequence itself.
18. Silicon Observability
| What silicon shows | What it says about the belief |
|---|---|
| command-bus saturation with idle data paths | §9 — one path serving two |
| DDR5 bandwidth near DDR4's despite double the rate | §14 row 4 — the rate doubled and the path did not |
| one sub-channel behaving differently from the other | §9 — a mode-register write landed on both or one |
ALERT_n asserting with no handler | §13 rank 4 — an unhandled device signal |
| corrected-error counts with no visible corruption | §13 rank 6; 28.5 §12's ECC visibility |
a tCCD penalty that varies with device width | §10; 16.4's verified x16 case |
Row 1 is the signature and it is measurable with two counters. DERIVED: command efficiency high and slot utilisation low is the shared-path fingerprint — CURRICULUM-DERIVED from 33.5 §6's four measures: measure A rises while measure B falls, and no timing parameter produces that combination.
Row 4 is worth one line because it is the only row in this module where the device is trying to tell you. DERIVED: ALERT_n is an output the device drives on a detected error, so a controller with no input for it is discarding a report rather than failing to measure something — CURRICULUM-DERIVED from 25.4: CRC operates in both directions with defined ALERT_n semantics, and §12's trace puts three unreplayed writes in a day behind it.
Row 5 is the one that is hardest to interpret with DDR4 habits. CURRICULUM-DERIVED from 25.4, which separates on-die ECC (bounded fault) from ECC transparency and error scrub, and 28.5 §12: the observed structure is not the fault structure. DERIVED: a rising corrected-error count is a real signal about the device and it says nothing about the pattern of the underlying faults, so the bit-structure analysis 28.5 teaches must be applied to a pre-correction observable that DDR5 may not expose.
19. Quantitative Reasoning
| Quantity | Truth | Under the belief | Gap | Provenance |
|---|---|---|---|---|
| access granularity | 64 B | 64 B | none | STRUCTURAL, 4.6 |
| beats per burst | 16 | 16 | none | STRUCTURAL |
| width per burst | 32 b | not considered | — | STRUCTURAL |
| un-halved counterfactual | 128 B | inexpressible | — | DERIVED |
| command paths per channel | 2 | 1 | 2× | STRUCTURAL, 25.2 |
| mode-register spaces | 2 | 1 | 2× | STRUCTURAL |
| obligations unchanged of 17 | 0 | 17 | 17 work items | DERIVED |
| duplicated / reshaped / added | 9 / 4 / 4 | 0 / 0 / 0 | — | DERIVED |
| command demand served, both active | 100% | 55% | 45% unserved | DERIVED, ILLUSTRATIVE |
tCCD same-group penalty error | up to 2× | 0 reported | configuration-dependent | CURRICULUM-DERIVED, 16.4 |
Sort by whether the belief names the quantity and this chapter's shape is unique in the module.
| Does the belief name it? | Quantities | Is the belief right? |
|---|---|---|
| Yes, and correctly | granularity, beats | exactly right |
| It does not consider | width per burst, the counterfactual | the omission is the error |
| Implicitly one | command paths, MR spaces | wrong by 2× |
| Implicitly zero | obligation deltas, work items | 17 of 17 |
DERIVED: the second row is this chapter's signature and it appears nowhere else in the module. The belief is right about the two quantities it names, and the quantity it does not consider — the width — is the one that carries the entire architectural consequence. A belief can be wrong by not having a field for something, and in the five preceding chapters that field was a magnitude; here it is a dimension of the design.
20. The Beliefs This One Generates
| Downstream belief | Why it follows | Where it is refuted |
|---|---|---|
| “the port is a re-clock” | if the generation is a speed bump | §10; 17 of 17 touched |
| “configuration is per-channel” | if the channel is the unit | §9; 25.2 |
| “DDR5 gives twice the bandwidth” | if only the rate changed | §14 row 4; 34.3 |
| “the same timing model applies” | if the hierarchy is unchanged | §10; 16.4 |
| “error patterns mean what they meant” | if the data path is unchanged | §18 row 5; 28.5 §12 |
The third row closes a loop with 34.3 and the loop is worth naming, because the two beliefs conceal each other. DERIVED: DDR5 gives twice the bandwidth is this belief feeding 34.3's — a peak figure that doubled, taken as an application figure that doubled. And when the measurement disappoints, 34.3's ratio explains it convincingly and incorrectly: the shortfall is a shared command path, not a level-1-to-5 reduction. Two of this module's six beliefs, in series, produce a correct-sounding diagnosis of the wrong cause.
21. Common Wrong Answers
-
“DDR5 is faster.” Correct, and it is the consequence rather than the change. CURRICULUM-DERIVED from 4.6: the beats doubled and the width halved, and the speed is what that bought.
-
“So the speed does not matter.” Inverted. The per-pin rate genuinely doubled and that is the point of the generation. DERIVED: the correction is about causation, not about magnitude — §19's first two rows are exactly right.
-
“Access size is unchanged, so nothing structural happened.” The invariant is the reason for the structural change. CURRICULUM-DERIVED from 4.6: 16 beats across 64 bits is 128 bytes, “Fatal” — so the width halved to hold 64 bytes.
-
“The commands are the same, so it is the same device.” §5: the belief is true at three layers and false at six. DERIVED: and the three are the layers firmware works in, which is why a driver ports and a controller does not.
-
“Two sub-channels is a packaging detail.” CURRICULUM-DERIVED from 25.2: the per-sub-channel command bus is “the load-bearing one”, and a shared bus is “one stream serving two data paths” — §9: 45% of the demand unservable.
-
“We can share the command path and clock it faster.” Then the command path is the binding link and the data paths idle — §18 row 1's signature. DERIVED: and the doubled beat count exists to raise the data rate, so binding on commands discards the generation's entire benefit.
-
“Mode registers are per-channel.” Per sub-channel. CURRICULUM-DERIVED from 25.2, which makes it “a command-path concern rather than a configuration detail” — §9: a write lands on both, succeeds, and leaves one sub-channel misconfigured with no error.
-
“The two sub-channels should always be configured identically.” Divergence is legal and normal, and §15's
p_divergence_is_permitted_and_countedexists so a property set does not forbid it. DERIVED: a symmetric configuration flow is a choice, and one that cannot express asymmetry cannot express the device. -
“Porting the controller is a re-clock.” §10: zero of seventeen obligations unchanged — nine duplicated, four reshaped, four added. DERIVED: nine of the seventeen are cheap, and zero are free.
-
“Nine duplicated means nine times the work.” No — duplication is the cheapest category, a parameterisation over a sub-channel index. DERIVED: the expensive four are the added ones, and the dangerous four are the reshaped ones, because those look unchanged.
-
“
tCCDworks the same way.” CURRICULUM-DERIVED from 16.4: the same-group penalty reaches 2× for column commands and on one verified x16 configuration disappears entirely — so a ported handler is wrong by up to 2× and the error is configuration-dependent, which is variety 10. -
“We will get twice the bandwidth.” The rate doubled. CURRICULUM-DERIVED from 34.3's five levels: level 1 doubled and the other four did not follow automatically — and §20's third row explains why the disappointment is then misdiagnosed.
-
“Bandwidth came in low, so it is the level-1-to-5 ratio.” That is the trap §20 names. DERIVED: on a shared-command-path design the shortfall is §9's 45%, and 34.3's ratio is a real effect that will explain the number convincingly and wrongly.
-
“On-die ECC is transparent, so it changes nothing for us.” CURRICULUM-DERIVED from 25.4, which lists transparency and error scrub as a separate obligation from the ECC itself, and 28.5 §12's visibility problem: the observed error structure is not the fault structure.
-
“
ALERT_nis optional.” CURRICULUM-DERIVED from 25.4: CRC operates in both directions andALERT_nhas defined semantics. §13 rank 4: the first CRC error asserts a signal an unported controller does not handle. -
“Directed refresh management is a server feature.” It is an obligation with a bounded configuration and a verified duration equation (25.4). DERIVED: §10 classifies refresh as reshaped for this reason — the old
REFstill exists and is no longer the whole obligation. -
“We bring up one sub-channel first, then the other.” Reasonable, and it is exactly why §9's defect ships. DERIVED: the two builds are identical until both demand in the same cycle — CURRICULUM-DERIVED from 31.2 §14: the dimension is the sub-channel population.
-
“Granularity is 64 bytes — that is just a fact.” Is it a constant in your model or an expression? §8: both models answer 64 for the specified case and only one answers 128 for the counterfactual — and the counterfactual is what explains the sub-channels.
-
“The generation names tell you it is incremental.” CURRICULUM-DERIVED from Module 4, which walks SDR through DDR5: each transition solved a different problem, and this one held granularity constant while doubling the beat count. A name sequence is not a change log.
-
“Four mutations survived, so the property set is weak.” M19 set the DDR5 parameters to DDR4's and made the belief true by construction. DERIVED: that is the module's final and cleanest instance of variety 12 — the mechanism is right and the scope is a parameter.
-
“
NDis seventeen because you chose seventeen.” Thirteen come from 31.1 §5's destructive-read property and four from 25.2 and 25.4. DERIVED: and M11 reducing it to thirteen is the belief itself — the DDR4 list applied to DDR5. -
“I know DDR5 has sub-channels.” The test is §10: can you classify the seventeen? DERIVED: knowing the feature and having priced the delta are different states, and §14's first row is what the second one changes.
22. Self-Check
- Give the two-line arithmetic that forced the sub-channel split, including the number 4.6 calls “Fatal”.
- Why is unchanged access granularity evidence for a structural change rather than against one?
- Name the three layers at which the belief is true and the six at which it fails.
- How many command paths, bank hierarchies and mode-register spaces does a 64-bit DDR5 channel have? Cite the chapter.
- A controller shares one command path across both sub-channels. Give the measured cost and the silicon signature.
- A mode-register write is issued for a channel. What does a DDR4-shaped controller do with it, and why does no error fire?
- Classify the seventeen obligations into the four delta classes, and give the counts. Which class is cheapest and which is most dangerous?
- Why is a ported
tCCDhandler wrong by up to 2×, and which variety does the configuration-dependence make it? - Bandwidth came in at 55% of expectation. Give two candidate causes, and say which chapter's ratio will explain it convincingly and wrongly.
- M19 set
D5_BITSto 64 andD5_BEATSto 8. What did that do to the belief, and what does it illustrate about this module? - M11 reduced
NDfrom 17 to 13. What dropped out of the audit, and which chapter's rule supplies the fix? - §19's table has a row the five preceding chapters do not. Name it, and say what kind of error it represents.
23. The Residual Risk
What this chapter cannot settle.
It cannot price the seventeen work items. §10 counts them and §14 says a re-clock estimate is wrong by seventeen. DERIVED: nine duplications, four re-derivations and four new designs are not equal, and converting the count to a schedule needs a plan — the same limit 34.4 §23 recorded for its thirteen.
It cannot validate its own obligation list. M11 reduced ND to 13 and nothing fired. DERIVED: the four added obligations come from 25.2 and 25.4, and the fix is an elaboration-time tie between the delta table and those chapters' capability lists — the third consecutive chapter in this module needing exactly that check, and the sixth in a row needing an artifact rather than a property.
It cannot describe a specific device. CURRICULUM-DERIVED from 16.4, whose same-group penalty disappears entirely on one verified x16 configuration: DERIVED: the delta's four reshaped entries are reshaped by amounts that depend on device width and speed grade, so §10 is a classification and not a quantification.
It cannot tell you which commands need two cycles on your device. §11's needs_two is an ILLUSTRATIVE assignment over four opcodes. CURRICULUM-DERIVED from 25.2, which owns the interface and its framing: DERIVED: the real mapping is part of the command encoding, so §11 models the consequence of getting the framing wrong and not the encoding itself — and a port needs the encoding from the device's specification.
And it cannot cover the generations before DDR5. CURRICULUM-DERIVED from Module 4: each transition from SDR onward solved a different problem, so generation N is just faster generation N−1 is a family of beliefs and this chapter refutes one member. DERIVED: the method transfers — find the invariant, ask what structure was changed to hold it — and the specific answer does not.
24. Where This Goes — and the Track Closes
Six beliefs, and the module is complete. So is the DDR track.
The six were about a number over-weighted, a cost treated as absent, two quantities identified as one, a component's nature, a process's lifetime, and a generation's relationship to its predecessor. DERIVED: every one had a non-empty region of truth, and in every one that region was where a first experiment lands.
Three findings hold across all six, and they are the module's result rather than any chapter's.
First, the region is always the bench. DERIVED: a row-hit idle read, a bandwidth benchmark, a sequential stream, one bank, one temperature, one sub-channel. Each belief is the correct description of a system simpler than the one being built, and the simplification is always the one a first test performs.
Second, every chapter's surviving mutations reconstructed its region. DERIVED: across the six chapters, twenty-two of twenty-nine survivors were a quantity or a scope that narrowed the stimulus until the belief was true. CURRICULUM-DERIVED from 33.4 §15's variety 12: the mechanism is complete and the scope is unconstrained — and this module is six independent demonstrations that a misconception and variety 12 are the same defect, one in a person and one in a property set.
Third, three of the six had a census whose denominator the belief supplied. DERIVED: 34.4's thirteen obligations, 34.5's six retraining triggers, and this chapter's seventeen delta entries — each reduced to the belief's own count, each passing its own completeness check. CURRICULUM-DERIVED from 33.1 §5, whose first review action is “arithmetic: count the blocks against thirteen”: the denominator must come from outside the design, and a belief is a design of a mental model.
A fourth finding is worth recording because it is about how these beliefs are held rather than about what they claim. DERIVED: in four of the six chapters the belief's evidence is not merely available but is the only evidence available at the moment the belief forms — a datasheet CL before any system exists, an availability fraction before any load, a peak rate before silicon, a DDR4 controller before a DDR5 device. CURRICULUM-DERIVED from 33.5 §13's observation that level 1 is the only level that exists pre-silicon: so these are not lazy inferences, they are decisions under uncertainty that stopped being labelled as such.
And that gives the module a single practical instruction, which is the same one 34.3 §10 arrived at by a different route. DERIVED: none of the six beliefs needs to be abandoned at the moment it is formed — each needs a grade attached. CL is the latency of a row hit at idle. Refresh costs 4.5% of bandwidth, on average. Peak is level 1 of five, assumed equal to level 5. The controller is an arbiter plus twelve. Training completes for two of eight values. DDR5 is faster because the width halved. Each qualification is a clause, and a clause is revisable where a fact is not.
And the track's closing sentence is not this module's. CURRICULUM-DERIVED from 28.4 §2, which 33.8 §24 already found generalising across eight review gates: “A FAILURE SIGNATURE IS EVIDENCE, NOT A VERDICT.”
DERIVED: so is a datasheet number, a benchmark result, a green regression, a completed bring-up, a closed ticket, a confident answer — and a belief that has never been wrong on the systems you have built. Each is evidence about something narrower than what it is usually taken to prove, and the whole of this track has been an inventory of those gaps.
Continue learning
Related tutorials
- Related topic
DDR5
A 16-beat burst on a 64-bit channel would double granularity. DDR5 halves the channel instead, into two independent 32-bit sub-channels — preserving access size exactly while doubling the number of independent request streams.
- Related topic
Dual Sub-Channels
Fourteen command bits with no RAS, CAS or WE at all, commands over one or two cycles, and CS_n inside the command code — plus a mode-register space duplicated per sub-channel.
- Related topic
Bank Groups
Not all bank pairs are equally independent. A bank group is the scope at which the internal column data path is shared, and the three-way classification of a request against its predecessor is the interface every later timing module consumes.
- Related topic
Channels
A channel has its own command bus, data bus and scheduling, so two channels contend for nothing. That independence means the address alone decides which channel a request uses, making the mapping — not the hardware — the thing that determines whether the parallelism is real.
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.
