Skip to content
VLSI Mentor

DDR · Module 4

SDR SDRAM

Making DRAM synchronous replaced an analog timing negotiation with a clocked contract, which is what made pipelining and counted bursts possible. It also fixes the vocabulary the rest of the curriculum depends on: clock frequency, transfer rate, data rate and bandwidth are four different quantities.

Modules 1 to 3 built a DRAM array from the cell upward. A 1T1C cell with no drive and no gain; a destructive read repaired by restoration; rows and columns as orthogonal selections over bitlines and wordlines; sense amplifiers that decide and hold; and a partitioned hierarchy producing controller-visible row state.

All of that describes what a DRAM device is. None of it describes how a controller and a device agree on when things happen. That agreement is the subject of this module, and the module's question is:

How did synchronous DRAM evolve into successive DDR generations, and which engineering bottleneck forced each change?

The module answers it as a chain, not a timeline: bottleneck → architectural response → new capability → new cost → next bottleneck. Each chapter inherits a pressure from the one before it.

This chapter is the baseline, and it has two jobs. It explains what making DRAM synchronous actually changed — which is less obvious and more consequential than it sounds. And it establishes a vocabulary that the entire rest of this curriculum depends on: clock frequency, transfer rate, data rate and bandwidth are four different quantities, and conflating them is the single most common error in memory-system discussion.

1. What Came Before a Clock

To see what synchronous DRAM changed, look at what it replaced.

Earlier DRAM was asynchronous. The device had no clock. A controller asserted control signals and then waited a specified amount of time before the device's response was guaranteed valid — timing enforced by the controller's own delay elements against the device's specified minimums. The interface was not a sequence of clocked events but a set of timing relationships the controller had to satisfy continuously.

Three consequences of that arrangement are worth naming, because each is what the clock fixed.

Every access was a fresh timing negotiation. Nothing was pipelined, because there was no shared notion of a cycle in which to pipeline. The controller drove, waited, sampled, and only then began the next access.

The controller carried the timing burden in analog form. Meeting a device's minimum intervals meant generating real delays and sampling at the right moment — a design problem that got harder as devices got faster and as the controller's own process technology changed independently of the memory's.

And the interface was hard to specify tightly. A contract expressed as a web of continuous timing relationships is harder to verify, harder to make interoperable across vendors, and harder to scale in frequency than one expressed as events on a shared clock.

So the change synchronous DRAM made was not "adding a clock" as a component. It was replacing a timing negotiation with a clocked contract: both sides sample and drive on defined edges of a shared clock, and the device's obligations are expressed in counts of cycles rather than in nanoseconds the controller must generate.

2. What the Clock Made Possible

Three capabilities followed, and all three are visible in every DDR generation since.

Pipelining. With a shared cycle, the device can accept a new command while an earlier one is still in progress internally. The controller issues, the device works, and the two overlap. This is the same idea Chapter 1.8 §7 called memory-level parallelism, appearing here as a device-interface capability rather than a requester property.

Bursts. Because transfers are now countable events on a clock, a single command can produce a defined sequence of transfers on consecutive cycles. One command, several data beats. That matters enormously given Chapter 3.1 §3's finding that a whole row participates in every access: if the expensive part is already done, moving several words out per command amortises it.

A countable latency contract. "Data appears N cycles after the column command" is a statement both sides can be built against. It is also a statement that can be specified, which is what makes multi-vendor interoperability possible — the R6 requirement Chapter 1.7 §4 argued was decisive for the tier.

What did not change is worth stating just as clearly. The array is the array. The cell still stores charge passively, the read is still destructive, restoration is still mandatory, and a row is still the unit of participation. Synchronising the interface changed the conversation, not the physics — and keeping that separation is why this module labels layers.

3. Four Quantities That Are Not Synonyms

This section is the most important thing in the chapter, and it will be referenced for the rest of the curriculum.

Clock frequency — how many clock cycles occur per second. Unit: hertz (Hz), commonly MHz. It is a property of the clock signal.

Transfer rate — how many data transfer events occur per second on one signal line. Unit: transfers per second, commonly MT/s (megatransfers per second). It is a property of the interface's data timing.

Data rate — how many bits per second cross one signal line. For a single-bit-per-transfer interface this is numerically the transfer rate, which is exactly why the two get conflated.

Bandwidth — how many bits or bytes per second cross the whole interface. Unit: bytes per second, commonly GB/s. It depends on the transfer rate and the width.

The relationships, stated carefully:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   transfers_per_second  =  clock_cycles_per_second  ×  transfers_per_cycle

   peak_bandwidth        =  transfer_rate  ×  interface_width

For SDR SDRAM, transfers_per_cycle is one. That single fact is what the name means — single data rate — and it is why, for this generation only, clock frequency in MHz and transfer rate in MT/s happen to be the same number. That coincidence is the origin of a decade of confusion, because it trained a generation of engineers to treat MHz and MT/s as interchangeable, and from DDR onward they are not.

4. The Structure of an SDR Transfer

With the vocabulary fixed, the transfer itself is simple — and its simplicity is what makes the limit visible.

A controller issues a command on a clock edge. The device's internal array access produces data, which is transferred one beat per clock cycle as a counted burst. The shared clock is the common timing reference for both the command path and the data path.Commandissued on an edgeArray accessModules 2 and 3Counted burstone beat per cycleData lineswidth × rate = bandwidthShared clockone timing referencestartsdatabeatstimes12
Figure 1 — the synchronous contract: one command produces a counted sequence of transfers, one per clock cycle.

One clock times everything. The command path and the data path share a single timing reference. That is the defining simplification of this generation, and §8 explains why it does not survive the next one.

The burst is counted, not negotiated. A command specifies how many beats follow, and both sides count. No handshake, no acknowledgement per beat — which is efficient and also means there is no backpressure: the data arrives on the cycles the contract says, whether or not the requester is ready. Building a consumer that is always ready is therefore part of using such an interface, and it stays true of DDR interfaces to this day.

And the array access is unchanged from Module 3. The "Array access" block is greyed deliberately: the expensive, state-dependent work of selecting a row and resolving it happens exactly as Chapter 3.5 described. This module changes the interface above it.

5. RTL — A Baseline Burst Engine

Problem

A synchronous interface must turn one command into a counted sequence of transfers on consecutive cycles, tracking where it is in the burst and signalling the last beat. This is the simplest complete expression of the clocked transfer contract, and it is the baseline every later chapter's model modifies.

Classification

SYNTHESIZABLE RTL. It is a burst sequencer — real digital logic of the kind a memory controller or a device's interface logic genuinely contains. It models no array, no cell, no sensing, and no analog signalling.

Interface

start with burst_len begins a burst. beat_valid marks each transfer cycle, beat_index says which beat it is, beat_first and beat_last mark the boundaries, and busy says a burst is in progress. illegal_start reports a start request that cannot be honoured.

How to simulate it

Following the convention established in Chapter 3.1 §5: vlog sdr_burst_engine.sv tb_sdr_burst_engine.sv then vsim -c tb_sdr_burst_engine -do "run -all"; with VCS vcs -sverilog sdr_burst_engine.sv tb_sdr_burst_engine.sv && ./simv; with Xcelium xrun -sv sdr_burst_engine.sv tb_sdr_burst_engine.sv. Every later block in Module 4 simulates the same way.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// SDR BURST ENGINE.  Classification: SYNTHESIZABLE RTL.
//
// One command -> a counted sequence of transfers, one beat per clock cycle.
// This is the BASELINE of Module 4's RTL progression: every later chapter
// modifies the relationship between the core, the beat count and the
// interface rate, and each modification is easiest to see as a delta on
// this block.
//
// It models NO array, NO cell, NO sensing and NO analog signalling. The
// expensive array work sits upstream (Modules 2 and 3).
//
// TRANSFERS PER CYCLE IS EXACTLY ONE here. That is what "single data rate"
// means, and it is the limit Chapter 4.2 attacks.
// ─────────────────────────────────────────────────────────────────────────
module sdr_burst_engine #(
  // Largest burst this engine supports. Must be >= 1.
  parameter int MAX_BURST = 8,
  // DERIVED. The guard keeps MAX_BURST == 1 legal rather than producing a
  // zero-width counter, which would be an illegal declaration.
  parameter int CNT_W = (MAX_BURST <= 1) ? 1 : $clog2(MAX_BURST)
) (
  input  logic             clk,
  input  logic             rst_n,

  input  logic             start,
  // Number of beats requested. Encoded as a plain count, so the legal
  // range is 1..MAX_BURST and zero is rejected rather than silently
  // treated as "no transfer" or as MAX_BURST.
  input  logic [CNT_W:0]   burst_len,

  output logic             beat_valid,
  output logic [CNT_W-1:0] beat_index,
  output logic             beat_first,
  output logic             beat_last,
  output logic             busy,
  // One-cycle report of a start that cannot be honoured: zero length, a
  // length above MAX_BURST, or a start while already bursting. Reported
  // rather than clamped, because clamping hides a requester bug.
  output logic             illegal_start
);

  // ── COMPILE-TIME legality. An illegal parameterisation is an elaboration
  //    error rather than a runtime surprise.
  if (MAX_BURST < 1) begin : g_bad_burst
    initial $fatal(1, "sdr_burst_engine: MAX_BURST must be >= 1");
  end

  // ── State. `remaining` counts beats still to transfer INCLUDING the one
  //    being transferred this cycle, so `remaining == 1` is the last beat.
  //    One extra bit over CNT_W so the full count MAX_BURST is
  //    representable alongside zero.
  logic [CNT_W:0]   remaining;
  logic [CNT_W-1:0] index_q;

  logic len_ok, can_start;
  assign len_ok    = (burst_len != '0) && (burst_len <= (CNT_W+1)'(MAX_BURST));
  assign can_start = start && len_ok && !busy;

  // ── Combinational outputs. `busy` is derived from `remaining` rather than
  //    held separately, so there is exactly one source of truth for whether
  //    a burst is in progress.
  assign busy       = (remaining != '0);
  assign beat_valid = busy;
  assign beat_index = index_q;
  assign beat_first = busy && (index_q == '0);
  assign beat_last  = busy && (remaining == (CNT_W+1)'(1));

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      remaining     <= '0;
      index_q       <= '0;
      illegal_start <= 1'b0;
    end else begin
      illegal_start <= 1'b0;

      if (can_start) begin
        // Load the count and reset the index. Both happen together: an
        // index that survived from a previous burst would mis-order the
        // new one, and that is the bug P3 in §6 exists to catch.
        remaining <= burst_len;
        index_q   <= '0;
      end else if (busy) begin
        // Count down. The index advances only while a burst is live, so it
        // is meaningful exactly when beat_valid is high.
        remaining <= remaining - (CNT_W+1)'(1);
        index_q   <= index_q + 1'b1;
      end

      // Report, never repair. A start during a burst is a requester error;
      // silently queueing or dropping it would hide the fault.
      if (start && (!len_ok || busy)) begin
        illegal_start <= 1'b1;
      end
    end
  end

endmodule

Combinational logic

len_ok and can_start decide whether a start is honourable. busy, beat_valid, beat_first and beat_last are all derived from remaining and index_q rather than held in separate registers — deliberately, so there is a single source of truth about burst progress and no possibility of two flags disagreeing.

Sequential logic

remaining loads on an accepted start and counts down otherwise; index_q resets on start and advances with it. The two always change together, which is what keeps ordering correct.

Cycle trace

With MAX_BURST = 8, assert start with burst_len = 4:

Cycleremainingindex_qbeat_validbeat_firstbeat_last
0 (start asserted)00000
140110
231100
322100
413101
504000

Four beats, indices 0 to 3, on four consecutive cycles. One beat per cycle, which is the whole point of the baseline.

Simulation

A directed test should observe exactly burst_len cycles of beat_valid per accepted start, beat_index advancing by one each cycle from zero, beat_first on the first and beat_last on the last, and illegal_start for a zero length, an over-length request, or a start during a burst.

Synthesis

A down-counter, an up-counter, a comparator and a small amount of decode — a few tens of flip-flops. It approximates the burst sequencer inside a controller's data path or a device's interface logic. It does not approximate any part of the DRAM array.

Corner cases

MAX_BURST == 1 gives CNT_W == 1 through the guard rather than $clog2(1) == 0, which would make logic [CNT_W-1:0] illegal. burst_len == 0 is rejected rather than treated as a silent no-op. burst_len > MAX_BURST is rejected rather than truncated — truncation would transfer a different number of beats than the requester asked for, with nothing reporting it. A start in the same cycle as the final beat is refused, because busy is still high; that is a deliberate choice discussed in §6's limitations, and a back-to-back-capable engine would need an accept-and-reload path.

Verification

What DV must prove: exactly burst_len beats per accepted start; indices monotonic from zero with no gaps or repeats; beat_last exactly on the final beat and nowhere else; no beats without an accepted start; every illegal start reported and none acted on; reset returning to idle from any point mid-burst.

SVA

§6.

Debugging

If a burst delivers one beat too few, check whether remaining is loaded with burst_len or with burst_len - 1 — an off-by-one here shortens every burst by exactly one beat, which shows up as a consistently missing final word. If beats are ordered wrongly after the first burst, check that index_q is reset on start rather than only on reset. If beat_last never asserts, compare the remaining == 1 test against the load value.

Limitations

No backpressure: the consumer must be ready, exactly as §4 said of the real interface. No back-to-back bursts without an idle cycle. No address, no data — this is the timing of a transfer, not its content. No notion of the array's state, so nothing here knows whether the row was open. And transfers_per_cycle is fixed at one, which is the constraint the next chapter removes.

6. Three Assertions Worth Writing

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

// P1 -- beats occur only inside a burst. The safety property: a transfer
// with no command behind it would put data on the interface that the
// consumer has no reason to expect.
property p_beats_only_when_busy;
  @(posedge clk) disable iff (!rst_n)
    beat_valid |-> busy;
endproperty
assert property (p_beats_only_when_busy);

// P2 -- the burst delivers EXACTLY the requested number of beats. Written
// as a counted sequence rather than as a running total, because the
// off-by-one described in §5's debugging notes satisfies any weaker
// "delivers some beats" property.
// The tempting form uses an UNBOUNDED repetition:
//
//   (can_start, n = burst_len) |=> beat_valid [*1:$] ##0 beat_last;
//
// and it is deliberately NOT asserted, because an unbounded eventuality
// cannot fail on a design that simply never finishes the burst. It proves
// "if it ever completes, it completes correctly" -- which is weaker than it
// looks, and weaker than anything a counted, finite sequence deserves.
//
// The bounded form is what is actually asserted: the burst starts on the
// next cycle at index zero, and reaches its last beat within MAX_BURST
// cycles with the index matching the length that was requested.
property p_exact_beat_count;
  logic [CNT_W:0] n;
  @(posedge clk) disable iff (!rst_n)
    (can_start, n = burst_len)
      |=> (beat_valid && (index_q == '0))
          ##[0:MAX_BURST-1] (beat_last
                             && (index_q == CNT_W'(n - (CNT_W+1)'(1))));
endproperty
assert property (p_exact_beat_count);

// P3 -- indices are monotonic with no gaps. Catches the reset-on-start bug
// from §5: an index that survives a previous burst produces correctly
// counted beats in the wrong order, which a count-only property misses.
property p_index_monotonic;
  @(posedge clk) disable iff (!rst_n)
    (beat_valid && !beat_first) |-> (index_q == ($past(index_q) + 1'b1));
endproperty
assert property (p_index_monotonic);

// P4 -- an illegal start is never acted on. The engine reports rather than
// repairs, and this is what makes that claim checkable.
property p_illegal_start_not_acted_on;
  @(posedge clk) disable iff (!rst_n)
    illegal_start |-> !$rose(busy);
endproperty
assert property (p_illegal_start_not_acted_on);

What these prove. P1 forbids transfers outside a burst. P3 is the one that earns its place: a count-only check passes a design whose indices are wrong, because the right number of beats appeared — so monotonicity is a separate property from count. P4 makes "report, never repair" verifiable.

And the deliberate lesson in P2. The first form uses [*1:$], an unbounded repetition, which cannot fail on a design that never finishes the burst — it proves "if it ever completes, it completes correctly", which is weaker than it looks. The bounded form is asserted instead. An unbounded eventuality in a property about a finite, counted sequence is almost always a mistake, and showing both is more useful than quietly using the right one.

What none of them prove. Nothing here says the data is correct — only that the transfer timing and sequencing are. Data correctness needs a reference model, which is a scoreboard rather than an assertion. And nothing proves the array had the data ready; that is the state contract Chapter 3.5 §10 established, one layer down.

7. The Baseline in Cycles

sdr_burst_engine — a four-beat burst at one beat per cycle

10 cycles
Ten cycles of the baseline burst engine. A start with burst length four is accepted, and four beats follow on four consecutive clock cycles with the index advancing from zero to three. The first and last beats are marked. Exactly one transfer occurs per clock cycle throughout.one beat per cycleone beat per cyclecommand acceptedcommand acceptedfirst beatfirst beatlast beat — 4 in 4 cycleslast beat — 4 in 4 cyclesclkstartburst_len4------------------busybeat_validbeat_index--0123----------beat_firstbeat_lastt0t1t2t3t4t5t6t7t8t9
Figure 2 — one transfer opportunity per clock cycle: the limit the next generation attacks.

Cycle 0 — the command. start with a length of four is accepted. Nothing transfers yet; the contract has been established.

Cycles 1 to 4 — four beats, four cycles. The phase band is the chapter's whole point. Each clock cycle carries exactly one transfer opportunity, and the burst uses all of them. There is no way to move a fifth word in those four cycles, because there is no fifth opportunity.

Cycle 5 — done. busy falls and the engine is available.

And the arithmetic that follows. Whatever the clock frequency is, the transfer rate on each data line equals it, because transfers_per_cycle = 1. To move data faster, a designer has exactly two levers: raise the clock frequency, or widen the interface. §8 explains why both ran out.

8. The Limit This Creates

The baseline works, and the reason it could not simply be scaled is the pressure the next chapter inherits. Two levers, both constrained.

Raising the clock frequency. This is the obvious lever and it runs into the physics Module 3 already established, plus interface physics this module will develop. On the array side, Chapter 3.5 §2 showed sensing is a regenerative process whose duration depends on the signal available, and Chapter 3.3 §1 showed that signal shrinking with density — so the array's internal access time does not fall just because a designer would like it to. On the interface side, every cycle must be long enough for a signal to be driven across a board, arrive, settle and be sampled reliably, on a bus with multiple attached loads. Both resist.

Widening the interface. Also obvious, also constrained — and Chapter 3.2 §4 already priced it: every external signal costs a pin on the package, a trace on the board, a driver, a receiver, and switching energy. Width is not a free parameter; it is one of the most expensive parameters in the system.

So the interesting question becomes a third lever. If the clock cannot rise indefinitely and the width cannot grow freely, the remaining option is to change how many transfers happen per clock cycle — which is the one term in §3's equation that nobody had touched.

That is exactly what the next generation does, and it is why the name is double data rate.

9. Common Misconceptions

"Synchronous DRAM just means the DRAM has a clock." Wrong mental model: the clock is a component that was added. Engineering action: the engineer treats synchronisation as an implementation detail and misses why the timing contract is expressed in cycles. Observable failure / bad conclusion: Modules 13 and 14's cycle-based timing parameters look like an arbitrary convention rather than a direct consequence, so they get memorised instead of derived. The engineer also cannot explain why pipelining and bursts became possible at all. Correct model: synchronisation replaced a continuous analog timing negotiation with a clocked contract, converting an analog timing problem into a digital sequencing problem — which is what made pipelining, bursts and a specifiable multi-vendor interface possible. Prevention: ask what the interface's obligations are expressed in. Nanoseconds the controller generates, or cycles both sides count?

"MHz and MT/s are interchangeable." Wrong mental model: one number describes interface speed. Engineering action: quoting a clock frequency where a transfer rate belongs, or comparing two parts by numbers that measure different things. Observable failure / bad conclusion: a factor-of-two error in every bandwidth calculation involving a DDR interface, and — worse — the appearance of agreement between two engineers who are using one number for two quantities. §7's exercise and 4.2 develop the consequence. Correct model: transfers_per_second = clock_cycles_per_second × transfers_per_cycle. The two are numerically equal only when transfers_per_cycle is one, which is true of this generation and of no later one. Prevention: MHz for clocks, MT/s for transfer rates, GB/s for bandwidth, and always state the width with a bandwidth figure.

"Bandwidth is a property of the memory." Wrong mental model: a device has a bandwidth. Engineering action: comparing memories by a single bandwidth number without reference to width, or assuming a quoted figure applies to a different interface width. Observable failure / bad conclusion: architecture decisions made on a number that does not describe the system being built. And, separately, the error Chapter 1.8 §3 dismantled: treating peak bandwidth as a performance prediction. Correct model: peak_bandwidth = transfer_rate × interface_width. It is a property of the interface, and it is a ceiling rather than a prediction — achieved bandwidth depends on the access pattern and the row state of Module 3. Prevention: never quote bandwidth without a width, and never quote peak bandwidth as an expectation.

"A burst means the memory is faster." Wrong mental model: bursting speeds up the array. Engineering action: expecting a burst to reduce access latency. Observable failure / bad conclusion: latency predictions that are wrong, and confusion about why the first beat of a burst is no earlier than a single transfer would have been. Correct model: a burst amortises an access that has already been paid for. Chapter 3.1 §3 established that a whole row participates regardless; a burst moves more of that already-sensed data out per command. It improves throughput per command, not the latency of the first beat. Prevention: separate "when does the first beat arrive" from "how much data does one command move".

10. Debugging — Measured Bandwidth Is Half the Expected Number

Symptom. A newly integrated memory interface delivers close to half the bandwidth the design was budgeted for. The interface is functional — data is correct — and the shortfall is consistent rather than intermittent.

A consistent factor of two is a strong clue, because most of the mechanisms that produce it are arithmetic or structural rather than subtle.

Mechanism 1 — the budget confused clock frequency with transfer rate. Inspect: the arithmetic in the original budget, specifically whether transfers_per_cycle appears in it at all. Expected evidence: the budget equals clock_MHz × width, with no transfers-per-cycle term. Discriminator: this is a spreadsheet bug, not a hardware bug — and it is the first thing to check because it costs nothing and is extremely common. If the measured number matches clock × width and the budget assumed twice that, the hardware is fine.

Mechanism 2 — every other transfer opportunity is unused. Inspect: the beat pattern on a trace — are beats on consecutive cycles, or on alternate ones? Expected evidence: beat_valid high every second cycle. Discriminator: a gap pattern in the beats themselves, visible directly. Causes include a burst engine that inserts an idle cycle between beats and a consumer that cannot accept back-to-back beats.

Mechanism 3 — bursts are shorter than intended. Inspect: beats per accepted command against the requested length. Expected evidence: consistently one fewer beat, or half the requested count. Discriminator: count beats per command. §5's off-by-one debugging note is the classic cause of "one fewer"; a truncated length parameter causes "half".

Mechanism 4 — the interface is narrower than the budget assumed. Inspect: the actual data width in the integration against the width in the budget. Expected evidence: an exact factor matching the width ratio. Discriminator: the factor. A width error gives exactly the width ratio; a rate error gives exactly two; and those are distinguishable when the numbers differ.

Mechanism 5 — the array, not the interface, is the limit. Inspect: the row hit and conflict classification from Chapter 3.6 §5, and whether the interface is idle while the array works. Expected evidence: the data lines idle for a large fraction of cycles, with the idle correlated to row changes. Discriminator: is the interface busy or idle? A busy interface delivering half the expected number is mechanisms 1 to 4; an idle interface means the bottleneck is upstream, and no interface change will help. This is Chapter 1.8 §13's variable separation applied here.

Discrimination, cheapest first. Re-derive the budget arithmetic with the transfers-per-cycle and width terms explicit — that alone resolves mechanisms 1 and 4 without touching hardware. Then look at whether the data lines are busy or idle, which splits interface-limited from array-limited. Only then count beats per command.

The reasoning lesson. A clean factor of two should always prompt an arithmetic check before a hardware investigation. Memory-system budgets have exactly two places a factor of two hides — the transfers-per-cycle term and the bits-versus-bytes conversion — and both are free to check. Engineers who reach for a logic analyser first regularly spend days on what a re-derivation would have found in minutes.

11. Interview Reasoning

"What did making DRAM synchronous actually change?" It replaced a continuous analog timing negotiation with a clocked contract. Previously a controller drove control signals and satisfied the device's specified minimum intervals using its own delay elements; afterwards both sides sample and drive on edges of a shared clock, and the device's obligations are expressed in counts of cycles. The consequence is the important part: it converted an analog timing problem into a digital sequencing problem, which is what made pipelining, counted bursts and a specifiable multi-vendor interface possible — and it is why the timing parameters of later modules are expressed in cycles at all.

"What is the difference between MHz and MT/s?" MHz measures a clock: how many cycles occur per second. MT/s measures transfer events on a data line: how many transfers occur per second. They are related by transfers_per_second = clock_cycles_per_second × transfers_per_cycle, and they are numerically equal only when there is exactly one transfer per cycle — which is true of SDR and of nothing after it. Treating them as interchangeable produces a factor-of-two error in every bandwidth calculation involving a DDR interface.

"Why does a burst not reduce latency?" Because the expensive work has already happened before the first beat. A whole row participates in an access regardless of how much data is wanted, and sensing must resolve before anything can be read. A burst moves more of that already-resolved data out per command, which improves throughput per command and amortises the array access — but the first beat arrives no earlier than it would have for a single transfer. Throughput and latency are different quantities, and a burst improves one.

"If you cannot raise the clock and cannot widen the bus, how do you raise bandwidth?" Change the remaining term. Bandwidth is transfer_rate × width, and transfer rate is clock_frequency × transfers_per_cycle. With the clock constrained by array access time and by signal settling on a loaded bus, and width constrained by pins, traces, drivers and switching energy, the untouched term is transfers per cycle — which is exactly what the next generation changes, and why it is called double data rate.

"An interface with no per-beat handshake has no backpressure. What does that oblige the consumer to do?" Be ready. The contract says data appears on defined cycles after the command, so a consumer that is not ready loses data — there is no signal with which to say "not yet". In practice that means the requester must have buffering sized for the committed burst before it issues the command, and a controller must not issue a command it cannot absorb the response to. That property is not an SDR quirk; it persists through DDR generations, which is why controller data paths are built around committed transfers rather than negotiated ones.

12. Engineering Check

An educational interface is clocked at 100 MHz, is 16 bits wide, and performs one transfer per clock cycle. Work through the following. These are educational figures chosen for clean arithmetic, not any real part's specification.

1. What is the transfer rate per data line? transfers_per_second = 100 × 10⁶ cycles/s × 1 transfer/cycle = 100 × 10⁶ transfers/s, i.e. 100 MT/s. For this generation only, the MHz and MT/s figures coincide — and that coincidence is what §3's callout warns about.

2. What is the peak bandwidth? peak_bandwidth = transfer_rate × width = 100 × 10⁶ transfers/s × 16 bits/transfer = 1.6 × 10⁹ bits/s. Converting: 200 MB/s, dividing by eight. Both unit conversions in one calculation — transfers to bits via the width, and bits to bytes via the factor of eight — and each is a place a factor error hides.

3. The clock is raised to 133 MHz. What happens to each quantity? Transfer rate becomes 133 MT/s and peak bandwidth becomes about 266 MB/s, both scaling linearly with the clock. Nothing about the array got faster — Chapter 3.5's sensing takes the time it takes — so the number of cycles the device needs for an access increases as the clock rises. That is a genuinely important consequence: raising the clock raises the cycle count of every timing parameter, which is why speed grades quote both.

4. Instead, the interface is widened to 32 bits at 100 MHz. Compare with question 3. Peak bandwidth becomes 400 MB/s — better than raising the clock to 133 MHz. But it costs 16 more pins, 16 more board traces, 16 more driver/receiver pairs and their switching energy. Widening buys bandwidth at a linear cost in the system's most expensive resource, which is why it is not the default answer.

5. A third proposal: keep 100 MHz and 16 bits, but perform two transfers per cycle. What is the peak bandwidth? 200 MT/s and 400 MB/s — the same as doubling the width, with no additional pins. That is the next chapter, and stating it this way shows why it was the attractive lever: it buys the width's benefit without the width's cost.

6. What does the third proposal make harder? The interval between transfer opportunities is halved, so everything about data timing tightens: driving, settling and sampling must all happen in half the time, on the same board. Nothing in the array changed, so the device's internal access is unaffected — but the interface now has half the margin. Chapter 4.2 is what that forced, and the answer involves sending timing information alongside the data rather than relying on the shared clock alone.

13. Summary

Making DRAM synchronous did not merely add a clock. It replaced a continuous analog timing negotiation — a controller generating delays to satisfy a device's specified minimums — with a clocked contract in which both sides drive and sample on shared edges and the device's obligations are expressed in counts of cycles. That converted an analog timing problem into a digital sequencing problem.

Three capabilities followed: pipelining, because there is now a shared cycle in which operations can overlap; counted bursts, because transfers became countable events, which amortises the whole-row access Module 3 showed is unavoidable; and a specifiable latency contract, which is what makes multi-vendor interoperability possible. What did not change is the array — the cell, the destructive read, restoration and row state are exactly as Modules 2 and 3 left them.

Four quantities must stay separate for the rest of this curriculum. Clock frequency (MHz) is a property of the clock. Transfer rate (MT/s) is how many transfer events occur per second on a line. Data rate is bits per second per line. Bandwidth (GB/s) is transfer_rate × width across the whole interface. They relate by transfers_per_second = clock_cycles_per_second × transfers_per_cycle, and for SDR — and only SDR — transfers_per_cycle is one, which makes MHz and MT/s numerically equal and is the origin of the most persistent confusion in the field.

And the baseline's limit is the pressure the rest of the module answers. Bandwidth has three terms. Clock frequency is constrained by array access time and by signal settling on a loaded bus. Width is constrained by pins, traces, drivers and switching energy. Which leaves the term nobody had touched: transfers per cycle.

14. What Comes Next

The baseline established a contract and exposed exactly one unused lever. Chapter 4.2 pulls it.

It answers what "double data rate" actually doubles — which is not the clock — and follows the consequence: halving the interval between transfer opportunities halves the time available to drive, settle and sample, on the same board, with the same array underneath. That is not a problem the clock can solve, and the response introduces two mechanisms that define every DDR generation since: a source-synchronous data strobe, so data carries its own timing rather than relying on a clock distributed separately, and a prefetch organisation, so the array can feed an interface running faster than the array itself.

Return to Memory Matrices and Hierarchy for the device this interface talks to, Rows for why a whole row participates in every access, or The Memory Wall Problem for why peak bandwidth predicts so little. 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.