DDR · Module 7
Activate (ACT)
ACT opens a row, and it is the right place to establish what a DDR command actually is: a sampled encoding, qualified for a target, carrying operands, interpreted against device state — four separate questions that must not be collapsed.
Module 6 established what crosses a DDR interface: which wires exist, who drives each one, when it is sampled, and how the set changed across generations. It stopped deliberately short of what the values mean.
This module closes that gap, and its question is:
How do encodings on the command interface cause a DRAM device to perform operations?
That sounds like it should be answered by a table. It is not, and the single most important thing this chapter does is explain why — because a table answers one of four questions and people routinely assume it answers all four.
Activate is the right command to start with. It is the only command that opens a row, so every other command in this module depends on it having happened. And because it is the first, it carries the module's conceptual scaffolding.
1. What Activate Requests
Semantically, ACT says: open row R in bank B.
That is all. It names a bank, it names a row, and it asks for that row to be brought into the bank's sense amplifiers. It moves no data. It produces nothing on DQ. The requester does not yet know which columns it wants, and does not need to.
What it changes is state. Chapter 5.2 established that a bank holds one open row at a time and that this is the scope of row-state exclusivity. ACT is the command that sets it:
bank B CLOSED + ACT(B, R) -> bank B OPEN with row RAnd what it requires is that the bank be closed. A bank already holding an open row cannot activate another — Chapter 5.2 §5's illegal_activate. To change rows you must precharge first, which is Chapter 7.4.
2. A Command Is Not a Signal
Chapter 6.4 §7 already dismantled "RAS# means activate". The command model makes the correction precise.
A command requires four things simultaneously, and missing any one means no command happened:
A sampling event. Chapter 6.1 §2: a command is a value sampled at a defined instant, not a level held on a wire.
Target qualification. Chapter 6.3 §1: the command bus is a broadcast. Every rank sees every encoding, and CS# decides which one acts. An unqualified encoding is not a command — it is a deselect, and the CA lines carry no obligation.
An encoding. The pattern that says which operation.
Operands. The bank, the row, and — as §5 shows — flags whose meaning depends on which command carries them.
So "which signal means activate" is not a well-formed question. In DDR3 the answer involves a combination of dedicated pins. In DDR4, ACT_n asserted low is the activate indication, and at that same event the three pins named RAS_n/CAS_n/WE_n are carrying row address bits. In DDR5 the command/address interface is encoded differently again.
The semantics are stable and the encoding is not — which is exactly why a controller should not think in pins.
3. Semantic Commands, and Why the Separation Matters
Here is the module's most valuable architectural lesson, and it is a design principle rather than a fact about DDR.
A memory controller's scheduling logic should reason in operations, not in pin patterns.
controller intent "I need row 500 of bank 3"
|
scheduler reasons in ACT / RD / WR / PRE / REF / MRS
|
semantic command DDR_CMD_ACT, bank=3, row=500
|
generation-specific encoder maps the operation onto this generation's CA
|
PHY launches the CA lines with correct electrical timing
|
CK sampling event the device samples
|
DRAM command decoder recovers the operation
|
state transition bank 3 now holds row 500The dashed return is not a message. Chapter 4.1 §4 established that DDR has no per-command acknowledgement — the device does not reply. It represents state the controller must model, which is why Chapter 5.2 §4 called the per-bank table a correctness structure rather than an optimisation.
4. RTL — The Semantic Command and Its Encoder
Engineering problem
Represent a command as an operation with operands, and map it onto a generation-specific encoding at a single, replaceable boundary.
Classification
SYNTHESIZABLE RTL — an educational controller/encoder-boundary architecture.
What it represents: the semantic command type, and the encoder that maps operations onto a generation's command/address interface.
What it explicitly does not represent: a scheduler — there is no queue, no arbitration, no reordering, and Module 17 owns those. No address decomposition into fields. No timing of any kind. No PHY: the encoder produces logical values, and Chapter 6.1 §8 established that turning them into electrically correct waveforms is the PHY's job.
Interface contract
cmd_valid with cmd and its operands presents a semantic command. The outputs are the generation-specific interface values. encode_unsupported reports an operation this generation's encoder cannot express.
State
Registered outputs only. Encoding is a pure function of the semantic command — which is the point: no history, no context, nothing to get out of step.
Combinational behaviour
The operation-to-encoding mapping and the operand placement.
Sequential behaviour
Output registration at the launch event.
How to simulate
vlog ddr_cmd_encode.sv tb_ddr_cmd_encode.sv then vsim -c tb_ddr_cmd_encode -do "run -all"; VCS vcs -sverilog ddr_cmd_encode.sv tb_ddr_cmd_encode.sv && ./simv; Xcelium xrun -sv ddr_cmd_encode.sv tb_ddr_cmd_encode.sv. Every RTL block in Module 7 simulates the same way.
Expected output
The same semantic DDR_CMD_ACT produces different interface values at GEN = 3 and GEN = 4 — the encoder absorbing the generation difference while the input is unchanged.
// ─────────────────────────────────────────────────────────────────────────
// DDR SEMANTIC COMMAND TYPE AND ENCODER.
// Classification: SYNTHESIZABLE RTL -- an educational
// CONTROLLER/ENCODER-BOUNDARY architecture.
//
// THE ARCHITECTURAL LESSON: a controller's scheduling logic should reason
// in OPERATIONS, not in pin patterns. The operations are stable across
// generations; the encoding is not. Putting the boundary here means the
// scheduler is generation-portable and only this block changes.
//
// ############ THE COMMAND BIT VALUES BELOW ARE EDUCATIONAL ############
// They are PLACEHOLDERS chosen so the structure of encoding is visible.
// They are NOT JEDEC encodings and correspond to no generation's actual
// bit combinations. Read the device specification for real encodings.
//
// WHAT IS REAL AND MODELLED STRUCTURALLY (verified, Chapter 6.6):
// DDR4 has a dedicated ACT_n. ACT_n LOW means "this is an activate",
// and the three multi-function balls then carry row address bits A16,
// A15, A14. ACT_n HIGH means those balls carry the legacy command bits.
// DDR3 has no ACT_n; the activate is one of the pin encodings.
// ######################################################################
//
// WHAT THIS DOES NOT REPRESENT: a scheduler (no queue, no arbitration, no
// reordering -- Module 17), address decomposition into fields (Module 8),
// any timing whatsoever (Modules 13/14), and the PHY -- this block emits
// LOGICAL values and Chapter 6.1 established that making them electrically
// correct is the PHY's job. DDR5's CA encoding is not modelled (Module 25).
// ─────────────────────────────────────────────────────────────────────────
// ── The semantic command set. NOT a JEDEC-defined type: this is an
// educational RTL architecture. The set here covers the operations
// Module 7's canonical chapters own.
typedef enum logic [2:0] {
DDR_CMD_NOP = 3'd0, // occupy the bus, request nothing (Section 6)
DDR_CMD_ACT = 3'd1, // open a row (this chapter)
DDR_CMD_RD = 3'd2, // column read (Chapter 7.2)
DDR_CMD_WR = 3'd3, // column write (Chapter 7.3)
DDR_CMD_PRE = 3'd4, // close a bank (Chapter 7.4)
DDR_CMD_REF = 3'd5, // refresh (Chapter 7.5)
DDR_CMD_MRS = 3'd6 // mode register set (Chapter 7.6)
} ddr_cmd_e;
module ddr_cmd_encode #(
// 3 = DDR3-style dedicated command pins, no ACT_n.
// 4 = DDR4-style with a dedicated ACT_n selecting the pin interpretation.
parameter int GEN = 4,
parameter int ROW_W = 17,
parameter int BANK_W = 4
) (
input logic clk,
input logic rst_n,
// ── Semantic input. This is what a scheduler emits.
input logic cmd_valid,
input ddr_cmd_e cmd,
input logic [BANK_W-1:0] cmd_bank,
input logic [ROW_W-1:0] cmd_row,
// ── Generation-specific interface output.
output logic cs_n,
// Present only in the DDR4-style encoding. Held deasserted at GEN 3,
// where no such signal exists.
output logic act_n,
// The three multi-function balls of Chapter 6.6. Their meaning depends
// on act_n, which is the whole point of that chapter.
output logic pin_ras_a16,
output logic pin_cas_a15,
output logic pin_we_a14,
output logic [ROW_W-4:0] addr_low,
output logic [BANK_W-1:0] bank_out,
// An operation this generation's encoder cannot express. Reported, never
// silently substituted -- emitting a different command than the
// scheduler asked for is the worst available failure.
output logic encode_unsupported
);
// ── COMPILE-TIME legality.
if ((GEN != 3) && (GEN != 4)) begin : g_gen
initial $fatal(1, "ddr_cmd_encode: GEN must be 3 or 4 (DDR5 is Module 25)");
end
// Three bits are multiplexed with address in the GEN 4 encoding, so the
// row address needs room for them plus at least one always-address bit.
if (ROW_W < 4) begin : g_row
initial $fatal(1, "ddr_cmd_encode: ROW_W must be >= 4");
end
if (BANK_W < 1) begin : g_bank
initial $fatal(1, "ddr_cmd_encode: BANK_W must be >= 1");
end
// ── EDUCATIONAL command patterns for the three legacy-style bits.
// Placeholders. Not JEDEC. See the header.
localparam logic [2:0] ENC_NOP = 3'b111;
localparam logic [2:0] ENC_ACT = 3'b011;
localparam logic [2:0] ENC_RD = 3'b101;
localparam logic [2:0] ENC_WR = 3'b100;
localparam logic [2:0] ENC_PRE = 3'b010;
localparam logic [2:0] ENC_REF = 3'b001;
localparam logic [2:0] ENC_MRS = 3'b000;
logic [2:0] enc_bits;
logic unsupported_now;
logic is_activate;
always_comb begin
// Default to the no-operation encoding. A default that decodes to NOP
// rather than to X or to an arbitrary command means an unhandled case
// requests nothing, which is the safe direction.
enc_bits = ENC_NOP;
unsupported_now = 1'b0;
is_activate = 1'b0;
unique case (cmd)
DDR_CMD_NOP: enc_bits = ENC_NOP;
DDR_CMD_ACT: begin
enc_bits = ENC_ACT;
is_activate = 1'b1;
end
DDR_CMD_RD: enc_bits = ENC_RD;
DDR_CMD_WR: enc_bits = ENC_WR;
DDR_CMD_PRE: enc_bits = ENC_PRE;
DDR_CMD_REF: enc_bits = ENC_REF;
DDR_CMD_MRS: enc_bits = ENC_MRS;
default: begin
// An operation outside the enum. Report it and encode nothing.
unsupported_now = 1'b1;
enc_bits = ENC_NOP;
end
endcase
end
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
// Reset to a fully deselected, non-committal interface. Chapter 6.3:
// deselect is a legal and meaningful state, and it is the right
// reset value because it requests nothing of any device.
cs_n <= 1'b1;
act_n <= 1'b1;
pin_ras_a16 <= 1'b1;
pin_cas_a15 <= 1'b1;
pin_we_a14 <= 1'b1;
addr_low <= '0;
bank_out <= '0;
encode_unsupported <= 1'b0;
end else begin
encode_unsupported <= 1'b0;
if (!cmd_valid) begin
// No command: deselect. Chapter 6.3 Section 3 established this is
// how a controller occupies the bus without requesting anything.
cs_n <= 1'b1;
act_n <= 1'b1;
end else begin
cs_n <= 1'b0;
encode_unsupported <= unsupported_now;
bank_out <= cmd_bank;
if (GEN == 4) begin
// ── DDR4-style. VERIFIED STRUCTURE (Chapter 6.6): ACT_n low
// means activate, and the three balls then carry the TOP
// three row-address bits. ACT_n high means they carry the
// legacy command bits.
act_n <= ~is_activate;
if (is_activate) begin
{pin_ras_a16, pin_cas_a15, pin_we_a14} <= cmd_row[ROW_W-1:ROW_W-3];
addr_low <= cmd_row[ROW_W-4:0];
end else begin
{pin_ras_a16, pin_cas_a15, pin_we_a14} <= enc_bits;
addr_low <= '0;
end
end else begin
// ── DDR3-style. No ACT_n exists; the activate is one of the
// encodings, and the row address travels only on the
// dedicated address lines. Held deasserted so a GEN 3
// instance never drives a signal its generation lacks.
act_n <= 1'b1;
{pin_ras_a16, pin_cas_a15, pin_we_a14} <= enc_bits;
addr_low <= cmd_row[ROW_W-4:0];
end
end
end
end
endmoduleCycle-by-cycle example
ROW_W = 17, semantic input DDR_CMD_ACT, bank=3, row=0x1A5C5:
GEN | cs_n | act_n | three balls | addr_low |
|---|---|---|---|---|
| 4 | 0 | 0 | row bits A16..A14 | remaining row bits |
| 3 | 0 | 1 (absent) | ENC_ACT | remaining row bits |
The semantic input is byte-identical in both rows. The scheduler that produced it does not know which generation it is driving. That is the payoff — and it is why GEN is a parameter of this block and of nothing upstream.
And notice what GEN 4 does with the row address. Three of its bits travel on balls named after command signals, because ACT_n has claimed the activate indication and freed them. Chapter 6.6 §3 derived why; here it is the encoder's job to place them.
Waveform expectation
§7. Watch cs_n fall as the command is launched and the three balls carry address rather than an encoding when act_n is low.
Synthesis implication
A small combinational decode plus output registers — tens of flops. Negligible, and that is the point: the layer that makes a controller generation-portable costs almost nothing. In a real controller this sits immediately before the PHY interface, and the GEN parameter would typically be a build-time configuration rather than a runtime one.
Corner cases
GEN outside {3, 4} does not elaborate — DDR5 is Module 25's and modelling it here would be a fiction. ROW_W == 4 gives a one-bit addr_low, the minimum legal configuration and the one where the concatenation widths are easiest to get wrong. A command outside the enum reports encode_unsupported and encodes NOP, never a substituted command. cmd_valid low produces deselect, which is also the reset state.
Debugging clues
If a GEN 4 activate produces a command encoding on the three balls instead of address bits, is_activate is not feeding act_n — and the device will decode whatever those row bits happen to look like. If the row address is short by three bits or has them misplaced, check the concatenation: the multiplexed bits are the most significant three, and putting them at the bottom produces plausible addresses for wrong rows, silently. If a GEN 3 instance drives act_n, the generation guard has been dropped.
Limitations
No scheduler, no queue, no arbitration. No timing. No address decomposition. No PHY. No DDR5. And the command bit values are educational placeholders, as the header states at length — the structure is verified and the values are not real.
5. Operands Mean Different Things in Different Commands
This is the observation that unifies the next three chapters, and it is worth meeting here.
An operand's meaning depends on which command carries it. The same physical address bit is interpreted differently depending on the operation it accompanies.
The clearest verified case, which Chapter 7.2 and Chapter 7.4 both build on: address bit A10 in DDR4.
A10 sampled with a READ or WRITE -> auto-precharge flag
HIGH = precharge after the access
A10 sampled with a PRECHARGE -> scope selector
HIGH = all banks, LOW = one bankSame wire, same sampling event, two unrelated meanings — and nothing distinguishes them except the command encoding present at the same event.
Chapter 7.6 has another: the bank and bank-group bits, which name a bank during ACT, RD and WR, select a mode register number during MRS.
6. NOP and Deselect Are Not the Same Thing
No canonical chapter in this module owns no-operation, so it belongs here — and the distinction is real.
Deselect is an event where CS# is not asserted. Chapter 6.3 §2 established that this is legal, common, and typically the most frequent state on the bus. The device is not addressed, so the CA lines carry no obligation and no command exists.
A no-operation command is an event where the device is addressed and the encoding requests nothing. The command bus is qualified, the encoding is decoded, and the resulting operation is "do nothing".
Both result in no state change, and they are different events.
Why the difference matters practically, in three ways.
A monitor must distinguish them. A deselect is not a command and should not appear in a command trace; a decoded no-operation is a command and should. A monitor that reports every event as a command produces a trace dominated by deselects, and a monitor that reports neither loses real commands.
They have different obligations on the CA lines. Chapter 6.1 §4 established that stability is owed only at qualified events. On a deselect the CA lines may carry anything; on a qualified no-operation they must be stable and must decode to the no-operation encoding.
And the generations treat them differently. Whether a dedicated no-operation encoding exists, and whether it is recommended over deselect, is generation- and device-specific. This module's DDR_CMD_NOP is the semantic "request nothing", and §4's encoder maps cmd_valid low to deselect and DDR_CMD_NOP to a qualified encoding — which makes the distinction structural rather than a matter of convention.
7. From Intent to State, in Cycles
ddr_cmd_encode — an activate travelling through the pipeline
10 cyclesFollow one command down the trace. The semantic ACT appears at cycle 1. The encoder drives the interface at cycle 2 — cs_n low, act_n low, and the three balls carrying ROW rather than a command encoding. The decode reports at cycle 3. The bank state changes at cycle 4.
Four distinct events for one command, and they are in four different layers. An engineer debugging "the wrong row opened" needs to know which of the four went wrong, and §9 is built on exactly that.
Cycle 6's NOP is the §6 distinction. cmd_valid was high at cycle 4, so the event was qualified — cs_n low — and the encoding requested nothing. Contrast cycles 2, 5 and 8, where cs_n is low because a command was launched, and cycles 0, 1, 3 and 9 where nothing was qualified at all.
These are representative educational cycles. The one-cycle encode and one-cycle decode latencies are properties of this model, and the interval between a command and its state change is not a timing requirement — Modules 13 and 14 own those.
8. Three Assertions Worth Writing
// VERIFICATION-ONLY, inside ddr_cmd_encode.
// P1 -- an unsupported operation encodes NOTHING. Substituting a different
// command would send the device an operation the scheduler never asked
// for, which is the worst available failure: the controller's state model
// and the device's state diverge with no error anywhere.
property p_unsupported_encodes_nop;
@(posedge clk) disable iff (!rst_n)
encode_unsupported |-> ({pin_ras_a16, pin_cas_a15, pin_we_a14} == ENC_NOP);
endproperty
assert property (p_unsupported_encodes_nop);
// P2 -- THE GENERATION PROPERTY. In the DDR4-style encoding, act_n is
// asserted exactly for an activate, and the three balls then carry row
// address rather than a command encoding. This is the verified structural
// fact of Chapter 6.6, asserted here so the encoder cannot drift from it.
property p_act_n_only_for_activate;
@(posedge clk) disable iff (!rst_n)
((GEN == 4) && !cs_n && !act_n) |-> ($past(cmd) == DDR_CMD_ACT);
endproperty
assert property (p_act_n_only_for_activate);
property p_act_n_carries_address;
@(posedge clk) disable iff (!rst_n)
((GEN == 4) && !cs_n && !act_n)
|-> ({pin_ras_a16, pin_cas_a15, pin_we_a14}
== $past(cmd_row[ROW_W-1:ROW_W-3]));
endproperty
assert property (p_act_n_carries_address);
// P3 -- a generation never drives a signal it does not have. At GEN 3
// there is no ACT_n, and an encoder that drove it would be describing
// hardware that does not exist.
property p_gen3_no_act_n;
@(posedge clk) disable iff (!rst_n)
(GEN == 3) |-> act_n;
endproperty
assert property (p_gen3_no_act_n);
// P4 -- no command without qualification. Chapter 6.3: an unqualified
// event is not a command, so a valid semantic command must produce an
// asserted chip select and no command must appear without one.
property p_qualified_iff_commanded;
@(posedge clk) disable iff (!rst_n)
$past(cmd_valid) |-> !cs_n;
endproperty
assert property (p_qualified_iff_commanded);P2 is the property that keeps the encoder honest about the generation it claims to implement. It is the only assertion here tied to a verified external fact rather than to internal consistency — and that makes it the one worth re-checking whenever the specification reference changes.
P1 encodes a safety direction. There are two ways to handle an operation the encoder cannot express: emit nothing, or emit something. They are not equally bad. Emitting nothing leaves the device's state matching the controller's model; emitting a substitute diverges them silently. The property fixes the choice so a later change cannot invert it.
What none of them prove. Nothing about whether the CA lines are electrically valid — Chapter 6.1 §6 established that setup, hold, jitter and margin are analog and unreachable by any digital assertion. Nothing about state legality: this encoder will happily encode an ACT to a bank that is already open, because encoding legality and state legality are different questions and §1's four-question model exists to keep them apart. And nothing about timing legality at all.
9. Debugging — The Wrong Row Opened
Symptom. A controller intended to activate row R in bank B. A different row is open, or a different bank. No errors reported anywhere.
§3's pipeline is the diagnostic structure, and this is its main payoff: the wrong operation reached the device, and there are four layers it could have gone wrong in. The productive first move is not to look at the pins but to find the earliest layer where intent and reality disagree.
Mechanism 1 — the scheduler's intent was already wrong. Inspect: the semantic command the scheduler emitted, upstream of the encoder. Expected evidence: DDR_CMD_ACT carrying the wrong row or bank operand. Discriminator: compare intent against the request that produced it. This is first because it costs nothing and because it eliminates the entire interface if true — an address-mapping error produces exactly this symptom and lives in Module 18.
Mechanism 2 — the encoder placed the operands wrongly. Inspect: the interface values against the semantic command. Expected evidence: the semantic command correct and the encoded row address differing — classically by a permutation of the top three bits, because Chapter 6.6's multiplexed balls carry them. Discriminator: compare the intended row number against the encoded one in binary. Chapter 6.6 §9 established this: a discrepancy confined to particular bit positions names a concatenation fault, while a scattered one names something upstream.
Mechanism 3 — the encoding was correct and the device decoded it differently. Inspect: whether ACT_n's interpretation matches on both sides. Expected evidence: a DDR4 device treating the three balls as a command encoding when the controller sent address, or the reverse. Discriminator: do phantom commands correlate with activates? Chapter 6.4 §9's first mechanism — and it points at a generation mismatch between the encoder and the device, not at a bug in either.
Mechanism 4 — the command was fine and the state was not what the controller believed. Inspect: whether the bank was already open when the ACT was issued. Expected evidence: the activate refused, leaving the previous row open — so the "wrong" row is a legitimately stale one. Discriminator: was the bank closed? This is a state-legality failure rather than an encoding one, and Chapter 5.2 §5's illegal_activate is the check that catches it. The symptom is identical and the layer is completely different.
Mechanism 5 — not the command path: the CA lines were not stable. Inspect: whether errors scale with rate or vary with temperature. Expected evidence: intermittent wrong rows rather than consistent ones. Discriminator: is it consistent or intermittent? A consistent wrong row is a logic fault — mechanisms 1 to 4. An intermittent one is Chapter 6.1 §10's margin territory, and no amount of reviewing encoder logic will find it.
Discrimination, cheapest first. Ask whether the fault is consistent or intermittent — one question, splitting mechanism 5 off entirely and deciding whether this is a logic investigation or a margin one. Then compare the scheduler's semantic intent against the request. Then compare the intended row against the encoded row in binary. Then check whether the bank was open.
The reasoning lesson. The semantic layer exists so this question has somewhere to be asked. Without it, "the wrong row opened" is one undifferentiated fault spanning four layers; with it, the scheduler's output is a small comparable value that either matches intent or does not — and that single comparison cuts the search in half before any waveform is examined. A layer that makes a bug locatable earns its place even when it costs logic, and this one costs almost none.
10. Common Misconceptions
"RAS# means activate." Wrong model: one control signal identifies the operation. Why it is tempting: it was true for SDR through DDR3, the name says "row", and most introductory material stops there. Consequence: a wrong reading of any DDR4 command interface. Chapter 6.6 §3 verified that DDR4's activate is signalled by ACT_n, and at that same event the ball named RAS_n is carrying row-address bit A16. A decoder built on this model reports a phantom command on every activate. Correct model: a command is a sampled encoding plus qualification plus operands, and which signals carry the encoding is generation-specific. The semantics — open a row — are stable; the encoding is not. Prevention: ask what identifies the operation in this generation. If you cannot name the selector, you cannot decode the interface.
"If the bit pattern decodes, the command is legal." Wrong model: successful decode implies executability. Why it is tempting: in most digital interfaces a well-formed request is a valid one, and decode is the visible step. Consequence: no state checking in the controller, and the four-question model collapsed to one. A perfectly decoded READ to a bank with no open row is a legal encoding and an illegal operation — and the device's response is not a helpful error but undefined behaviour or data from whatever row happens to be open, which Chapter 5.2 §4 showed returns plausible wrong data silently. Correct model: encoding legality, state legality and timing legality are three separate questions with three different owners. Decode answers only the first. Prevention: for any command, ask what must already be true. If the answer is "a row must be open", decode has not established it.
"The controller should store raw DDR pin combinations internally." Wrong model: the controller's natural representation is the wire format. Why it is tempting: it is what goes out, so carrying it internally seems to avoid a translation. Consequence: scheduling logic that must be rewritten for each generation despite the scheduling decisions being identical, a checker that needs the encoder's logic before it can compare anything, and — most damaging — no layer at which to ask whether the intent or the encoding was wrong. §9's investigation has nowhere to start. Correct model: the scheduler reasons in semantic operations; a single replaceable encoder maps them to the generation's representation. Operations are architecture; encodings are a generation detail. Prevention: ask whether a change of DDR generation would touch your scheduling logic. If it would, the boundary is in the wrong place.
"NOP and deselect are the same thing." Wrong model: both mean nothing happens, so they are interchangeable. Why it is tempting: the observable outcome — no state change — is identical. Consequence: a monitor that cannot produce a useful command trace, reporting either every bus event as a command or none. And a misunderstanding of the CA lines' obligations: Chapter 6.1 §4 established that stability is owed only at qualified events, so a deselect imposes none and a qualified no-operation does. Correct model: deselect is not a command — the device is not addressed. A no-operation is a command — the device is addressed and the encoding requests nothing. Prevention: look at chip select. If it is deasserted, nothing was commanded.
"A correct functional simulation proves the CA timing is valid." Wrong model: if the right commands arrive in simulation, the interface works. Why it is tempting: the commands genuinely do arrive correctly, and that is real evidence about the logic. Consequence: shipping an interface whose command lines do not meet their setup requirement, producing the hardest fault class — Chapter 6.1 §10's intermittent misinterpretation with no functional failure. Simulation has no representation of setup, hold, jitter or margin, so it cannot distinguish an adequately timed command from a marginal one. Correct model: functional simulation verifies encoding, semantics and state legality. CA timing validity is established by static timing analysis, PHY characterisation and measurement — and Chapter 6.1 §6 explains why no digital assertion reaches it. Prevention: keep an explicit list of properties simulation cannot validate. Command-line timing belongs on it.
11. Interview Reasoning
"What actually makes a DDR command a command?" Four things simultaneously. A sampling event, because a command is a value sampled at a defined instant rather than a level held on a wire. Target qualification, because the command bus is a broadcast that every rank receives — chip select is what decides which device acts, so an unqualified encoding is not a command at all. An encoding that identifies the operation. And operands, which for an activate are the bank and the row. Missing any one of those and no command happened, which is why "which signal means activate" is not a well-formed question.
"Why separate a semantic command from its pin encoding in a controller?" Because the operations are stable across generations and the encodings are not. A scheduler's decisions — which bank to open, when to precharge, how to interleave — are identical for DDR3, DDR4 and DDR5, so putting the boundary before the encoding means only the encoder changes. It also makes the scheduler testable, since a semantic command is a small enumerated value that can be compared against a reference model directly, rather than a pin pattern the checker must decode using logic it might share bugs with. And most practically, it gives you a place to stand when the wrong operation reaches the device: you can ask whether the intent was wrong or the encoding was wrong, and those are different bugs in different layers.
"Why can a valid command encoding still be an illegal command?" Because decoding and legality are different questions. Decode tells you what operation the bits request; it says nothing about whether that operation is permitted in the device's current state. A READ that decodes perfectly is illegal if the target bank has no open row, because a column access reads from whatever row is currently held in the sense amplifiers and there is nothing there. There is also a fourth question beyond that — whether the operation is allowed now, given how recently the previous command was issued — and that is timing legality, which belongs to the timing modules. Four questions, four different causes, four different owners.
"What does ACT require and what does it change?" It requires that the target bank be closed, and it changes that bank's state to open holding the named row. It moves no data and produces nothing on the data bus — the requester has not yet said which columns it wants and does not need to. The prerequisite is the important half: a bank already holding an open row cannot activate another, so changing rows means precharging first. That is why the activate is the command every other command in the module depends on having happened.
"A controller intended to open row R and a different row is open. How do you narrow it down?" First by asking whether the fault is consistent or intermittent, because that decides whether this is a logic investigation or a margin one — a consistently wrong row is logic, an intermittent one is command-line timing and no amount of reviewing encoder code will find it. If it is consistent, compare the scheduler's semantic output against the request that produced it, because an address-mapping error produces this symptom and eliminates the interface entirely if true. Then compare the intended row number against the encoded one in binary rather than decimal, because a discrepancy confined to the top three bits points at the multiplexed command balls being concatenated in the wrong positions. And it is worth checking whether the bank was already open when the activate was issued, because then the activate was refused and the "wrong" row is a legitimately stale one — a state-legality failure with an identical symptom and a completely different cause.
12. Engineering Exercise
Educational encodings and cycle counts throughout; no timing parameters are implied.
1. A decoder reports a well-formed READ. Name two further questions before the device can execute it. State legality — does the target bank have an open row? And timing legality — has enough separation elapsed since the previous command? Decode answered neither, and the two have different owners: this module and Modules 13/14 respectively.
2. §4's encoder is given DDR_CMD_ACT at GEN = 4 and at GEN = 3. What differs at the interface, and what differs upstream? At the interface: GEN 4 asserts act_n low and places row bits on the three multi-function balls; GEN 3 places an encoding there and drives no act_n. Upstream, nothing differs at all — the semantic command is identical. That is the entire value of the boundary.
3. A DDR4 device decodes a command on every activate the controller issues. Which layer, and what is the fingerprint? The decoder is reading the three balls as a command encoding while act_n is low and they carry address. The fingerprint is that the phantom rate equals the activate rate exactly — Chapter 6.4 §9's first mechanism. It is a generation-interpretation mismatch, not a bug in either side's logic.
4. Why does §4's encoder report encode_unsupported rather than substituting a similar command? Because substituting sends the device an operation the scheduler never requested, so the controller's state model and the device's state diverge with no error anywhere — and Chapter 5.2 §4 showed that divergence surfaces later as plausible wrong data. Encoding nothing keeps them consistent, which is the safe direction and is why §8's P1 fixes the choice.
5. Classify: a controller issues ACT to bank 3, then ACT to bank 3 again with a different row, with no intervening command. What fails, and which of the four questions? The second activate. Encoding is fine, semantics are fine, and state legality fails — bank 3 already holds an open row, so Chapter 5.2's illegal_activate applies. A precharge must come between them. Note that this is not a timing failure; it would be illegal after any interval.
6. A scheduler is being ported from DDR3 to DDR4. Using §3's pipeline, name what must change and what must not. The encoder must change — act_n, the multiplexed ball placement, the encoding values. The scheduler must not change at all: which bank to open, when to precharge, how to order accesses are the same decisions. If the port touches scheduling logic, the semantic boundary was in the wrong place — which is §10's third misconception, and the test for it.
13. Summary
A command is not a signal. It is a sampled encoding, qualified for a target, carrying operands, interpreted against device state — and those are four requirements that must all hold.
The module's organising idea is that four different questions get conflated. Encoding — what bits were sampled, generation-specific. Semantics — what operation they request, generation-independent. State legality — whether that operation is allowed given current state, which this module owns. Timing legality — whether it is allowed now, which Modules 13 and 14 own. A command can pass the first two and fail the third; it can pass three and fail the fourth.
ACT requests: open row R in bank B. It moves no data. It requires the bank closed and changes it to open holding that row — and every other command in this module depends on it having happened.
A controller should reason in operations, not pin patterns. The scheduler emits semantic commands; a single replaceable encoder maps them to the generation's representation. That buys generation portability, testability, and — most practically — a layer at which to ask whether a fault was intent or encoding. §9's investigation has nowhere to start without it.
Operands mean different things in different commands. Verified: DDR4's A10 is an auto-precharge flag with a read or write, and a scope selector with a precharge. Bank bits name a bank with ACT and select a mode register with MRS. So decode is ordered — identify the operation, then interpret its operands — and a decoder that extracts fields in parallel will misread half of them.
And NOP is not deselect. A deselect is not a command: the device is not addressed and the CA lines carry no obligation. A no-operation is a command: the device is addressed and the encoding requests nothing.
14. What Comes Next
Chapter 7.2 takes the first command that depends on this one.
READ names a column in a row that is already open — it does not open anything, which is the misconception the chapter has to dismantle. And it introduces the auto-precharge variant: RDA is not a different command but a READ carrying A10 high, which schedules a precharge the controller never explicitly issues.
That makes 7.2 the natural home for the decoder — the inverse of §4's encoder — because extracting an operand whose meaning depends on the command is exactly what a decoder has to get right.
Return to CK / CK# for the sampling event a command is defined by, CS# for the qualification that makes an encoding a command, WE# for DDR4's ACT_n and the multi-function balls, or Banks for the row state ACT changes. The full path is on the DDR tutorials index.
Continue learning
Related tutorials
- Related topic
CKE — Clock Enable
CKE decides whether a device samples commands at all. It qualifies using its previous value rather than its current one — and in DDR5 the function survives while the dedicated pin does not.
- Related topic
Bank-Group Address
Bank groups are a DDR4 and DDR5 field, which makes this the first address field that may not exist. How the bank index splits between group and bank decides whether consecutive accesses are neighbours or strangers.
- Related topic
Row Opening
ACTIVATE transfers no data. It changes a bank from closed to holding one row, and it does so over an interval rather than instantly — which is why a bank has transitional states and why a controller must track them.
- Related topic
Burst Reads
One read command returns several transfers because the array moves more data per access than the interface is wide. That makes beat counting a correctness obligation, not bookkeeping.
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.
