DDR · Module 19
DQS Handling
On a write the PHY generates the strobe. On a read it must decide when to listen, because the strobe is not driven between bursts — so the gate is an estimate of a window the PHY cannot see.
Chapter 19.3 aligned a command with the data that belongs to it and left two things unbuilt. On a write, the data the gearbox launches has to be accompanied by a strobe, because the device captures against that strobe and not against a clock. On a read, 19.3 §3 showed that the receive side needs a window rather than an instant.
This chapter builds both, and they are much less symmetric than they sound.
On a write the PHY generates the strobe, so it knows exactly where it is. On a read the strobe is generated by the device, arrives after a journey the PHY cannot measure, and is not driven at all between bursts — so the PHY must decide when to listen using an estimate.
That asymmetry is the chapter. Everything difficult about DQS handling is on the receive side, and it is difficult for one reason: the gate is a guess about a signal the PHY cannot observe until it has already committed to listening.
1. The Write Side Is the Easy One
Take the easy direction first, because it makes the hard one legible by contrast.
On a write, Chapter 6.10 established that the controller side drives the strobe. The PHY generates it, alongside the data 19.2's gearbox is launching, in a defined relationship to that data.
Everything about this is knowable at the PHY:
- When it starts — the PHY decided, via 19.3's launch offset.
- How long it lasts — the burst length, which the controller programmed (12.1).
- Where it sits relative to the data — a relationship the PHY constructs, because it is generating both signals from the same place.
- When it stops — the PHY decided that too.
There is no estimate anywhere in that list. The transmit strobe is a signal the PHY authors from scratch, and the only hard part is the electrical one of getting it onto a wire with the right characteristics, which is Module 22's.
2. The Read Side Has a Hole in It
Now the hard direction, and the structural fact that creates the whole difficulty.
Between bursts, the read strobe is not driven by anybody. The device drives it during a read burst and releases it afterwards; the PHY drives it during a write burst and releases it afterwards. In the intervals between, the line is floating — owned by nobody, carrying whatever the electrical environment leaves on it.
Chapter 6.10 established that ownership handoff. Its consequence for a receiver is severe:
a naive receiver, always listening
line floating -> noise, coupling, reflections, slow drift
an edge-sensitive receiver sees EDGES here
and captures whatever DQ happens to carry
burst arrives -> real edges, real data
line floating -> more spurious edges, more garbage capturedAn always-listening receiver does not merely capture extra data — it captures extra data that looks exactly like real data. There is no flag on a spurious beat. It enters the assembler (19.2 §6), takes a position in a word, and shifts every subsequent beat.
So the PHY must listen only during the burst, and that requires a control signal that opens the receive path at the start and closes it at the end.
That control is the gate. Its existence is not an optimisation; without it the receive path has no defined behaviour at all.
3. The Gate Is an Estimate
Here is the part that makes gating genuinely hard, and it is worth stating as sharply as possible.
The gate must open before the strobe arrives — because if it opens after the first edge, that edge is gone. But the PHY cannot detect the strobe's arrival in order to open the gate, because detecting it is what the gate enables. The information needed to open the gate correctly is on the other side of the gate.
So the gate is opened on a prediction:
RD command committed at the PHY
|
| CL cycles <- programmed, from the mode register (14.9)
| + flight time out <- physical, not knowable by calculation
| + device response <- device-internal
| + flight time back <- physical, not knowable by calculation
v
strobe actually arrives at the PHY's pinsOnly the first term is computable. The rest is a round trip through a board the designer has never measured — and the sum is precisely Chapter 19.3 §2's two-term decomposition, appearing again on the receive side. A programmed part anyone can look up, and a measured part somebody must find.
4. Believed Window Versus Actual Window
The cleanest way to hold this chapter's idea is as two windows that ought to coincide.
| The actual strobe window | The believed window | |
|---|---|---|
| What it is | when the strobe is genuinely driven on the wire | when the PHY's gate is open |
| Who determines it | the device, plus the board's delays | the PHY, from CL and a trained offset |
| Modelled by | 6.10's dqs_ownership_window | §6's phy_dqs_gate_ctrl |
| Knowable at design time? | no | yes — it is what the PHY was told |
| Failure if they disagree | — | §3's two symptoms |
Chapter 6.10's block and this chapter's block model the same interval from opposite sides. That is not duplication; it is the whole point. One describes what happens, the other describes what the PHY believes happens, and a verification environment that instantiates both and compares them is checking exactly the thing that matters. §10 builds that comparison.
It also explains why 6.10's block carries preamble and postamble parameters and this one does not. The preamble exists so that the actual window begins before the data does, giving a receiver something to align to. How wide it is, and what it is for, is 6.10's subject. What this chapter needs from it is only that the actual window is wider than the data, which is the margin the gate is aiming at.
5. The Gate in Time
EDUCATIONAL TIMING — cycle positions show ordering and window structure only. No edge placement, no sub-cycle relationship, and no device parameter is implied. The real gate position is a trained, largely sub-cycle value (§3).
A read burst: the actual strobe window, the PHY's gate, and what a late gate costs
10 cyclesRead the two gate traces against each other. gate_ok is open from cycle 4, before the first beat at cycle 5 — that lead is what the actual window's extra width buys, and it is the margin the gate is spending. gate_late opens at cycle 7 — three cycles later than it should — and the consequence is immediate and permanent: captured_late shows two beats where four were sent, because B0 and B1 arrived at cycles 5 and 6 while the path was still closed.
The assembler downstream has no way to know. It receives two beats and a burst framing signal, places them, and produces a word that is two beats short. Chapter 19.2 §6's captured_first framing limits the damage to one burst rather than shifting all subsequent ones — but the burst itself is simply wrong, and nothing in the digital path can detect it.
6. Generating and Gating
The drawing's asymmetry is §1 against §2. The transmit path has no input from a trained setting on the drawing because the PHY authored every part of it; the receive path has one, and everything difficult follows from that.
7. The Gate Controller
// ─────────────────────────────────────────────────────────────────────
// phy_dqs_gate_ctrl
//
// CLASSIFICATION
// Synthesizable educational RTL. Sequential. One responsibility:
// produce the receive gate window for a read burst -- open it before
// the strobe is expected, hold it for the burst, close it after.
//
// It models the PHY's BELIEF about when the strobe will be present,
// expressed in whole cycles. The actual strobe window is Chapter
// 6.10's dqs_ownership_window; §4 is about the difference.
//
// WHAT IT DOES NOT MODEL
// - NO CAPTURE. What happens to DQ once the gate is open -- edge
// sampling, where the sampling point sits, setup and hold -- is
// Module 20 entirely. This block produces an enable and stops.
// - NO SUB-CYCLE POSITION. A real gate edge is placed to a fraction
// of a bit period by a delay element (Chapter 19.1 §5). This
// counts whole cycles and §8 states plainly that the quantity
// which decides success is therefore outside the model.
// - NO GATE TRAINING. gate_offset is an opaque INPUT. How a good
// value is searched for is Chapter 21.3's subject.
// - No preamble or postamble semantics. Chapter 6.10 owns the
// structure of the actual window; this block only needs it to be
// wider than the data, which is the margin it spends.
// - No electrical behaviour of an undriven line (Module 22).
// - No write-side strobe generation: that path has no estimate in it
// (§1) and is a timed enable off Chapter 19.3's launch trigger.
// ─────────────────────────────────────────────────────────────────────
module phy_dqs_gate_ctrl #(
parameter int MAX_LATENCY = 48,
parameter int MAX_BEATS = 16,
// Cycles the gate opens ahead of the expected first edge, and holds
// past the expected last one. Margin, spent deliberately: too little
// and a small error loses beats, too much and more floating line is
// admitted (§9).
parameter int LEAD_CYCLES = 1,
parameter int TRAIL_CYCLES = 1,
parameter int LAT_W = (MAX_LATENCY <= 1) ? 1 : $clog2(MAX_LATENCY + 1),
parameter int BEAT_W = (MAX_BEATS <= 1) ? 1 : $clog2(MAX_BEATS + 1)
) (
input logic clk,
input logic rst_n,
// ── From Chapter 17.1's commit, seen at the PHY.
input logic rd_cmd_committed,
input logic [BEAT_W-1:0] burst_beats,
// ── Chapter 19.3 §2's two terms again, on the receive side.
input logic [LAT_W-1:0] cl_cycles, // programmed (14.9)
input logic [LAT_W-1:0] gate_offset, // measured, opaque here
input logic gate_trained,
// ── The gate. Everything the capture path is allowed to see.
output logic gate_open,
// ── Observability. Published separately so a checker can compare
// this believed window against Chapter 6.10's actual one (§10).
output logic waiting,
output logic [LAT_W-1:0] countdown,
output logic err_gate_untrained,
output logic err_overlapping_read,
output logic err_zero_beats
);
if (MAX_LATENCY < 1) $fatal(1, "phy_dqs_gate_ctrl: MAX_LATENCY must be >= 1");
if (MAX_BEATS < 1) $fatal(1, "phy_dqs_gate_ctrl: MAX_BEATS must be >= 1");
if (LEAD_CYCLES < 0) $fatal(1, "phy_dqs_gate_ctrl: LEAD_CYCLES must be >= 0");
if (TRAIL_CYCLES < 0) $fatal(1, "phy_dqs_gate_ctrl: TRAIL_CYCLES must be >= 0");
// ── When the first edge is expected, less the lead -- and less one
// more for the state register's own latency. The FSM reaches
// G_OPEN one cycle after its countdown expires, so loading
// (arrive - LEAD) would open the gate at (arrive - LEAD + 1) and
// silently consume the whole lead. With LEAD_CYCLES = 1 that
// yields ZERO real lead; with LEAD_CYCLES = 0 it opens a cycle
// LATE and loses the first beat, which is §3's failure caused by
// the block meant to prevent it.
// Saturated at zero: a lead larger than the latency would mean
// opening before the command was issued, which is a parameter
// error rather than a runtime condition.
localparam int LEAD_TOTAL = LEAD_CYCLES + 1;
logic [LAT_W:0] arrive;
logic [LAT_W:0] open_at;
assign arrive = {1'b0, cl_cycles} + {1'b0, gate_offset};
assign open_at = (arrive > (LAT_W+1)'(LEAD_TOTAL))
? arrive - (LAT_W+1)'(LEAD_TOTAL)
: '0;
// ── How long the gate stays open: the burst, plus trailing margin.
logic [LAT_W:0] hold_cycles;
assign hold_cycles = {1'b0, LAT_W'(burst_beats)}
+ (LAT_W+1)'(LEAD_TOTAL)
+ (LAT_W+1)'(TRAIL_CYCLES);
typedef enum logic [1:0] {
G_IDLE = 2'd0, // closed; line floating, admitting nothing
G_WAIT = 2'd1, // command seen, counting toward the open point
G_OPEN = 2'd2 // admitting the strobe to the capture path
} gate_state_e;
gate_state_e state;
logic [LAT_W-1:0] cnt;
assign gate_open = (state == G_OPEN);
assign waiting = (state == G_WAIT);
assign countdown = cnt;
// ── Opening a gate against an unestablished offset puts the window
// in an arbitrary place. Reported, not prevented: this block does
// not police bring-up order, Chapter 19.5's lifecycle does.
assign err_gate_untrained = rd_cmd_committed && !gate_trained;
// A second read whose window would overlap the first. A single-window
// controller cannot represent two; §9 states the limitation.
assign err_overlapping_read = rd_cmd_committed && (state != G_IDLE);
assign err_zero_beats = rd_cmd_committed && (burst_beats == '0);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= G_IDLE;
cnt <= '0;
end else begin
unique case (state)
G_IDLE:
if (rd_cmd_committed && burst_beats != '0) begin
if (open_at == '0) begin
// Degenerate but legal: the window starts immediately.
state <= G_OPEN;
cnt <= LAT_W'(hold_cycles);
end else begin
state <= G_WAIT;
cnt <= LAT_W'(open_at);
end
end
G_WAIT:
if (cnt <= LAT_W'(1)) begin
state <= G_OPEN;
cnt <= LAT_W'(hold_cycles);
end else begin
cnt <= cnt - LAT_W'(1);
end
G_OPEN:
if (cnt <= LAT_W'(1)) begin
// Closing is as important as opening: a gate left open
// admits the floating line again (§2), and the capture
// path has no way to tell that from more burst.
state <= G_IDLE;
cnt <= '0;
end else begin
cnt <= cnt - LAT_W'(1);
end
default: state <= G_IDLE;
endcase
end
end
endmoduleOn the write side there is no equivalent block in this chapter, and the omission is deliberate rather than an oversight. Transmit strobe generation is a timed enable hung off 19.3's launch trigger — it starts when the PHY says, runs for the burst, and stops. There is no estimate, no window to predict, and no failure mode that is not already covered by 19.3's alignment or Module 22's electrical behaviour. Writing a block for it would add lines without adding a lesson.
8. What the Assertions Prove
// ── P1. The gate is closed unless a read put it there. The property
// that forbids the always-listening receiver of §2 -- which is the
// default behaviour of a design with no gate at all.
property p_gate_only_after_read;
@(posedge clk) disable iff (!rst_n)
$rose(gate_open) |-> $past(state == G_WAIT || rd_cmd_committed, 1);
endproperty
a_gate_only_after_read: assert property (p_gate_only_after_read);
// ── P2. The gate always closes. A gate that opens and never closes
// admits the floating line indefinitely, and the capture path
// cannot distinguish that from a very long burst.
property p_gate_closes;
@(posedge clk) disable iff (!rst_n)
gate_open |-> ##[1:$] !gate_open;
endproperty
a_gate_closes: assert property (p_gate_closes);
// ── P3. The open window is exactly the burst plus both margins.
// Catches a hold computation that forgets the lead it already
// spent -- which shortens the window at the far end and loses the
// LAST beats rather than the first, a symptom easily mistaken for
// a postamble problem.
property p_window_length;
@(posedge clk) disable iff (!rst_n)
$rose(gate_open)
|-> (gate_open [*1:$]) ##0 (countdown == LAT_W'(1));
endproperty
a_window_length: assert property (p_window_length);
// ── P4. One window per read. A second command while a window is live
// is reported rather than silently merged into the first.
property p_overlap_reported;
@(posedge clk) disable iff (!rst_n)
(rd_cmd_committed && (waiting || gate_open)) |-> err_overlapping_read;
endproperty
a_overlap_reported: assert property (p_overlap_reported);
// ── P5. An untrained gate is reported. Not blocked -- Chapter 19.5
// owns bring-up order -- but never silent, because the resulting
// window lands arbitrarily and the symptom looks like corruption.
property p_untrained_reported;
@(posedge clk) disable iff (!rst_n)
(rd_cmd_committed && !gate_trained) |-> err_gate_untrained;
endproperty
a_untrained_reported: assert property (p_untrained_reported);
// ── Covers. The error paths are the ones a directed happy-path test
// never reaches, and P4 and P5 check nothing without them.
c_untrained_read: cover property (@(posedge clk) disable iff (!rst_n)
rd_cmd_committed && !gate_trained);
c_overlapping: cover property (@(posedge clk) disable iff (!rst_n)
rd_cmd_committed && gate_open);
c_immediate_open: cover property (@(posedge clk) disable iff (!rst_n)
rd_cmd_committed && open_at == '0);What they prove. That the gate is a genuine window with a cause: it opens only in response to a read, it always closes, its length matches the burst and margins, and the two bring-up-order violations are reported.
What they do not prove — and on this block the gap is total. Not one property is sensitive to whether the window is in the right place. P1 through P5 pass identically for a gate_offset of 3, of 30, or of a value that puts the window entirely outside the burst. The block counts faithfully to whatever number it is given, and correctness of the count is independent of correctness of the value.
That is not a defect in the properties. It is the boundary of the layer: §3 established that the right value is not computable, only measurable, and a property cannot check a number against a measurement that has not been taken. The gate position is verified on hardware, with real signals, which is Module 21's subject — and §10's cross-check is the closest a simulation can come.
Vacuity. P2's ##[1:$] is satisfied by any eventual close and proves nothing about when; P3 carries the length claim and is the one that can actually fail. P1's antecedent requires a rising edge on gate_open, so a test with no reads passes it trivially — which is what c_immediate_open and the other covers exist to rule out.
9. Corner Cases
| Situation | Correct behaviour | Failure if mishandled |
|---|---|---|
gate_trained low at a read | window opens; error reported | an arbitrarily placed window, presenting as corruption |
burst_beats = 0 | no window; error reported | a zero-length or never-closing gate |
LEAD_CYCLES exceeds total latency | open_at saturates to zero; opens immediately | an attempt to open before the command — unrepresentable |
| second read while waiting | reported; not merged | two bursts sharing one window, half of each lost |
| second read while open | reported | the same, with the first burst truncated |
MAX_BEATS = 1 | BEAT_W guarded; one-beat burst works | zero-width beat count |
LEAD_CYCLES = 0 | legal; window opens exactly at the expected edge | no margin — any error at all loses the first beat |
TRAIL_CYCLES = 0 | legal; closes at the last expected beat | no margin at the far end; late bursts lose their tail |
| reset mid-window | gate closes immediately | a gate stuck open, admitting the floating line |
gate_offset changes while waiting | the loaded count is unaffected | a window that moves mid-flight during recalibration |
The two zero-margin rows are worth reading together. LEAD_CYCLES and TRAIL_CYCLES are margin deliberately spent: each cycle of lead protects against the window being late at the cost of admitting one more cycle of floating line. That is a genuine trade and it has no universally right answer — it depends on how much the trained value can drift and how badly the floating line behaves, both of which are board properties. Module 21 chooses the centre; these parameters choose how much error the centre can absorb.
10. DV — Comparing Belief Against Reality
This is the one block in Module 19 whose verification has a genuinely good answer in simulation, and it comes from §4's observation.
Instantiate both windows and compare them. Drive Chapter 6.10's dqs_ownership_window from the device's behaviour to produce the actual strobe window, and this chapter's phy_dqs_gate_ctrl from the PHY's command stream to produce the believed window. Then check the relationship that has to hold:
for correct reception, on every burst:
actual_window MUST BE ENTIRELY INSIDE believed_window
not merely overlapping, and not merely coincident:
gate opens strictly before the strobe becomes active
gate closes strictly after it goes inactiveThat is a stronger and more useful check than either block alone, and it is a containment property rather than an equality one — which is the right shape, because the margins of §9 are supposed to make the believed window larger.
The reference model should compute the actual window's bounds from the stimulus independently, not from 6.10's block, so that a shared misunderstanding cannot hide.
GATE CONTAINMENT VIOLATION
read index : 7
command at cycle : 2,140
cl_cycles : 17
gate_offset : 6
LEAD / TRAIL : 1 / 1
believed window : cycles 2,162 .. 2,168 (gate_open)
actual window : cycles 2,160 .. 2,167 (strobe driven)
containment : FAILED at the opening edge
actual starts : 2 cycles BEFORE the gate opens
beats lost : 2 of 4 (the first two)
diagnosis : the believed window is late. The programmed term is
correct by construction, so the discrepancy is in the
measured term -- gate_offset is 2 cycles too large,
or the real round trip is 2 cycles shorter than the
trained value assumes.
symptom shape : DETERMINISTIC displacement. Every burst loses the
same first two beats, so read words are consistently
short rather than randomly corrupt (§3).
NOT indicated : anything about sub-cycle position. Containment at
cycle granularity is necessary and nowhere near
sufficient; a window can contain the burst by whole
cycles and still sample in the wrong place entirely.The last block is the one that keeps the report honest. Cycle-level containment is a real check that catches real bugs, and it is still only the coarse half of the problem.
Directed cases worth running: MAX_BEATS = 1; LEAD_CYCLES = 0, where containment must fail the moment the actual window is even slightly early; a gate_offset swept across its range, which should show containment passing over a band of values rather than one — and the width of that band is exactly the margin Module 21 is trying to centre in; back-to-back reads that overlap; and a reset landing inside an open window.
11. Synthesis and What Is Missing
Cost. Two state bits, one LAT_W-wide counter, and two adders. Instantiated per byte lane, because 19.3 §5 established that the physical term differs per lane and therefore so does the gate position.
What a production gate has that this does not:
- Sub-cycle edge placement, which is the entire difficulty and is a delay element rather than logic.
- Per-lane independence beyond parameterisation — real gates are trained per lane and can differ.
- Pipelining. One window at a time is a real limitation; Chapter 14.6's column spacing permits reads closer together than the latency, so a production PHY tracks several windows.
err_overlapping_readmarks the boundary rather than hiding it. - Drift tracking. Temperature and voltage move the correct position during operation, which is why 19.5 has a periodic path and not only a bring-up one.
- A defined response to a strobe that never arrives — a read that gets no data at all needs a timeout somewhere, and where that lives is a system decision.
12. Debugging
Symptom: read words are consistently short or displaced by the same amount every time. A late gate (§3). Deterministic displacement is the signature. Check containment at the opening edge before suspecting anything in capture, because Module 20's failures corrupt rather than displace.
Symptom: read words contain garbage at the start, varying from burst to burst. An early gate. The varying content is the tell — floating-line behaviour is not repeatable, so a deterministic-looking error is not this.
Symptom: reads work at low rate and fail at full rate. Margin, not logic. The gate's cycle placement is rate-independent; what changes with rate is how much of a bit period a given sub-cycle error represents. This is Module 21's centring problem or Module 22's margin problem, and no RTL inspection will resolve it.
Symptom: one lane loses beats and the others are fine. Per-lane gate position (§11). Not the gearbox, which slices uniformly (19.2 §14), and not the controller, which does not know lanes exist.
Symptom: the first read after bring-up fails and later ones succeed. Check err_gate_untrained. A read issued before the gate offset is established opens a window in an arbitrary place; once training completes, subsequent reads work — which makes the failure look transient when it is actually an ordering problem (19.5).
Symptom: back-to-back reads lose data, isolated reads are fine. err_overlapping_read. A single-window controller meeting closely-spaced column reads cannot represent both windows, and the loss lands on whichever burst the merged window misses.
13. Misconceptions
“DQS is just another clock.” It is not free-running, it is not always driven, and its owner changes with the direction of the data (6.10). Those three properties are exactly why a gate is needed. Clue: a receive path with no gate at all.
“DQS replaces CK.” CK still carries the command/address path (19.1 §4). The strobe times data only. Clue: a PHY block diagram with one timing reference.
“Read and write use the same strobe path in reverse.” §1 against §2 — one is authored with no estimate, the other is predicted. Clue: a receive design derived from the transmit design by flipping a direction bit.
“The gate can be opened when the strobe is detected.” Detecting it is what the gate enables (§3). Clue: a design with an edge detector upstream of the gate.
“A wider gate is always safer.” More lead admits more floating line before the burst. Margin is spent in both directions and §9's trade has no universal answer. Clue: margin parameters set to their maximum "to be safe".
“Lost beats mean a capture problem.” Lost beats at the start, deterministically, mean a gate problem. Capture failures corrupt. Clue: a debug effort that starts at Module 20 without checking containment.
“If the gate logic is correct the gate is correct.” §8 — every property passes on a window in the wrong place. Clue: gate sign-off from simulation alone.
“Gate position can be calculated from the datasheet.” Only the programmed term can. The round trip through the board cannot (19.3 §2). Clue: a design with a gate constant and no training step.
14. Interview Reasoning
“Why does a DDR PHY need a DQS gate?” Because the strobe is not driven between bursts, so an always-listening receiver captures noise that is indistinguishable from data. The strong answer names indistinguishable — that is why it matters.
“Why can't the PHY just detect the strobe and open then?” Because detection requires the receive path to be enabled, which is what the gate controls. The information is on the far side of the decision.
“Reads lose the first two beats of every burst, identically.” A late gate. Then the discriminator: deterministic displacement points at the gate, varying corruption points at an early gate or at capture.
“What is the difference between the gate window and the strobe window?” One is what the PHY believes, the other is what occurs. Containment of the second inside the first is the correctness condition (§10).
“What can simulation prove about a gate?” That it opens only on a read, always closes, and has the right length — and containment, if the actual window is modelled. Not that it is in the right place at sub-cycle precision, which is measured on hardware.
“Why is the gate trained per lane?” Because lanes have different board traces, so the round trip differs per lane (19.3 §5).
15. Exercises
1. With cl_cycles = 17, gate_offset = 6, LEAD_CYCLES = 2 and a read committed at cycle 500, give arrive, open_at and hold_cycles, then the first and last cycle on which gate_open is high for a four-beat burst with TRAIL_CYCLES = 1.
2. §5's waveform shows a gate two cycles late losing two beats. Redraw the captured row for a gate two cycles early. How many beats are captured, and how many of them are real?
3. LEAD_CYCLES = 0. Give the smallest gate-position error that loses a beat, and say why the same error is harmless with LEAD_CYCLES = 2.
4. Construct a stimulus that sets err_overlapping_read. What is the minimum read spacing that avoids it, in terms of the window length?
5. Write the containment property of §10 as SVA. Which signal must come from outside phy_dqs_gate_ctrl, and why can the property not live inside that module?
6. All five properties in §8 pass with gate_offset set to zero. Describe the hardware behaviour and explain why no RTL property can object.
7. A colleague proposes holding the gate open permanently to avoid losing beats. Describe what the assembler receives, and why the resulting words are worse than short ones.
8. Explain why a single-lane beat loss exonerates both the controller and 19.2's gearbox, naming what each does uniformly across lanes.
16. Where This Goes
Three chapters have now consumed the same two things without ever producing them. 19.3 needed a trained_offset and a trained_valid. This chapter needed a gate_offset and a gate_trained. And every block since 19.1 has been gated by a phy_operational that nothing has yet asserted.
Those signals are not incidental plumbing. They are the reason a DDR interface has a bring-up sequence at all, and the reason a PHY is not usable the instant reset is released.
Chapter 19.5 supplies them: the lifecycle that takes a PHY from reset to operational, what has to happen in what order, which parts run once and which run continuously, and what it means for a trained value to become valid — or to stop being valid while traffic is running.
The algorithms that find those values remain Module 21's, and the box marked CAPTURE is still Module 20's.
Continue learning
Related tutorials
- Related topic
The DQS Concept
A strobe is only trustworthy for the wires that shared its path, which is why DQ is grouped into byte lanes each with its own strobe. And the strobe's phase relative to the data is not the same on a read as on a write.
- Related topic
DDR (DDR1)
Double data rate doubles transfer opportunities per clock cycle, not the clock. Two mechanisms make that survivable: a 2n prefetch so a slow array can feed a fast interface, and a source-synchronous DQS strobe so data carries its own timing.
- Related topic
RAS# — Row Address Strobe
RAS# is named after a mechanism it no longer uses. In asynchronous DRAM it was literally a clock that latched a row address; in synchronous DRAM it became a level sampled by CK — and in DDR4 it is not even a dedicated pin.
- Related topic
DQS — The Data Strobe
DQS carries the data's own timing reference along the same path as the data. It is directional, it is not free-running, and the strobe window is wider than the data window — three facts that make it nothing like CK.
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.
