DDR · Module 16
DDR4 / DDR5 Bank-Group Concepts
The same-group penalty is not one number. It reaches twice for column commands, tracks that for activates on x8 parts, and on one verified x16 configuration disappears entirely.
Three chapters have treated banks as interchangeable. Chapter 16.1's budget counted activations without asking which bank; 16.2's vector treated every bank identically; 16.3's spread counted distinct banks without distinguishing them.
They are not interchangeable, and Chapter 5.3 established why: bank groups are the scope at which part of the column data path is shared. So two accesses to different banks come in two varieties, spaced differently.
This chapter is about how differently — and the verified answer is not a single number:
The same-group penalty reaches 2× for column commands, tracks that for activates on x8 parts, and on one verified x16 configuration disappears entirely.
1. Five Levels, Not Three
Before any timing, a disambiguation — because five distinct hierarchy levels get collapsed routinely, and a claim about one is frequently applied to another.
| Level | What it is | What it owns |
|---|---|---|
| Channel | an independent memory interface | its own command bus, data bus and controller port |
| Subchannel | a DDR5 module-level division of a channel | its own command and data path within the module |
| Rank | a set of devices selected together | shares the channel's buses; selected by chip select |
| Bank group | a division within a device | shares part of the column data path (Chapter 5.3) |
| Bank | independent row state | its own open row (Chapter 5.2) |
2. What Chapter 5.3 Established
Briefly, because it is prerequisite rather than content.
Chapter 5.3 §1 established that a bank group is the scope at which part of the column data path was not replicated — the resource that separates one group from another. §2 established the generation qualification, including that bank groups do not exist before DDR4 and that the organisation is device-width dependent. §3 established the classification of a candidate against its predecessor, and §5's bank_group_classifier implements it.
That table is Chapter 5.3's and this chapter cites rather than repeats it. What it does not carry — because it is a Module 5 overview chapter — is how much the distinction costs, which turns out to vary along three axes at once.
3. The Penalty Is Not One Number
Three readings, and the third is the one nobody expects.
The column penalty grows with speed. From 1.25× at DDR4-1600 to 2.00× at DDR4-3200 — nCCD_S stays at 4 while nCCD_L climbs to 8. So a column command following one in the same group costs twice the spacing of one in a different group, at the fastest grade.
Why it grows is visible in the numbers. nCCD_S is constant at 4 cycles across every grade, which is the signature of a structural requirement (Chapter 13.2 §5's vocabulary) — four cycles is four cycles at any clock. nCCD_L rises, which is the signature of an absolute-time requirement being converted at a shortening clock period. The shared-within-a-group resource has a recovery time in real time; the different-group path does not.
The activate penalty behaves completely differently on x16. On x8 it tracks the column penalty exactly — 1.25× to 2.00×. On x16 it stays between 1.12× and 1.25×, and at DDR4-1866 it is exactly 1.00×.
And the width interaction compounds with Chapter 16.1's finding. An x16 part has 2 bank groups against x4/x8's 4 (Chapter 5.3's table), so there are fewer different-group choices available — and the different-group spacing is itself worse in absolute terms, 9 cycles against 4 at DDR4-3200. Fewer alternatives, each less rewarding.
4. DDR4 to DDR5 — What Carries and What I Could Not Close
So the organisational change from DDR4 to DDR5 is substantial: twice the bank groups and twice the banks at a given width. An x8 part goes from 4 groups and 16 banks to 8 groups and 32 banks.
One structural consequence that does not depend on unverified figures. Doubling the group count at fixed banks-per-group means a randomly chosen pair of banks is less likely to share a group — with 4 groups, a different bank is in the same group roughly 3 times in 15; with 8 groups, roughly 3 in 31. So more groups makes the cheaper relationship more common, independently of what the penalty is. That follows from the organisation alone, and Module 18 owns making it happen deliberately rather than by chance.
5. RTL — Selecting the Timing Domain
Collision check. Chapter 5.3 §5's bank_group_classifier classifies a candidate against its predecessor as same-group or different-group — and is reused, since that is exactly its job. Chapter 14.6's column_turnaround_matrix selects a column magnitude from the group relation and the read/write turnaround pair. Chapter 14.7's activate_spacing_resolver resolves the dual-term tRRD specification per group class. Chapter 8.4's bg_bank_field_map extracts the fields.
What none of them does is validate the organisation and select across command classes together. column_turnaround_matrix handles column commands; activate_spacing_resolver handles activates; neither checks that the configured bank/group organisation is internally consistent, and §3 showed the penalty differs between the two classes in a way that a design handling them in separate blocks can get inconsistently wrong.
The engineering problem. Given a candidate's group relationship and command class, select the applicable spacing — and validate the organisation itself, because §4 showed bank and group counts are width-dependent and a mismatched configuration produces silently wrong classification.
Classification: controller-side combinational timing-domain selection with configuration validation. A pure function; no clock, no state.
What it does not model. No array internals and no bank-group datapath — Chapter 5.3 §1 establishes what resource is shared and this block asserts nothing about its implementation. No classification — bank_group_classifier supplies it. No enforcement — the magnitudes go to the guards that hold the countdowns. And no DDR5 values, per §4.
// ─────────────────────────────────────────────────────────────────────
// bank_group_timing_domain
//
// CLASSIFICATION
// Controller-side combinational timing-domain selection with
// configuration validation. A pure function of its inputs.
//
// WHAT IT MODELS
// §3's selection, across BOTH command classes at once:
// (same-group | different-group) × (column | activate)
// → the applicable spacing, in cycles
// plus validation of the ORGANISATION itself, because §4 shows
// bank and group counts are device-width dependent and a
// mismatched configuration misclassifies silently.
//
// WHAT IT DOES NOT MODEL
// No array internals and NO BANK-GROUP DATAPATH. Chapter 5.3 §1
// establishes what resource is shared; this block asserts
// nothing about how it is built.
// No classification -- Chapter 5.3's bank_group_classifier owns
// deciding same-group versus different-group and supplies it.
// No enforcement -- the selected magnitude goes to the guards that
// hold the countdowns (Chapters 14.6, 14.7, 4.5).
// NO DDR5 VALUES. §4 states plainly that DDR5 timing figures were
// not retrievable; the parameters carry whatever the integrator
// supplies and this block takes no position on their generation.
//
// WHY BOTH CLASSES IN ONE BLOCK
// §3's finding is that the penalty DIFFERS between column commands
// and activates -- 2.00x versus 1.22x on x16 at DDR4-3200, and
// exactly 1.00x for activates on x16 at DDR4-1866. A design
// handling the two classes in separate blocks can hold
// inconsistent assumptions about "the" group penalty. Selecting
// both here makes the asymmetry explicit and checkable.
//
// ORGANISATION VALIDATION -- §35's requirement made structural
// NUM_BANKS % NUM_BANK_GROUPS == 0 is required: a device whose
// banks do not divide evenly among groups cannot be addressed by
// the field split Chapter 8.4 describes. Checked at elaboration,
// because a violated assumption here corrupts every downstream
// classification and does so silently.
//
// GENERATION SCOPE
// Generation-NEUTRAL in structure. Every magnitude is a parameter
// and §3's verified DDR4 figures are WIDTH- and GRADE-specific, so
// a table copied across widths is the failure §9 describes.
// ─────────────────────────────────────────────────────────────────────
module bank_group_timing_domain #(
parameter int NUM_BANKS = 16,
parameter int NUM_BANK_GROUPS = 4,
// §3's verified DDR4 figures are the intended values. Column
// spacing is width-independent; activate spacing is not.
parameter int CCD_S = 4, // different group, column
parameter int CCD_L = 8, // same group, column
parameter int RRD_S = 4, // different group, activate
parameter int RRD_L = 8, // same group, activate
parameter int CYC_W = 8,
parameter int BG_W = (NUM_BANK_GROUPS <= 1) ? 1 : $clog2(NUM_BANK_GROUPS),
parameter int BK_W = (NUM_BANKS <= 1) ? 1 : $clog2(NUM_BANKS)
) (
// ── The relationship, from Chapter 5.3's bank_group_classifier.
input logic same_bank_group,
input logic same_bank,
// ── Which class of command the candidate is. 0 = column, 1 = ACT.
input logic cmd_is_activate,
input logic cand_valid,
// ── The selected requirement, in cycles.
output logic [CYC_W-1:0] spacing_cycles,
// ── §3's observability: the penalty this configuration carries for
// THIS command class, as a ratio numerator and denominator so a
// consumer can compare without dividing. Published because §3
// shows the two classes can differ, and a design that assumes
// one penalty is wrong about the other.
output logic [CYC_W-1:0] penalty_num,
output logic [CYC_W-1:0] penalty_den,
// The group distinction makes NO difference for this class in this
// configuration. §3's x16 DDR4-1866 activate case. Published so a
// scheduler can skip group-steering effort that cannot pay.
output logic distinction_is_null,
// ── Scope error: a same-bank candidate is NOT a bank-group timing
// question at all -- it is tCCD to the same bank, or tRC for an
// activate (Chapters 14.6, 14.4). Reported rather than silently
// answered with a group magnitude.
output logic same_bank_misuse
);
// ── Elaboration guards.
if (NUM_BANKS < 1) begin : g_banks
initial $fatal(1, "bank_group_timing_domain: NUM_BANKS must be >= 1");
end
if (NUM_BANK_GROUPS < 1) begin : g_bgs
initial $fatal(1, "bank_group_timing_domain: NUM_BANK_GROUPS must be >= 1");
end
// §35's organisational invariant. A device whose banks do not divide
// evenly among groups cannot use the field split of Chapter 8.4, and
// the resulting misclassification is silent.
if ((NUM_BANKS % NUM_BANK_GROUPS) != 0) begin : g_divide
initial $fatal(1, "bank_group_timing_domain: NUM_BANKS must divide evenly among NUM_BANK_GROUPS");
end
if (NUM_BANK_GROUPS > NUM_BANKS) begin : g_order
initial $fatal(1, "bank_group_timing_domain: NUM_BANK_GROUPS must be <= NUM_BANKS");
end
// Same-group spacing must not be SHORTER than different-group.
// §3 verified they can be EQUAL -- the x16 DDR4-1866 activate case --
// so the check is >=, not >. Getting this backwards would flag a
// legitimate configuration as an error.
if (CCD_L < CCD_S) begin : g_ccd
initial $fatal(1, "bank_group_timing_domain: CCD_L must be >= CCD_S");
end
if (RRD_L < RRD_S) begin : g_rrd
initial $fatal(1, "bank_group_timing_domain: RRD_L must be >= RRD_S");
end
logic [CYC_W-1:0] sel_s, sel_l;
always_comb begin
// Select the parameter pair for this command class. §3's whole
// point is that the two classes have independent penalties.
sel_s = cmd_is_activate ? CYC_W'(RRD_S) : CYC_W'(CCD_S);
sel_l = cmd_is_activate ? CYC_W'(RRD_L) : CYC_W'(CCD_L);
spacing_cycles = same_bank_group ? sel_l : sel_s;
// Penalty as a fraction, so a consumer compares without dividing.
penalty_num = sel_l;
penalty_den = sel_s;
distinction_is_null = (sel_l == sel_s);
// A same-bank candidate is not a group question. Chapter 14.6's
// same-bank column spacing and Chapter 14.4's tRC own those, and
// answering with a group magnitude would be confidently wrong.
same_bank_misuse = cand_valid && same_bank;
end
endmoduleInterface contract. same_bank_group arrives from Chapter 5.3's classifier — this block classifies nothing. same_bank_misuse exists because a same-bank candidate is not a bank-group question at all: same-bank column spacing and tRC own it, and returning a group magnitude for it would be confidently wrong rather than merely unhelpful.
Parameter contract. Four magnitudes, two per command class, because §3 found the classes differ. NUM_BANKS % NUM_BANK_GROUPS == 0 is enforced at elaboration — §35's invariant, and a violated one corrupts every downstream classification silently. Note the _L >= _S checks use greater-or-equal, not strictly greater: §3 verified a configuration where they are equal, and a strict check would reject a legitimate part.
Why distinction_is_null is published. §3's x16 DDR4-1866 activate case has nRRD_S == nRRD_L == 6. A scheduler steering activates across bank groups there is spending effort for zero benefit, and the only way it can know is to be told. This is the chapter's most practically useful output.
Why the penalty is a fraction rather than a ratio. A numerator and denominator avoid a divider and avoid a rounding decision — the same restructuring habit as Chapter 15.1 §6's multiply-and-compare. A consumer comparing two configurations cross-multiplies.
Corner cases. NUM_BANK_GROUPS == 1: every candidate is same-group, which is the pre-DDR4 organisation Chapter 5.3 §2 describes, and BG_W is 1 by the guard. CCD_L == CCD_S or RRD_L == RRD_S: legal, distinction_is_null asserts — the verified x16 case. same_bank with same_bank_group: both true, and same_bank_misuse fires because the same-bank relation dominates. NUM_BANKS == NUM_BANK_GROUPS: one bank per group, which divides evenly and is legal though unusual.
Synthesis implications. Two 2-to-1 muxes and a comparator. The elaboration checks cost nothing. This is deliberately tiny — the chapter's content is in the parameters and their provenance, not in logic.
Failure modes. One penalty pair for both command classes — §3's central finding is that they differ, by 2.00× against 1.22× on x16 at DDR4-3200. A parameter table copied across device widths — the activate figures are width-dependent and the column figures are not, so copying gets one right and one wrong. A strict _L > _S check — rejects the verified x16 DDR4-1866 configuration. Answering a same-bank candidate with a group magnitude — silently applies the wrong obligation entirely. Applying _S/_L across ranks — §1's scope error.
6. Selecting the Domain, in Cycles
CONFIG A — x8, DDR4-3200 CCD_S=4 CCD_L=8 RRD_S=4 RRD_L=8
CONFIG B — x16, DDR4-1866 CCD_S=4 CCD_L=5 RRD_S=6 RRD_L=6
candidate relation class A spacing B spacing null?
──────────────────────────────────────────────────────────────────
col, diff BG different column 4 4 —
col, same BG same column 8 5 no
ACT, diff BG different activate 4 6 —
ACT, same BG same activate 8 6 YES ← B
──────────────────────────────────────────────────────────────────
A penalties: column 8/4 = 2.00× activate 8/4 = 2.00×
B penalties: column 5/4 = 1.25× activate 6/6 = 1.00×Three observations.
Config A's two classes agree and config B's do not. On x8 at DDR4-3200 both penalties are 2.00×, so a single “group penalty” notion happens to work. On x16 at DDR4-1866 the column penalty is 1.25× and the activate penalty is 1.00× — the same part, the same cycle, two different answers.
distinction_is_null fires for config B's activates and nothing else. A scheduler on that part should steer column commands across groups and need not bother steering activates at all.
Config B's different-group activate spacing is worse in absolute terms than config A's same-group spacing — 6 cycles against... no, against A's 8. But it is worse than A's different-group 4, by 50 %. A narrower part is slower at cross-bank activation even when it gets the better group relationship, which is Chapter 16.1 §5's width finding arriving from another direction.
7. Four Assertions Worth Writing
Where these live. bank_group_timing_domain is combinational and has no clk or rst_n port — it is a pure function of its inputs. A concurrent property needs a sampling event, so these belong in a testbench or a bind unit, sampled on the surrounding environment's clock. Chapter 13.2 §9 develops what that costs: the properties check once per sampling edge rather than on every input change, which is acceptable here because the selection changes only when the configuration or the classified relation changes, and both are stable across many cycles.
// ── P1. The selected spacing matches the (relation × class) table.
// Catches a design that uses one penalty pair for both command
// classes -- §3's central finding is that they differ, and §6
// shows a verified part where they differ within one cycle.
property p_selection_matches_the_table;
@(posedge clk) disable iff (!rst_n)
( spacing_cycles ==
( cmd_is_activate
? (same_bank_group ? CYC_W'(RRD_L) : CYC_W'(RRD_S))
: (same_bank_group ? CYC_W'(CCD_L) : CYC_W'(CCD_S)) ) );
endproperty
a_selection_matches_the_table: assert property (p_selection_matches_the_table);
// ── P2. Same-group spacing is never shorter than different-group.
// A CONFIGURATION property, and the check is >= because §3
// verified a part where they are EQUAL. A strict > here would
// reject a legitimate configuration, which is why the elaboration
// guard uses >= too.
property p_same_group_never_cheaper;
@(posedge clk) disable iff (!rst_n)
(penalty_num >= penalty_den);
endproperty
a_same_group_never_cheaper: assert property (p_same_group_never_cheaper);
// ── P3. The null flag is exactly the equality. Catches a flag
// derived from a threshold or a ratio comparison, which would
// misreport the x16 DDR4-1866 activate case -- the one
// configuration where group steering cannot pay.
property p_null_flag_is_exact;
@(posedge clk) disable iff (!rst_n)
(distinction_is_null == (penalty_num == penalty_den));
endproperty
a_null_flag_is_exact: assert property (p_null_flag_is_exact);
// ── P4. A same-bank candidate is REPORTED, never answered with a
// group magnitude. Catches the scope error of §1: same-bank
// spacing belongs to Chapter 14.6 and tRC to Chapter 14.4, and
// silently returning a group value is confidently wrong.
property p_same_bank_is_reported;
@(posedge clk) disable iff (!rst_n)
(cand_valid && same_bank) |-> same_bank_misuse;
endproperty
a_same_bank_is_reported: assert property (p_same_bank_is_reported);
// ── C1. Both relations and both classes are REACHED, and the null
// case is covered. A design tested only on different-group column
// commands has exercised one of four table entries.
c_same_group_column: cover property (@(posedge clk) disable iff (!rst_n)
(cand_valid && same_bank_group && !cmd_is_activate));
c_same_group_activate: cover property (@(posedge clk) disable iff (!rst_n)
(cand_valid && same_bank_group && cmd_is_activate));
c_null_distinction: cover property (@(posedge clk) disable iff (!rst_n)
distinction_is_null);What these prove. That selection matches the four-entry table; that the configuration respects _L >= _S; that the null flag is an exact equality rather than a threshold; and that a same-bank candidate is reported rather than misanswered.
What these do not prove, and the first is the chapter's central limitation.
Nothing here proves the parameters belong to the device. §3 established the figures are width- and grade-dependent, and §4 that DDR5's are not established at all. A block configured with x8 activate figures on an x16 part satisfies every property and applies 4 cycles where 9 are required — a violation on every cross-group activate, undetectable from inside. That is a part-number-and-datasheet check no simulation discharges.
Nothing here proves the classification is right. same_bank_group is an input from Chapter 5.3's classifier, which in turn depends on Chapter 8.4's field extraction. A wrong bank-group field produces a confident wrong relation and every property here passes.
And nothing here enforces anything. The magnitudes go to guards; whether those guards honour them is their properties' business.
Vacuity. C1's three covers exist because a testbench exercising only different-group column commands touches one of four entries — and the null cover requires a configuration where the penalty vanishes, which most do not have.
8. DV — Checking the Domain Independently
Invert the representation. The block selects from parameters via muxes. A checker should hold the datasheet table indexed by width and grade and look up the expected spacing from the part's identifying information — so a wrong parameter produces a disagreement rather than agreement.
Derive the group relation independently. §7's second limitation: the relation is an input, and a checker consuming it inherits any field-extraction error. It should decode the bank-group field from the observed address using the part's organisation, which is Chapter 8.4's mapping.
Check both classes, and check the null case deliberately. §6 showed a verified part where the two classes disagree within one cycle; a checker testing one class has verified half the table.
BANK-GROUP TIMING DOMAIN ERROR
cycle : 7731
part : x16, DDR4-1866 [from part identification]
─────────────────────────────────────────────────────────────────
previous ACT : BG1 / bank 2, cycle 7726
candidate ACT : BG1 / bank 5
relation : SAME bank group [decoded independently]
class : activate
─────────────────────────────────────────────────────────────────
design spacing : 8 cycles ← from an x8 parameter table
datasheet spacing : 6 cycles [nRRD_L, x16, DDR4-1866]
different-group : 6 cycles [nRRD_S — IDENTICAL]
penalty : 1.00× → the group distinction is NULL here
─────────────────────────────────────────────────────────────────
consequence : not a violation — the design is CONSERVATIVE
by 2 cycles on every same-group activate
root question : is the parameter table from the wrong width?Two things to steal. Showing the different-group figure beside the same-group one makes the null case self-evident — the reader sees 6 and 6 and needs no further explanation. And classifying the finding as conservative rather than a violation is the honest call: an over-long spacing costs throughput and breaks nothing, which changes its urgency and is exactly the distinction Chapter 13.3 §4 drew between safe-and-slow and fast-and-wrong.
9. Debugging
Symptom. Failures or throughput loss that correlate with whether consecutive commands target the same bank group.
| Candidate mechanism | Evidence | Discriminator |
|---|---|---|
_S and _L swapped | Violations only on same-group pairs; different-group clean | The decisive check: partition the violating pairs by group relation. If they are all same-group, the shorter magnitude is being applied to the longer case. §3's 2.00× at DDR4-3200 makes this a large error. |
| Parameter table from the wrong width | Activate spacing wrong, column spacing right | §3 — column figures are width-independent and activate figures are not. A design wrong on one class and right on the other is almost certainly a width mismatch. |
| One penalty pair for both classes | Wrong on whichever class has the smaller penalty | §6's config B: 1.25× column against 1.00× activate on one part. |
| Bank-group field extraction wrong | Relation misclassified; violations correlate with address bits | Chapter 8.4. Decode independently — §8. |
_S/_L applied across ranks | Violations on rank transitions | §1's scope error. These are bank-group relations, not rank relations. |
| Group steering effort with no benefit | No violations; effort spent, throughput unchanged | distinction_is_null. §3's x16 DDR4-1866 activate case — the penalty is 1.00× and steering cannot pay. |
| DDR4 assumptions carried to DDR5 | Organisation mismatch: group count and bank count both wrong | §4. DDR5 doubles both at a given width. |
The discriminator that defines this chapter is whether the error affects activates, column commands, or both. §3 established that column figures are width-independent and activate figures are width-dependent — so a design that is correct for column spacing and wrong for activate spacing has a width mismatch, and one that is wrong for both has a grade or table error. That single partition separates the two most common causes without further instrumentation.
The second discriminator is whether the violating pairs are same-group or different-group. All same-group means the magnitudes are swapped or the longer one is under-configured; mixed means the classification itself is wrong.
Responsible layer. If the relation is correctly decoded, the table matches the part's width and grade, and both classes are selected independently — then this chapter is exonerated, and remaining throughput questions belong to how addresses map onto groups (Module 18) and what the scheduler does with the choice (Module 17).
10. Common Misconceptions
“Bank groups are only address-bit bookkeeping.” Tempting because the group is selected by address bits and looks like another field. Why it is wrong: Chapter 5.3 §1 established it is the scope at which part of the column data path is shared, and §3 quantifies the consequence — up to twice the column spacing for a same-group pair at DDR4-3200. Consequence: a mapping chosen without regard to groups, and a scheduler blind to a 2× timing difference. Replacement model: a timing domain that address bits happen to select. Debugging clue: throughput varying with address patterns that differ only in the group bits.
“DDR4 and DDR5 bank-group rules are identical.” Tempting because the concept carries over and the names look similar. Why it is wrong: §4 — the organisation demonstrably differs, with DDR5 doubling both group count and bank count at a given width, and DDR5's timing semantics are not established here at all. Consequence: a controller ported on the assumption of identical rules, with wrong field widths and possibly wrong timing. Replacement model: verify organisation and timing per generation. Debugging clue: a port whose group decode produces out-of-range values.
“More bank groups mean proportionally more bandwidth.” Tempting because groups relieve a timing constraint and more of them sounds like more parallelism. Why it is wrong: §1 — a bank group is inside a device and shares the same command and data buses. Chapter 16.1 §2's form B is unchanged by group count. What more groups buy is that a randomly chosen bank pair is less likely to share a group (§4), which makes the cheaper relation more common — not more data path. Consequence: a bandwidth model that scales with group count. Replacement model: groups change the distribution of spacing, not the interface width. Debugging clue: a peak-bandwidth figure that grew when the part's group count did.
“The same-group penalty is a single ratio.” Tempting because one number is easy to remember and it is roughly 2× on the most commonly discussed parts. Why it is wrong: §3 — it varies with command class, device width and speed grade, from 2.00× down to 1.00× on a verified x16 DDR4-1866 configuration for activates. Consequence: a scheduler that hard-codes a penalty and steers commands on a benefit that does not exist for that part and class. Replacement model: four parameters from the part's own table. Debugging clue: group-steering effort producing no measurable change.
“tCCD is only a same-bank constraint.” Tempting because column commands are per-bank operations and it feels like a bank-local delay. Why it is wrong: Chapter 14.6 §2 established the resource is the shared column path, so tCCD constrains column commands across banks and is refined — not relaxed — by the group relation. Consequence: a controller that issues column commands to different banks without spacing, violating on exactly the traffic bank parallelism was meant to enable. Replacement model: a shared-path constraint with a group-scoped refinement. Debugging clue: violations on consecutive column commands to different banks.
“A bank group is like a channel or a rank.”
Tempting because all three are hierarchy levels above the bank. Why it is wrong: §1 — a channel has its own interface, a rank is a set of devices sharing the channel's buses and selected by chip select, and a bank group is a division inside a device. They are three levels with three different resource ownerships. Consequence: applying _S/_L relations across ranks, which is a scope error, or expecting group-level parallelism at channel scale. Replacement model: five distinct levels with distinct ownership. Debugging clue: a timing rule applied at a level its parameter table never mentioned.
“If same-group is slower, always steer to different groups.”
Tempting because it follows directly from the penalty and it is easy to implement in a mapping. Why it is wrong: §3's null case — on a verified x16 DDR4-1866 part, same-group and different-group activates cost the same, so steering activates there is pure overhead. And Chapter 16.3 showed steering has its own costs in lost locality. Consequence: mapping and scheduling complexity that cannot pay on that part. Replacement model: steer where the penalty is real, which means knowing the part's four figures. Debugging clue: a distinction_is_null condition nobody checked.
11. Interview Reasoning
“What problem do bank groups expose to the controller?” That “a different bank” is not one relationship but two. Part of the column data path is shared within a group and not across groups, so two accesses to different banks are spaced differently depending on whether those banks share a group. The controller therefore has to classify each candidate against its predecessor and select the applicable timing — and, if it can influence which banks requests land in, it has a lever it did not previously have.
“How big is the same-group penalty?” It depends on three things, which is the real answer. For column spacing on a verified DDR4 part it rises from 1.25× at DDR4-1600 to 2.00× at DDR4-3200, and is width-independent. For activate spacing on an x8 part it tracks that exactly; on an x16 part it stays near 1.2× — and at DDR4-1866 it is exactly 1.00×, meaning no penalty at all for activates while the column penalty on that same part is still 1.25×. So a design that hard-codes one ratio is wrong about the magnitude everywhere and wrong about the existence somewhere.
“Why does the different-group spacing stay constant across speed grades while the same-group spacing rises?” That is the signature of two different kinds of requirement. A figure that stays at four cycles at every clock is structural — four cycles is four cycles regardless of period. A figure that rises as the clock speeds up is an absolute-time requirement being converted into a shortening cycle. So the shared-within-a-group resource has a recovery time in real time, and the different-group path does not — which is consistent with the group being the scope at which that resource was not replicated.
“Which parts of your bank-group explanation are DDR4-specific?” All the numbers, and the organisation. The verified figures are from a named DDR4 datasheet with a device width and speed grade attached. The organisation — four bank groups on x4 and x8, two on x16 — is DDR4, and DDR5 differs substantially: eight groups and thirty-two banks on an x8 part. What is generation-neutral is the structure: a group is a timing domain, the relation between consecutive commands selects a magnitude, and the magnitude depends on command class.
“What changes in DDR5?”
The organisation demonstrably doubles — twice the bank groups and twice the banks at a given width — which I have from a vendor document via search and corroborated against this curriculum's own organisation table. What I could not establish is whether the _S/_L naming carries, or what DDR5's timing values are, so I would not state those without a citation. One consequence follows from organisation alone: with more groups, a randomly chosen bank pair is less likely to share one, so the cheaper relation becomes more common even if no timing value changed.
“How would you debug a failure that appears only for same-bank-group traffic?” Partition the violating pairs by group relation first — all same-group points at the magnitudes being swapped or the longer one under-configured. Then check whether the error affects activates, column commands or both, because column figures are width-independent and activate figures are not: wrong on activates and right on columns is almost certainly a device-width mismatch in the parameter table. That single partition separates the two most common causes without adding instrumentation.
“Is a bank group a channel?” No, and the distinction matters for bandwidth reasoning. A channel has its own command and data interface, so channels genuinely multiply throughput. A bank group is inside a device and shares the same buses as every other group — so more groups do not create more data path. What they change is the distribution of command spacing: a larger group count makes the cheaper different-group relation more likely for a random bank pair. And a subchannel is a third thing again, a module-level division with its own path, which is why the two are worth keeping separate when reading DDR5 material.
12. Engineering Exercises
1. Read the table. Using §3's verified figures, give the column and activate spacing for an x8 DDR4-2666 part, both relations, and both penalties.
Worked: column — nCCD_S = 4, nCCD_L = 7, penalty 1.75×. Activate — nRRD_S = 4, nRRD_L = 7, penalty 1.75×. On x8 the two classes agree at every grade, which is why a single-penalty assumption survives on x8 parts and breaks on x16.
2. Find the null case. Scan §3's x16 activate row and identify every grade where the penalty is below 1.25×. What does that mean for a scheduler?
Worked: every grade except DDR4-2933 — the penalties are 1.20, 1.00, 1.17, 1.14, 1.12, 1.25, 1.22. So on x16 parts the activate penalty is almost always under 25 % and at DDR4-1866 is zero. A scheduler steering activates across groups on an x16 part is chasing a benefit between nothing and a quarter of one spacing — while the column penalty on the same parts still reaches 1.25× and is worth steering.
3. Diagnose from the class split. A controller violates activate spacing and never violates column spacing. Give the most likely cause and the check.
Worked: a device-width mismatch in the parameter table. §3 shows column figures are width-independent — 4 and 8 at DDR4-3200 for every width — while activate figures are not: 4/8 on x8 against 9/11 on x16. So a table copied across widths gets the column values right by accident and the activate values wrong. The check is to compare the configured nRRD_S against the part's width row.
4. Count the opportunity change. With 4 bank groups of 4 banks, what fraction of the other banks share a group with a given bank? Repeat for 8 groups of 4, and say what changes.
Worked: with 4 groups of 4, a bank has 3 same-group companions out of 15 other banks — 20 %. With 8 groups of 4, 3 out of 31 — 9.7 %. So doubling the group count roughly halves the chance that two randomly chosen banks share a group, making the cheaper relation about twice as common without any timing value changing. That is the organisational consequence §4 derives without needing DDR5 timing figures.
5. Catch the strict check. §5's elaboration guard uses CCD_L >= CCD_S rather than >. Construct the configuration that a strict check would wrongly reject, and say what would happen.
Worked: x16 DDR4-1866 activates, where nRRD_S = nRRD_L = 6. A strict RRD_L > RRD_S guard would fail elaboration on a legitimate, verified part configuration — so the design would be unbuildable for that device. The lesson generalises: an invariant derived from “same group is worse” must permit equality, because the data shows equality occurs.
6. Separate the levels. For each statement, name the hierarchy level it concerns and say whether it is correct: (a) two of these can be accessed with genuinely independent command buses; (b) these share part of the column data path; (c) these are selected by chip select; (d) a DDR5 module has two of these.
Worked: (a) channels — correct; also DDR5 subchannels, which have their own command and data path. (b) bank groups — correct, Chapter 5.3 §1. (c) ranks — correct. (d) subchannels — correct per §4's reported figure. The instructive part is that (a) has two valid answers at two different levels, which is precisely why §1's disambiguation is needed.
7. Argue the boundary. §4 declines to publish DDR5 timing figures. Argue that reporting them with a caveat would be more useful, then rebut.
13. Summary
Chapter 5.3 established what a bank group is — the scope at which part of the column data path is shared — and its organisation by generation and width. This chapter established how much it costs, and the answer has three axes.
Five hierarchy levels must stay distinct. Channel, subchannel, rank, bank group, bank — with different resource ownership at each. _S and _L are bank-group relations; applying them across ranks is a scope error, and expecting channel-like parallelism from groups mistakes a device-internal division for an independent interface.
The same-group penalty is not one number. Verified from a named DDR4 datasheet: the column penalty rises from 1.25× at DDR4-1600 to 2.00× at DDR4-3200 and is width-independent. The activate penalty tracks it exactly on x8 — and on x16 stays between 1.12× and 1.25×, reaching exactly 1.00× at DDR4-1866, where the group distinction makes no difference at all to activates while still making a 1.25× difference to column commands on that same part.
The shape of the numbers explains itself. nCCD_S is constant at 4 cycles across every grade — the signature of a structural requirement. nCCD_L rises — the signature of an absolute-time requirement converted at a shortening clock. That is Chapter 13.2 §5's distinction appearing in a bank-group table.
DDR4 to DDR5 changes the organisation substantially — twice the groups and twice the banks at a given width, corroborated from two independent routes. DDR5 timing semantics are not established here, and neither is whether the _S/_L naming carries; the seventh such gap in this curriculum. One consequence follows from organisation alone: more groups makes the cheaper relation roughly twice as likely for a random bank pair.
bank_group_timing_domain selects across both command classes, because §6 showed a verified part where they disagree within one cycle; validates the organisational invariant that banks divide evenly among groups; uses >= rather than > for the _L-versus-_S check because equality is verified to occur; and publishes distinction_is_null so a scheduler can skip steering effort that cannot pay.
And the debugging partition: wrong on activates and right on columns is a device-width mismatch, because column figures are width-independent and activate figures are not.
14. Module 16 in One Chain
The module asked why DRAM has banks and bank groups, what can overlap, what still couples them, and how a controller exploits concurrency without mistaking independence for unlimited parallelism.
Bank-level parallelism is concurrency of internal resource state, not independence of the interface. Chapter 16.1 made that quantitative: the sustained rate of row openings is 4 / nFAW, a bound containing no bank term, and across every verified width and grade the rolling activation window is the binding constraint — never the spacing, and never the bank count. At DDR4-3200 that is one row opening every 4.00, 8.50 or 12.00 cycles for x4, x8 and x16. Banks provide independent places for the four permitted rows, not more openings.
Legality is computed before policy, across every bank at once. Chapter 16.2 produced the candidate vector through three filters — state, timing, shared resource — and stopped there deliberately. The trap it exists to expose is replacing timing legality with bank != previous_bank, which answers state independence while pretending to answer timing, cannot see any cross-bank obligation, and fails more the better the design spreads work.
Row-hit rate and bank-level parallelism are different quantities that conflict. Chapter 16.3 worked two legal policies with identical makespan and identical hit rate where one request waited 17 cycles instead of 5 — and showed that both common proxies are structurally blind to the difference, because makespan is set by the shared path and hit rate counts classifications. The concentration pathology is the sharpest case, since a ratio over served requests improves as starvation worsens.
And “a different bank” is two relationships, not one — with a penalty that varies by class, width and grade, and vanishes in at least one verified configuration.
The resource-scope ledger, stated once so nothing in the module contradicts it:
| Constraint | Scope | Prior event | Candidate event | Generation |
|---|---|---|---|---|
| open-row state | per bank | ACTIVATE / PRECHARGE | column command | neutral |
| tRCD, tRAS, tRP, tRC | per bank | that bank's command | that bank's next | neutral |
tRRD _S / _L | bank group | any ACTIVATE | next ACTIVATE | DDR4 verified |
| tFAW | rank-wide rolling | accumulation of activates | next ACTIVATE | DDR4 verified |
tCCD _S / _L | bank group | any column command | next column command | DDR4 verified |
| command bus | channel | any command | any command | neutral |
| data bus | channel | any column command | any column command | neutral |
| refresh | rank / narrower | Chapter 15.2 | — | generation-dependent |
Three scopes above the bank — group, rank, channel — and every one of them couples banks that are independent in state. That is the module's whole answer to why more banks is not more parallelism.
Module 17 takes up the controller that uses all of this: the scheduler that picks from 16.2's vector, the queues that decide which request per bank is the candidate, the refresh manager that Chapter 15.3 deferred to it, and the arbitration that 16.3 showed has no universally correct answer.
Continue learning
Related tutorials
- 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
tCCD — CAS-to-CAS Delay
The first parameter that is not bank-local. Column spacing is constrained by resources every bank shares, and DDR4 splits it by bank group — so a per-bank state machine cannot enforce it.
- Related topic
DDR4
DDR4 is the generation where prefetch depth stops changing. With granularity already at a cache line, the rate had to come from overlapping independent accesses instead — which is what bank groups are, and why peak bandwidth became conditional on the access pattern.
- Related topic
tRRD — Row-to-Row Delay
Two different banks does not mean unconstrained parallelism. tRRD spaces activates across banks, published as the greater of a cycle floor and an absolute time — with a verified value that depends on page size.
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.
