DDR · Module 3
Wordlines
A wordline looks like a digital enable and is not one. One conductor gates every access transistor in a row, so driving it takes real effort, and only the intended row may ever be asserted — which makes row decoding a safety function with a one-hot invariant.
Chapter 3.3 took the vertical conductor and found the electrical heart of the technology in it. This chapter takes the horizontal one, and it would be easy to assume it is the trivial counterpart: a control line, raised to select a row, lowered to deselect it. A Boolean.
It is not, and the central question is why:
What does it actually mean to select a row, and why is that selection an engineered operation rather than a free Boolean choice?
Two answers, and they operate on different layers. Physically, one conductor gates the access transistor of every cell in a row, which makes it long and heavily loaded — so asserting it is an act of driving a real load, taking real effort and real time. Digitally, asserting the wrong conductor, or two at once, destroys data with no error reported anywhere. So row decoding is not a convenience that turns an index into a selection: it is a safety-critical function with an invariant, and this is the chapter where Module 3's RTL becomes a decoder and an assertion about one-hot behaviour.
1. What the Conductor Has to Do
Start from the job, because the job explains the load.
A wordline runs horizontally across a row and connects to the gate of every cell's access transistor along its length. To select the row it must bring all of those gates to a level that turns their transistors on — and to deselect, back to a level that turns them off.
Three properties of that job, each with a consequence.
It drives many gates. Every cell in the row presents a gate to this one conductor. Gates are capacitive loads, and the conductor must charge and discharge all of them to change the row's selection state.
It is long. It spans the row, so it has its own capacitance to the substrate and to the conductors crossing it — including every bitline it crosses, which is one per column. A long conductor also has resistance along its length, which matters in a way §2 develops.
And it must reach every cell in the row with enough level to actually switch the transistor. Not approximately: a cell whose access transistor is only partly on connects its storage node weakly, which corrupts the charge sharing Chapter 3.3 §2 depends on and produces a marginal, condition-dependent read of exactly the kind 3.3 §10 describes.
Read the figure right to left as well as left to right. Left to right is the intent: an index becomes a selection. Right to left is the cost: the load opposes the driver, and the driver has to be sized for it.
2. Why Driving It Is an Engineered Operation
Now the consequence that makes this chapter necessary. A conductor with distributed capacitance and distributed resistance does not change state everywhere at once.
The driver is at one end (or, in real designs, arranged to reduce the problem). The gates are distributed along the length. Charging the conductor means moving charge through its resistance to reach the far capacitance — so the far end of the conductor reaches its final level later than the near end. The relationship is qualitative and reliable: longer conductor, more distributed load, slower to bring the whole row to a switching level.
Three engineering consequences, all of which reach the system.
Selection has a duration, and the duration is a physical property. It is not a clock cycle chosen by a designer; it is how long the conductor takes to bring every gate in the row to a level that fully switches it. This is one of the contributions to why an access to a new row is expensive — and it is a floor unrelated to how fast the external interface runs, which is Chapter 1.8 §2's asymmetry appearing again on the other axis.
The far cells are the worst case, so the design is sized for them. Nothing may begin that depends on the row being connected until the last cell's transistor is properly on. A design that began sensing based on the near end's state would read the far cells through partly-on transistors.
And row width is therefore an architectural variable, exactly as bitline length was. More cells per row amortises the decoder and driver across more cells — better density — while making the conductor longer and slower. Fewer cells per row is faster and less dense. This is the same trade as Chapter 3.3 §5, on the orthogonal axis, and it pushes toward the same resolution: partition the array so no single conductor has to span everything. Chapter 3.6 collects both arguments.
3. Exclusivity Is a Physical Requirement, Not a Convention
Now the digital layer, and the reason this chapter's RTL is worth writing.
Chapter 2.4 §7 established the rule and this chapter can now locate it precisely. At most one wordline within a group of cells sharing bitlines may be asserted at a time.
Follow what happens if two are. Two wordlines assert, so in each column two cells are connected to the same bitline simultaneously. Their charges mix with each other and with the bitline's. The resulting condition reflects neither cell. Sensing resolves something, and whatever it resolves is then restored into both cells — so both now hold the same wrong value.
Three properties of that failure make it the most dangerous fault class in the array:
It destroys data rather than corrupting a read. The bad value is written back into both rows by the ordinary restore mechanism (Chapter 2.6 §1). The loss is permanent until those locations are written again.
It is reported by nothing. The array has no digital state, cannot evaluate legality, and cannot signal a fault (Chapter 2.4 §1). The decoder asserts two outputs; the array obeys.
And it affects two rows per event, which is the diagnostic signature Chapter 2.4 §10 and 3.1 §11 both used to separate it from other faults.
So "assert exactly one, or none" is a safety property. Not an optimisation, not a convention that could be relaxed — a requirement whose violation silently destroys stored data. That is precisely the shape of requirement that belongs in an assertion, and §5 writes it.
4. RTL — A Row Decoder With an Invariant
The problem being solved. A row address is a binary index. The array needs exactly one asserted conductor. Something must convert one into the other, and must be incapable of asserting two.
Abstraction level. Digital control. The decoder is genuinely a digital circuit — this is the one place in Module 3 where the RTL corresponds fairly directly to hardware that exists, rather than modelling a consequence.
What it models. Binary-to-one-hot decoding with an enable, plus range handling for the case where the row count is not a power of two.
What it deliberately does NOT model. No conductor, no capacitance, no resistance, no drive strength, no propagation along the line, and no timing — those are §1 and §2's subject and belong to prose. It is also not a literal model of a modern DRAM row decoder: real devices decode hierarchically, in stages, matched to the partitioned array of 3.6, because a single flat decoder with one output per row in a device does not scale. §4's synthesis note and limitations are explicit about that, and the flat version is used here because it makes the invariant visible.
Interface. enable and row_index in; a one-hot row_select vector out; index_invalid reporting an index that names no row.
How to simulate it. As in 3.1 §5: vlog row_decoder.sv tb_row_decoder.sv then vsim -c tb_row_decoder -do "run -all".
// ─────────────────────────────────────────────────────────────────────────
// ROW DECODER. Classification: SYNTHESIZABLE RTL.
//
// Converts a binary row index into a one-hot selection vector. This is a
// real digital function -- but it is NOT a literal model of a modern DRAM
// row decoder, which decodes HIERARCHICALLY in stages matched to a
// partitioned array (see 3.6 and the limitations below). The flat form is
// used here because it makes the one-hot invariant of §3 visible.
//
// It models NOTHING about the conductor: no capacitance, no resistance, no
// drive, no propagation, no timing. Those are §1 and §2.
// ─────────────────────────────────────────────────────────────────────────
module row_decoder #(
parameter int ROWS = 8,
// DERIVED. The guard keeps ROWS == 1 legal rather than producing a
// zero-width index, which would be an illegal declaration below.
parameter int ROW_W = (ROWS <= 1) ? 1 : $clog2(ROWS)
) (
input logic enable,
input logic [ROW_W-1:0] row_index,
// One-hot when enabled and the index is valid; all-zero otherwise.
output logic [ROWS-1:0] row_select,
// High when the index names a row that does not exist. Only reachable
// when ROWS is not a power of two. It is an OUTPUT rather than an
// assumption because silently selecting nothing and silently selecting
// the wrong row look identical from here -- and one of them destroys data.
output logic index_invalid
);
// ── COMPILE-TIME legality. An illegal parameterisation is an elaboration
// error rather than a runtime surprise.
if (ROWS < 1) begin : g_bad_rows
initial $fatal(1, "row_decoder: ROWS must be >= 1");
end
// An index beyond the populated rows can only occur when ROWS is not a
// power of two. With a power-of-two ROWS this condition is constant false
// and optimises away entirely.
assign index_invalid = (ROWS < (1 << ROW_W)) && (row_index >= ROW_W'(ROWS));
// ── THE DECODE. Written as an explicit comparison per output rather than
// as a shift, for two deliberate reasons:
//
// 1. A shift (`1 << row_index`) is wider than ROWS whenever ROWS is not
// a power of two, so it needs a truncation that can silently drop
// the only set bit -- producing an all-zero vector that looks like
// "nothing selected" rather than an error.
// 2. The comparison form makes the one-hot property structural: each
// output is asserted only by its own index matching, so two outputs
// cannot both be high unless the comparison itself is broken.
//
// Correctness beats brevity here, because §3's failure is silent.
always_comb begin
row_select = '0;
if (enable && !index_invalid) begin
for (int r = 0; r < ROWS; r++) begin
row_select[r] = (row_index == ROW_W'(r));
end
end
end
endmoduleCombinational decisions. One comparison per row, gated by enable and by index validity. The default assignment of '0 at the top of the always_comb is what guarantees the all-zero case is reachable and that no latch is inferred — every output is assigned on every path.
Sequential updates. None. The decoder is purely combinational, which is itself worth noting: the selection is a function of the current index, never a remembered state. What remembers which row is selected is 3.1's tracker, and keeping the two separate is why each is simple.
Cycle-by-cycle example. With ROWS = 8, ROW_W is 3. enable = 0 gives row_select = 8'b0000_0000 regardless of the index. enable = 1, row_index = 5 gives 8'b0010_0000 — exactly one bit. With ROWS = 6, ROW_W is still 3, and row_index = 6 sets index_invalid with row_select all zero: nothing is selected, and the design is told why.
Simulation expectations. An exhaustive test over every index with enable both low and high: row_select must be all-zero whenever enable is low or index_invalid is high, and must have exactly one bit set otherwise, at the position matching the index. For a non-power-of-two ROWS, indices at and above ROWS must set index_invalid.
Synthesis implications. ROWS comparators of ROW_W bits each, plus the enable gating — small at modest ROWS, and growing linearly with row count, which is the scaling fact that matters. A flat decoder with one output per row in a real device would be an enormous combinational structure with an enormous fan-out, which is precisely why real designs decode in stages against a partitioned array. That is a limitation of this model, not of DRAM.
Corner cases, and why each guard exists. ROWS == 1 gives ROW_W == 1 through the guard rather than $clog2(1) == 0, which would make logic [ROW_W-1:0] an illegal declaration. ROWS of zero is an elaboration error. A non-power-of-two ROWS makes some index values name no row, which index_invalid reports rather than aliasing. And the shift-versus-comparison choice in the comment is a corner case in its own right: the shift form is shorter and can silently produce an all-zero vector when truncated.
Debugging observations. If two outputs are ever high, the comparison logic or the index width is wrong — and §5's first assertion catches it immediately. If nothing is selected when something should be, check enable and index_invalid before suspecting the decode. If the wrong row is selected, compare the index width here against the width the address decomposition of 3.2 §5 produces; a field-width mismatch shows up exactly here, with the power-of-two offset signature 3.2 §9 described.
Limitations. Flat rather than hierarchical, so it does not scale to a real device's row count and does not model staged decoding. No timing, no drive, no conductor. No notion of which row is currently selected — that is 3.1. One array, so no selection among local structures; 3.6 adds that layer.
5. Three Assertions Worth Writing
The one-hot property from §3 is the reason this section exists, and it is a good illustration of an invariant that is cheap to state and expensive to omit.
// VERIFICATION-ONLY, bound to row_decoder. The module is combinational, so
// the sampling clock comes from the testbench, not from the module.
// P1 -- THE safety property of §3: never more than one conductor asserted.
// $onehot0 accepts exactly zero or one bit set, which is precisely the legal
// set -- "none selected" is legal, "two selected" destroys two rows with no
// error reported anywhere.
property p_select_is_onehot0;
@(posedge clk)
$onehot0(row_select);
endproperty
assert property (p_select_is_onehot0);
// P2 -- and the positive direction, which P1 alone does not give. When
// enabled with a valid index, EXACTLY one output is asserted and it is the
// right one. P1 would be satisfied by a decoder that always output zero;
// this is what forbids that.
property p_enabled_selects_the_named_row;
@(posedge clk)
(enable && !index_invalid) |-> (row_select == (ROWS'(1) << row_index));
endproperty
assert property (p_enabled_selects_the_named_row);
// P3 -- nothing is selected when selection is not permitted. Catches an
// enable that has been optimised out of the decode path, which is invisible
// to P1 and P2 because both only constrain the enabled case.
property p_nothing_selected_when_disabled;
@(posedge clk)
(!enable || index_invalid) |-> (row_select == '0);
endproperty
assert property (p_nothing_selected_when_disabled);What these prove, and why all three are needed. P1 is the safety half: no two conductors. P2 is the liveness-and-correctness half: the right one, and exactly one. P1 alone is satisfied by a decoder that selects nothing, ever — which is why a one-hot check by itself is a weaker guarantee than it looks. P3 closes the remaining gap by constraining the disabled case, which neither of the others touches. Together they pin the decoder's whole function.
What they do not prove. Nothing here says the conductor was driven properly, reached every gate, or settled before anything depended on it. Those are §2's physical properties, are not observable in digital simulation, and belong to circuit simulation and characterisation. An assertion on a decoder proves the decoder commanded the right selection — never that the array performed it. Real designs are additionally verified against device models, and the physical properties against silicon.
And note what P2's form costs. ROWS'(1) << row_index is a clean specification precisely because it is not how the decoder is implemented — the implementation uses comparisons for the reasons §4's comment gives. Writing the property in a different form from the design is deliberate: an assertion that restates the implementation proves only that the code equals itself.
6. Verification Perspective
The decoder is exhaustively verifiable, and that is unusual enough to exploit. The input space is enable times the index range — small for any testable ROWS. Exhaustive beats random here, and a regression that uses random stimulus on a module it could enumerate is leaving certainty on the table.
Parameter configurations are part of the design. ROWS == 1; a power of two; a non-power-of-two; and a value large enough to make the synthesis scaling visible. As Chapter 1.6 §4 argued, a parameterised module is several designs.
The non-power-of-two case needs its own attention because it is the only configuration where index_invalid can assert. Test the last valid index, the first invalid one, and the maximum the index width allows.
Integration is where the real bugs live. The decoder is almost trivially correct in isolation; what fails in practice is the interface between it and the address decomposition of 3.2 — a field width disagreement, or an index taken from the wrong bits. So the verification target is the pair, not the decoder alone, and the check is the reassembly property 3.2 §6 provides.
And one property worth asserting at the integration level rather than here. Only one decoder within a group sharing bitlines may be enabled at a time. This module cannot check that — it can only see its own outputs — so the property belongs wherever the enables are generated. Noticing that an invariant sits at a different level from where it is felt is a genuinely useful verification skill.
Coverage targets. Every index; every index with enable low; index_invalid both asserted and not; each parameter configuration elaborated; and at the integration level, every combination of decoder enables.
7. Common Misconceptions
"A wordline is just a digital enable." Wrong model: asserting it is free and instantaneous, like setting a control bit. Engineering action: the engineer treats row selection as a zero-cost operation, and models an access as though the expensive part were elsewhere. Resulting bug: performance models with no term for selection duration, and an inability to explain why a row change costs what it does or why row width is a design decision. Correct model: it is a long conductor driving every access-transistor gate in the row, with distributed capacitance and resistance. Asserting it means driving a real load, and the far end settles after the near end. Prevention: think "drive a bus", not "set a flag".
"One giant row would amortise the decoder best." Wrong model: wider rows are strictly better because the periphery is shared further. Engineering action: proposing very wide rows to improve density. Resulting bug: a conductor so long and heavily loaded that selection becomes slow, and a far end that settles well after the near end — so the whole row's selection duration is set by its worst cell. Density improves and access cost degrades. Correct model: the same trade as Chapter 3.3 §5 on the orthogonal axis. Row width amortises the decoder and driver while lengthening the conductor, and partitioning is how real designs get much of both. Prevention: before widening a row, name what the far end's settling does to the access.
"Selecting two rows would just read both." Wrong model: a benign double read. Engineering action: not treating one-hot decoding as a safety property, and omitting the invariant from verification. Resulting bug: permanent destruction of two rows, with no error anywhere. Both cells' charges mix, sensing resolves something meaningless, and the restore mechanism writes that meaningless value into both rows. Correct model: exclusivity is a physical requirement whose violation silently destroys stored data. §3 is the mechanism. Prevention: P1 in §5, plus the integration-level enable property §6 names.
"A one-hot assertion proves the decoder works."
Wrong model: $onehot0 is sufficient.
Engineering action: asserting the safety property and considering the module verified.
Resulting bug: a decoder that selects nothing satisfies $onehot0 perfectly. So does one that selects the wrong single row. Both pass, and the second is a wrong-row access — 3.1 §11's investigation.
Correct model: safety and correctness are separate properties. P1 forbids two; P2 requires the right one; P3 constrains the disabled case.
Prevention: for any "at most one" invariant, ask what forbids "none" and what forbids "the wrong one".
"The decoder in a tutorial is how a DRAM device decodes rows." Wrong model: a flat one-output-per-row decoder is the real structure. Engineering action: reasoning about decoder area, fan-out or delay in a real device from the flat model, or assuming the address arrives as a single index into a global row space. Resulting bug: conclusions that do not survive contact with a real device, whose decoding is staged and matched to a partitioned array. Correct model: the flat form makes the invariant visible and does not scale. Real devices decode hierarchically — which is 3.6's subject. Prevention: §4's synthesis note. When a model's cost scales badly, ask what real designs do instead.
8. Debugging — The Wrong Row Was Selected
Symptom. Accesses reach the wrong row. Reproducible, no error reported. In some cases two rows are found corrupted per event; in others exactly one row is read incorrectly with nothing destroyed.
Start by counting. How many rows are affected per event? Two means two conductors were asserted — mechanism 1. One, with data destroyed, means a sequencing fault (Chapter 2.6 §11). One, read incorrectly with nothing destroyed, means a decode or index fault — mechanisms 2 to 4. That single question splits the space before any waveform is opened.
Mechanism 1 — two conductors asserted. Inspect: the row_select vector for $onehot0, and whether two decoders in the same bitline group were enabled together. Expected evidence: two damaged rows in a consistent pairing, and the pairing maps onto two decoder outputs. Discriminator: P1 fails in simulation. In a lab, the consistent pair is the signature — arbitrary corruption does not pair.
Mechanism 2 — the index is right and the field width is wrong. Inspect: the index width the decoder was elaborated with against the width the address decomposition produces. Expected evidence: the wrong row is a consistent power-of-two offset from the intended one, and the error appears above a magnitude threshold — the point where the disputed bit first matters. Discriminator: the arithmetic signature, exactly as 3.2 §9 described. This is the most common integration fault in the pair.
Mechanism 3 — an out-of-range index was allowed to alias. Inspect: whether ROWS is a power of two, and whether index_invalid is consumed by anything. Expected evidence: only high indices misbehave, and they map onto low rows. Discriminator: non-power-of-two dimensions plus an ignored validity output. Note the trap: a consumer that never checks the signal behaves identically to one that has no such signal.
Mechanism 4 — the decoder is right and the tracker is wrong. Inspect: 3.1's open_row_id against the index actually presented to the decoder. Expected evidence: the decoder selected exactly what it was asked for, and it was asked for the wrong thing. Discriminator: compare the decoder's input against the request. If the input is wrong, the fault is upstream and this chapter is exonerated — 3.1 §11 continues it.
Mechanism 5 — selection was correct but incomplete. Inspect: whether the failures concentrate in cells far from the driver, and whether they are condition-dependent rather than deterministic. Expected evidence: a positional gradient and sensitivity to temperature or supply — because a partly-switched access transistor connects its cell weakly. Discriminator: determinism. Mechanisms 1 to 4 are deterministic decode faults; this one is a margin fault and behaves like 3.3 §10's mechanisms.
Discrimination in three questions. How many rows per event? Two exits to mechanism 1. Is the wrong row a power-of-two offset away, and does the failure have a magnitude threshold? Yes points at mechanism 2 or 3. Was the decoder's input correct? No exits to mechanism 4. Is it deterministic? No points at mechanism 5.
The reasoning lesson. Decode faults leave arithmetic signatures — consistent offsets, bit-boundary thresholds, aliasing of high indices onto low rows — while margin faults leave statistical signatures. The two require completely different investigations, and the first observation usually separates them. An engineer who starts by asking what kind of signature is this? rather than what data came back? converges far faster.
9. Interview Reasoning
"Why is a wordline not simply a digital enable?" Because it drives the gate of every access transistor in the row, so it is a long conductor with distributed capacitance and resistance rather than a short net driving a few loads. Asserting it means charging that whole distributed load, and the far end reaches a switching level after the near end — so selection has a real duration, and the design must wait for the worst cell rather than the nearest. A strong answer names the consequence: selection duration is a physical floor unrelated to how fast the external interface runs.
"What happens if two wordlines in the same bitline group are asserted, and why is it the worst fault in the array?" In each column two cells are connected to one bitline, their charges mix, and the resulting condition reflects neither. Sensing resolves something meaningless and the restore mechanism writes it back into both cells, so two rows are permanently destroyed. It is the worst fault because nothing reports it — the array has no digital state and cannot refuse or signal — and because the damage is written back rather than merely misread. Its signature is two damaged rows per event in a consistent pairing.
"Is $onehot0(row_select) enough to verify a row decoder?"
No, and this is a good discriminator of verification maturity. $onehot0 forbids two selections, which is the safety property, but it is satisfied perfectly by a decoder that selects nothing and by one that selects the wrong single row. It needs a companion property requiring that, when enabled with a valid index, exactly one output is asserted and it is the one the index names — plus a third constraining the disabled case, which neither of the others touches.
"Why does row width involve a trade-off at all?" Because it is the same trade as bitline length, on the orthogonal axis. A wider row amortises the decoder and driver across more cells, which improves density and cost per bit, while making the conductor longer and more heavily loaded — so selection is slower and the far end settles later. Narrower rows are faster and less dense. Real designs resolve it by partitioning the array so no single conductor spans everything, which buys short conductors while keeping periphery affordable.
"Why is a flat one-output-per-row decoder not how real devices work?" Because it scales linearly in comparators and in fan-out with row count, so at a real device's row count it would be an enormous combinational structure driving an enormous load. Real devices decode hierarchically, in stages matched to a partitioned array — select a local structure, then a row within it — which keeps each stage's fan-out and each conductor's length manageable. The flat form is a teaching device that makes the one-hot invariant visible.
10. Engineering Check
A decoder is elaborated with
ROWS = 6. The address decomposition feeding it produces a 3-bit row index. During a test sweep, accesses to some addresses reach the wrong row and others appear to do nothing at all.
1. Why is a 3-bit index the right width, and what does that imply? $clog2(6) is 3, so three bits are needed to name six rows — and three bits can express eight values. Two of them, 6 and 7, name rows that do not exist. The index space is larger than the row space, which is possible for every non-power-of-two dimension.
2. What should happen for index values 6 and 7? index_invalid asserts and row_select is all zero — nothing is selected, and the design is told why. That is the "appear to do nothing" case in the symptom, and it is the decoder behaving correctly.
3. So where do the wrong-row accesses come from? Not from the decoder, if index_invalid is being produced. The most likely cause is that the consumer ignores index_invalid and proceeds as though a row had been selected — in which case the access targets whatever the rest of the design assumes. Alternatively the index is being taken from the wrong address bits, which is mechanism 2 in §8 and shows a power-of-two offset signature.
4. What is the dangerous version of this, and why is it worse than either symptom? A decoder implemented with a shift rather than comparisons. 1 << row_index for index 6 sets a bit beyond the six-bit output, so truncating it yields all zero — indistinguishable from "nothing selected" — while a different truncation or width could alias it onto a real row. Silently selecting nothing and silently selecting the wrong row look identical from the decoder's boundary, and one of them destroys data. §4's comment is exactly about this.
5. Which property would have caught it in review? P3 in §5 pins the disabled-or-invalid case to all-zero, so an aliasing implementation fails immediately. P2 pins the valid case to the named row. Note that P1 alone would have passed all of these faults, which is why §5 insists on all three.
6. What is the cleanest way to avoid the whole class of problem? Constrain ROWS to a power of two where the design allows it, which makes the invalid case unreachable and the range logic constant-fold away. Where it does not allow it, treat index_invalid as a signal that must be consumed, and assert that consumers do. Making an illegal case unreachable is better than handling it — and where it cannot be made unreachable, making it loud is better than making it safe-looking.
11. Summary
A wordline is the row-selection conductor, and the chapter's reframing is that it is not a signal but a load: it connects to the gate of every access transistor in the row, so it is long, carries distributed capacitance from those gates and from every conductor it crosses, and has resistance along its length.
Therefore asserting it is an engineered operation. The far end reaches a switching level after the near end, so selection has a real duration set by the worst cell rather than the nearest — a physical floor unrelated to interface speed. And row width becomes an architectural variable: wider amortises the decoder and driver but lengthens the conductor, which is the same trade as bitline length on the orthogonal axis, pushing toward the same resolution of partitioning the array.
On the digital side, exclusivity is a physical requirement, not a convention. Two asserted conductors connect two cells to one bitline; their charges mix; sensing resolves something meaningless; and the restore mechanism writes that back into both rows. Two rows destroyed, permanently, with nothing reporting it — because the array has no digital state and cannot refuse.
So row decoding is a safety-critical function with an invariant, and the invariant needs three properties rather than one: at most one output asserted, exactly the named output when enabled and valid, and nothing asserted when not. $onehot0 alone is satisfied by a decoder that selects nothing and by one that selects the wrong row.
And the decoder's faults are diagnosable because they leave arithmetic signatures — consistent power-of-two offsets, bit-boundary thresholds, high indices aliasing onto low rows — which is what separates them from the statistical signatures of margin faults.
12. What Comes Next
Four chapters have built the array's structure: rows, columns, and the two conductors that select them. One thing has been used repeatedly and never opened.
Every chapter so far has said that sensing resolves the small difference, that it needs a reference, that it is expensive and therefore shared, and that its result is strong enough to restore the row. Chapter 3.5 is that circuit's function — the deepest chapter in the module. It answers how a tiny analog disturbance becomes a reliable digital value, why the same operation simultaneously creates a temporary copy of the whole row, and why an active row therefore has a completely different access cost from a closed one. It is also where the module's RTL turns to the state that matters most to a controller: a row being selected is not yet a row being usable.
Return to Bitlines for the conductor this one crosses, Rows for what selection produces, or The DRAM Cell (1T1C) for the transistor this conductor gates. The full path is on the DDR tutorials index.
Continue learning
Related tutorials
- Related topic
The Refresh Requirement
Leakage produces a rule about the passage of time rather than about any operation. What the maintenance operation actually does, why it costs device availability, and how a digital design tracks a deadline, arbitrates it against traffic, and proves it never silently drops the obligation.
- Related topic
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.
- Related topic
Rows
A DRAM row is not an address range. It is the group of cells one shared selection conductor connects at the same instant — and that physical fact is where row granularity, controller-visible row state and state-dependent access cost all come from.
- Related topic
Sense Amplifiers
How a tiny analog disturbance becomes a reliable digital value, why the same operation simultaneously creates a temporary copy of the whole row, and why a selected row is not yet a usable row — the state distinction every memory controller is built around.
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.
