Skip to content
VLSI Mentor

DDR · Module 6

CS# — Chip Select

The command bus reaches every rank, so every rank sees every command. Chip select decides which one acts — and because selecting nothing is legal and common, it is at most one, not exactly one.

Chapter 6.1 established when the command inputs mean something. Chapter 6.2 established whether a device is sampling them at all. This chapter answers the remaining question: of the devices that are listening, which one is being addressed?

The question exists because of a structural fact from Chapter 5.4 §3: the command and address bus reaches every rank on a channel. There is no separate command path per rank — that would multiply the most expensive and most heavily loaded signals in the system, which is exactly what Chapter 4.4 §2 showed DDR3 went to considerable trouble to avoid.

So every rank sees every command. Something must decide which of them acts, and that something is CS# — one wire per rank, driven by the controller side, asserted low.

The interesting property is not that it selects. It is that selecting nothing is legal, common, and necessary — which changes how the signal must be verified, and is where most engineers get its assertion wrong.

1. Broadcast, Then Select

The arrangement is worth stating plainly because it inverts a common expectation.

The CA lines do not carry a device address. A command on the bus does not say "rank 1, activate row 500". It says "activate row 500", and every rank connected to that bus receives it identically.

Selection is a separate, parallel mechanism. CS# is a bundle of per-rank wires, and the rank whose CS# is asserted at the sampling event is the one that acts. All others see the same command and do nothing.

The command and address bus is a broadcast that every rank receives identically and which carries no device address, so on its own nothing happens. Chip select provides one wire per rank, of which at most one is asserted low at any sampling event, and the rank so selected is the one that acts on the broadcast command. Selecting no rank is legal and is the common idle state.CA + commandbroadcast to all ranksEvery rank sees itno device addressNothing happenson its ownCS# per rankone wire eachAt most one lownone is legalThat rank actsnow it is an instructionreachesdrivesselectsneeds12
Figure 1 — the CA bus carries no device address; CS# is what makes a broadcast into an instruction.

Why broadcast-then-select rather than addressing? Because addressing would cost either extra CA bits on every command or extra command encodings, and selection is needed on every single command — so it belongs on a dedicated wire. This is 6.1's thesis running in the opposite direction from CKE: a function required every event justifies a pin, while a function invoked occasionally does not.

And it scales the right way. Adding a rank adds one CS# wire. Encoding rank into the command would require widening the command encoding for every command whether or not multiple ranks exist — paying in the common case to serve the uncommon one.

2. At Most One, Not Exactly One

The property that matters for both design and verification:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   CS# is ONE-HOT-OR-NONE.

   At most one rank selected at any sampling event.
   Zero ranks selected is legal, common, and necessary.

Zero is not an error state. It is the idle state, and on a typical command bus it is the most frequent state — a memory interface spends many events issuing nothing at all.

A sampling event with no rank selected is a deselect, and it means precisely that no device acts. Chapter 6.1 §4's model already relied on this: CA stability is only checked when a command is qualified, because on deselect events the CA lines are free to carry anything.

3. Deselect Is Doing Work

It is tempting to read "no rank selected" as "nothing happening", and that undersells it.

Deselect is how the controller occupies the command bus without issuing a command. The bus is a shared resource with a sampling event every cycle; between real commands, something must be on it, and deselect is that something.

It is also how the controller creates spacing. Chapter 4.5 §5 established that accesses to the same bank group need a longer minimum separation than accesses across groups, and Modules 13 and 14 formalise every such interval. The controller creates those intervals by issuing deselects — the command bus does not idle, it deselects.

And it bounds the blast radius of an unqualified glitch. Because CA lines carry no obligation on deselect events, a disturbance on them during idle is harmless. Only qualified events can damage anything, which is a meaningful robustness property: the interface is only sensitive on the fraction of events that are actually commands.

4. RTL — Rank Selection

Engineering problem

Turn a command targeted at a rank index into a per-rank active-low select bundle, guarantee at most one is asserted, make deselect the default, reject an out-of-range rank, and measure the distribution of commands across ranks.

The distribution matters because Chapter 5.4 §12 established that alternating ranks per access costs a bus handoff and gains nothing — so a controller that cannot see its own rank distribution cannot notice it is doing that.

Classification

SYNTHESIZABLE RTL. A decoder, a qualification gate and telemetry — genuinely present in every multi-rank controller's command path.

What it represents: the selection contract. Which rank is addressed, active-low encoding, deselect as the default, and per-rank command accounting.

What it explicitly does not represent: command encoding, which is Module 7; address field decomposition, which is Modules 8 and 18; rank data-bus ownership, which is Chapter 5.4's rank_bus_owner and is a different resource with a different lifetime; and any electrical property of the select wires. Selecting a rank for a command is not the same as that rank owning the data bus, and conflating them is §8's third misconception.

Interface contract

cmd_valid with cmd_rank requests a command to a rank. cs_n is the active-low bundle. deselect reports an event with no rank selected. rank_invalid reports an out-of-range index. cnt_rank gives the distribution and cnt_deselect the idle count.

State

Per-rank saturating counters and a deselect counter. The selection itself is combinational — a decode of the current request, with no memory, which is the structural expression of §1's per-event nature.

Combinational behaviour

Range check, active-low one-hot decode, deselect derivation.

Sequential behaviour

Counters only.

How to simulate

vlog cs_rank_decoder.sv tb_cs_rank_decoder.sv then vsim -c tb_cs_rank_decoder -do "run -all".

Expected result: exactly one cs_n bit low per valid in-range request and all bits high otherwise; counters partitioning the events between the ranks and deselect.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// CS RANK DECODER.  Classification: SYNTHESIZABLE RTL.
//
// The command/address bus is a BROADCAST reaching every rank and carrying
// no device address. Chip select is what makes it an instruction to one
// rank. This decodes a rank index into the active-low per-rank bundle.
//
// CS# IS ONE-HOT-OR-NONE, NOT ONE-HOT. Deselect -- no rank asserted -- is
// legal, common, and on a typical command bus the MOST frequent state.
// Section 4's assertions use $onehot0 for that reason.
//
// WHAT THIS DOES NOT REPRESENT: command encoding (Module 7), address field
// decomposition (Modules 8, 18), rank DATA-BUS ownership (Chapter 5.4's
// rank_bus_owner -- a different resource with a different lifetime), or any
// electrical property of the select wires. Selecting a rank for a COMMAND
// is not the same as that rank owning the DATA BUS.
// ─────────────────────────────────────────────────────────────────────────
module cs_rank_decoder #(
  parameter int NUM_RANKS = 2,
  parameter int ACC_W     = 16,
  parameter int RK_W      = (NUM_RANKS <= 1) ? 1 : $clog2(NUM_RANKS)
) (
  input  logic                 clk,
  input  logic                 rst_n,

  input  logic                 cmd_valid,
  input  logic [RK_W-1:0]      cmd_rank,

  // ACTIVE LOW, one bit per rank. Deselect is all ones.
  output logic [NUM_RANKS-1:0] cs_n,
  output logic                 deselect,
  output logic                 rank_invalid,

  output logic [ACC_W-1:0]     cnt_rank [NUM_RANKS],
  output logic [ACC_W-1:0]     cnt_deselect
);

  // ── COMPILE-TIME legality.
  if (NUM_RANKS < 1) begin : g_nr
    initial $fatal(1, "cs_rank_decoder: NUM_RANKS must be >= 1");
  end

  // ── Range check. NOT `cmd_rank >= RK_W'(NUM_RANKS)`: that cast truncates
  //    to zero whenever NUM_RANKS is a power of two, making the comparison
  //    always true. Generated only where it can ever fire -- the pattern
  //    Chapter 5.1 Section 5 established and this module reuses throughout.
  logic rank_bad;
  if (NUM_RANKS >= (1 << RK_W)) begin : g_rk_full
    assign rank_bad = 1'b0;
  end else begin : g_rk_check
    assign rank_bad = ({1'b0, cmd_rank} >= (RK_W+1)'(NUM_RANKS));
  end
  assign rank_invalid = cmd_valid && rank_bad;

  logic select_ok;
  assign select_ok = cmd_valid && !rank_bad;

  // ── The decode. Built by starting from all-deselected and clearing ONE
  //    bit, so multiple simultaneous selection is UNREPRESENTABLE rather
  //    than merely forbidden. Section 6's $onehot0 property then holds by
  //    construction, which is the strongest form of guarantee available.
  always_comb begin
    cs_n = {NUM_RANKS{1'b1}};
    if (select_ok) cs_n[cmd_rank] = 1'b0;
  end

  assign deselect = (cs_n == {NUM_RANKS{1'b1}});

  // ── Saturating telemetry. Chapter 5.4 Section 12 established that
  //    alternating ranks costs a bus handoff per access and gains nothing,
  //    so a controller that cannot see its own rank distribution cannot
  //    notice it is doing that.
  logic [ACC_W:0] r_sum, d_sum;
  always_comb begin
    r_sum = {1'b0, cnt_rank[select_ok ? cmd_rank : RK_W'(0)]} + (ACC_W+1)'(1);
    d_sum = {1'b0, cnt_deselect} + (ACC_W+1)'(1);
  end

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      for (int r = 0; r < NUM_RANKS; r++) cnt_rank[r] <= '0;
      cnt_deselect <= '0;
    end else if (select_ok) begin
      cnt_rank[cmd_rank] <= r_sum[ACC_W] ? {ACC_W{1'b1}} : r_sum[ACC_W-1:0];
    end else begin
      // Deselect events are counted too. Command-bus occupancy is a real
      // metric: a bus that is 90% deselect is not necessarily idle -- it
      // may be spacing commands it is required to space (Modules 13/14).
      cnt_deselect <= d_sum[ACC_W] ? {ACC_W{1'b1}} : d_sum[ACC_W-1:0];
    end
  end

endmodule

Cycle-by-cycle example

NUM_RANKS = 2:

Cyclecmd_validcmd_rankcs_n[0]cs_n[1]deselect
010010
10111
211100
30111
410010

Note what the CA lines are doing in this table: nothing. They are not shown because they are irrelevant to the selection — the same command value can appear at cycles 0 and 2 and be executed by different ranks. That separation is the chapter's point, and it is why a monitor that records CA without recording CS# has recorded nothing useful.

Waveform expectation

§5. Watch that cs_n is all-ones on every non-command event and that exactly one bit is low otherwise.

Synthesis implication

A decoder of NUM_RANKS gates, a comparator, and NUM_RANKS + 1 saturating counters. Negligible. The decode sits directly on the command path's critical timing, so in a real controller it is usually registered and the rank index is resolved a cycle early — this block leaves it combinational to keep the contract visible.

Corner cases

NUM_RANKS == 1 gives RK_W == 1 through the guard, and the range check materialises because one legal encoding of two exists — Chapter 5.1 §5's degenerate case again. cmd_valid low always produces deselect, so deselect is the reset-consistent default. An out-of-range rank produces deselect, not a wrong selection — which is the safe failure: selecting nothing is harmless, selecting the wrong rank corrupts state belonging to a device the controller was not addressing.

Debugging clues

If two ranks respond to one command, this block is not the cause — it cannot express that — so look at the select wires' routing, at whether a rank is configured to respond to the wrong select, or at a second driver on the select net. If a rank never receives commands, check the distribution counters before checking the decode: an even distribution with one rank idle means the requests are not targeting it, which is an address-mapping question (Module 18) rather than a decode one. If the deselect count is near zero on a working system, the telemetry is being gated on cmd_valid rather than counting every event.

Limitations

No command content, no addressing, no data-bus ownership, no electrical behaviour. No modelling of the fact that CS# must satisfy the same stability contract as the CA lines — Chapter 6.1 §4 owns that, and in a real interface CS# is subject to it too, because it is part of the command. And no representation of DDR5's extended CS_n responsibilities, which §7 covers in prose.

5. Same Command, Different Rank

cs_rank_decoder — broadcast command bus, per-rank selection

10 cycles
Ten cycles with two ranks. The same activate command value appears on the command and address bus at several events, and which rank executes it is determined entirely by which chip select is driven low. Between commands both chip selects are high, which is a deselect and is the most common state. The rank zero command counter advances only on the events where its select is low.alternating ranksalternating ranksconsecutive, rank 0consecutive, rank 0rank 0 executes ACTrank 0 executes ACTsame value — rank 1same value — rank 1deselect, not idledeselect, not idleCKca_busACT--ACT--RDRD--ACT----cs_n[0]cs_n[1]deselectcnt_rank[0]0111123333cnt_rank[1]0001111122cnt_deselect0011222334t0t1t2t3t4t5t6t7t8t9
Figure 2 — identical command values, executed by different ranks, with deselect between.

Cycles 0 and 2 carry the identical value ACT and are executed by different ranks. Nothing on the CA bus distinguishes them. A trace that captured only the command bus would show two identical events and would be unable to explain why two different devices changed state.

Cycle 1 is a deselect and the counter advances. It is not a gap in the trace; it is an event on the bus that means "no device acts". By cycle 9 the deselect count is 4 of 10 events — on a real interface that fraction is usually far higher, and it is not waste: Modules 13 and 14' minimum separations are created by exactly these events.

The two phases are the Chapter 5.4 §12 lesson in miniature. Cycles 0 to 3 alternate ranks, paying a data-bus handoff on each; cycles 4 and 5 issue consecutively to rank 0, which does not. The distribution counters are what make that visible, and a controller without them cannot notice it is alternating.

Representative educational cycles. The spacing between commands here is chosen for legibility, not derived from any timing requirement.

6. Three Assertions Worth Writing

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// VERIFICATION-ONLY, inside cs_rank_decoder.

// P1 -- ONE-HOT-OR-NONE. $onehot0, NOT $onehot: deselect is legal and is
// the most common state, so $onehot would fail on nearly every event and
// would very likely be weakened into uselessness rather than corrected.
// Note cs_n is ACTIVE LOW, so the property is about the inverted bundle.
property p_at_most_one_selected;
  @(posedge clk) disable iff (!rst_n)
    $onehot0(~cs_n);
endproperty
assert property (p_at_most_one_selected);

// P2 -- the selected rank is the requested one. P1 forbids selecting many;
// this requires selecting the RIGHT one, and without it a decoder that
// always selected rank 0 would pass P1 perfectly.
property p_selects_requested_rank;
  @(posedge clk) disable iff (!rst_n)
    (cmd_valid && !rank_invalid) |-> !cs_n[cmd_rank];
endproperty
assert property (p_selects_requested_rank);

// P3 -- an invalid rank selects NOTHING rather than something wrong.
// Selecting nothing is harmless; selecting the wrong rank corrupts state
// in a device the controller was not addressing, and Chapter 4.5 Section 3
// established that a misdirected command has unbounded blast radius.
property p_invalid_deselects;
  @(posedge clk) disable iff (!rst_n)
    rank_invalid |-> deselect;
endproperty
assert property (p_invalid_deselects);

// P4 -- no selection without a request. Guards against a decoder that
// asserts a select on idle events, which would make every deselect a
// spurious command.
property p_no_select_without_cmd;
  @(posedge clk) disable iff (!rst_n)
    !cmd_valid |-> deselect;
endproperty
assert property (p_no_select_without_cmd);

P1 is the assertion this chapter exists to get right, and the $onehot0-versus-$onehot choice is not a detail — it is the difference between a property that runs clean and catches real multi-select faults, and one that fails constantly and gets weakened.

P2 is the companion that makes P1 meaningful. A decoder hard-wired to rank 0 satisfies P1 on every event. Restrictive properties always need a companion that requires something, and this module will keep needing them.

P3 encodes a safety direction. There are two ways to handle an invalid index — select nothing, or select something — and they are not equally bad. The property fixes the choice, so a later "optimisation" that masks the index instead of rejecting it fails a test rather than shipping.

What none of them prove. Nothing about whether CS# meets its stability obligation at the sampling event — that is 6.1's analog contract and no digital assertion reaches it. Nothing about the command's content or legality, which is Module 7. And nothing about data-bus ownership: a rank selected for a command does not thereby own the data bus, and Chapter 5.4 §6's properties are the ones that govern that.

7. What DDR5 Added to CS_n

Chapter 6.2 §6 established that DDR5 removed the dedicated CKE pin and moved power-down entry and exit onto CS_n together with CA-bus command encoding. Chapter 6.7 covers the same happening to ODT.

So CS_n in DDR5 is doing more than selecting. It remains the per-event qualifier this chapter describes, and it additionally participates in signalling that used to have its own wires.

Why CS_n was the natural place to put them. Because it is already the signal that distinguishes "this event concerns you" from "this event does not" — and every function being moved is per-device. Power-down applies to a device; termination applies to a device. A function that must be directed at a specific device needs a device-selection mechanism, and one already existed.

The architectural consequence is worth stating. In DDR4, a controller could assert ODT or change CKE outside its command stream — those were independent wires with their own timing. In DDR5 those become commands, which means they are scheduled, they occupy command-bus events, and they compete with reads and writes for bandwidth. A control action that was free in one generation costs a command slot in the next, and a controller ported naively will under-provision its command scheduling.

8. Common Misconceptions

"CS# is just a generic enable." Wrong model: chip select is an on/off gate with no architectural content. Why it is tempting: functionally it does gate, and the name suggests nothing more. Consequence: failing to recognise that selection is per-event and per-rank, and therefore that a command trace without CS# is uninterpretable. Also missing why DDR5 could load more functions onto it — an enable would be an odd place to put power-state control; a device selector is the obvious place. Correct model: CS# is the mechanism that converts a broadcast CA bus into an instruction directed at one rank. It carries the entire device-targeting information of the interface, because the CA lines carry none. Prevention: ask where the device address is. It is not on the CA bus — it is the CS# bundle.

"CS# is one-hot." Wrong model: exactly one rank is selected at any time. Why it is tempting: "select" implies something is selected, and one-hot is the usual encoding for selection. Consequence: an assertion that fails on the majority of events, which — worse than failing — tends to get weakened until it no longer catches the genuine multi-select fault. And a controller design with no representation of deselect, which then has nothing to issue between commands. Correct model: one-hot-or-none. Zero selected is legal, common, and the most frequent state; it is also how the controller occupies the bus while creating the minimum separations later timing modules require. Prevention: $onehot0, and more generally: when a property fails constantly, suspect the property's model of the legal state space before weakening it.

"A rank selected for a command owns the data bus." Wrong model: chip select and data-bus ownership are the same selection. Why it is tempting: both are per-rank, both are about "which device", and in a simple mental model they co-occur. Consequence: conflating two resources with completely different lifetimes. A command event is one sampling event; data-bus ownership spans an entire burst and persists long after the command that caused it. A controller that models them as one thing cannot represent a read whose data returns while a different rank is being commanded. Correct model: CS# selects a rank for one command event. Chapter 5.4's rank_bus_owner governs the data bus, with grant, duration and handoff. They are different mechanisms on different timescales. Prevention: ask how long each lasts. One event versus a burst is not a subtle difference.

"Every DRAM device has its own command path to the controller." Wrong model: devices are individually wired. Why it is tempting: it is how a small system would naturally be built, and it makes selection unnecessary. Consequence: a completely wrong model of the interface's cost structure and of why DDR3's routing topology mattered. Command and clock reaching every device is precisely what makes them the hardest signals on the board — Chapter 4.4 §2 — and per-device command paths would multiply the system's most expensive signals. Correct model: one command and address bus per channel, broadcast to every rank, with per-rank selection. Chapter 5.5 is the level at which command paths are actually replicated — and that is a channel, not a device. Prevention: count the command buses. There is one per channel, and that is the whole reason CS# exists.

9. Debugging — The Wrong Rank Responded

Symptom. A command takes effect on a device the controller was not addressing. State in an unaddressed rank changes; the intended rank appears not to have received the command. Data may be corrupt in regions the failing access never touched.

This is the highest-blast-radius fault class in the interface. Chapter 4.5 §3 established that a misdirected command damages state belonging to accesses that were never issued — so the symptom appears far from the cause, and the corrupted region has no relationship to the failing request.

Mechanism 1 — the rank index was wrong before the decode. Inspect: the controller's rank field for the request, upstream of the select decode. Expected evidence: the index already naming the wrong rank. Discriminator: compare intent against the wires. This is first because it costs nothing and because it eliminates the entire interface from the investigation if true — an address-mapping error (Module 18) produces exactly this symptom.

Mechanism 2 — more than one select is asserted. Inspect: the select bundle at the failing event. Expected evidence: two wires low simultaneously. Discriminator: count the asserted selects. If §4's decoder is generating them this is impossible by construction, so the cause is downstream — routing, a second driver on the net, or a device configured to respond to a select it should ignore. The decode and the wires are different suspects and the count distinguishes them.

Mechanism 3 — CS# did not meet its stability obligation. Inspect: CS# timing relative to the sampling event, with the same discipline Chapter 6.1 §4 applied to CA. Expected evidence: errors scaling with rate and varying with temperature. Discriminator: is it a margin failure? CS# is part of the command and is subject to the same setup obligation as the CA lines — a fact that is easy to forget precisely because CS# is thought of as "just an enable".

Mechanism 4 — the module's rank configuration is not what the controller believes. Inspect: how many ranks are physically present and how selects map to them, against the controller's configuration. Expected evidence: a controller addressing ranks that do not exist, or a select mapped to a different physical rank than assumed. Discriminator: read the detected configuration. Chapter 5.6 §1 established that a module carries one or more ranks and that the counts are separate numbers; an integration that assumed a 1R module and received a 2R one produces this.

Mechanism 5 — not selection: the command was fine and the address was wrong. Inspect: whether the right rank acted on the wrong row or bank. Expected evidence: the correct device changing state incorrectly. Discriminator: did the wrong device respond, or the right device do the wrong thing? This is the single most useful question in the whole list and it is available immediately from the symptom. The first is a selection fault; the second is addressing (Module 8) or bank-state (Chapter 5.2), and they share no diagnostic steps.

Discrimination, cheapest first. Ask whether the wrong device responded or the right device misbehaved — one question, and it splits mechanism 5 off entirely. Then compare the controller's rank index against the wires. Then count asserted selects at the failing event. Then read the detected rank configuration. Only then engage with margin.

The reasoning lesson. "Wrong device" and "wrong operation" are different faults, and the distinction is free to make but easy to skip — both present as "memory is corrupted", and an investigator who does not ask which one is looking at will search the union of two disjoint suspect lists. Selection faults are identified by who responded; addressing faults by what they did. Establishing which before anything else is the cheapest possible narrowing, and it is available from the first failing trace.

10. Interview Reasoning

"How does one command bus address several ranks?" It does not address them at all. The command and address bus is a broadcast — every rank on a channel receives every command identically, and the CA lines carry no device address. Selection is a separate parallel mechanism: one chip-select wire per rank, and the rank whose select is asserted at the sampling event is the one that acts. The reason it is a dedicated wire rather than an encoding is frequency: selection is needed on every single command, and a function required every event justifies a pin, whereas encoding rank into the command would widen the encoding for every command whether or not multiple ranks exist.

"Should a chip-select bundle be one-hot?" One-hot-or-none. Zero ranks selected is legal, common, and typically the most frequent state — it is a deselect, meaning no device acts, and it is how the controller occupies the bus between commands and creates the minimum separations that timing rules require. Practically this matters most in verification: asserting $onehot fails on nearly every event, and the danger is not the failure but that it tends to get weakened until it no longer catches the genuine fault of two ranks acting on one command. $onehot0 is the correct property, and the general lesson is that a property failing constantly usually means the property's model of the legal state space is wrong, not that the design is broken.

"Is chip select the same as rank ownership of the data bus?" No, and they have completely different lifetimes. Chip select qualifies one command event — it is evaluated fresh at each sampling event and has no memory. Data-bus ownership spans an entire burst, is granted, held stable for the duration, and released with a handoff cost on every change. They can be out of step: a read's data can be returning from one rank while the controller is issuing a command to another. A controller that models them as one mechanism cannot represent that, which is a real limitation rather than a simplification.

"Why did DDR5 move power-down and termination control onto CS_n?" Because both functions are per-device and CS_n was already the per-device selection mechanism. A function that must be directed at a specific device needs a device selector, and one already existed. The trade is that in DDR4 those were independent wires the controller could drive outside its command stream, with their own timing; in DDR5 they become commands — scheduled, occupying command-bus events, competing with reads and writes for bandwidth. So a control action that was essentially free becomes one that costs a command slot, and a controller ported without accounting for that will under-provision its command scheduling.

"A command takes effect on a rank you did not address. Where do you start?" By asking whether the wrong device responded or the right device did the wrong thing, because those are disjoint faults with no shared diagnostic steps and the answer is available from the first failing trace. If it is genuinely the wrong device, compare the controller's own rank index against the select wires — an address-mapping error produces this symptom and eliminates the interface entirely if true. Then count how many selects were asserted at the failing event, which separates a decode fault from a wiring or configuration fault, since a properly built decoder cannot assert two. Then check the detected rank configuration against what the controller believes, because a module with more ranks than assumed produces exactly this. Margin comes last, though it is worth remembering chip select is part of the command and subject to the same stability obligation as the address lines — which is easy to forget when you think of it as just an enable.

11. Engineering Exercise

Educational cycles; no timing values implied.

1. Two ranks are present. The controller issues an identical ACT value on the CA bus at two different events, and two different rows end up open in two different devices. Was anything wrong? No — that is the interface working correctly. The CA value carries no device address; CS# selected a different rank each time. A monitor recording only the CA bus would see two identical events and be unable to explain the outcome, which is why a command monitor must capture CS# as part of the command.

2. A verification engineer asserts $onehot(~cs_n) and sees failures on 70% of events. What is the correct response? Fix the property, not the design. The failures are deselects, which are legal. $onehot0 is correct. The dangerous response is to weaken the property to something vaguer, which would also stop catching the genuine multi-select fault — two ranks driving the shared data bus.

3. A system has one rank. Is CS# still needed? Yes, because deselect is still needed. Without a way to say "no device acts", every sampling event would be a command, and the controller would have no way to occupy the bus while creating required separations. Selection between ranks is only half the signal's job; distinguishing command from non-command is the other half, and it survives at one rank.

4. §4's decoder is given an out-of-range rank index. It produces deselect. Argue for this over selecting rank 0. Selecting nothing is harmless — no device acts, and the controller's model of what happened matches reality. Selecting rank 0 executes a command on a device the controller was not addressing, and Chapter 4.5 §3 established a misdirected command has unbounded blast radius: it can precharge a bank in use or activate a wrong row, corrupting state belonging to an access that was never issued. The two failure modes are not comparable, and §6's P3 fixes the choice so a later change cannot silently invert it.

5. A command bus shows 85% deselect events. Is the interface underutilised? Not necessarily, and probably not. Deselects create the minimum separations between commands that Modules 13 and 14 require — same-bank-group spacing, activate-to-activate intervals, and so on. The command bus being mostly deselect is normal; what would indicate underutilisation is the data bus being idle, which is a different measurement entirely.

6. In DDR5, a controller needs to change a device's termination setting. How does that differ from DDR4, and what must the controller's scheduler account for? In DDR4 it asserts a dedicated ODT wire, outside the command stream. In DDR5 it issues a command — CS_n plus CA encoding — which must be scheduled, occupies a command-bus event, and competes with reads and writes. The scheduler must budget command bandwidth for control actions that previously consumed none, and a naive port will under-provision it.

12. Summary

The command and address bus is a broadcast. It reaches every rank on a channel and carries no device address — because replicating the command path per device would multiply the system's most expensive and most heavily loaded signals, which is exactly what Chapter 4.4 showed the interface works hard to avoid.

CS# is what converts that broadcast into an instruction. One active-low wire per rank, evaluated fresh at every sampling event, with no memory — the contrast with CKE's state-with-history semantics being the structural point.

It is one-hot-or-none, not one-hot. Deselect is legal, common, and usually the most frequent state on the bus. That makes $onehot0 the correct property, and the trap is real: $onehot fails constantly and tends to get weakened past the point where it catches the genuine fault of two ranks acting on one command.

Deselect is doing work. It occupies the bus between commands, it is how the controller creates the minimum separations Modules 13 and 14 require, and it bounds the interface's sensitivity — only qualified events carry obligations, so a disturbance on the CA lines during deselect is harmless.

Selection is not data-bus ownership. CS# qualifies one command event; Chapter 5.4's ownership spans a whole burst with grant, duration and handoff. Different resources, different lifetimes, and they can legitimately be out of step.

An invalid selection must deselect, not default. Selecting nothing is harmless; selecting the wrong rank has unbounded blast radius.

And DDR5 loaded more onto CS_n — power-down entry and exit, and termination control — because every function being moved is per-device, and CS_n was already the per-device selector. The cost is that control actions which were independent wires become scheduled commands, competing for command-bus bandwidth.

13. What Comes Next

The next three chapters take a group of signals that once carried the command itself.

Chapter 6.4 begins with RAS# — a signal whose name describes a mechanism that no longer exists, in an interface where it is no longer a dedicated pin. It is the first of the RAS# / CAS# / WE# trio, and the trio's real lesson is not what each one did but what happened when three signals could no longer encode enough commands.

That question — and DDR4's answer to it — is where Chapter 6.6 ends up, and it is the clearest demonstration in this module of pins giving way to encoding.

Return to CK / CK# for the sampling events CS# qualifies, CKE for the other qualification signal and its history semantics, or Ranks for the structure chip select selects among. The full path is on the DDR tutorials index.

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.