DDR · Module 31
DDR vs LPDDR
The access contract is identical and all thirteen obligations are shared, so no structural argument separates these two. The deciding quantity is energy under the actual duty cycle and idle-duration distribution, not power and not bandwidth.
Chapter 31.1 compared two access contracts. This chapter compares one contract against itself.
That is the finding, and it is the opposite shape from the previous chapter. LPDDR and DDR share axis A1 completely: the same destructive read, therefore the same restore, the same row buffer, the same precharge, the same refresh obligation, the same timing-legality framework, and all thirteen of 31.1 §5's controller obligations. A reader arriving expecting another difference in kind will not find one.
So the decision cannot be made on structure, and it turns on a quantity instead:
The deciding quantity is energy under the duty cycle the system actually has — not power, not energy per bit, and not bandwidth. And because duty cycle is a property of the workload rather than of the market segment, the labels mobile and server are proxies that fail at the edges.
Two consequences that the rest of the chapter earns. First, the obligation set does not change kind — it grows: LPDDR adds obligations on top of the thirteen rather than removing any, so the low-power part needs the larger controller. Second, legality gains a dimension — a command can be timing-legal and still inadmissible because the device is in a state that does not accept it.
1. The Axis That Does Not Move
Axis A1 is identical, and stating that first closes off most of the arguments people make.
Both technologies store a bit as charge on a capacitor addressed by one transistor. Both destroy the value when they read it. CURRICULUM-DERIVED from 2.4, 2.5 and 2.6 — and 31.1 §4's causal chain therefore runs identically for both:
A1 read destroys the stored value -- SAME for both
-> restore is part of the access -- SAME
-> a rebuilt row is held somewhere -- SAME (row buffer)
-> access cost depends on what is held -- SAME (C2 answered "yes")
-> completion time is not constant -- SAME (C1 "neither")
-> "which row is open" is controller state -- SAME
charge leaks while idle -- SAME
-> periodic rewrite is mandatory -- SAME
-> the memory needs the bus for itself -- SAME (C3 "yes")So 31.1 §1's four contract questions get the same four answers. Both technologies present the same access contract, and therefore neither is admissible where the other is not. Stage one of 31.1 §1's decision cannot separate them at all, which is why this chapter is entirely about stage two.
Three arguments this rules out, and each is heard often:
| Argument | Why axis A1's identity refutes it |
|---|---|
| “LPDDR is simpler because it is for small systems” | the obligation set is the same thirteen, plus more — §7 |
| “LPDDR has different timing so the controller is different in kind” | the same four constraint classes of 13.3, the same scope taxonomy, different values |
| “You can use LPDDR where DDR's latency variability is unacceptable” | the variability is structural and shared; §1's chain produces it identically |
The third is the dangerous one, because it is an admissibility claim and admissibility claims close questions. A block that cannot tolerate 31.1 §6's completion spread cannot tolerate either of these technologies, and choosing the low-power one does not help.
2. What Is the Same, Counted
Chapter 31.1 §5 counted thirteen obligations that exist because of A1. Run the same table for this comparison and it is uniform:
| Obligation | DDR | LPDDR | Difference |
|---|---|---|---|
| Row state per bank, three-valued | yes | yes | none in kind |
| Precharge before a different row | yes | yes | values |
| Activate-to-column separation | yes | yes | values |
| Minimum row-open time | yes | yes | values |
| Column spacing, scoped by group | yes | yes | grouping differs by generation — 24.4 §8 |
| Activate rate limiting | yes | yes | values |
| Refresh accrual ledger | yes | yes | and §12 is about who owns it when |
| Refresh execution with a drain | yes | yes | scope options differ — 24.2 §8 |
| Read-return prediction | yes | yes | values |
| Write-delivery deadline | yes | yes | values |
| Direction turnaround | yes | yes | values |
| Legality as a maximum over rules | yes | yes | plus a second dimension — §8 |
| Scheduling among legal candidates | yes | yes | none in kind |
Thirteen for thirteen. DERIVED: the difference between these two technologies is zero obligations removed and several added, which is the reverse of the intuition that a low-power part is a reduced part.
And one row deserves its correction stated immediately, because the claim is common and a verified measurement contradicts it. CURRICULUM-DERIVED from 24.2 §8, which checked a datasheet rail by rail at two speed grades in two width modes and found every refresh current identical between all-bank and per-bank refresh: per-bank refresh does not refresh less — it refreshes the same total in smaller pieces. What it buys is availability, converting a device-wide stall into a partial one. So per-bank refresh is a performance mechanism and must not be entered in an energy comparison at all.
3. The Objective Changed, Not the Contract
If the contract is identical, what actually differs? The quantity each technology's design decisions were taken to minimise — and that propagates into the interface, the channel shape and the state set without ever changing axis A1.
| Axis | DDR profile | LPDDR profile | Owner |
|---|---|---|---|
| A1 cell mechanism | destructive | destructive | identical — §1 |
| A2 obligations | thirteen | thirteen plus power-state obligations | §7 |
| A3 granularity | burst-shaped | finer minimum access, more channels | 24.3 §8 |
| A4 channel shape | fewer, wider | more, narrower | 4.7 §5, 24.3 §9 |
| A5 latency composition | the same terms | the same terms plus a wake term | §8 |
| A6 bandwidth rung | rungs 1 and 2 | rungs 1 and 2, at a different point | 30.8 §2 |
| A7 physical coupling | socketed or soldered, replaceable | soldered, often package-on-package, not replaceable | §16 |
Row A5 is the one that changes the latency model rather than its numbers. A device in a low-power state must be brought out of it before an access can proceed, so an access's completion time acquires a term that depends on the device's state at the moment of the request — which is a second history dependence layered on top of the row-state one. So LPDDR's completion spread is strictly wider than DDR's, not narrower, and §8 is that fact as a legality test.
Row A7 is the irreversible one and it is not an energy argument at all. A part that cannot be replaced cannot be upgraded, cannot be swapped on failure, and cannot be probed with an interposer during bring-up — so choosing it forecloses debug options that 30.10 §2's observability collapse already makes scarce. That belongs in the decision even though it appears in no power budget.
4. Three Quantities, and Why a Comparison Picks the Wrong One
CURRICULUM-DERIVED from 24.1 §2, which owns these three and the warning that comes with them — a mechanism praised without saying which quantity it improves has not been explained:
| Quantity | Measures | Only one of these is a speed |
|---|---|---|
| Energy per bit | what it costs to move one bit | an efficiency |
| Idle power | what the device costs while moving nothing | an overhead |
| Peak bandwidth | the most it can move at once | the speed |
And 24.1 §2 owns the three ways they pull apart, each of which makes a naive comparison wrong in a different direction: raising the data rate can improve energy per bit, because the surrounding circuitry is awake for less time; a deeper idle state improves idle power and worsens energy per bit when the device is woken often; and a wider channel improves peak bandwidth while worsening energy per bit for small accesses.
So every single-number comparison between these technologies is wrong, and predictably so:
| Compare on | What it wrongly concludes | Because |
|---|---|---|
| Peak bandwidth | the sustained-throughput part always wins | ignores that most systems are idle most of the time — 24.1 §3 |
| Idle power | the low-power part always wins | ignores the exit cost paid on every wake — 24.2 §5 |
| Energy per bit | whichever part moves data faster | a bit that was moved and discarded still cost its energy — 12.4 |
| Active power | the low-power part, usually wrongly | a part that takes twice as long at half the power spent the same energy |
The last row is the error worth naming because it is dimensionally obvious and still common. Power is not the quantity a battery depletes; energy is. A comparison in watts has dropped the time axis, and the time axis is exactly what the duty cycle restores.
5. The Deciding Quantity, Derived
The quantity is average energy per unit of delivered work, evaluated at the system's actual duty cycle. DERIVED, and every term stays abstract for the reason 24.2 §5 gives — an exit energy cannot be computed from a published exit latency and a steady-state current, so inventing one would be the error this curriculum refuses.
Let D = duty cycle, the fraction of time the memory is active
T = the interval being accounted over
Pa = active power for the profile
Pi = idle power for the profile
W = the work delivered in the interval (bits)
average power = D x Pa + (1 - D) x Pi
energy per bit = ( D x Pa + (1 - D) x Pi ) x T / W
now DIFFERENCE the two profiles. Let
dPi = Pi(sustained) - Pi(low-power) the IDLE advantage
dPa = Pa(low-power) - Pa(sustained) the ACTIVE penalty
(sign not assumed)
the low-power profile is ahead when
(1 - D) x dPi > D x dPa
and the crossover duty cycle is
D* = dPi / ( dPi + dPa )Read the closed form rather than any number, because the form is the transferable part.
If dPa <= 0 — no active penalty — then D* is 1 or undefined, and the low-power profile wins at every duty cycle. That case is real and worth naming: 24.1 §2's first example is exactly it, since a faster device can be more efficient per bit because the surrounding circuitry is awake for less time.
If there is an active penalty, D* is strictly between 0 and 1, and above it the sustained profile wins. DERIVED, ILLUSTRATIVE, following 24.2 §5's practice of abstract units rather than invented currents — take dPi = 4 and dPa = 6:
D* = 4 / (4 + 6) = 0.40
so at duty cycles below 40% the low-power profile is ahead, and
above 40% the sustained profile is.
recompute at dPi = 4, dPa = 2: D* = 4/6 = 0.667
recompute at dPi = 1, dPa = 6: D* = 1/7 = 0.143
DERIVED, all three. Note the sensitivity: a fourfold change in
the idle advantage moves the crossover from 14% to 67%. The
crossover is NOT a robust constant, which is why §16 measures it
rather than assuming it.And the exit cost has not been forgotten — it lives inside Pi, and that is where the break-even hides. CURRICULUM-DERIVED from 24.2 §5: for a state with per-tick saving s and exit cost e, entering is worth it when s × d > e, so the break-even idle duration is d* = e / s. So the effective Pi a profile achieves is not its datasheet idle power — it is whatever its state machine actually attains given the distribution of idle durations, and a device woken more often than d* never reaches its deep-state figure at all.
DERIVED, and this is the sentence worth carrying out of the section: the deciding quantity is not a duty cycle alone but a duty cycle and an idle-duration distribution — because the same 2% active fraction achieved as one long idle and as ten thousand short ones produces completely different effective idle power. A comparison given only an average duty cycle is under-specified.
6. The Inversion — Duty Cycle Is Not a Market Segment
Now apply §5 to the two cases everybody has in mind, and watch the labels come apart.
CURRICULUM-DERIVED from 24.1 §3, whose ILLUSTRATIVE model takes a device active 2% of the time and shows, with active costing 50 units and idle 1 unit, that the idle state contributes 49.5% of average power — with idle costing one fiftieth of active. And its follow-on result: improving the active case by 20% moves the average very little, because the active term was never the majority.
against §5's ILLUSTRATIVE D* = 0.40 :
a phone in a pocket D ~ 0.02 -> far BELOW D*
a phone sustaining a camera
or game pipeline D ~ 0.5+ -> ABOVE D*
a server running sustained
analytics D ~ 0.7+ -> far above D*
an edge node or a burst-scaled
instance, idle between requests D ~ 0.05 -> far BELOW D*
DERIVED reading: two of the four cases sit on the side of the
crossover their MARKET SEGMENT does not predict.So the labels are proxies, and they fail at exactly the interesting edges.
A mostly-idle server has the mobile problem. Its average power is dominated by a state in which it is doing nothing, and every argument Module 24 makes applies to it. CURRICULUM-DERIVED from 24.1 §3's arithmetic, which is about a duty cycle and never about a phone.
And a phone sustaining a workload has the server problem. During a camera pipeline or a sustained render the idle term nearly vanishes, so the comparison is decided by active efficiency and by 24.1 §4's thermal ceiling — there is no fan, so the sustained case is bounded by heat rather than by energy, which is a different constraint again.
The decision is made on the duty cycle and the idle-duration distribution, and a design that reasons from the market segment has substituted a proxy for a measurement. The proxy is usually right, and the cases where it is wrong are the ones that reach a design review.
The honest qualification, and it must accompany the inversion: the two technologies are not freely interchangeable regardless of what the arithmetic says. Availability, capacity per channel, physical form, replaceability (axis A7) and ecosystem constrain the choice independently of energy, and §5's crossover answers only the energy question. A candidate who presents D* as the answer has made the mistake this module's central law warns against — naming one deciding quantity when the decision has several, and §16 is the ordered measurement that respects that.
7. The Obligation Set Grows
§2 established that no obligation is removed. Now count what is added, and note that every addition is controller state — the low-power part needs the larger controller.
| Added obligation | State it requires | Owner |
|---|---|---|
| The device's power state, tracked | a state register, and it must agree with the device | 24.2 §1 |
| Illegal transitions, enforced | a transition legality matrix | 24.2 §3 |
| Entry and exit cost accounting | the s and e terms of the break-even — 24.2 §5 | 24.2 §6 |
| An idle-duration predictor | history, and a policy that can be wrong in both directions | 24.2 §5 |
| Who owns refresh right now | an ownership flag, and §12 is what happens when it is wrong | 24.2 §4 |
| PASR mask state, with a retention consequence | a mask, plus the rule that a masked region's contents are gone | 24.2 §9 |
| Command qualification by state | the contract that a command is only accepted when qualified | 6.2 |
| Rail state and sequencing | an ordering invariant with forbidden orders | 24.5 |
| Reconfiguration of a runtime-variable interface | a guard, where the interface is configurable | 24.4 §15 |
DERIVED: thirteen obligations become twenty-two, and none of the original thirteen got cheaper.
Two of these rows are qualitatively unlike anything in the original thirteen, and they are the interesting ones.
The idle-duration predictor is the first obligation in this curriculum that is allowed to be wrong. Every one of the thirteen is a correctness obligation — a timing rule is either respected or violated. A prediction is a policy that will be wrong sometimes by construction, and CURRICULUM-DERIVED from 24.2 §5, being wrong is asymmetric: entering a deep state for a short idle pays e and recovers little, while staying shallow through a long idle forgoes savings. So the controller now contains a component whose specification is statistical, and 24.2 §14 records the corner case where a device oscillates because its predictor is wrong in both directions alternately.
And the PASR mask is the first obligation whose violation destroys data silently. CURRICULUM-DERIVED from 24.2 §9: it is a mask with a retention consequence — a region excluded from self refresh is not preserved. So the controller must know which addresses it has agreed to forget, and reading one back returns something rather than an error. That is an obligation with no error signal, which is the shape 30.4 §5 identified for a missed write deadline.
8. Legality Gains a Second Dimension
Chapter 13.3 owns legality as a maximum over every applicable timing rule. Once a power state exists, that is no longer the whole test.
DDR legality, one dimension:
legal(cmd) = ( elapsed >= required ) for every applicable rule
= a MAXIMUM over candidates (13.3, 30.3 §3)
LPDDR legality, two dimensions:
legal(cmd) = TIMING_LEGAL(cmd) -- as above
AND STATE_ADMITS(cmd, device_state) -- NEW
and the two are NOT commensurable:
TIMING_LEGAL becomes true by WAITING.
STATE_ADMITS becomes true only by ACTING -- something must
issue an exit, and the exit is itself a command
that the current state must admit.That distinction is the section's point and it has a real consequence. CURRICULUM-DERIVED from 6.2, which owns the command-qualification contract: a command is only accepted when the device is qualified to receive it. So a scheduler that models legality as wait until the counters allow it will wait forever in a low-power state, because no counter is what is blocking it.
And the failure mode is a deadlock rather than a violation, which makes it the harder bug: nothing illegal was issued, no assertion fires, and the controller simply stops. Chapter 30.5 §3's four-stage separation is what diagnoses it — it is not yet a candidate is the correct answer, and the follow-up which rule blocks it returns no rule, which is the signature.
So the structural requirement is that the exit is scheduled as an action, not awaited as a condition — and §10's admission block makes that explicit by separating the two dimensions into two signals that are computed differently and reported separately.
9. Two Profiles, as a Stack
Read it as an accumulation, not a divergence. In 31.1 §8 the bottom layer was the cause of the differences; here the bottom layer is the thing that does not differ, and the two highlighted layers sit on top of a shared stack. The low-power profile is the sustained profile plus two layers, and that picture is the chapter's answer to which one has the simpler controller.
10. RTL — Admission Under Two Profiles
§8's two dimensions, as one module. The PROFILE parameter selects whether state admissibility exists at all, and the two dimensions are computed separately and reported separately so that §8's deadlock signature — no rule blocks it — is observable rather than inferred.
// ---------------------------------------------------------------------
// access_admission -- the parameterised comparative block of §10.
//
// CLASSIFICATION: synthesisable, ILLUSTRATIVE parameter values, and
// CORRECT as written. The intentionally defective block is §11.
//
// WHAT IT IS: the admission gate for one access, under either
// profile. It extends 31.1 §9's frontend along exactly one axis --
// §8's second legality dimension -- and deliberately keeps the first
// dimension identical, because §2 established that the thirteen
// shared obligations do not differ between these technologies.
//
// WHY IT EXISTS HERE: §8 argues that TIMING_LEGAL becomes true by
// WAITING and STATE_ADMITS becomes true only by ACTING, and that a
// scheduler conflating them waits forever. The two output signals
// below are that argument: `blocked_by_timing` and
// `blocked_by_state` are never merged, so 30.5 §3's question "why
// has it not issued" has a distinct answer for each.
//
// HOW TO RUN IT: elaborate with PROFILE_LOW_POWER = 1, drive the
// device into a low-power state, and present an access.
// EXPECTED RESULT: admit is low, blocked_by_state is HIGH and
// blocked_by_timing is LOW -- and `exit_req` is asserted, because
// the state dimension requires an ACTION rather than a wait.
// EXPECTED TRACE: no timing counter is what blocks the access, and
// the block says so on a dedicated output.
//
// SYNTHESIS: a transition-legality ROM plus the shared per-bank
// counters. The sustained profile elaborates neither the ROM nor the
// state register.
//
// LIMITATIONS: models the ADMISSION test, not the policy that chooses
// when to enter a low-power state -- 24.2 §6 owns that selector and
// this block does not duplicate it. It models one outstanding access
// so the two dimensions, rather than concurrency, are what the
// reader compares.
// ---------------------------------------------------------------------
module access_admission #(
// The profile parameter. Unlike 31.1's DESTRUCTIVE_READ this one
// does NOT change the access contract -- §1 -- so it is a
// FEATURE-SET parameter rather than a contract parameter, and
// 31.1 §12's warning about re-deriving obligations applies with
// less force. It still changes the INTERFACE, which §14 tests.
parameter bit PROFILE_LOW_POWER = 1'b1,
parameter int BANKS = 8,
parameter int TRCD = 14, // ILLUSTRATIVE
parameter int TRP = 14, // ILLUSTRATIVE
parameter int TXSR = 64, // ILLUSTRATIVE self-refresh exit interval
// COUNT, not INDEX. Each counter must REPRESENT the threshold it is
// compared against, so it needs $clog2(threshold + 1) bits. TXSR is
// the largest, and it is the one that would saturate first -- which
// would make the exit interval's comparison unreachable and admit
// an access before the device was ready.
parameter int CNT_W = $clog2((TXSR > TRP ? (TXSR > TRCD ? TXSR : TRCD)
: (TRP > TRCD ? TRP : TRCD)) + 1),
parameter int BANK_W = $clog2(BANKS)
)(
input logic clk,
input logic rst_n,
input logic req_valid,
input logic [BANK_W-1:0] req_bank,
// Shared dimension: the thirteen obligations of §2, reduced here to
// the two counters this block needs. 13.3 owns the full taxonomy.
input logic row_open_i,
input logic [CNT_W-1:0] since_act_i,
input logic [CNT_W-1:0] since_pre_i,
// Low-power dimension. Driven only when the profile has one.
input logic [2:0] dev_state,
input logic [CNT_W-1:0] since_exit_i,
output logic admit,
output logic blocked_by_timing,
output logic blocked_by_state,
output logic exit_req,
output logic [7:0] obligation_count
);
// Device power states. 24.2 §1 owns the point that the state set is
// the DEVICE's and not a textbook's; these five are the shape the
// admission test needs and the encoding is local to this block.
localparam logic [2:0] ST_ACTIVE = 3'd0;
localparam logic [2:0] ST_IDLE = 3'd1;
localparam logic [2:0] ST_PWRDOWN = 3'd2;
localparam logic [2:0] ST_SELFREF = 3'd3;
localparam logic [2:0] ST_EXITING = 3'd4;
initial begin
if (BANKS < 1) $fatal(1, "access_admission: BANKS must be >= 1");
if (TRCD < 1 || TRP < 1) $fatal(1, "access_admission: timing must be >= 1");
if (PROFILE_LOW_POWER && TXSR < 1)
$fatal(1, "access_admission: low-power profile needs TXSR >= 1");
end
// ---- Dimension one: TIMING. Becomes true by WAITING. Identical in
// both profiles, because §2 counted thirteen for thirteen.
logic timing_ok;
always_comb begin
if (row_open_i) timing_ok = (since_act_i >= TRCD[CNT_W-1:0]);
else timing_ok = (since_pre_i >= TRP[CNT_W-1:0]);
end
generate
if (PROFILE_LOW_POWER) begin : g_low_power
// ---- Dimension two: STATE. Becomes true only by ACTING. ---------
logic state_ok;
always_comb begin
unique case (dev_state)
ST_ACTIVE, ST_IDLE : state_ok = 1'b1;
// 6.2's command-qualification contract: in a gated state the
// device does not accept commands at all. No counter is
// blocking this, which is §8's whole point.
ST_PWRDOWN, ST_SELFREF : state_ok = 1'b0;
// Exiting: the interval must elapse. This is the ONE part of
// the state dimension that does become true by waiting, and
// it is why the state machine needs a distinct EXITING state
// rather than going straight to ACTIVE.
ST_EXITING : state_ok = (since_exit_i >= TXSR[CNT_W-1:0]);
default : state_ok = 1'b0; // unknown state admits nothing
endcase
end
// The ACTION the state dimension requires. A scheduler that only
// waits will wait forever (§8), so the request to leave is an
// OUTPUT of the admission test rather than somebody else's job.
assign exit_req = req_valid
&& (dev_state == ST_PWRDOWN || dev_state == ST_SELFREF);
assign admit = req_valid && timing_ok && state_ok;
// Reported SEPARATELY and never merged. 30.5 §3: an empty result
// from a combined block is a loop that found nothing; a labelled
// block is a reportable fact with an attributable cause.
assign blocked_by_timing = req_valid && !timing_ok;
assign blocked_by_state = req_valid && timing_ok && !state_ok;
assign obligation_count = 8'd22; // §7's count
end else begin : g_sustained
// No state dimension. Legality is one-dimensional, and that is
// the ONLY difference this parameter makes -- §1.
assign exit_req = 1'b0;
assign admit = req_valid && timing_ok;
assign blocked_by_timing = req_valid && !timing_ok;
assign blocked_by_state = 1'b0;
assign obligation_count = 8'd13; // §2's count
end
endgenerate
endmoduleThe two blocked_by_* outputs are the block's real contribution. A controller that reports only did not issue cannot distinguish a wait from a deadlock. With them, §8's signature is a single observation: blocked_by_state high and blocked_by_timing low means no rule is blocking the access and something must act.
11. RTL Review — The Wake Path
The intended contract. CURRICULUM-DERIVED from 24.2 §4, whose third table row is the whole difference: in power down the refresh obligation still belongs to the controller, and in self refresh the device takes it over.
- On a committed self-refresh entry, ownership of the refresh obligation transfers to the device.
- While the device owns it, the controller's refresh debt must not accrue — the device is maintaining the array, so no obligation is accumulating for the controller to discharge.
- While the device owns it, the controller must issue no refresh command.
- On exit, ownership returns to the controller and accrual resumes from the debt that existed at entry — not from a debt accumulated during the state.
- Reset leaves ownership with the controller.
// ---------------------------------------------------------------------
// lp_wake_path -- INTENTIONALLY DEFECTIVE, for review (§11).
//
// CLASSIFICATION: synthesisable, ILLUSTRATIVE, and CONTAINS A BUG.
//
// WHAT IT IS MEANT TO DO: the five-clause contract above -- carry the
// refresh obligation across a self-refresh handover in both
// directions, so that the controller resumes with a correct debt.
//
// WHY IT EXISTS HERE: §5 establishes that the deciding quantity is
// energy under the duty cycle, and §7 that "who owns refresh right
// now" is one of the obligations the low-power profile adds. This
// block is what happens when that ownership is tracked for the
// PURPOSE of clause 3 and forgotten for the purpose of clause 2.
//
// HOW TO RUN IT: enter self refresh, remain there for many refresh
// intervals, exit, and watch `debt`.
// EXPECTED RESULT under clause 4: debt on exit equals debt at entry.
// EXPECTED TRACE: `debt` must be STABLE for the whole residency.
//
// SYNTHESIS: one ownership flag, one debt counter, one exit timer.
// LIMITATIONS: this block carries the LEDGER across the handover. It
// does not implement the accrual rule itself -- 15.3 owns the credit
// ledger with its verified postponement and pull-in allowance, and
// this block consumes `interval_tick` from it rather than
// reimplementing the accounting (17.3 §7's one-writer rule). Nor does
// it decide WHEN to enter the state: 24.2 §6 owns that selector.
// ---------------------------------------------------------------------
module lp_wake_path #(
parameter int TXSR = 64, // ILLUSTRATIVE exit interval
// COUNT, not INDEX: the debt counter must represent the largest
// debt the verified allowance permits (15.3), and saturating it
// understates the obligation -- which is the WRONG direction for a
// correctness obligation, because an understated debt is a refresh
// that never happens.
parameter int DEBT_W = 8,
parameter int TMR_W = $clog2(TXSR + 1)
)(
input logic clk,
input logic rst_n,
input logic sre_commit, // self-refresh entry committed
input logic srx_commit, // exit committed
input logic interval_tick, // from 15.3's ledger
input logic ref_issued, // a REF command committed
output logic dev_owns_refresh,
output logic [DEBT_W-1:0] debt,
output logic wake_busy,
output logic ctrl_may_refresh
);
logic [TMR_W-1:0] exit_tmr;
// Clause 3 is honoured: the controller is forbidden to refresh while
// the device owns the obligation. This line is CORRECT, and it is
// the reason the defect is hard to see -- ownership IS tracked, and
// it IS used.
assign ctrl_may_refresh = !dev_owns_refresh && !wake_busy;
always_ff @(posedge clk) begin
if (!rst_n) begin
dev_owns_refresh <= 1'b0; // clause 5
debt <= '0;
wake_busy <= 1'b0;
exit_tmr <= '0;
end else begin
// ---- Ownership transfer, both directions. Clauses 1 and 4's
// ownership half are correct.
if (sre_commit) begin
dev_owns_refresh <= 1'b1;
end
if (srx_commit) begin
dev_owns_refresh <= 1'b0;
wake_busy <= 1'b1;
exit_tmr <= '0;
end
// ---- The exit interval.
if (wake_busy) begin
if (exit_tmr >= TXSR[TMR_W-1:0]) wake_busy <= 1'b0;
else exit_tmr <= exit_tmr + 1'b1;
end
// ---- Accrual and discharge.
if (interval_tick && debt != {DEBT_W{1'b1}})
debt <= debt + 1'b1; // <-- THE DEFECT
else if (ref_issued && debt != '0)
debt <= debt - 1'b1;
end
end
endmoduleBefore reading on: which clause, and why is the defect's size proportional to a quantity no regression reproduces?
12. The Defect — The Ledger That Kept Counting
The violated clause is 2, and the defect is an omitted term: the accrual is gated on neither dev_owns_refresh nor wake_busy. The controller's debt keeps accumulating for the entire time the device is maintaining the array itself.
Clause 3 is honoured, and that is precisely what conceals it. dev_owns_refresh is tracked, and it is consumed — by ctrl_may_refresh. So a reviewer checking “does this block know who owns refresh?” finds that it does. The ownership flag is used for the obligation it must not discharge and ignored for the obligation it must not accrue.
ILLUSTRATIVE, and the units are refresh intervals rather than any
published figure -- 15.3 owns tREFI and this block quotes none.
suppose the device is in self refresh for 4,000 refresh intervals
(a phone in a pocket; 24.1 §3's 2% duty cycle produces residencies
of this order routinely).
contract, clause 2 and 4:
debt at entry = 0
debt during = 0, STABLE for 4,000 intervals
debt at exit = 0
refreshes owed on wake = 0 -- the device did them all
this block:
debt at entry = 0
debt during = 1, 2, 3, ... saturating at 255 (DEBT_W = 8)
debt at exit = 255
refreshes owed on wake = 255
so on wake the refresh manager:
1. drains all banks (17.3's DRAIN phase),
2. issues 255 REF commands the device did not need,
3. holds the gate closed for the whole occupancy window,
4. and only then serves the access that caused the wake.Three consequences, and the first is the one this chapter is about.
It spends the energy the state was entered to save. CURRICULUM-DERIVED from 24.2 §5's break-even: entering is worth it when s × d > e. This defect adds a term to e that is proportional to d — the longer you stay, the more it costs to leave — which inverts the break-even entirely. A state whose whole justification is that saving accumulates with residency now has an exit cost that accumulates with residency too, so d* ceases to exist and the deep state never pays.
It also destroys the wake latency, and that is the symptom a user reports. The access that triggered the wake waits behind a drain plus 255 refresh occupancies.
And the saturation makes it worse in a way worth noticing. At DEBT_W = 8 the counter stops at 255, so the bug's cost is capped — which sounds like mercy and is the opposite. A capped error is a constant, and a constant looks like a fixed wake latency rather than a bug proportional to residency, so the investigation looks for a fixed cost and finds none.
Now the review question: why does no regression catch this?
Because the defect's magnitude is proportional to residency, and residency is the one quantity a test bench does not reproduce. A bring-up test enters self refresh and exits a few intervals later — debt accrues to 3, three unnecessary refreshes are issued, nobody notices. The behaviour is identical in kind to the shipped behaviour and differs only in scale. CURRICULUM-DERIVED from 4.7 §11, which owns the debug narrative this produces — battery life is worse than the power model predicted — and the reason it is hard: the model and the silicon disagree by an amount that depends on a usage pattern the model did not include.
And there is a sharper verification finding inside that, which §14 develops. An antecedent cover on dev_owns_refresh would be non-zero in that bring-up test. So the property was not vacuous — it was exercised, at a scale where the defect is invisible.
A refinement of vacuity worth carrying: an antecedent cover proves that a condition occurred. It does not prove that the condition occurred at a scale where the defect it guards is observable. For a defect whose magnitude is proportional to a duration, the coverage item must be on the DURATION, not on the event.
The correction, and the deletion matters as much as the gate:
// CORRECTED. Clause 2: while the device owns the obligation,
// nothing is accruing for the controller to discharge. The
// gate is `dev_owns_refresh`, the same flag clause 3 already
// consumed -- so the fix adds no state, and the bug was never
// a missing signal. It was a signal used for one of its two
// obligations.
//
// `wake_busy` is included because the exit interval is still
// the device's: 24.2 §4's handover completes when the exit
// interval elapses, not when SRX commits.
if (interval_tick && !dev_owns_refresh && !wake_busy
&& debt != {DEBT_W{1'b1}})
debt <= debt + 1'b1;
else if (ref_issued && debt != '0)
debt <= debt - 1'b1;And the structural finding, which is larger than the gate: an ownership flag has two duties — it forbids the owner's action and it suspends the non-owner's accounting — and a design that consumes it for one is not thereby correct for the other. Grepping for every use of an ownership flag and checking that both duties are served is a real review technique, and it generalises past refresh: the same shape appears wherever 17.3 §7's one-writer rule hands a piece of state between two owners.
13. RTL — The Crossover, Computed
§5's deciding quantity as hardware, so that §6's inversion becomes a measurement a running system can report rather than an argument in a review.
// ---------------------------------------------------------------------
// duty_cycle_crossover -- verification/telemetry, CORRECT as written.
//
// CLASSIFICATION: synthesisable telemetry. Drives nothing.
// ILLUSTRATIVE parameter values, ABSTRACT energy units.
//
// WHAT IT DOES: measures the observed duty cycle and the observed
// idle-duration distribution, and reports which side of §5's
// crossover the system is actually on.
//
// WHY IT EXISTS HERE: §6 shows that the market-segment labels are
// proxies which fail at the edges, and §5 shows the crossover is
// sensitive -- a fourfold change in the idle advantage moved it from
// 14% to 67%. An argument that sensitive must be measured on the
// real system, not assumed from the segment.
//
// ENERGY UNITS ARE ABSTRACT, and deliberately. 24.2 §5 is explicit
// that an exit ENERGY cannot be computed from a published exit
// LATENCY and a steady-state CURRENT without knowing the voltage and
// the activity during exit. So D_PI and D_PA are INPUTS supplied by
// whoever characterised the parts, exactly as 24.2 §7's selector
// takes s and e abstractly. Inventing them would be the error this
// module refuses.
//
// HOW TO RUN IT: run the real workload, read `below_crossover` and
// `short_idle_frac` at the end of the window.
// EXPECTED RESULT: a phone-like workload reports below_crossover
// high; a sustained workload reports it low.
//
// SYNTHESIS: three counters, one comparator, one multiply-free
// cross-multiplication. No divider.
//
// LIMITATIONS: reports the ENERGY side of the decision only. §6's
// qualification stands -- availability, capacity per channel, form
// factor and replaceability (axis A7) constrain the choice
// independently, and this block measures none of them.
// ---------------------------------------------------------------------
module duty_cycle_crossover #(
parameter int WIN = 1048576, // accounting window, cycles
// Abstract energy-rate differences, supplied by characterisation.
// D_PI = idle advantage of the low-power profile (>= 0)
// D_PA = active penalty of the low-power profile (may be 0)
parameter int D_PI = 4, // ILLUSTRATIVE, abstract units
parameter int D_PA = 6, // ILLUSTRATIVE, abstract units
// The idle duration below which a deep state cannot pay --
// 24.2 §5's d* = e/s, supplied rather than computed here.
parameter int D_STAR = 512, // ILLUSTRATIVE, cycles
// COUNT, not INDEX: every counter below must REPRESENT WIN, so it
// needs $clog2(WIN + 1) bits. Sized $clog2(WIN) the active counter
// saturates one short of a fully active window, understating the
// duty cycle -- the instrument failing in the direction that makes
// the low-power profile look better than it is.
parameter int CNT_W = $clog2(WIN + 1)
)(
input logic clk,
input logic rst_n,
input logic mem_active, // the memory moved data this cycle
input logic idle_begin, // an idle interval started
input logic idle_end, // and ended
input logic win_tick, // end of the accounting window
output logic [CNT_W-1:0] r_active,
output logic [CNT_W-1:0] r_idle_events,
output logic [CNT_W-1:0] r_short_idles,
output logic below_crossover,
output logic result_valid
);
initial begin
if (WIN < 2) $fatal(1, "duty_cycle_crossover: WIN must be >= 2");
if (D_PI < 0 || D_PA < 0)
$fatal(1, "duty_cycle_crossover: energy differences must be >= 0");
// §5's degenerate case, made explicit rather than silently
// dividing by zero: with no idle advantage and no active penalty
// the crossover is undefined and the comparison is not an energy
// question at all.
if (D_PI == 0 && D_PA == 0)
$fatal(1, "duty_cycle_crossover: D_PI and D_PA both zero -- no crossover exists");
if (D_STAR < 1) $fatal(1, "duty_cycle_crossover: D_STAR must be >= 1");
end
logic [CNT_W-1:0] c_active, c_events, c_short, idle_len;
logic in_idle;
always_ff @(posedge clk) begin
if (!rst_n) begin
c_active <= '0; c_events <= '0; c_short <= '0;
idle_len <= '0; in_idle <= 1'b0;
r_active <= '0; r_idle_events <= '0; r_short_idles <= '0;
below_crossover <= 1'b0; result_valid <= 1'b0;
end else if (win_tick) begin
r_active <= c_active;
r_idle_events <= c_events;
r_short_idles <= c_short;
result_valid <= 1'b1;
// §5's test, cross-multiplied so no divider is needed and no
// fixed-point rounding can move the verdict:
//
// low-power ahead iff (1 - D) * D_PI > D * D_PA
// with D = c_active / WIN, multiply through by WIN:
// (WIN - c_active) * D_PI > c_active * D_PA
//
// DERIVED, and the cross-multiplied form is exact.
below_crossover <= ((WIN - c_active) * D_PI) > (c_active * D_PA);
c_active <= '0; c_events <= '0; c_short <= '0;
end else begin
result_valid <= 1'b0;
if (mem_active && c_active != {CNT_W{1'b1}}) c_active <= c_active + 1'b1;
// Idle-duration distribution. §5's closing result: a duty cycle
// alone is UNDER-SPECIFIED, because the same 2% active fraction
// reached as one long idle and as ten thousand short ones gives
// completely different effective idle power. So count the idles
// that are too short for a deep state to pay (24.2 §5's d*).
if (idle_begin) begin
in_idle <= 1'b1;
idle_len <= '0;
if (c_events != {CNT_W{1'b1}}) c_events <= c_events + 1'b1;
end else if (in_idle) begin
if (idle_end) begin
in_idle <= 1'b0;
if (idle_len < D_STAR[CNT_W-1:0] && c_short != {CNT_W{1'b1}})
c_short <= c_short + 1'b1;
end else if (idle_len != {CNT_W{1'b1}}) begin
idle_len <= idle_len + 1'b1;
end
end
end
end
// The fraction of idle intervals too short to pay. Reported as a
// pair rather than a percentage, because 27.5's closure model and
// 30.8 §11's range rule both say a derived single number invites a
// sign-off it cannot support. A consumer that wants a percentage
// divides the two and owns the rounding.
// short_idle_frac = r_short_idles / r_idle_events
endmoduleThe block reports a pair rather than a percentage, deliberately. CURRICULUM-DERIVED from 27.5, whose closure model refuses to produce a single percentage, and 30.8 §11's rule that a derived statistic needs its range asserted: a single reported fraction invites a conclusion the measurement cannot support, and two counters let the consumer see the denominator.
And r_short_idles is the section's real deliverable, because it answers §5's closing result. A system whose idles are mostly shorter than d* never reaches its deep state's idle power at all, so its effective dPi is far below the datasheet difference — and it will sit on the sustained side of the crossover while its market segment says otherwise.
14. SVA Review — Proving a Handover
The properties written for §11's block, and both are good properties:
// Offered as "proves the refresh handover is correct".
// P1: clause 3. Correct, and it PASSES on the defective block.
property p_no_ctrl_refresh_while_device_owns;
@(posedge clk) disable iff (!rst_n)
dev_owns_refresh |-> !ctrl_may_refresh;
endproperty
assert property (p_no_ctrl_refresh_while_device_owns)
else $error("controller permitted a refresh while the device owned it");
// P2: clauses 1 and 5, the ownership transitions. Also correct,
// also passes.
property p_ownership_transfers_on_commit;
@(posedge clk) disable iff (!rst_n)
sre_commit |=> dev_owns_refresh;
endproperty
assert property (p_ownership_transfers_on_commit)
else $error("ownership did not transfer on self-refresh entry");Q. Both pass on §11's defective block. What do they prove, and what is missing?
They prove the ownership half of the contract and say nothing about the accounting half. Neither property mentions debt — the signal the defect corrupts — so neither can observe it. That is 30.9 §6's variety 2 exactly: a property that does not name the contract's key signal is about something else.
And the diagnosis is sharper than “they forgot a property”. The contract has two obligations attached to one flag — §12's structural finding — and the property set covers the obligation the flag forbids while omitting the one it suspends. So the property set has the same blind spot as the design, which is the pattern 30.4 §9 established: a property written from the same mental model as the design cannot detect that the model is wrong.
What actually covers clause 2:
// Clause 2. It names `debt`, so it cannot pass while `debt` moves.
// $stable is the right operator: the claim is not that debt is
// zero -- it may be non-zero at entry, and clause 4 requires that
// value to survive -- but that it does not CHANGE.
property p_debt_stable_while_device_owns;
@(posedge clk) disable iff (!rst_n)
dev_owns_refresh |-> $stable(debt);
endproperty
assert property (p_debt_stable_while_device_owns)
else $error("refresh debt accrued while the device owned the obligation");
// Clause 4, stated as the end-to-end obligation rather than as a
// per-cycle one. The debt on exit must equal the debt at entry,
// which is a claim about a PAIR of events and needs the value
// sampled at the first.
property p_debt_survives_the_handover;
logic [DEBT_W-1:0] entry_debt;
@(posedge clk) disable iff (!rst_n)
(sre_commit, entry_debt = debt) |-> (!srx_commit throughout
(##[1:$] (srx_commit && debt == entry_debt)));
endproperty
assert property (p_debt_survives_the_handover)
else $error("debt on exit differs from debt at entry");
// The exit interval, which clause 4's correction also gates on --
// 24.2 §4's handover is not complete until the interval elapses.
property p_no_accrual_during_wake;
@(posedge clk) disable iff (!rst_n)
wake_busy |-> $stable(debt) || ref_issued;
endproperty
assert property (p_no_accrual_during_wake)
else $error("debt accrued during the exit interval");
// Saturation must never be reached, because a saturated debt
// UNDERSTATES a correctness obligation -- a refresh that never
// happens. 30.8 §11's range rule, applied where the direction of
// the error matters.
property p_debt_never_saturates;
@(posedge clk) disable iff (!rst_n)
debt != {DEBT_W{1'b1}};
endproperty
assert property (p_debt_never_saturates)
else $error("refresh debt saturated: the obligation is now understated");
// §8's deadlock signature, asserted as a liveness BOUND rather
// than as unbounded eventuality -- 30.9 §5 Q2, and MAX_WAKE is
// justified from TXSR plus the drain rather than chosen.
property p_state_block_resolves;
@(posedge clk) disable iff (!rst_n)
blocked_by_state |-> ##[1:MAX_WAKE] (admit || !req_valid);
endproperty
assert property (p_state_block_resolves)
else $error("a state-blocked access did not resolve within the bound");
// ---- Covers. And this is where §12's refinement bites.
// The EVENT cover. Non-zero in any bring-up test that enters self
// refresh at all -- so it proves the antecedent occurred and says
// NOTHING about whether the defect was observable.
cover property (@(posedge clk) disable iff (!rst_n) dev_owns_refresh);
// The DURATION cover. This is the one that finds §11's defect, and
// it is the instrument §12's refinement demands: for a defect whose
// magnitude is proportional to a residency, the coverage item must
// be on the RESIDENCY. LONG_RESIDENCY is chosen so that a correct
// design's debt would be unchanged and a defective one's would have
// saturated -- i.e. above 2**DEBT_W intervals.
cover property (@(posedge clk) disable iff (!rst_n)
dev_owns_refresh [*LONG_RESIDENCY]);
// The handover in both directions, separately, because entry and
// exit have different bugs.
cover property (@(posedge clk) disable iff (!rst_n) sre_commit);
cover property (@(posedge clk) disable iff (!rst_n) srx_commit);
// A non-zero debt at entry, which is the case clause 4 is actually
// about. With debt zero at entry, p_debt_survives_the_handover
// holds trivially on the defective block's saturation as well.
cover property (@(posedge clk) disable iff (!rst_n)
sre_commit && debt != '0);
// §8's signature, covered so that the deadlock case is known to
// have been reached rather than merely guarded.
cover property (@(posedge clk) disable iff (!rst_n)
blocked_by_state && !blocked_by_timing);The duration cover is the section's deliverable and it is the generalisable finding.
For a defect whose magnitude is proportional to a duration, an event cover is not enough. The coverage item must be on the duration, and the threshold must be chosen so that a correct design and a defective one produce different answers.
That is a refinement of 30.9 §6's variety 6 rather than a new variety — the antecedent did hold, so the property was never vacuous. It held at a scale where the consequent could not distinguish the two designs, and the honest name for that is a scale-vacuous cover. CURRICULUM-DERIVED from 30.7 §10's demand that a trained input be swept rather than held at one value: the same argument, applied to a duration rather than to a parameter.
Follow-up an interviewer should ask: how do you pick LONG_RESIDENCY without making the regression unaffordable? From the defect's own arithmetic, not from the workload. §12 shows the counter saturates after 2**DEBT_W intervals, so a residency just above that is the shortest stimulus that separates the two designs — far shorter than a realistic pocket residency and long enough to be conclusive. Deriving a coverage threshold from the failure mechanism rather than from the use case is what makes it affordable, and it is the same move 30.4 §9 makes when it covers overlapping commits at the block level rather than at the system level.
15. What the Admission Block's Assertions Prove
§10's block needs its own set, and the interesting ones are about the separation of the two dimensions rather than about either dimension.
// The two dimensions must be MUTUALLY EXCLUSIVE as reported, or
// §8's signature is unreadable. This is the property that makes
// the two outputs worth having: if both can be high at once, a
// report of "blocked by state" no longer means "no rule blocks it".
property p_block_reasons_are_exclusive;
@(posedge clk) disable iff (!rst_n)
$onehot0({blocked_by_timing, blocked_by_state});
endproperty
assert property (p_block_reasons_are_exclusive)
else $error("both block reasons asserted: the signature is ambiguous");
// Admission and blocking must partition the request. An access is
// admitted, or blocked for exactly one stated reason -- never
// neither, which would be an unreported stall.
property p_request_is_accounted;
@(posedge clk) disable iff (!rst_n)
req_valid |-> (admit ^ (blocked_by_timing || blocked_by_state));
endproperty
assert property (p_request_is_accounted)
else $error("a request was neither admitted nor attributed to a cause");
// The CONTRACT invariant, with the parameter in the ANTECEDENT and
// not in the claim -- 31.1 §14's test for whether a property may be
// shared across configurations. It may.
property p_sustained_never_blocks_on_state;
@(posedge clk) disable iff (!rst_n)
(!PROFILE_LOW_POWER) -> (!blocked_by_state && !exit_req);
endproperty
assert property (p_sustained_never_blocks_on_state)
else $error("the sustained profile reported a state block");
// §8's action requirement: a state block must REQUEST an exit.
// Waiting cannot clear it, so a block that does not ask is a
// deadlock by construction.
property p_state_block_requests_exit;
@(posedge clk) disable iff (!rst_n)
blocked_by_state |-> exit_req;
endproperty
assert property (p_state_block_requests_exit)
else $error("state-blocked without requesting an exit: deadlock");
// The unknown-state case admits nothing. 7.4's three-valued
// discipline, at the power-state layer rather than the bank layer.
property p_unknown_state_admits_nothing;
@(posedge clk) disable iff (!rst_n)
(PROFILE_LOW_POWER && !(dev_state inside
{ST_ACTIVE, ST_IDLE, ST_PWRDOWN, ST_SELFREF, ST_EXITING}))
|-> !admit;
endproperty
assert property (p_unknown_state_admits_nothing)
else $error("an access was admitted with an unrecognised device state");
// The configuration covers, per 31.1 §14: a parameterised
// comparison needs a coverage item per configuration, and the
// regression must be shown to have entered both arms.
cover property (@(posedge clk) disable iff (!rst_n)
obligation_count == 8'd22); // low-power arm
cover property (@(posedge clk) disable iff (!rst_n)
obligation_count == 8'd13); // sustained armp_state_block_requests_exit is the one that encodes §8's asymmetry, and it is the property a sustained-profile engineer would never think to write: it says that a block which becomes true only by acting must generate the action. A design that merely reports the block and waits satisfies every timing property in the chapter and never issues another command.
16. What Would You Measure?
Q. You must choose between these two technologies for a new SoC. What do you measure, in what order, and what closes the question early?
| Measurement | What it settles | Cost | Owner |
|---|---|---|---|
| Is the form factor or replaceability constrained? | axis A7 — and it can close the question with no energy work at all | hours | §3 |
| The workload's duty cycle | which side of §5's crossover the system is on | days | 24.1 §3 |
| The idle-duration distribution, not just the mean | whether the deep state is ever reached — §5's closing result | days | 24.2 §5 |
short_idle_frac from §13, on the real workload | the effective dPi, rather than the datasheet difference | days | §13 |
Characterised dPi and dPa for the candidate parts | the crossover itself, which §5 shows is sensitive | weeks, and it needs the vendors | §5 |
| The thermal ceiling under the sustained case | the constraint that binds when the duty cycle is high — there is no fan | weeks | 24.1 §4 |
| Capacity per channel against the requirement | whether the choice is available at all | hours | 24.3 §4 |
| The predictor's error distribution, if a low-power profile is chosen | §7's statistical obligation, and 24.2 §14's oscillation corner | weeks | 24.2 §5 |
Row one is first because it is the only row that can close the question in an afternoon. If the product must accept field-replaceable memory, the low-power profile is unavailable regardless of every energy argument below it — and an investigation that began with duty cycle has spent a week to reach a conclusion that axis A7 settled immediately.
Row three is the row that is usually skipped and the one §5 proves is load-bearing. A duty cycle alone is under-specified, so a comparison handed only 2% active cannot compute an effective idle power. Two systems with identical duty cycles and different idle-duration distributions sit on opposite sides of the crossover.
And row eight is the one that has no analogue in the sustained profile. CURRICULUM-DERIVED from 24.2 §5: predicting the idle duration wrong is asymmetric, and 24.2 §14 records the case where a device oscillates because its predictor is wrong in both directions alternately. So choosing the low-power profile commits the project to owning a statistical component, and its error distribution is a deliverable rather than an implementation detail.
17. Common Wrong Answers
“LPDDR is a simplified DDR.” §2, §7. Thirteen obligations for thirteen, and nine added. The low-power part needs the larger controller.
“LPDDR has lower latency variability.” §1, §3. The variability is structural and shared, and the low-power profile widens it by adding a wake term that depends on the device's state at the moment of the request.
“Use LPDDR where DDR's variability is unacceptable.” §1. An admissibility claim, and a false one: both present the same access contract, so neither is admissible where the other is not.
“LPDDR uses less power.” §4. Power is not what a battery depletes. A part that takes twice as long at half the power spent the same energy, and the comparison in watts has dropped the time axis.
“Compare the idle currents.” §4, §5. Idle power is one of 24.1 §2's three quantities, and the effective idle power a system attains depends on its idle-duration distribution rather than on the datasheet figure.
“Compare the peak bandwidths.” §4. Only one of the three quantities is a speed, and most systems are idle most of the time — 24.1 §3 shows the idle term contributing nearly half the average at a 2% duty cycle.
“Mobile means LPDDR and server means DDR.” §6. Those are proxies for duty cycle, and two of §6's four cases sit on the side of the crossover their segment does not predict.
“The deeper state is the better state.” §5, and 24.2 §5 owns the correction: it is better for longer idles, and the break-even is d* = e/s. A device woken more often than d* never reaches its deep-state figure.
“A 2% duty cycle tells you what you need.” §5. Under-specified. The same 2% as one long idle and as ten thousand short ones gives completely different effective idle power.
“Per-bank refresh saves energy.” §2, and 24.2 §8 owns the measurement that contradicts it — every rail identical at two grades in two width modes. It buys availability, so it must not appear in an energy comparison at all.
“Self refresh and power down are two depths of the same thing.” §7, and 24.2 §4 owns the distinction that matters: who owns the refresh obligation. In power down it is still the controller's.
“The device self-refreshed, so the controller has nothing to do on wake.” §12. It has to not do something — stop accruing — and a block that tracks ownership for one of its two duties is not thereby correct for the other.
“PASR saves refresh energy for free.” §7, and 24.2 §9 owns it as a mask with a retention consequence: an excluded region is not preserved, and reading it back returns something rather than an error.
“Legality is a timing question.” §8. Once a power state exists it has a second dimension, and that dimension becomes true only by acting — so a scheduler that waits will wait forever, with no rule blocking it.
“Nothing illegal was issued, so the controller is fine.” §8. The state-dimension failure is a deadlock, not a violation: no assertion fires and the controller simply stops.
“The handover assertions pass.” §14. Neither of them names debt. The property set has the same blind spot as the design.
“The self-refresh cover is non-zero, so the case was exercised.” §12, §14. It was exercised at a scale where the defect is invisible. For a defect proportional to a duration, the coverage item must be on the duration.
“We will reproduce it by running the real workload in simulation.” §14. Derive the coverage threshold from the failure mechanism — just past the counter's saturation — rather than from the use case, or the stimulus is unaffordable and still inconclusive.
18. Self-Check
-
State which of the seven axes is identical between these two technologies, and name three arguments that identity refutes.
-
From §2's table, explain why the difference is zero obligations removed and several added, and give the one row whose common claim a verified measurement contradicts.
-
Write §5's crossover in closed form. Then say what happens to it when the active penalty is zero, and why that case is real rather than hypothetical.
-
Recompute §5's crossover for
dPi = 2, dPa = 2and fordPi = 8, dPa = 2. State what the sensitivity implies for how the decision should be made. -
Give two of §6's four cases that sit on the side of the crossover their market segment does not predict, and say what actually decides each.
-
Explain in two sentences why a duty cycle alone is under-specified, and name the second statistic required.
-
Name four of the nine obligations the low-power profile adds. Identify the one that is allowed to be wrong and the one whose violation has no error signal.
-
Explain why
TIMING_LEGALandSTATE_ADMITSare not commensurable, and give the two-signal observation that distinguishes a wait from a deadlock. -
Find the defect in §11 without reading §12. Then explain why clause 3 being honoured is what conceals it, and why the defect's magnitude is proportional to something a regression does not reproduce.
-
State the scale-vacuity refinement from §14 in one sentence, and explain how to choose the duration threshold so the regression stays affordable.
19. Where This Goes
These two technologies present the same access contract, so the decision is entirely stage two. Axis A1 is identical and none of 31.1's structural argument transfers; the obligation set grows from thirteen to twenty-two rather than shrinking; legality gains a dimension that becomes true only by acting; the deciding quantity is energy under the actual duty cycle and idle-duration distribution; and the crossover is sensitive enough that the market-segment label is a proxy which fails at exactly the interesting edges.
Three results carry forward. An ownership flag has two duties — it forbids the owner's action and suspends the non-owner's accounting — and serving one is not serving both. For a defect whose magnitude is proportional to a duration, an event cover is scale-vacuous and the coverage item must be on the duration, with its threshold derived from the failure mechanism rather than the use case. And a block that becomes legal only by acting must generate the action, or it satisfies every timing property and issues nothing again.
Chapter 31.3 changes the axis that has so far been in the background. A1 stays identical a second time — the cell is the same destructive 1T1C — but axis A4 moves further than any axis has moved in this module, and it moves for a reason that is not about memory at all: a package has a finite perimeter, and beyond a certain bandwidth no arrangement of pins on that perimeter can carry the traffic. The deciding quantity becomes bandwidth per unit of connection budget, the controller's cost becomes replication rather than addition, and axis A7 becomes irreversible in a way that forecloses the capacity decision you have not made yet.
Continue learning
Related tutorials
- Related topic
LPDDR Evolution
LPDDR is not low-power DDR. It is the same reasoning run against a different constraint set — no socket, a fixed battery, no airflow — which produces low-swing signalling, split command and data clocks, and power states expensive enough to reshape the controller.
- Related topic
Mobile-Memory Mission
A phone asks three different things of its memory and they trade against each other. At a 2% duty cycle nearly half the average power is spent idle, and below 1% it is two thirds.
- Related topic
Low-Power Features
A named device's own state diagram defines the states, and several transitions between them are illegal. Per-bank refresh draws identical current to all-bank refresh on every rail — it buys availability, not energy.
- Related topic
Mobile-Power Management
LPDDR4X lowers two rails and deletes a third. Two of four LPDDR5X rails go unused in self refresh — so gating them saves nothing in the memory, and a bad shutdown order survives ten thousand clean power cycles.
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.
