Skip to content
VLSI Mentor

DDR · Module 18

Row-Bank-Column Mapping

Two lossless address maps over the same device disagree about every resource a workload touches. The field order decides what changes on the next cache line, and that decides row locality and bank distribution before the controller sees anything.

Chapter 8.6 built the complete seven-field mapper, proved it lossless, and inverted it from observed commands. It ended by noting that two maps can both be perfectly lossless and still disagree about three fields out of seven — and then deferred the obvious next question.

This module answers it. The question is not how to slice an address. It is which slicing, and why.

A mapping policy does not change a single DDR timing rule. It changes which resources a workload presents to those rules.

That sentence is the whole of Module 18, and this chapter establishes the mechanism behind it: the field order decides what changes on the next access, and what changes on the next access decides everything downstream.

1. One Device, Two Maps

Fix a device and an address width, and keep them fixed for the whole module.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  EDUCATIONAL CONFIGURATION — NOT A JEDEC-MANDATED ADDRESS MAP
  Chosen small so every worked number can be checked by hand.

    byte offset      6 bits      64-byte access granule
    column           4 bits      16 columns
    bank             2 bits      4 banks per group
    bank group       2 bits      4 bank groups      -> 16 banks
    row              8 bits      256 rows
    ------------------------------------------------
    physical address 22 bits     4 MiB of device

Now two orders over exactly those fields. Both use every bit once; both are lossless; both address the same 4 MiB.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  POLICY R — "row-bank-column", locality-first

    21                14 13   12 11   10 9      6 5        0
    +-------------------+-------+-------+--------+----------+
    |        row        |  bg   | bank  | column |  offset  |
    +-------------------+-------+-------+--------+----------+

  POLICY B — bank-interleaved, distribution-first

    21                14 13     10 9   8 7   6 5        0
    +-------------------+--------+-----+-----+----------+
    |        row        | column | bg  |bank |  offset  |
    +-------------------+--------+-----+-----+----------+

Stated algebraically, because a picture alone has never caught a bug:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  POLICY R                          POLICY B
    offset = PA[5:0]                  offset = PA[5:0]
    column = PA[9:6]                  bank   = PA[7:6]
    bank   = PA[11:10]                bg     = PA[9:8]
    bg     = PA[13:12]                column = PA[13:10]
    row    = PA[21:14]                row    = PA[21:14]

The row field is in the same place in both. Only the middle changes — and the middle is where the module's entire argument lives.

2. The Low Bits, and the Fields That Are Not Here

Two things about §1's configuration need stating before any conclusion rests on it, because both are routinely glossed over and both change the arithmetic.

The six offset bits are not a DDR field. They are the bits the access granularity consumes before the map sees anything. Four different quantities get conflated here, and they are genuinely different:

QuantityWhat it isIn this configuration
Byte addresswhat the requester suppliesthe full 22 bits
Access granulethe smallest unit the controller maps64 B — PA[5:0] is within it
DDR burstbeats the device transfers per column commandModule 12's subject
DDR columnthe operand the device receivesPA[9:6] or PA[13:10], by policy

A column value is not a cache-line address and a burst length is not a cache-line size. They are related through the map and the device's transfer width, and Chapter 12.1 owns the relationship. What matters here is narrower: the offset bits are consumed below the map, so no field in §1 is influenced by them, and a stride smaller than 64 B cannot change any decoded field at all.

And there is no rank or channel field. Chapter 8.6's mapper carries seven fields; this module's configuration uses five, and the omission is deliberate rather than an oversight.

Rank (8.5) and channel (5.1) sit above the device in the hierarchy, and including them would add a second axis of distribution on top of the bank axis this module is isolating. Both policies in §1 place their fields identically outside the middle, so the middle is the only variable — the same control §7's row-boundary analysis relies on.

What changes when they are present is worth one sentence each, because the reasoning transfers unchanged. A channel field low in the address interleaves consecutive granules across independent interfaces, which is the strongest form of distribution available, since channels do not share a command or data bus the way banks do (16.1 §2). A rank field low in the address distributes across devices that do share the bus, and therefore buys less than it appears to — and costs rank-to-rank turnaround (5.4). Neither is universal: Chapter 18.4 shows that channel interleaving in particular is a configurable platform decision rather than an architectural constant.

One worked decode, in full binary, so the field boundaries are unambiguous. Take PA = 0x0A4C0:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  0x0A4C0  =  0000001010010011000000        (22 bits, bit 21 on the left)

  bit       21 20 19 18 17 16 15 14 | 13 12 | 11 10 | 9  8  7  6 | 5..0
  value      0  0  0  0  0  0  1  0 |  1  0 |  0  1 | 0  0  1  1 | 000000

  POLICY R  |--------- row ---------|-- bg -|- bank-|-- column --|offset
             row = 0x02 = 2           bg = 2  bank=1  col = 3      0

  bit       21 20 19 18 17 16 15 14 | 13 12 11 10 | 9  8 | 7  6 | 5..0
  value      0  0  0  0  0  0  1  0 |  1  0  0  1 | 0  0 | 1  1 | 000000

  POLICY B  |--------- row ---------|--- column ---|- bg -|-bank-|offset
             row = 0x02 = 2           col = 0x9 = 9  bg = 0 bank=3   0

Same address, same device, both lossless — and they disagree about where it lives. Policy R places it in bank 1 of group 2, which is flat bank 9, at column 3. Policy B places it in bank 3 of group 0, which is flat bank 3, at column 9. Reconstructing either set of five fields returns 0x0A4C0 exactly, which is Chapter 8.6's round trip and is not in dispute. Which bank the access lands in is.

3. The Only Question That Matters

Do not read a field diagram by naming the fields. Read it by asking one question:

When the address advances by one access granule, which field changes?

A field at bit position p changes once every 2^p bytes. So the field sitting immediately above the offset is the field that changes first, and it changes on every single consecutive access.

PolicyField just above the offsetChanges everyConsequence for a sequential walk
Rcolumn, at bit 664 Bstays in one bank, one row; walks the columns
Bbank, at bit 664 Bchanges bank on every access
The causal chain that address mapping sits at the head of. A system physical address enters on the left. The mapping policy, which is controller and platform policy rather than a device specification, splits it into resource fields: row, bank group, bank, column and byte offset. Those fields determine which bank each access lands in and which row that bank must hold. Compared against the bank's currently open row, that produces a hit, closed or conflict classification, which in turn determines the command sequence the request needs. In parallel, the spread of accesses across banks determines how much bank-level parallelism is available. Both outcomes feed the controller's command opportunities. A separate note shows that the device timing rules sit beside this chain and are not altered by it: the mapping changes how often each rule is encountered, never what the rule is.System addressfrom the requesterMapping policycontroller, not JEDECResource fieldsrow / bg / bank / colWhich bankand which rowRow relation9.3 — hit / closed /conflictBank spread16.1 — parallelismCommand opportunity17.1 consumes thisTiming rulestRCD / tRP / tCCDUNCHANGEDmapping alters frequency12

4. Eight Consecutive Cache Lines

The rule above, made concrete. Eight accesses from 0x00000, one access granule apart.

PAPA[13:6]R: bankR: rowR: colB: bankB: rowB: col
0x0000000000000000000
0x0004000000001001100
0x0008000000010002200
0x000C000000011003300
0x0010000000100004400
0x0014000000101005500
0x0018000000110006600
0x001C000000111007700

The bank column is the whole story. Policy R holds it at 0 and advances col. Policy B advances it on every row of the table while col stays at 0.

Extend to sixteen accesses and the counts are exact:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  16 consecutive access granules from 0x00000

    Policy R    distinct banks :  1 of 16     distinct rows : 1
    Policy B    distinct banks : 16 of 16     distinct rows : 1

5. What That Becomes at the Device

Apply Chapter 9.3's taxonomy — HIT, CLOSED, CONFLICT — with every bank starting closed. Nothing new is defined here; the classification is read off the decoded fields and the bank's currently open row.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  POLICY R — eight sequential granules
    0x00000  bank  0  row 0  col 0   prev: none   CLOSED    -> ACT then RD
    0x00040  bank  0  row 0  col 1   prev: row 0  HIT       -> RD
    0x00080  bank  0  row 0  col 2   prev: row 0  HIT       -> RD
    0x000C0  bank  0  row 0  col 3   prev: row 0  HIT       -> RD
    0x00100  bank  0  row 0  col 4   prev: row 0  HIT       -> RD
    0x00140  bank  0  row 0  col 5   prev: row 0  HIT       -> RD
    0x00180  bank  0  row 0  col 6   prev: row 0  HIT       -> RD
    0x001C0  bank  0  row 0  col 7   prev: row 0  HIT       -> RD

  POLICY B — the same eight granules
    0x00000  bank  0  row 0  col 0   prev: none   CLOSED    -> ACT then RD
    0x00040  bank  1  row 0  col 0   prev: none   CLOSED    -> ACT then RD
    0x00080  bank  2  row 0  col 0   prev: none   CLOSED    -> ACT then RD
    0x000C0  bank  3  row 0  col 0   prev: none   CLOSED    -> ACT then RD
    0x00100  bank  4  row 0  col 0   prev: none   CLOSED    -> ACT then RD
    0x00140  bank  5  row 0  col 0   prev: none   CLOSED    -> ACT then RD
    0x00180  bank  6  row 0  col 0   prev: none   CLOSED    -> ACT then RD
    0x001C0  bank  7  row 0  col 0   prev: none   CLOSED    -> ACT then RD

6. The Bit-Influence Matrix

The compact form of everything above: which decoded field owns each physical-address bit.

PA bitChanges everyPolicy RPolicy B
0–51–32 Boffsetoffset
664 Bcolumnbank
7128 Bcolumnbank
8256 Bcolumnbank group
9512 Bcolumnbank group
101 KiBbankcolumn
112 KiBbankcolumn
124 KiBbank groupcolumn
138 KiBbank groupcolumn
14–2116 KiB+rowrow

Read a row of this table and you can answer a design question without simulating anything.

“Which address bit changes the bank?” Bit 10 under R; bit 6 under B. “What stride moves to a new bank?” 1 KiB under R; 64 B under B. “What stride leaves the bank unchanged?” Any multiple of 16 KiB under R; any multiple of 1 KiB under B — and that second answer is Chapter 18.3's entire subject.

The matrix is also the debugging tool. When traffic concentrates unexpectedly, the question is always which bits of my address stream are actually varying, compared against which bits this map uses for bank selection. §13 works that procedure.

7. Row Boundaries

One case deserves separate treatment because it is where a sequential stream stops being free.

Under Policy R, the row field is PA[21:14], so a row covers 2^14 bytes — 16 KiB — of contiguous physical address. Walk to the end of it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  0x03FC0   row 0   bg 3  bank 3  col 15      last granule of row 0's span
  0x04000   row 1   bg 0  bank 0  col  0      first granule of row 1's span

Three fields change at once, and the important one is subtle: the bank returns to 0. Bank 0's open row is still row 0, and the request wants row 1 in bank 0 — a CONFLICT by Chapter 9.5's definition, requiring PRE, then ACT, then the column command.

So under Policy R a purely sequential walk is not uniformly cheap. It is 256 cheap accesses followed by one expensive one, repeating. The cost is amortised and small; the shape is worth knowing, because it is the first thing that a naive "sequential is all hits" model gets wrong.

Under Policy B the same boundary at 0x04000 lands in bank 0 as well, and with col also returning to 0 — but bank 0's open row was row 0 from 16 accesses earlier, so it is equally a conflict. The boundary behaves the same way in both policies, because the row field is in the same place in both. That is a useful control: it isolates the middle-field difference as the only variable in this comparison.

8. Where the Decode Already Lives

Module 18 writes no new address mapper, and saying so explicitly prevents the most likely structural mistake in this module.

ResponsibilityOwnerBlockModule 18 does
Full seven-field PA decode8.6sys_addr_mapperconsume
Losslessness / inversion8.6addr_roundtrip_checkconsume
Bank-low vs bank-high, one field8.3bank_field_policyconsume
Row / column / BG / rank fields8.18.5field blocksconsume
Hit / miss / conflict classification9.3row_request_classifierconsume
Bank-state model5.2ddr_bank_state_tableconsume

What is missing from that list — and what this chapter's block supplies — is the thing none of them does: turn a policy into the answer to “which field owns this bit, and at what stride does it move?” That is §6's matrix, computed rather than tabulated by hand.

9. The Bit-Influence Block

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────
// mapping_bit_influence
//
// CLASSIFICATION
//   Synthesizable educational RTL. Purely combinational. One
//   responsibility: for a declared field order, report which decoded
//   field each physical-address bit belongs to, and the byte stride at
//   which each field first changes.
//
//   It is a POLICY DESCRIPTOR, not a mapper. It decodes nothing.
//
// WHAT IT DOES NOT MODEL
//   - No address decode. Chapter 8.6's sys_addr_mapper does that, and
//     this module deliberately does not duplicate it.
//   - No reconstruction or losslessness proof. Chapter 8.6 owns both.
//   - No bank state, no classification. Chapters 5.2 and 9.3 own them.
//   - No hashing. Bits map to exactly one field here; Chapter 18.3's
//     bank_xor_hash is where one PA bit starts influencing two fields.
//   - No timing, no scheduling, no performance claim.
// ─────────────────────────────────────────────────────────────────────
module mapping_bit_influence #(
  parameter int PA_W     = 22,
  parameter int OFFSET_W = 6,
  parameter int COLUMN_W = 4,
  parameter int BANK_W   = 2,
  parameter int BG_W     = 2,
  parameter int ROW_W    = 8,
  // 0 = POLICY R : row | bg | bank | column | offset
  // 1 = POLICY B : row | column | bg | bank | offset
  parameter int POLICY   = 0
) (
  // ── One bit per PA position, reporting the owning field.
  //    0 = offset, 1 = column, 2 = bank, 3 = bank group, 4 = row.
  output logic [PA_W-1:0][2:0] bit_field,

  // ── The byte stride at which each field first changes: 2^lsb.
  //    Published as the LSB position rather than the stride itself so
  //    the value stays narrow; the stride is 2^value by construction.
  output logic [5:0] column_lsb,
  output logic [5:0] bank_lsb,
  output logic [5:0] bg_lsb,
  output logic [5:0] row_lsb,

  // ── The field immediately above the offset — §3's question answered
  //    structurally. This is the field a sequential walk sweeps first.
  output logic [2:0] first_field_above_offset
);

  // ── Every field must be at least one bit wide: a zero-width field
  //    has no bit positions to report and would make the part-selects
  //    below illegal. Resolved at elaboration rather than at runtime.
  if (OFFSET_W < 1) $fatal(1, "mapping_bit_influence: OFFSET_W must be >= 1");
  if (COLUMN_W < 1) $fatal(1, "mapping_bit_influence: COLUMN_W must be >= 1");
  if (BANK_W   < 1) $fatal(1, "mapping_bit_influence: BANK_W must be >= 1");
  if (BG_W     < 1) $fatal(1, "mapping_bit_influence: BG_W must be >= 1");
  if (ROW_W    < 1) $fatal(1, "mapping_bit_influence: ROW_W must be >= 1");
  // The fields must exactly tile the address. A gap would leave a PA
  // bit owned by nothing; an overlap would make the map lossy, which
  // Chapter 8.6 §2 showed is the one failure a round trip detects.
  if (OFFSET_W + COLUMN_W + BANK_W + BG_W + ROW_W != PA_W)
    $fatal(1, "mapping_bit_influence: field widths must sum to PA_W");
  if (POLICY != 0 && POLICY != 1)
    $fatal(1, "mapping_bit_influence: POLICY must be 0 or 1");

  localparam logic [2:0] F_OFFSET = 3'd0;
  localparam logic [2:0] F_COLUMN = 3'd1;
  localparam logic [2:0] F_BANK   = 3'd2;
  localparam logic [2:0] F_BG     = 3'd3;
  localparam logic [2:0] F_ROW    = 3'd4;

  // ── Field LSBs follow directly from the order. Both policies place
  //    offset at 0 and row at the top; they differ only in the middle,
  //    which is §1's observation expressed as arithmetic.
  localparam int R_COL_LSB  = OFFSET_W;
  localparam int R_BANK_LSB = R_COL_LSB  + COLUMN_W;
  localparam int R_BG_LSB   = R_BANK_LSB + BANK_W;

  localparam int B_BANK_LSB = OFFSET_W;
  localparam int B_BG_LSB   = B_BANK_LSB + BANK_W;
  localparam int B_COL_LSB  = B_BG_LSB   + BG_W;

  localparam int ROW_LSB    = OFFSET_W + COLUMN_W + BANK_W + BG_W;

  assign column_lsb = 6'((POLICY == 0) ? R_COL_LSB  : B_COL_LSB);
  assign bank_lsb   = 6'((POLICY == 0) ? R_BANK_LSB : B_BANK_LSB);
  assign bg_lsb     = 6'((POLICY == 0) ? R_BG_LSB   : B_BG_LSB);
  assign row_lsb    = 6'(ROW_LSB);

  // ── §3's rule as hardware: whichever field has the smallest LSB
  //    above the offset is the one a sequential walk sweeps first.
  assign first_field_above_offset = (POLICY == 0) ? F_COLUMN : F_BANK;

  // ── Walk every PA position once and name its owner. A loop rather
  //    than five part-selects, so that adding a field later cannot
  //    leave a position silently unassigned.
  always_comb begin
    for (int b = 0; b < PA_W; b++) begin
      if (b < OFFSET_W)                bit_field[b] = F_OFFSET;
      else if (b >= ROW_LSB)           bit_field[b] = F_ROW;
      else if (POLICY == 0) begin
        if      (b < R_BANK_LSB)       bit_field[b] = F_COLUMN;
        else if (b < R_BG_LSB)         bit_field[b] = F_BANK;
        else                           bit_field[b] = F_BG;
      end else begin
        if      (b < B_BG_LSB)         bit_field[b] = F_BANK;
        else if (b < B_COL_LSB)        bit_field[b] = F_BG;
        else                           bit_field[b] = F_COLUMN;
      end
    end
  end

endmodule

Simulating it. Elaborate once per policy and print bit_field from bit 0 upward; the output is §6's matrix, column by column. With the chapter's defaults, POLICY = 0 reports bank_lsb = 10 and POLICY = 1 reports bank_lsb = 6 — the two numbers that produced every difference in §4 and §5.

Synthesis. Everything here is elaboration-time constant. The generated hardware is a set of constant drivers, and a synthesis tool will fold the whole module away. That is appropriate: it is a descriptor meant to be read by a checker or a testbench, and the point of writing it in RTL rather than in a comment is that a checker can hold the mapper to it — §10's P2 does exactly that.

10. What the Assertions Prove

These properties are combinational and this block has no clock, so they belong in a testbench or a bind unit sampled on the surrounding environment's clock — the same arrangement Chapter 16.2 used for its combinational mask block.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── P1. Every PA bit is owned by exactly one field, and the fields
//    tile the address with no gap and no overlap. The elaboration
//    guard checks the WIDTHS sum; this checks the ASSIGNMENT actually
//    realises that sum, which is a different claim.
property p_fields_tile_address;
  @(posedge clk) disable iff (!rst_n)
    ($countones({ (bit_field_count_offset == OFFSET_W),
                  (bit_field_count_column == COLUMN_W),
                  (bit_field_count_bank   == BANK_W),
                  (bit_field_count_bg     == BG_W),
                  (bit_field_count_row    == ROW_W) }) == 5);
endproperty
a_fields_tile_address: assert property (p_fields_tile_address);

// ── P2. THE property that makes this block worth writing. The
//    descriptor must agree with the real mapper: the bit the
//    descriptor calls the bank LSB must be the bit that, when
//    toggled, changes sys_addr_mapper's bank output and nothing else.
//    This is what turns a comment into a checkable contract.
property p_bank_lsb_moves_bank;
  @(posedge clk) disable iff (!rst_n)
    (probe_valid && probe_addr_b == (probe_addr_a ^ (1 << bank_lsb)))
      |-> (mapper_bank_b != mapper_bank_a)
       && (mapper_row_b  == mapper_row_a);
endproperty
a_bank_lsb_moves_bank: assert property (p_bank_lsb_moves_bank);

// ── P3. A bit the descriptor assigns to the row field must not move
//    the bank. The mirror of P2, and the one that catches a field
//    boundary that is off by one -- the most common mapper bug, and
//    the hardest to see by inspection.
property p_row_bit_leaves_bank;
  @(posedge clk) disable iff (!rst_n)
    (probe_valid && probe_addr_b == (probe_addr_a ^ (1 << row_lsb)))
      |-> (mapper_bank_b == mapper_bank_a)
       && (mapper_row_b  != mapper_row_a);
endproperty
a_row_bit_leaves_bank: assert property (p_row_bit_leaves_bank);

// ── P4. The descriptor is a pure function of parameters, so it must
//    never change during a run. Catches a testbench that reparameterised
//    one instance and compared it against another.
property p_descriptor_stable;
  @(posedge clk) disable iff (!rst_n)
    $stable(bank_lsb) && $stable(row_lsb)
    && $stable(column_lsb) && $stable(bg_lsb);
endproperty
a_descriptor_stable: assert property (p_descriptor_stable);

// ── Covers. P2 and P3 are single-bit-toggle properties; if the
//    stimulus never toggles those exact bits they pass having checked
//    nothing at all.
c_bank_lsb_toggled: cover property
  (@(posedge clk) disable iff (!rst_n)
     probe_valid && probe_addr_b == (probe_addr_a ^ (1 << bank_lsb)));
c_row_lsb_toggled:  cover property
  (@(posedge clk) disable iff (!rst_n)
     probe_valid && probe_addr_b == (probe_addr_a ^ (1 << row_lsb)));

What they prove. That the declared field order and the mapper's actual behaviour agree at the boundaries that matter, verified by toggling one address bit and observing exactly one field move.

What they do not prove. Nothing here says the map is lossless — that is Chapter 8.6 §2's round trip, and a map can pass P1 through P4 while aliasing two addresses if a field is read twice. Nothing says the policy is a good one; P2 is equally satisfied by both policies in §1, which is the point. And nothing says the workload will exercise the bits the matrix describes — that is 18.3's subject, and it is where the difference between a correct map and a useful one appears.

Vacuity is the live risk here, which is why both covers exist. P2 and P3 fire only on an address pair differing in exactly one specific bit. A random-address testbench will essentially never generate such a pair, so without directed single-bit-toggle stimulus these properties pass while checking nothing. §12's walking-bit test is what makes them real.

11. Corner Cases

Address mappers fail at boundaries far more often than in the middle, and most of the failures are parameterisation rather than logic.

SituationCorrect behaviourFailure if mishandled
a field declared zero-widthelaboration failurelogic [-1:0] — an illegal declaration, or a silently absent field
widths do not sum to PA_Welaboration failurea gap leaves a PA bit owned by nothing; an overlap makes the map lossy
POLICY outside its legal setelaboration failurethe always_comb default silently produces one policy while the caller believes the other
every field one bit widelegal; bit_field still tiles the addressloops that assume a field spans more than one bit position
OFFSET_W equal to PA_Welaboration failure by the sum checkno mapped field exists and every access decodes identically
address above the device8.6's addr_above_device flags ithigh bits silently truncated, wrapping onto a valid location
field boundary off by onethe walking-bit test names the bitone field a bit too wide and its neighbour a bit too narrow — and it still round-trips
offset narrower than the access granulethe granule's constant bits enter a mapped field; half that field's range becomes unreachable (§2)

The last two rows are the ones worth memorising, because both survive a losslessness check. A round trip verifies that the decomposition is reversible; it does not verify that the fields sit where you intended. Those are independent properties needing independent tests — the round trip for the first, §12's walking bit for the second.

12. DV — The Walking-Bit Test

The independent model must not re-slice the address the way the RTL does. Chapter 8.6 §8 established the general form of that rule; here the concrete instruction is: if the DUT uses part-selects, the checker uses masks and shifts, expressed from the algebra in §1 rather than copied from the RTL.

The highest-value directed test in all of address mapping is the walking bit:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  for b in 0 .. PA_W-1:
      A = 0
      B = 1 << b
      decode A and B
      record which decoded fields differ

One pass produces the entire bit-influence matrix empirically, from the DUT, with no reference to how the DUT was written. Compare it against §6's table and every field-boundary error appears as a single misplaced row.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  WALKING-BIT MISMATCH
    policy under test     : R
    PA bit toggled        : 10
    expected field (§6)   : bank
    observed field change : column
    expected bank delta   : yes      observed : no
    expected column delta : no       observed : yes
    first differing field : column
    diagnosis  : the column field is one bit too wide, or the bank
                 field's LSB is one too high. Both present identically
                 at this bit and are distinguished by bit 9: if bit 9
                 also moves the column, the column is too wide.
    blast radius : every bank-distribution result in 18.2 computed
                   against this mapper is measuring the wrong field.

The last two lines are what makes the report worth building. A single-bit report that names two candidate root causes and the discriminating experiment saves the engineer the step they would otherwise have to invent.

Beyond walking bits, the directed set worth running: all-zeros; all-ones within the legal width; each field's boundary at −1, boundary, +1; two addresses differing only in a bank-select source bit; two differing only in a row bit; the last granule of a row's span and the first of the next; and a full round trip through 8.6's addr_roundtrip_check to confirm losslessness has not been broken by the reordering.

13. Debugging

Symptom: a sequential workload concentrates in one bank.

This is expected under Policy R and pathological under Policy B, so the first move is to establish which map is actually in force — not which one the documentation claims.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  what varies in the address stream?
    └─ capture the stream; XOR consecutive addresses; note which bits move
         └─ compare against the bank field's bit range (§6)
              ├─ bank bits are varying → the mapping is not the problem;
              │    look at the scheduler (17.4) or the bank state (5.2)
              └─ bank bits never vary → the stream's varying bits and the
                   map's bank bits do not overlap
                     ├─ intended (Policy R, sequential) → this is by design
                     └─ unintended → 18.3's stride aliasing

Symptom: the decode is correct but the bank distribution is wrong. Both can be true at once, and conflating them wastes days. Losslessness and field placement are independent properties: 8.6's round trip will happily pass on a map whose bank bits sit somewhere useless. Run the walking-bit test — it checks placement, which the round trip does not.

Symptom: two mappers disagree and both round-trip. Then both are lossless and they are simply different maps, exactly as Chapter 8.6 §5 showed. The question is not which is correct but which one the other component — the firmware, the model, the monitor — is assuming. That is 18.4's problem, and it is a documentation problem before it is a hardware one.

Symptom: everything works until the address crosses a power of two. Almost always an off-by-one field boundary. The discriminator is §12's walking bit at exactly the suspected boundary, and the tell is a field that responds to one bit too many.

14. Misconceptions

“JEDEC defines the physical-address map.” It defines what the device does with a row, bank and column it is given. The transformation from a system address is controller and platform policy — 18.4 quotes a vendor saying so. Clue: a design that expects one map to be portable across platforms.

“Row bits are always the highest bits.” They are highest in both policies here, and that is a choice this chapter made to isolate one variable. It is common, not universal. Clue: a bit diagram drawn from memory rather than from the configuration.

“Bank bits are always low-order.” They are at bit 6 under B and bit 10 under R. Clue: an assumed 1 KiB bank stride that has never been checked against the map in force.

“Contiguous addresses stay in one row.” Only for as long as the fields below the row field last — 16 KiB here — and §7 shows the boundary is a conflict, not a free transition. Clue: a model that predicts a 100% hit rate for sequential traffic.

“Sequential traffic always produces row hits.” Under Policy B, eight sequential granules produced zero hits and eight activations. Clue: a hit-rate expectation that does not name the mapping it assumes.

“More row hits is always better.” §5 — Policy R's seven hits are serialised in one bank. Chapter 16.3 built an entire chapter on hit rate and bank parallelism being different quantities. Clue: a mapping chosen on hit rate alone.

“Spreading across banks is always better.” The mirror error, and 18.3 shows a stride where the spreading map collapses to a single bank. Clue: a policy justified by "more parallelism" with no reference to the workload.

“Different banks are fully independent.” They share the command bus, the data bus, the activation budget, and within a bank group part of the column path (16.4). Clue: a bandwidth estimate that scales linearly with bank count.

“A cache-line address is a DDR column address.” Here one access granule is 64 B and the column field is four bits selecting among 16 such granules within a row's span. They are related by the map, not equal. Clue: a column value used directly as an address offset.

“If it round-trips, the mapping is right.” A round trip proves losslessness. It says nothing about placement, and nothing about whether it matches the map some other component assumes. Clue: a mapper verified only by reconstruction.

“Changing the mapping changes the timing parameters.” tRCD, tRP and tCCD are device properties. The mapping changes how often each one is encountered. Clue: a proposal to "fix tRCD" by remapping.

15. Interview Reasoning

“Why does address mapping belong to the controller rather than the DRAM?” The device is told a row, bank and column; it has no notion of a system address. The transformation is where system knowledge lives — page size, interleaving, channel count — none of which the DRAM can see.

“Two maps both round-trip. Can they behave differently?” Yes, completely — §1's two policies produce opposite resource behaviour on identical addresses. The follow-up that separates understanding from recall: what would you measure to tell them apart? Bank distribution over a known stream, or a walking-bit test.

“Which address bit changes the bank, and how would you find out?” Read it off the field order if you have it; toggle single bits and observe the decode if you do not. The second answer is the stronger one, because it works on a system whose map you have not been given.

“What changes on the next cache line?” The field immediately above the offset. Answering with that rule rather than with a specific field shows the reasoning transfers to any map.

“Your sequential benchmark gets a 95% row-hit rate and disappointing bandwidth. What do you suspect?” A map that concentrates the stream in one bank — high hit rate, no parallelism, everything serialised behind one bank's column timing. Then name the measurement that distinguishes it: distinct banks touched per window.

“What does mapping change, and what does it not?” It changes which resources a workload presents to the timing rules. It changes no timing rule, no command semantics, and no device behaviour.

16. Exercises

1. Under Policy R, give the smallest positive stride that changes the bank group on every access. Verify against §6.

2. Under Policy B, decode 0x0A4C0 into offset, bank, bank group, column and row. Then reconstruct the address from those five fields and confirm you recover 0x0A4C0.

3. Policy R's row span is 16 KiB. What is Policy B's row span, and why is the answer the same? Which property of the two policies makes it so?

4. Walk 32 consecutive granules from 0x03F00 under Policy R. How many CONFLICT classifications occur, and at which addresses?

5. A colleague proposes moving the row field to PA[13:6] and the column to PA[21:14]. The map is still lossless. Describe what a sequential walk now does, and name the field that a 64-byte stride now moves.

6. Write the walking-bit expected-result table for Policy B, bits 6 through 14. Which two adjacent bits would be indistinguishable if the bank field were one bit wider than declared?

7. P2 and P3 both pass on a mapper whose bank and bank-group fields are swapped. Write the additional property that catches it.

8. Explain why mapping_bit_influence synthesises to constants, and why that is an argument for writing it in RTL rather than against it.

17. Where This Goes

The mechanism is established: the field order decides what changes on the next access, and that decides which resources a stream touches.

Chapter 18.2 takes one fixed address stream, runs it through both policies, and measures what each produces — row relations and bank distribution together, because 16.3 proved that either one alone misleads. 18.3 asks what happens when the workload's stride and the map's bank bits interact badly, and introduces hashing as the standard answer. 18.4 asks the question this chapter has been quietly assuming away: on a real system, how do you know which map is in force?

Continue learning

Standards & specifications

Governing standard
JEDEC JESD79 (DDR SDRAM)(opens JEDEC Solid State Technology Association in a new tab)

Defines the DDR SDRAM device itself — signals, command encoding, mode registers, timing parameters and the initialisation sequence — one document per generation. Memory-controller microarchitecture, address-mapping policy, PHY training algorithms and board-level design are not specified by it.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the DDR curriculum.