Skip to content
VLSI Mentor

DDR · Module 2

Restore Operations

Sensing consumed the stored state, so something must put it back. What restoration drives, why it covers a whole row, why a restored row is then cheap to access again, and an educational control model that cannot skip a prerequisite the array is unable to enforce.

Chapter 2.5 followed a read through five stages and stopped at the last one. The charge was shared away, the small shift was amplified into a full-strength value, and then the chapter said the access could not end — because the cell was left holding a condition close to the reference and far from either target.

This chapter is that final stage, and it closes Module 2. The central question:

Sensing has produced a strong, correct value and the cell has lost its state. What has to happen next, what does it cost, and what does a digital system have to build so that it cannot get the order wrong?

The first two answers are mechanism. The third is where this module's physics finally becomes state machines and assertions — and where the answer to the question a software engineer finds strangest about DRAM stops being a curiosity and becomes obvious.

1. What Restoration Actually Drives

Be precise about the direction of the work, because the surprising part is which component does it.

After sensing, two things are true at once. The cell holds a diluted condition that carries no recoverable information. The sensing circuitry holds the resolved value at full strength — a strong, definite digital condition, produced by amplification.

So the repair is available, and it has a specific shape: the strong thing drives the weak thing. The sensing circuitry, still connected to the bitline, and the bitline still connected to the cell through the access transistor that has remained on, drives the bitline to the full level corresponding to the resolved value. The cell, connected to that bitline, is charged or discharged toward the same level. When the wordline eventually falls, the cell is left isolated again — this time holding a properly separated state.

Three points that matter and are easy to get backwards.

The cell is a passive recipient. It does not participate in its own repair; it has no drive and no gain (Chapter 2.1 §4). It is charged up or drained down by something stronger than itself, through the same switch and the same wire that consumed it.

The access transistor must still be on. Restoration happens through the connection that caused the destruction. If the wordline fell when the data became known, the path to the cell would be gone and the cell would keep its diluted condition — Chapter 2.5 §12's failure, viewed from the other side.

And restoration is only possible because sensing amplified. Nothing before stage 4 was strong enough to restore anything: not the cell, and not the small shared condition on the bitline. This is why the ordering is rigid rather than conventional — the repair depends on the product of the operation that broke it.

2. Why the Whole Row

A read asked for one location. Restoration covers an entire row, and this is not an optimisation — it is forced, twice over.

It is forced by selection. One wordline serves many cells (Chapter 2.4 §3), so asserting it connected every cell in the row to its own bitline. Every one of them shared its charge away. Every one of them now holds a diluted condition. A read of one location destroyed a whole row's worth of stored states, so a whole row's worth must be repaired.

It is forced by the arrangement. Each column has its own bitline and its own sensing circuitry, and each resolved its own cell independently and in parallel. So the machinery to restore every column is already engaged and already holds the right value for each. Restoring one column and abandoning the rest would not be cheaper; it would simply lose the rest.

Two consequences worth carrying well beyond this module.

The row is the unit of repair, as it was the unit of participation. Every mechanism in DRAM that operates on rows does so for this reason, traceable back to one control wire per row instead of one per cell.

And this is what makes the refresh obligation affordable. Chapter 2.3 §1 said maintenance is "inherently coarse" and pointed here for the reason. Because one operation re-establishes a whole row, the deadline can be met with a manageable number of operations. A per-cell requirement would be unmeetable — and it is worth noticing that the property making refresh affordable is the same property making a single read expensive. The row granularity is simultaneously the cost and the saving.

3. A Restored Row Is Sitting in the Sensing Circuitry

Here is the consequence that turns out to matter most for everything above the device, and it is a genuinely surprising one.

At the end of §1, the sensing circuitry for every column holds the resolved value for that column — the whole row's contents, at full strength, in digital form, outside the array. That state does not evaporate when restoration finishes. As long as the row remains selected, the row's data is available in the sensing circuitry, already resolved.

Which means a further access to a different location in the same row does not need any of Chapter 2.5's expensive stages. No bitline preparation, no connection, no charge sharing, no amplification. The value is already there; it only has to be selected and routed out.

That is the entire mechanical explanation of the behaviour Chapter 1.4 demonstrated at cycle level. The model in that chapter had an "open row" whose accesses were cheap and a row change that was expensive, and it presented that as the defining property of the tier. Here is why:

AccessWhat must happenWhy
Same row as the one already resolvedselect a column and route the value outthe row is already resolved in the sensing circuitry (§3)
Different rowfinish restoring the current row, return the bitlines to a known condition, then run all five stagesthe sensing circuitry and bitlines are occupied, and a new small signal needs a clean reference (2.5 §2)
A resolved row's values are held at full strength in the sensing circuitry outside the array. A same-row access selects a column from that resolved data and needs none of the read stages. A different-row access must first finish restoring the current row and return the bitlines to a known condition before the five stages can run again.Cell arrayrow still selectedSensing circuitryholds the resolved rowSame-row accessselect a column — cheapDifferent rowrestore, prepare, resolveresolvedroute outmust free12
Figure 1 — the resolved row stays outside the array, which is why a same-row access is cheap and a row change is not.

And this is where a fundamental idea of the whole curriculum originates. The resolved row held in the sensing circuitry is what later modules call the row buffer, and the difference between the two rows of that table is what makes a memory controller a scheduler rather than a translator: it can reorder requests to exploit the cheap case. Module 5 gives the structure its proper treatment, Module 9 the commands, and Modules 16 to 18 the scheduling and address-mapping consequences. This chapter's contribution is the derivation — the row buffer is not a cache someone added, it is the unavoidable residue of the sensing mechanism.

4. Restore Versus Refresh, Finally Side by Side

Chapter 2.3 §1 distinguished these and promised the full comparison once the mechanism was built. It is built now.

RestoreRefresh
Triggered byan access that just happeneda deadline in elapsed time
Why it is neededsensing consumed the row's chargeleakage narrowed every cell's margin
Chooses its target?no — the row that was accessedyes — a location nobody asked for
Can it be deferred?no, it is part of the accesswithin stated latitude, yes
Data used?yes, it is the access's resultno, discarded
Owned bythe device's access sequencethe controller's scheduling (2.3, Module 15)

They are the same physical operation. Both connect a row, resolve it, and drive it back at full strength. The machinery does not distinguish them.

They answer different problems. One repairs a disturbance that an access created; the other pre-empts a decay that time created. And this is exactly why a busy system still needs refresh: accesses restore only the rows they happen to touch, while the deadline applies to all of them (Chapter 2.3 §8).

Which is the cleanest way to see refresh. It is a read whose data is thrown away, issued because a clock said so rather than because anyone wanted the value. The restoration was the entire purpose.

5. The Ordering Rules This Creates

Restoration is where the physics hands the digital system a set of prerequisites. State them plainly, because §6 is about enforcing them.

R1 — A column access requires a resolved row. There is nothing to route out until sensing has produced values. Accessing a column before that returns an undecided condition.

R2 — Restoration must complete before the row is released. Dropping the wordline early leaves the cells holding diluted conditions, destroying the row. Chapter 2.5 §12 is this failure.

R3 — A different row cannot be resolved until the bitlines are returned to a known condition. A new small signal needs a clean reference (2.5 §2), and the sensing circuitry must be free.

R4 — Only one row per bitline group may be selected at a time. Two rows connected to one bitline mix their charges and destroy both (Chapter 2.4 §7).

Four rules, and note their common shape: each one is a prerequisite, and none of them can be enforced by the array. The array has no digital state, cannot refuse an illegal operation, and cannot report one (Chapter 2.4 §1). Every one of these must therefore be enforced by logic outside it — which is the last and largest thing Module 2 hands to the rest of the curriculum, and the reason the next section is RTL.

6. RTL — An Access Sequence That Cannot Skip a Step

What this models. The four ordering rules of §5, as a state machine: an access that must resolve a row before touching a column, must finish restoring before releasing it, and must return the array to a known condition before resolving a different row. It reports an error rather than proceeding when asked to do something the sequence forbids.

What it deliberately does NOT model. Any cell, charge, capacitance, bitline or sense amplifier — this is digital control over a physical mechanism, never a model of the mechanism (Chapter 2.1 §7). No DDR commands, no timing parameters, no banks, no addressing beyond a row index, no data path, no queueing, no refresh scheduling, no bursts. It is smaller than a real controller by several orders of magnitude, and Module 17 is where real controllers are built.

Interface. A requester presents req_valid with a row, a column and a kind (column access, or release the row). The model answers ack, or err when the request violates the sequence. row_open and open_row report the array's state so a requester — or a test — can see what the device believes.

How to simulate it. vlog dram_access_seq.sv tb_dram_access_seq.sv then vsim -c tb_dram_access_seq -do "run -all"; with VCS vcs -sverilog dram_access_seq.sv tb_dram_access_seq.sv && ./simv; with Xcelium xrun -sv dram_access_seq.sv tb_dram_access_seq.sv.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// EDUCATIONAL DIGITAL CONTROL MODEL of the access-sequencing rules in §5.
//
// This is NOT a DRAM cell, NOT a sense amplifier, NOT a DDR command engine,
// and NOT a memory controller. It models ONE thing: the prerequisites the
// physical mechanism imposes, and the enforcement the array cannot provide
// for itself.
//
// THE CYCLE COUNTS ARE PEDAGOGICAL, chosen to be legible in a waveform.
// They are not DDR timing parameters and no device value is implied.
module dram_access_seq #(
  parameter int ROWS          = 8,
  parameter int COLS          = 4,
  // Representative stage durations. The ORDERING is what this model teaches;
  // the values are arbitrary. Each must be >= 1.
  parameter int RESOLVE_CYCLES = 2,   // connect + share + sense (2.5 §2-§5)
  parameter int RESTORE_CYCLES = 2,   // drive the row back (§1)
  parameter int PREPARE_CYCLES = 1,   // return bitlines to a known condition
  parameter int ROW_W = (ROWS <= 1) ? 1 : $clog2(ROWS),
  parameter int COL_W = (COLS <= 1) ? 1 : $clog2(COLS)
) (
  input  logic             clk,
  input  logic             rst_n,

  // Request. Held until ack or err.
  input  logic             req_valid,
  input  logic [1:0]       req_kind,    // see kind_e
  input  logic [ROW_W-1:0] req_row,
  input  logic [COL_W-1:0] req_col,

  output logic             ack,
  // Asserted for one cycle when a request violates the sequence of §5. The
  // array itself could never report this -- that is the point of the model.
  output logic             err,

  // Array state, exposed so a requester (and §8's properties) can see it.
  output logic             row_open,
  output logic [ROW_W-1:0] open_row,
  output logic             busy
);

  typedef enum logic [1:0] {
    KIND_OPEN   = 2'd0,   // resolve a row
    KIND_COLUMN = 2'd1,   // access a column of the resolved row
    KIND_CLOSE  = 2'd2    // restore + release the row
  } kind_e;

  typedef enum logic [2:0] {
    S_IDLE,      // no row resolved; bitlines in a known condition
    S_RESOLVE,   // connecting, sharing, sensing (2.5 stages 2-4)
    S_OPEN,      // a row is resolved and held in the sensing circuitry (§3)
    S_RESTORE,   // driving the row back at full strength (§1)
    S_PREPARE,   // returning bitlines to a known condition (R3)
    S_ERROR      // a request violated the sequence
  } state_e;

  state_e state, state_n;

  localparam int WAIT_MAX = (RESOLVE_CYCLES > RESTORE_CYCLES)
                            ? ((RESOLVE_CYCLES > PREPARE_CYCLES) ? RESOLVE_CYCLES
                                                                 : PREPARE_CYCLES)
                            : ((RESTORE_CYCLES > PREPARE_CYCLES) ? RESTORE_CYCLES
                                                                 : PREPARE_CYCLES);
  localparam int WAIT_W = (WAIT_MAX <= 1) ? 1 : $clog2(WAIT_MAX + 1);
  logic [WAIT_W-1:0] wait_cnt;

  // ── Request legality, evaluated against the CURRENT array state. Each term
  //    is one rule from §5, which is why they are written separately rather
  //    than collapsed: a reader should be able to point at the rule. ───────
  logic legal_open, legal_column, legal_close, legal;
  // R3/R4: a row may be resolved only from IDLE -- no row open, bitlines ready.
  assign legal_open   = (state == S_IDLE);
  // R1: a column access requires the requested row to be the resolved one.
  assign legal_column = (state == S_OPEN) && row_open && (open_row == req_row);
  // R2: releasing is legal only when a row is actually open.
  assign legal_close  = (state == S_OPEN) && row_open;

  always_comb begin
    unique case (kind_e'(req_kind))
      KIND_OPEN:   legal = legal_open;
      KIND_COLUMN: legal = legal_column;
      KIND_CLOSE:  legal = legal_close;
      default:     legal = 1'b0;
    endcase
  end

  always_comb begin
    state_n = state;
    unique case (state)
      S_IDLE, S_OPEN: begin
        if (req_valid) begin
          if (!legal) state_n = S_ERROR;
          else unique case (kind_e'(req_kind))
            KIND_OPEN:   state_n = S_RESOLVE;
            // A column access on a resolved row needs none of 2.5's stages
            // (§3): it completes without leaving S_OPEN.
            KIND_COLUMN: state_n = S_OPEN;
            KIND_CLOSE:  state_n = S_RESTORE;
            default:     state_n = S_ERROR;
          endcase
        end
      end
      S_RESOLVE: if (wait_cnt == 1) state_n = S_OPEN;
      // R2 then R3: restoration must COMPLETE, and only then may the
      // bitlines be prepared. Two states, never one.
      S_RESTORE: if (wait_cnt == 1) state_n = S_PREPARE;
      S_PREPARE: if (wait_cnt == 1) state_n = S_IDLE;
      S_ERROR:                      state_n = (state == S_ERROR && row_open)
                                                ? S_OPEN : S_IDLE;
      default:                      state_n = S_IDLE;
    endcase
  end

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      state    <= S_IDLE;
      wait_cnt <= '0;
      ack      <= 1'b0;
      err      <= 1'b0;
      // Reset makes no claim about the ARRAY -- it only resets this
      // controller's belief. A design coming out of reset must not assume a
      // row is open, which is why row_open starts low.
      row_open <= 1'b0;
      open_row <= '0;
    end else begin
      state <= state_n;
      ack   <= 1'b0;
      err   <= 1'b0;

      // Load the wait counter on entry to a counted state; otherwise count.
      if (state_n != state) begin
        unique case (state_n)
          S_RESOLVE: wait_cnt <= WAIT_W'(RESOLVE_CYCLES);
          S_RESTORE: wait_cnt <= WAIT_W'(RESTORE_CYCLES);
          S_PREPARE: wait_cnt <= WAIT_W'(PREPARE_CYCLES);
          default:   wait_cnt <= '0;
        endcase
      end else if (wait_cnt != '0) begin
        wait_cnt <= wait_cnt - 1'b1;
      end

      // A column access on an already-resolved row completes immediately.
      if ((state == S_OPEN) && req_valid && legal
          && (kind_e'(req_kind) == KIND_COLUMN)) begin
        ack <= 1'b1;
      end

      // Stage completions.
      if (wait_cnt == 1) begin
        unique case (state)
          S_RESOLVE: begin
            // The row is now resolved and held in the sensing circuitry (§3).
            row_open <= 1'b1;
            open_row <= req_row;
            ack      <= 1'b1;
          end
          // Restoration finished; the row's cells hold a separated state
          // again. Only NOW is it safe to stop considering it open.
          S_RESTORE: row_open <= 1'b0;
          S_PREPARE: ack      <= 1'b1;
          default: ;
        endcase
      end

      if (state == S_ERROR) err <= 1'b1;
    end
  end

  assign busy = (state != S_IDLE) && (state != S_OPEN);

endmodule

Cycle-level behaviour. From S_IDLE, an open request spends RESOLVE_CYCLES in S_RESOLVE and lands in S_OPEN with row_open set — this is Chapter 2.5's stages 2 to 4. Column accesses to that row are then acknowledged without leaving S_OPEN, which is §3's cheap case. A close request spends RESTORE_CYCLES in S_RESTORE and then PREPARE_CYCLES in S_PREPARE before returning to S_IDLE. A request that violates §5 produces err and does not proceed.

State, and why each piece exists. state tracks which stage the array is in, because the prerequisites are stated in terms of stages. row_open and open_row are separate for the reason Chapter 1.4 §6 gave: "no row open" and "row zero open" are different facts, and conflating them grants a spurious first-access hit. wait_cnt is sized from the longest stage by a localparam so a parameter change cannot silently truncate it.

The design decisions that carry the lesson. Three, and each is a rule from §5 made structural rather than documented.

S_RESTORE and S_PREPARE are separate states. Collapsing them into one wait would be shorter code and would lose the distinction R2 and R3 draw: restoration repairs the row, preparation readies the bitlines for a different row. They are different work on different structures, and a design that merges them cannot express the case where a row is restored and then reopened without a full preparation.

row_open is cleared when restoration completes, not when a close is requested. Clearing it early would let the controller believe the row was safely closed while the cells were still holding diluted conditions — Chapter 2.5 §12's bug, expressed in a single misplaced assignment.

Illegality produces err rather than being silently sequenced. The model could have inserted the missing prerequisite automatically and "helped". It deliberately does not, because the array cannot help, and a requester that depends on being rescued is a requester that will break against hardware that does not rescue it. Making the caller confront the rule is the teaching point.

Expected result. Open row 3, then two column accesses, then close. All four acknowledge, with the column accesses completing far sooner than the open. Then request a column access from S_IDLE with no row open: err rises and nothing proceeds. Then open row 3 and immediately request row 5 without closing: err again — R3 refusing.

Expected waveform. Figure 2 in §7 is the first of those sequences with the illegal request appended.

Synthesis implication. A six-state machine, a small counter, a row register and a flag — a few tens of flip-flops plus comparators. Fully synthesizable. Nothing here describes how a DRAM device is built internally; a real device is not an RTL state machine, and its equivalent of these rules is enforced by the controller, which is what this model stands in for.

Limitations. One row open at a time, so no bank parallelism — a real device's ability to hold several rows open in different banks is Module 5's subject and one of the most important performance mechanisms in the curriculum. No data path. No refresh integration, though Chapter 2.3's tracker is the piece that would drive a close-and-refresh sequence here. No real timing. No bursts, no queueing, no reordering, no addressing beyond a row index.

Debugging observations. If err never asserts in a test that expects it, check that the stimulus is not always opening before accessing — the illegal case becomes unreachable. If a column access is acknowledged after a close, check whether row_open is being cleared at the request rather than at the completion. If the model hangs, verify every stage parameter is at least 1, as the counted-wait control flow requires.

7. The Lifecycle, in Cycles

dram_access_seq — resolve, two column accesses, close, then an illegal request

10 cycles
Twelve cycles of the access sequencer. A row is resolved over three cycles and row-open asserts. Two column accesses to that row are acknowledged immediately without leaving the open state. A close request drives restoration and then bitline preparation, and row-open clears only when restoration completes. A final column access with no row open is refused with an error.restore then preparerestore then preparerow resolved — now openrow resolved — now opencolumn access: no stagescolumn access: no stagesrestoring the whole rowrestoring the whole rowno row open — refusedno row open — refusedclkreq_validreq_kindOPEN--COLCOLCLOS------COL--stateRSLVRSLVOPENOPENOPENRESTRESTPREPIDLEERRrow_openackerrt0t1t2t3t4t5t6t7t8t9
Figure 2 — resolve once, access cheaply, then restore and prepare; an access attempted out of order is refused rather than silently sequenced.

Cycles 0–1 — resolving. Chapter 2.5's stages 2 to 4: connect, share, amplify. Nothing can be accessed yet; row_open is low. This is the expensive part of any access to a new row.

Cycle 2 — the row is open. row_open rises and the first ack lands. The row's contents are now resolved and held in the sensing circuitry (§3).

Cycles 3–4 — two column accesses, acknowledged one after another. Each is served without leaving S_OPEN and without touching the array. Compare with cycles 0–1: the same device, a much cheaper access, purely because the row was already resolved. This is the whole of Chapter 1.4's cost asymmetry, now derived rather than asserted.

Cycles 5–6 — restoration. The close request drives the row back at full strength. Note row_open stays high through cycle 6 and clears only at the end of restoration — the row is not safely closed until its cells hold a separated state again.

Cycle 7 — preparation. The bitlines are returned to a known condition, which R3 requires before a different row can be resolved. Separate work, separate state — collapsing it into the restore wait would lose the distinction.

Cycle 9 — the refusal. A column access arrives with no row open. err asserts and nothing is attempted. A design that instead "helpfully" opened a row would be hiding a requester bug that real hardware will not hide.

8. Four Assertions Worth Writing

These state §5's rules against the model's own signals. All four are checkable from the interface and the exposed state — which is the only place they can be checked, because the array has no digital observables (Chapter 2.4 §5).

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

// P1 -- R1. A column access is acknowledged only when the requested row was
// actually the resolved one. This is the property whose violation returns an
// undecided value, and it is the reason `open_row` is compared rather than
// merely `row_open` being checked.
property p_column_requires_matching_open_row;
  @(posedge clk) disable iff (!rst_n)
    (ack && $past(kind_e'(req_kind) == KIND_COLUMN))
      |-> $past(row_open && (open_row == req_row));
endproperty
assert property (p_column_requires_matching_open_row);

// P2 -- R2. The row is never considered closed until restoration has
// completed. Written on the FALLING edge of row_open so it pins the exact
// moment the belief changes: clearing it at the close REQUEST instead of at
// the completion is a one-line bug that destroys the row.
property p_row_closes_only_after_restore;
  @(posedge clk) disable iff (!rst_n)
    $fell(row_open) |-> $past(state == S_RESTORE && wait_cnt == 1);
endproperty
assert property (p_row_closes_only_after_restore);

// P3 -- R3 and R4 together. Resolving a row is only ever entered from IDLE,
// which is the state in which no row is open AND the bitlines are prepared.
// This is what prevents two rows being connected to one bitline group, and
// it is written on the state TRANSITION so it fails at the decision.
property p_resolve_only_from_idle;
  @(posedge clk) disable iff (!rst_n)
    (state == S_RESOLVE && $past(state != S_RESOLVE))
      |-> $past(state == S_IDLE);
endproperty
assert property (p_resolve_only_from_idle);

// P4 -- the stages are never skipped. Restoration is always followed by
// preparation, never directly by a new resolve. A design that shortcut this
// would leave the bitlines in an unknown condition for the next small signal.
property p_restore_then_prepare;
  @(posedge clk) disable iff (!rst_n)
    (state == S_RESTORE && state_n != S_RESTORE) |-> (state_n == S_PREPARE);
endproperty
assert property (p_restore_then_prepare);

What each buys. P1 is R1 with the subtlety that matters: it compares the row index, not merely whether something is open, so it catches a controller that tracks openness but loses track of which row. P2 pins the single most dangerous assignment in the design — clearing row_open early is one line, produces no immediate symptom, and destroys the row. P3 collapses R3 and R4 into one checkable claim by asserting that resolution is only ever entered from the state where both prerequisites hold, which is far more robust than enumerating the illegal predecessors. P4 forbids a stage skip that would leave the bitlines unprepared — the failure that makes the next read wrong rather than this one.

What they do not claim. Nothing here proves any cell was actually restored: the array is on the analog side of the boundary, so no assertion can reach it. These properties prove the control never commands an illegal sequence, which is the strongest thing digital verification can establish about a physical mechanism — and stating the limit is part of the lesson. A real controller is additionally verified against a vendor device model that independently rejects illegal sequences, exactly because self-checking control proves nothing about the medium (Chapter 1.5 §9 made the same point about flash).

9. Verification Perspective

The invariants are all prerequisites, which changes how they are tested. A prerequisite violation is not a wrong value — it is a legal-looking operation issued in an illegal state. So the stimulus that finds these bugs is stimulus that gets the order wrong, and a testbench that only ever issues well-formed sequences will never produce one.

Directed illegal sequences belong in the plan. Column access with no row open. Column access to a row other than the resolved one. Resolving a second row without closing the first. Closing with nothing open. Each should produce err and no state change — and each should be a directed test, because random stimulus constrained to be legal will never generate them.

The boundary cases are where real defects live. A request arriving in the exact cycle a stage completes. A close requested one cycle after a column access. Back-to-back opens of the same row. Reset asserted during each of the three counted stages.

And one contract deserves explicit thought: what may be assumed after reset? The model resets row_open low, and the comment says why — reset clears the controller's belief and does nothing to the array. A design that came out of reset assuming a row was open would access an unresolved row; a design that assumed the array was in a known condition would issue a resolve without preparation. The honest contract is that nothing about the array is known after reset, and a real initialisation sequence must establish it.

Coverage worth asking for. Every state entered; every legal request kind from every state; every illegal combination refused; the same-row cheap path and the row-change expensive path both exercised, with their cycle costs recorded. That last one matters because it makes the §3 asymmetry measured rather than assumed — which is exactly the instrumentation Chapter 1.4 §13's exercise asked for.

10. Common Misconceptions

"Restore is an optimisation the device performs for efficiency." Wrong model: restoration is something clever that could be skipped or deferred for speed. Engineering consequence: a controller that releases a row as soon as data is returned, or treats the restore interval as negotiable overhead. Since the array cannot refuse and reports nothing, the result is silent row destruction. Observable failure: data loss in rows accessed immediately before a row change, reproducible, with no error anywhere — Chapter 2.5 §10's first mechanism. Correct model: restoration is the completion of the access. The read consumed the row's state and the amplified value is the only thing strong enough to re-establish it. Not optional, not deferrable. Prevention: treat "data returned" and "array free" as two pieces of state, and never derive the second from the first.

"Restore and refresh are the same operation." Wrong model: one mechanism with two names. Engineering consequence: an inability to reason about either one's trigger, cost or schedule. The usual symptom is believing that a busy system needs no refresh, since accesses restore what they touch. Correct model: the same physical operation, driven by different obligations. §4's table is the comparison: restore is compelled by an access that just happened; refresh is compelled by a deadline, on a row nobody asked for, with its data discarded. Prevention: ask what triggered it — an access, or the clock?

"The row buffer is a cache that DRAM designers added for performance." Wrong model: a deliberate architectural feature, which could have been designed differently or left out. Engineering consequence: treating the same-row cost advantage as an implementation detail that might not hold, rather than as a structural property every DRAM device has. Correct model: it is the unavoidable residue of sensing (§3). Resolving a row necessarily leaves the row's values at full strength in the sensing circuitry; keeping the row selected keeps them available. Nobody added it — it could not have been avoided. Prevention: derive it from the mechanism. The performance consequences then follow as facts about the device rather than as vendor features.

"A column access to an open row still touches the cells." Wrong model: every access goes to the array. Engineering consequence: incorrect cost models, and confusion about why same-row accesses are cheap or why a long sequence of them does not repeatedly disturb the row. Correct model: once resolved, the row's values are in the sensing circuitry. A column access selects among those and routes one out. The cells are not disturbed again, which is why repeated same-row accesses are both cheap and harmless. Prevention: remember that after §1 the strong copy is outside the array, not in it.

"An out-of-order request will be rejected by the device." Wrong model: the hardware protects itself, so a sequencing bug produces an error. Engineering consequence: the most dangerous belief in this module. The array has no digital state, cannot evaluate legality, cannot refuse, and cannot report (Chapter 2.4 §1). An illegal sequence is simply performed, with physical consequences. Observable failure: data destruction with no error signal anywhere, discovered later by an unrelated read. Correct model: every rule in §5 must be enforced by logic outside the array. The err output in §6 exists in the controller, not in the device. Prevention: the assertions in §8. When a fault damages state silently, the check must be on the logic that could cause it.

11. Debugging — A Row Is Correct Until the Next Row Is Opened

Symptom. Reads return correct data. But a row that was read correctly is found corrupted later, and the corruption correlates with the controller having subsequently opened a different row. Rows that are read repeatedly without an intervening row change are fine.

The correlation with a following row change is the diagnostic gift here, and it narrows the space immediately.

Mechanism 1 — the row was released before restoration completed. What to observe: the interval between the close request and the new resolve, against RESTORE_CYCLES, and whether row_open clears at the request or at the completion. Expected evidence: the new resolve beginning sooner than restoration could have finished. How to discriminate: P2 in §8 fails on the exact cycle. Without it, inspect where row_open is assigned — clearing it at the request is the single-line version of this bug, and it is the most likely cause given the symptom.

Mechanism 2 — restoration ran but preparation was skipped. What to observe: whether S_PREPARE is entered every time before a new resolve. Expected evidence: the newly opened row returning wrong data, while the previously read row is intact — the opposite pattern from mechanism 1. How to discriminate: which row is damaged. The old row means restoration; the new row means preparation. P4 catches this one.

Mechanism 3 — two rows were connected at once. What to observe: the row selection for one-hot legality and stability. Expected evidence: two rows damaged per event, in a consistent pairing. How to discriminate: count the damaged rows, as Chapter 2.4 §10 established. P3 in §8 prevents the state-machine route to this, but a decoder fault below the state machine would not be caught by it.

Mechanism 4 — the controller lost track of which row was open. What to observe: open_row against the row the requester believes is open, particularly after an error or an aborted sequence. Expected evidence: column accesses acknowledged but returning data from a different row — wrong data with no destruction. How to discriminate: whether anything was actually lost. If a later read of the original row is correct, nothing was destroyed and this is a tracking bug. P1 catches it.

Mechanism 5 — not this chapter. What to observe: whether corruption correlates with elapsed time, temperature or access density rather than with row changes. How to discriminate: reproducibility and the correlation variable. Statistical, condition-dependent corruption is Chapter 2.2 §8; deterministic corruption tied to a row change is this chapter.

Root-cause discrimination in two questions. Which row is damaged — the old one or the new one? Old → restoration was cut short (mechanism 1). New → preparation was skipped (mechanism 2). And how many rows per event? Two → they were connected together (mechanism 3). Then: was anything destroyed at all, or just misread? Misread only → a tracking bug (mechanism 4).

The reasoning lesson. Every mechanism in this list is a prerequisite violation, and none of them produces an error from the hardware. The investigation is therefore entirely about reconstructing the order of control events — which is why a controller that exposes its state, as the model in §6 does, is dramatically more debuggable than one that does not. Observability of control state is not a luxury when the medium cannot report faults.

12. Interview Reasoning

"Why does a DRAM read contain a write?" Because sensing consumed the row's stored charge. After the charge is shared onto the bitline the cells hold a diluted condition carrying no recoverable information, so the resolved full-strength value must be driven back through the still-open access transistors to re-establish the separation. It is the completion of the read, not a side effect — and it is only possible because sensing amplified: neither the cell nor the diluted bitline condition could restore anything.

"Why does restoration cover a whole row when only one location was read?" Because one wordline serves many cells, so selecting the row connected every cell in it to its own bitline and every one of them shared its charge away. The whole row was destroyed, so the whole row must be repaired — and the machinery to do it is already engaged, since each column's sensing circuitry independently resolved its own cell. A strong answer adds that this is also what makes the refresh obligation affordable: one operation maintains a whole row.

"Why is an access to an already-open row so much cheaper?" Because the row's values are already resolved and held at full strength in the sensing circuitry — the residue of the earlier sensing. A column access only has to select among them and route one out: no bitline preparation, no connection, no charge sharing, no amplification, and no disturbance of the cells. That asymmetry is the origin of the row buffer, and it is why a memory controller is a scheduler that tries to keep requests inside one row.

"Is the row buffer a cache?" Functionally it behaves like one, but it was not added as a feature — it is the unavoidable consequence of the sensing mechanism. Resolving a row necessarily leaves the row's contents at full strength outside the array, and keeping the row selected keeps them available. Calling it a cache invites the assumption that it could have been designed differently or omitted; deriving it from sensing shows it could not.

"What happens if a controller opens a new row too early?" The previously accessed row is left holding diluted conditions and its data is destroyed — and nothing reports it, because the array has no digital state, cannot evaluate legality and cannot refuse. The failure surfaces later, at an unrelated read of that row, with nothing connecting it to the cause. This is why the ordering rules must be enforced by logic outside the array and why the properties that check them are control-path assertions rather than data comparisons.

"Restore and refresh use the same machinery. Why are they different obligations?" Because they answer different problems and are triggered differently. Restoration repairs a disturbance an access just created; it is compelled by that access, targets the row that was accessed, uses the data, and cannot be deferred. Refresh pre-empts the decay that leakage causes; it is compelled by a deadline, targets a row nobody asked for, discards the data, and may be scheduled within stated latitude. That distinction is exactly why a busy system still needs refresh — accesses only restore the rows they happen to touch.

13. Engineering Check

A controller is being optimised. A profiler shows that closing a row costs restoration plus preparation, and that a substantial fraction of row changes are followed by a request that would have hit the row just closed. An engineer proposes skipping the preparation stage when reopening the same row that was just closed, on the grounds that the bitlines were left in a condition that row's own data produced.

1. Is the premise about the bitlines correct? Partly, and that is what makes the proposal dangerous. After restoration the bitlines were driven to full levels corresponding to that row's data — so they are in a known condition, but a known condition that depends on the data, not the defined reference condition a new small signal must be measured against (Chapter 2.5 §2).

2. What goes wrong if preparation is skipped? The next read's small shift is measured against the wrong starting point. For cells whose value matches what the bitline was left holding, the read will appear correct; for cells whose value differs, the shift may be swamped or reversed. The result is data-dependent wrong reads — correct for some patterns and wrong for others, which is among the hardest failure signatures to diagnose. It is Chapter 2.5 §10's fifth mechanism, deliberately introduced.

3. Is there a legitimate version of the underlying idea? Yes, and it is the interesting part: do not close the row at all. If a substantial fraction of row changes are followed by a request to the row just closed, the error is in the decision to close, not in the preparation. Keeping the row open serves those requests with §3's cheap path and pays neither restoration nor preparation. That is a real controller policy — Module 23 treats the open-versus-closed page question properly — and it addresses the same profile without violating any physics.

4. Why is the distinction between the two proposals worth noticing? One tries to make a mandatory stage cheaper; the other avoids needing the stage at all. Prerequisites imposed by physics cannot be optimised; the decisions that invoke them can. That is the same line Chapter 2.3 §2 drew about refresh — when to do required work is an engineering decision, whether to do it is not — and it is the most transferable idea in Module 2.

5. Which assertion would have caught the original proposal in review? P4 in §8: restoration must be followed by preparation. An implementation that skipped preparation on a same-row reopen violates it immediately, in simulation, on the first occurrence — long before anyone sees data-dependent read failures in a lab.

6. What measurement would justify the legitimate version? The fraction of row changes followed within some window by a request to the row just closed, and the average number of column accesses per open row. Those two together say whether a policy change would pay — and they are exactly the counters Chapter 1.4 §13's exercise asked for, now with the mechanism behind them fully derived.

14. Summary

After sensing, the cell holds a diluted condition carrying no recoverable information, and the sensing circuitry holds the resolved value at full strength. Restoration is the strong thing driving the weak thing: the resolved value is driven onto the bitline and through the still-open access transistor into the cell, re-establishing the separation the read consumed. The cell is a passive recipient — it has no drive and no gain, and it is repaired through the same connection that destroyed it.

It covers a whole row, forced twice: selection connected every cell in the row, so every one lost its state; and each column's sensing circuitry already holds the right value, so the machinery is already engaged. The row is the unit of repair because it was the unit of participation — and this is what makes the refresh obligation affordable, since one operation maintains a whole row.

The residue is the consequence that shapes everything above the device. A resolved row remains available at full strength in the sensing circuitry, so a further access to the same row needs none of Chapter 2.5's stages — no preparation, no connection, no sharing, no amplification. That is the row buffer, and it was never added as a feature: it is the unavoidable residue of sensing. The gap between that cheap path and the expensive row change is why a memory controller is a scheduler.

Restore and refresh are the same physical operation with different obligations. Restore is compelled by an access that just happened, targets the accessed row, uses the data, and cannot be deferred. Refresh is compelled by a deadline, targets a row nobody asked for, discards the data, and may be scheduled within stated latitude. Which is why a busy system still needs refresh.

And the mechanism leaves a set of prerequisites — a column access needs a resolved row; restoration must complete before release; a different row needs prepared bitlines; only one row per bitline group at a time — none of which the array can enforce. It has no digital state, cannot evaluate legality, cannot refuse, and cannot report. Every rule must be enforced by logic outside it, which is the last and largest thing Module 2 hands to the rest of the curriculum.

15. Module 2 in One Chain

This closes the module, so the ending is the argument rather than six summaries.

Capacitor storage — a bit is a quantity of charge on a node, a continuous physical state, and the digital value is created outside the cell by a sensing decision rather than retrieved from it. The cell has no drive and no gain, and those two absences generate everything that follows.

Charge storage and leakage — the node is connected to its surroundings by unavoidable high-resistance paths, and nothing drives it to contest the loss. What degrades is not a bit but the margin between the two states, until the sensing decision becomes unreliable. Passive storage plus uncontested loss equals a finite lifetime.

The refresh requirement — that finite lifetime becomes a rule about the passage of time: every location re-established within a bounded interval. It costs device availability for reasons unrelated to traffic, and it is a correctness obligation that must be tracked, enforced structurally, and made observable.

The DRAM cell — one access transistor, one capacitor, one wordline deciding when, one shared bitline deciding where. The content is a cost budget: everything else a memory needs was moved outside and shared. Shared selection makes the row the unit of access; the bitline's much larger capacitance makes the signal small.

The destructive-read property — isolated, connected, shared, sensed, restored. Connecting a driveless cell to a much larger capacitance redistributes its charge: the bitline shifts slightly in a revealing direction and the cell's state is consumed. Sensing is amplification, not detection. Data becomes valid at stage four; the array is not finished until stage five.

Restore operations — the amplified value drives the row back through the still-open connection, because nothing weaker could. A read therefore contains a write, a resolved row stays available and makes same-row accesses cheap, and the mechanism leaves prerequisites the array cannot enforce.

Read the chain backwards and the DDR standard falls out. Row-oriented commands exist because selection is shared. Timing constraints exist because the stages are physical processes that must not overlap. A scheduler exists because access cost depends on which row is resolved. A refresh manager exists because margin decays on a deadline. And a controller exists at all because the array has no digital state and can enforce nothing. None of it is arbitrary. All of it is the cell budget, seen from far away.

16. What Comes Next

Module 2 has been careful about one thing throughout: it has talked about a wordline, a bitline, a row and the sensing circuitry, without ever saying how many, how they are arranged, or how the sensing circuit works. Every one of those was deferred with a pointer.

Module 3 is where they are collected. Rows and columns as organising structures rather than as consequences of one cell's wiring. Bitlines and wordlines as engineered objects with their own length, capacitance, drive requirements and timing — the quantities this module could only describe qualitatively. The sense-amplifier circuit itself, which Module 2 used as a function five times and never opened. And the subarray and mat hierarchy that a real device is actually built from, which is why a billion-cell array is not one enormous grid.

You now know why every one of those structures has to exist, and what job it is doing. That is the right position from which to learn how they are built.

Return to The Destructive-Read Property for the mechanism this chapter completes, The Refresh Requirement for the obligation that shares its machinery, or The DRAM Cell (1T1C) for the structure underneath. For the system-level consequence of state-dependent access cost, see DRAM and The Memory Wall Problem. 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.