DDR · Module 33
Architecture Review Checklist
The first of eight pre-tapeout gates. Eight review items asked of a controller architecture before RTL exists, each one a question whose pass criterion is a named mechanism rather than an intention — and whose weak build produces a document that reads as thorough.
This is the first of the eight gates a DDR controller must clear, and it is the only one conducted before any RTL exists.
That is its whole difficulty. There is no line to read, no waveform to inspect, no regression to run. An architecture review is conducted on intent — and intent is exactly the thing that is always sound when described by the person who formed it.
So the review question is never is this architecture correct. It is:
For every invariant this architecture claims, what mechanism enforces it — and what happens on the cycle the mechanism is absent?
Every finding in this chapter is an architecture that is internally consistent, reviewable, defensible in a meeting, and missing a mechanism. A document that says the scheduler will not issue illegal commands has stated a requirement and named no enforcement. A document that says legality is computed as a maximum over every applicable rule in a dedicated filter, and the arbiter consumes its output and never recomputes it has named one.
Eight items follow. Each one is a question a reviewer asks out loud, with the evidence to demand and the escape it prevents.
1. How To Use This Chapter
Each of the eight review items answers the same eight questions. The facets are fixed so that a reviewer can work the list without re-deriving what to ask.
| Facet | What it settles |
|---|---|
| Under review | the architectural claim being examined |
| Invariant at risk | the property that breaks if the claim has no mechanism |
| Where it lives | the specific document artifact, not the chapter of it |
| Evidence to demand | what the reviewer should ask to see, in this meeting |
| What escapes | the bug that reaches RTL and then silicon |
| How DV proves it | the stimulus that would falsify it once RTL exists |
| Telemetry | what exposes it after tapeout |
| Misleading evidence | what makes the missing mechanism look present |
The last facet is the hard one, and at this gate it is harder than at any of the seven that follow. A broken RTL produces a reassuring waveform, a clean lint run and a passing regression — three artifacts a reviewer can at least read. A broken architecture produces a reassuring document, and the document was written by the person answering your questions.
2. The One-Sentence Model
An architecture review is sound when every invariant has a named enforcing mechanism, when legality is a separate box from policy, when there is exactly one commit point, when every bound is derived rather than chosen, when every unknown has a defined refusal, and when every configuration-dependent property is marked as configuration rather than as architecture — and “the architecture was reviewed” is bit 0.
3. What This Chapter Owns
| Ground | Owner |
|---|---|
| The scheduler pipeline, the commit point, the request-to-command expansion | 17.1 |
| The request entry, the one-writer rule, allocation versus scheduling versus completion order | 17.2 |
| The refresh manager, the drain, and why refresh is not a request | 17.3 |
| The layered mask, starvation demonstrated, the bounded bypass | 17.4 |
| The ready/valid contract, metadata stability, causal backpressure | 17.5 |
| The four constraint classes and earliest-legal-time as a maximum | 13.3 |
| The thirteen obligations the destructive read creates | 31.1 §5 |
| The requester-class taxonomy and its two axes | 32.1 §3 |
| Reviewing the RTL against this architecture | 33.2 |
| Reviewing the environment that judges that RTL | 33.4 |
| Reviewing the architecture before RTL exists | this chapter |
The boundary with 33.2 is worth stating precisely, because the two gates share a vocabulary. This gate asks what mechanism was specified. The next asks whether the code is that mechanism. A finding this chapter calls “no mechanism enforces the single-commit rule” becomes, in 33.2, “two always_ff blocks assign this register” — the same escape, seen before and after the code was written.
4. Teaching-Model Boundary And Source Discipline
Every RTL block in this chapter is a teaching model. Each isolates one architectural invariant so the mechanism's presence and absence can be compared directly. None is a production DDR controller, an implementation of any JEDEC flow, or a complete design.
Nothing here states a normative DDR detail. No timing value, command encoding, mode-register field, pin name or capacity appears as fact. The invariants under review — enforcement, separation, single-commit, derived bounds, defined refusal, configuration marking — are general architectural properties that any synchronous memory controller must satisfy, and they are examined in general form deliberately so the review technique transfers.
| Claim class | How it is marked |
|---|---|
| General architectural reasoning | stated plainly |
| Teaching abstraction | declared in the RTL header |
| Illustrative parameter | ILLUSTRATIVE at every concrete figure |
| Derived arithmetic | DERIVED, shown with its inputs and recomputed |
| Taken from a verified chapter | CURRICULUM-DERIVED, with chapter and section named |
| Holds across generations | STRUCTURAL |
Every model is built twice. A parameter selects between the robust build — what the review should require — and the weak build, containing exactly the missing mechanism under discussion, written as a competent engineer would write it if the mechanism had never been specified, not as a caricature. Every item's headline number is the gap between the two builds, and each model computes that gap itself so it can detect its own weak build.
5. Review Item 1 — Which Obligations Does This Architecture Carry, and Is Any Assumed Away?
Under review. The architecture's statement of what state the controller must maintain.
Invariant at risk. Completeness. An obligation that is not in the architecture is not in the RTL, is not in the verification plan, and is discovered in silicon.
Where it lives. The block diagram's state list, and the absence of a block.
The count is known and it is not negotiable. CURRICULUM-DERIVED from 31.1 §5: the destructive-read property creates thirteen controller obligations — three-valued row state per bank, precharge separation, activate-to-column separation, minimum row-open time, scoped column spacing, activate rate limiting, refresh accrual, refresh execution with a drain, read-return prediction, write-delivery deadline, direction turnaround, legality as a maximum over rules, and scheduling among legal candidates. Chapter 32.1 §1 confirmed that all five platform classes carry all thirteen and that none removes any.
So the first review action is arithmetic: count the blocks against thirteen.
// ---------------------------------------------------------------------
// obligation_census -- TEACHING MODEL. Review item 1.
//
// CLASSIFICATION: verification-only. Drives nothing. ILLUSTRATIVE
// geometry. Built TWICE.
//
// WHAT IT IS: an elaboration-time and runtime census of which of
// 31.1 §5's thirteen obligations an architecture actually
// instantiated. The robust build declares all thirteen and asserts
// the count; the weak build omits the two that are easiest to
// forget, and it omits them the way a real architecture does -- by
// not having a block for them rather than by setting a flag false.
//
// WHY IT EXISTS HERE: an architecture review has no code to read, so
// the only mechanical check available is a COUNT. This model makes
// the count executable.
//
// HOW TO RUN IT: elaborate with ROBUST = 1 and with ROBUST = 0 and
// compare `obligations_present` against `OBLIGATIONS_REQUIRED`.
// EXPECTED RESULT: robust reports 13; weak reports 11.
// EXPECTED TRACE: `census_err` is low in the robust build and HIGH
// in the weak build, computed identically in both so the model
// detects its own weak build.
//
// SYNTHESIS: none.
// LIMITATIONS: it counts DECLARED obligations. It cannot tell
// whether a declared obligation is correctly implemented -- that is
// 33.2's gate, and saying so is the boundary of §3.
// ---------------------------------------------------------------------
module obligation_census #(
parameter bit ROBUST = 1'b1,
// CURRICULUM-DERIVED from 31.1 §5. Not an ILLUSTRATIVE figure --
// it is the count that chapter derived and 32.1 §1 confirmed.
parameter int OBLIGATIONS_REQUIRED = 13,
parameter int OBL_W = $clog2(OBLIGATIONS_REQUIRED + 1)
)(
input logic clk,
input logic rst_n,
output logic [OBL_W-1:0] obligations_present,
output logic [12:0] obligation_mask,
output logic census_err
);
// One bit per obligation, in 31.1 §5's order.
localparam int O_ROW_STATE = 0; // three-valued, per bank
localparam int O_PRECHARGE = 1;
localparam int O_ACT_TO_COL = 2;
localparam int O_MIN_ROW_OPEN= 3;
localparam int O_COL_SPACING = 4; // scoped by group
localparam int O_ACT_RATE = 5; // rolling window
localparam int O_REF_ACCRUAL = 6; // the credit ledger
localparam int O_REF_EXEC = 7; // manager with a drain
localparam int O_RD_PREDICT = 8;
localparam int O_WR_DEADLINE = 9;
localparam int O_TURNAROUND = 10;
localparam int O_LEGALITY = 11; // a MAXIMUM over rules
localparam int O_SCHEDULING = 12;
logic [12:0] mask;
always_comb begin
mask = '0;
// Obligations every architecture remembers, because they appear
// in the block diagram as boxes.
mask[O_ROW_STATE] = 1'b1;
mask[O_PRECHARGE] = 1'b1;
mask[O_ACT_TO_COL] = 1'b1;
mask[O_MIN_ROW_OPEN] = 1'b1;
mask[O_COL_SPACING] = 1'b1;
mask[O_REF_ACCRUAL] = 1'b1;
mask[O_REF_EXEC] = 1'b1;
mask[O_RD_PREDICT] = 1'b1;
mask[O_WR_DEADLINE] = 1'b1;
mask[O_LEGALITY] = 1'b1;
mask[O_SCHEDULING] = 1'b1;
if (ROBUST) begin
// The two an architecture omits most often, and the reason is
// the same for both: neither is a per-bank counter, so neither
// fits the row of per-bank boxes the diagram already has.
mask[O_ACT_RATE] = 1'b1; // a ROLLING WINDOW, not a counter
mask[O_TURNAROUND] = 1'b1; // a RANK-scope property
end
// <-- THE DEFECT, in the weak build: the two bits above stay low
// and nothing in the architecture notices, because no other
// obligation depends on them.
end
assign obligation_mask = mask;
assign obligations_present = OBL_W'($countones(mask));
// The truth, computed IDENTICALLY in both builds so the model can
// detect its own weak build.
assign census_err = (obligations_present != OBLIGATIONS_REQUIRED[OBL_W-1:0]);
endmoduleThe measurement.
DERIVED, recomputed:
ROBUST = 1 : obligations_present = 13 census_err = 0
ROBUST = 0 : obligations_present = 11 census_err = 1
gap = 2 obligations, and the two are the rolling activate window
(14.8) and direction turnaround (30.5 §7).Why those two and not others is the item's real content. Every other obligation on the list is a per-bank counter, and a block diagram that has one row of per-bank boxes accommodates all of them naturally. CURRICULUM-DERIVED from 14.8, the activate rate limit is a rolling window over a history rather than a counter, and CURRICULUM-DERIVED from 30.5 §7, direction turnaround is a rank-scope property of a shared bus. Neither has a natural home in a per-bank diagram, so neither gets drawn, so neither gets specified.
Evidence to demand. Ask for the obligation list as a list, not as a diagram, and count it. Then ask which obligation each block enforces and which blocks enforce none — a block with no obligation is either a convenience or a misunderstanding, and both are worth knowing.
What escapes. A controller that issues activates faster than the device permits, and a controller that changes bus direction without accounting for the turnaround. Neither is caught by a per-bank timing check, because neither is a per-bank rule.
How DV proves it. Drive four activates inside the window and check the fifth is refused; drive a read immediately followed by a write and check the spacing. Both are short directed tests, and both are absent from a testbench built from the same diagram the architecture was.
Telemetry. A rolling-window occupancy counter and a turnaround-cycle counter. CURRICULUM-DERIVED from 30.8 §13: turnaround cycles as a share of bus cycles is one of the measurements that distinguishes a scheduling problem from a workload one, so the counter is wanted for performance reasons even when the obligation was remembered.
Misleading evidence. A complete-looking block diagram in which every per-bank obligation has a box. The diagram is evidence of the eleven that fit its shape, and its neatness is what makes the two missing ones invisible.
6. Review Item 2 — Is Legality a Separate Box From Policy?
Under review. The boundary between which commands may issue and which command should issue.
Invariant at risk. Correctness, and the entire diagnosability of the controller.
Where it lives. The arrow between two boxes on the pipeline diagram — or the absence of the boundary those two boxes would have.
CURRICULUM-DERIVED from 17.4 §3, which owns the rule and states the consequence exactly: a broken legality filter issues illegal commands with a brilliant policy; a broken policy issues legal commands badly. The first is a protocol violation and the second a performance problem, and keeping them in separate blocks keeps their bugs separable. Chapter 17.4 §3 names the inverse as the inverse error, which is worse: a design that lets the arbiter apply timing rules directly will issue an illegal command the first time two rules interact in a way its ordering did not anticipate.
// ---------------------------------------------------------------------
// legality_policy_split -- TEACHING MODEL. Review item 2.
//
// CLASSIFICATION: synthesisable teaching model. Built TWICE.
//
// WHAT IT IS: one grant, computed two ways. The robust build filters
// for legality and then chooses among the survivors. The weak build
// folds a priority into the legality test -- which is how it is
// written when the architecture drew one box instead of two.
//
// WHY IT EXISTS HERE: 17.4 §3 states the rule and 30.5 §10 shows the
// defect it prevents. This model puts both builds side by side so
// the gap is a number rather than an argument.
//
// HOW TO RUN IT: present a candidate that is URGENT and NOT LEGAL.
// EXPECTED RESULT: robust refuses it; weak grants it.
// EXPECTED TRACE: `illegal_grants` is 0 in the robust build and
// non-zero in the weak build, computed identically in both.
//
// SYNTHESIS: two mask ANDs and a priority encoder.
// LIMITATIONS: models the SPLIT, not a scheduler. 17.1 owns the
// pipeline and 17.4 the layered mask; this block has one preference
// layer because one is enough to show the boundary.
// ---------------------------------------------------------------------
module legality_policy_split #(
parameter bit ROBUST = 1'b1,
parameter int NUM_ENTRIES = 8,
parameter int CNT_W = 16
)(
input logic clk,
input logic rst_n,
input logic [NUM_ENTRIES-1:0] valid,
input logic [NUM_ENTRIES-1:0] legal_mask, // from the FILTER
input logic [NUM_ENTRIES-1:0] urgent, // a POLICY input
output logic [NUM_ENTRIES-1:0] grant,
output logic [CNT_W-1:0] illegal_grants,
output logic [CNT_W-1:0] total_grants,
output logic split_err
);
function automatic logic [NUM_ENTRIES-1:0] lowest(input logic [NUM_ENTRIES-1:0] m);
return m & (~m + 1'b1);
endfunction
logic [NUM_ENTRIES-1:0] cand, pick;
always_comb begin
if (ROBUST) begin
// Legality FIRST, as a set. Policy operates INSIDE it.
cand = valid & legal_mask;
pick = (|(cand & urgent)) ? lowest(cand & urgent) : lowest(cand);
end else begin
// <-- THE DEFECT: urgency is OR-ed into the candidate set, so a
// policy input can produce a grant that legality excluded.
// This is how it is written when the architecture has one
// box: "pick the urgent one, else the legal one".
cand = (valid & legal_mask) | (valid & urgent);
pick = lowest(cand);
end
end
assign grant = pick;
always_ff @(posedge clk) begin
if (!rst_n) begin
illegal_grants <= '0;
total_grants <= '0;
end else begin
if (|grant) begin
if (total_grants != {CNT_W{1'b1}}) total_grants <= total_grants + 1'b1;
// The truth, computed IDENTICALLY in both builds.
if ((grant & ~legal_mask) != '0)
if (illegal_grants != {CNT_W{1'b1}}) illegal_grants <= illegal_grants + 1'b1;
end
end
end
// SAFETY: a grant must be a subset of the legal set, always.
assign split_err = ((grant & ~legal_mask) != '0);
endmoduleThe measurement.
ILLUSTRATIVE stimulus: 8 entries, 64 cycles. Entry 3 is urgent
throughout and legal on 12 of the 64 cycles.
DERIVED, recomputed:
ROBUST = 1 : total_grants = 64 illegal_grants = 0
ROBUST = 0 : total_grants = 64 illegal_grants = 52
gap = 52 illegal commands out of 64 grants -- 81.3%.And the number is the wrong thing to focus on. DERIVED: 81.3% is an artifact of a stimulus in which one entry is urgent and usually illegal. The transferable figure is that the robust build's count is structurally zero — grant is cand & … and cand is valid & legal_mask, so no input combination can produce an illegal grant. The weak build's count is a function of the stimulus, which means a lightly-loaded test can report zero and prove nothing.
Evidence to demand. Ask which box computes legality and which box consumes it, and ask whether the policy box has access to the timing state at all. If it does, the separation is a drawing convention rather than a mechanism — and 17.4 §3's second argument applies: a block that filters and then chooses, where the filter reads state the previous choice modified, is choosing from a set shaped by its own past behaviour, and reasoning about fairness becomes intractable.
What escapes. An illegal command issued with a sensible-looking grant, and — worse — a controller that cannot report why nothing issued. CURRICULUM-DERIVED from 17.4 §3: an empty result from a combined block is a loop that found nothing, while an empty mask arriving at a pure policy block is a reportable fact with an attributable cause.
How DV proves it. Hold one entry urgent and illegal and check the grant is empty. Chapter 30.5 §11 owns the property — (grant & ~legal_mask) == '0 — and notes that nobody writes it, because the property list is produced by the same mental model as the design.
Telemetry. Two counters: cycles with a non-empty legal mask and no commit, and cycles with an empty legal mask broken down by binding rule. CURRICULUM-DERIVED from 30.5 §13: those two together are the whole diagnosis, and they are only separable because legality and policy are separate boxes.
Misleading evidence. A pipeline diagram with two boxes drawn and one signal crossing between them, where the signal is a hint rather than a filter. The drawing shows the separation and the interface does not enforce it, which is the architectural form of 31.2 §12's ownership flag: present, consumed for one duty, and not for the other.
7. Review Item 3 — Where Is the Commit Point, and Is There Exactly One?
Under review. The instant at which architectural state is permitted to change.
Invariant at risk. Every timing model in the design. If state advances on a different event from the one the device sees, the controller's belief and the device's condition diverge and never reconverge.
Where it lives. The pipeline diagram's stage boundaries, and which stage the state-update arrows leave from.
CURRICULUM-DERIVED from 17.1 §7, which owns the commit point as the single instant at which architectural state is permitted to change. The architectural claim under review is not that a commit point exists — every design has one — but that there is exactly one and that every state update is fed by it.
// ---------------------------------------------------------------------
// commit_point_singularity -- TEACHING MODEL. Review item 3.
//
// CLASSIFICATION: synthesisable teaching model. Built TWICE.
//
// WHAT IT IS: per-bank timing state advanced from one event or from
// two. The robust build updates only on `commit`. The weak build
// updates on `grant`, which is what an architecture specifies when
// its diagram shows the state update leaving the arbiter stage.
//
// WHY IT EXISTS HERE: 17.1 §7 owns the commit point and 30.5 §3 owns
// the four-stage separation in which grant and commit are distinct.
// The gap between the builds is the number of cycles the controller's
// model disagrees with the bus.
//
// HOW TO RUN IT: grant a command and then DROP it (the bus slot went
// elsewhere) without committing.
// EXPECTED RESULT: robust leaves the timing state untouched; weak
// advances it and then believes a command issued that did not.
// EXPECTED TRACE: `model_error_cycles` accumulates in the weak build
// and stays at zero in the robust build.
//
// SYNTHESIS: one counter per bank plus a shadow counter used only to
// detect the model's own divergence.
// LIMITATIONS: one bank, one rule. 13.3 owns the full taxonomy and
// 33.2 reviews whether the code implements this correctly; this
// block reviews whether the ARCHITECTURE named the right event.
// ---------------------------------------------------------------------
module commit_point_singularity #(
parameter bit ROBUST = 1'b1,
parameter int TRCD = 14, // ILLUSTRATIVE
parameter int CNT_W = $clog2(TRCD + 1),
parameter int ERR_W = 16
)(
input logic clk,
input logic rst_n,
input logic grant, // policy chose it
input logic commit, // it reached the bus
output logic [CNT_W-1:0] since_act,
output logic [ERR_W-1:0] model_error_cycles,
output logic commit_err
);
// The TRUTH: state advanced only by the commit, computed in BOTH
// builds so the model detects its own weak build.
logic [CNT_W-1:0] truth;
always_ff @(posedge clk) begin
if (!rst_n) begin
since_act <= '0;
truth <= '0;
model_error_cycles <= '0;
end else begin
// Age both.
if (since_act != {CNT_W{1'b1}}) since_act <= since_act + 1'b1;
if (truth != {CNT_W{1'b1}}) truth <= truth + 1'b1;
if (ROBUST) begin
if (commit) since_act <= '0;
end else begin
// <-- THE DEFECT: the state advances on SELECTION rather than
// on COMMIT. Written this way because the architecture's
// diagram drew the state-update arrow leaving the arbiter.
if (grant) since_act <= '0;
end
// The truth, always on commit.
if (commit) truth <= '0;
// Divergence, accumulated identically in both builds.
if (since_act != truth)
if (model_error_cycles != {ERR_W{1'b1}})
model_error_cycles <= model_error_cycles + 1'b1;
end
end
assign commit_err = (since_act != truth);
endmoduleThe measurement.
ILLUSTRATIVE: TRCD = 14. A grant is dropped (no commit) on cycle
10 and the real commit happens on cycle 24.
DERIVED, recomputed:
ROBUST = 1 : since_act tracks truth exactly.
model_error_cycles = 0
ROBUST = 0 : since_act resets at 10, truth resets at 24.
the two disagree for 14 cycles.
model_error_cycles = 14
and the consequence: on cycle 24 the weak build believes 14
cycles have elapsed since the activate. They have not. It will
permit a column command TRCD cycles too early.DERIVED: the error equals the grant-to-commit gap, so an architecture in which grants always commit has a zero-cycle error and an architecture with arbitration over a shared bus does not. CURRICULUM-DERIVED from 30.5 §3: granted but not committed is one of the four distinct explanations a four-stage design can offer, so a design that cannot distinguish grant from commit cannot report that explanation either.
Evidence to demand. Ask which signal every state update is gated on, and ask whether a grant can fail to commit. If the answer is no, ask what happens when refresh occupancy closes the gate — CURRICULUM-DERIVED from 17.3 §2, during occupancy normal commands are illegal, not deprioritised, so a grant issued into that window cannot commit.
What escapes. A column command issued before its separation has elapsed, at a rate equal to the frequency of dropped grants. It is a protocol violation whose rate depends on contention, so it appears under load and vanishes in a directed test.
How DV proves it. Force a grant to be dropped and check the timing state did not advance. Chapter 30.5 §11 owns the property shape, and the stimulus is three lines: assert grant, hold commit low, check $stable on the counter.
Telemetry. A grants-that-did-not-commit counter. CURRICULUM-DERIVED from 30.5 §13, which lists it as one of the seven scheduler instruments — and it is the one that makes this defect visible without knowing it exists, because a non-zero count on a design that claims grants always commit is a contradiction.
Misleading evidence. A waveform in which the counter resets exactly when the command appears on the bus — which is what the reviewer expects and also exactly what the weak build produces whenever the grant does commit. The two builds are indistinguishable on every cycle except the dropped ones.
8. Review Item 4 — What Is the Requester Class Set, and Does the Protocol Carry It?
Under review. The architecture's model of who is asking.
Invariant at risk. Every policy decision that depends on distinguishing requesters — and the controller's ability to shed work under pressure without violating anything.
Where it lives. The upstream interface's signal list.
CURRICULUM-DERIVED from 32.1 §3, which owns the taxonomy and its two independent axes — deadline and droppability — and the finding that all four combinations occur. CURRICULUM-DERIVED from 32.1 §4, droppability is a class nothing upstream models, because 17.5's one-handshake-one-entry contract has no third outcome.
The architectural question is not which classes exist but can the controller tell.
// ---------------------------------------------------------------------
// class_awareness_probe -- TEACHING MODEL. Review item 4.
//
// CLASSIFICATION: synthesisable teaching model. Built TWICE.
//
// WHAT IT IS: an admission boundary that sheds work under pressure.
// The robust build receives a class code on the interface and sheds
// only the droppable class. The weak build receives no class code --
// the architecture did not put one on the interface -- and must
// therefore either shed nothing or shed indiscriminately.
//
// WHY IT EXISTS HERE: 32.1 §6 establishes that whether the protocol
// labels classes is an INTEGRATION property, so it is decided at
// THIS gate and cannot be recovered later. The gap is what the
// controller can do under pressure.
//
// HOW TO RUN IT: offer a mix at capacity with all four classes.
// EXPECTED RESULT: robust sheds only prefetch-class requests; weak
// sheds the oldest regardless of class, or stalls everything.
// EXPECTED TRACE: `wrong_class_shed` is 0 in the robust build and
// non-zero in the weak build, computed identically in both.
//
// SYNTHESIS: a two-bit decode and one counter.
// LIMITATIONS: models the INTERFACE question. 32.1 §9 owns the
// admission structure itself and 17.5 the handshake contract.
// ---------------------------------------------------------------------
module class_awareness_probe #(
parameter bit ROBUST = 1'b1,
parameter int CNT_W = 16
)(
input logic clk,
input logic rst_n,
input logic req_valid,
// The class code. Present on the interface in BOTH builds so the
// model can compute the truth -- but the weak build does not READ
// it, which is what "the protocol does not carry it" means once
// the RTL exists.
input logic [1:0] req_class, // 0=demand 1=prefetch 2=wb 3=xlate
input logic under_pressure,
output logic shed,
output logic [CNT_W-1:0] wrong_class_shed,
output logic [CNT_W-1:0] total_shed,
output logic class_err
);
localparam logic [1:0] CL_DEMAND = 2'd0;
localparam logic [1:0] CL_PREF = 2'd1;
localparam logic [1:0] CL_WB = 2'd2;
localparam logic [1:0] CL_XLATE = 2'd3;
// The TRUTH: only the prefetch class is droppable. 32.1 §3.
logic droppable_truth;
assign droppable_truth = (req_class == CL_PREF);
always_comb begin
if (ROBUST) begin
// The interface carries the class, so shedding is precise.
shed = req_valid && under_pressure && (req_class == CL_PREF);
end else begin
// <-- THE DEFECT: no class information is available, so the
// architecture's only options are to shed nothing (and
// stall a deadline class) or to shed by age. This build
// sheds under pressure without knowing what it sheds --
// which is what an unlabelled interface forces.
shed = req_valid && under_pressure;
end
end
always_ff @(posedge clk) begin
if (!rst_n) begin
wrong_class_shed <= '0;
total_shed <= '0;
end else if (shed) begin
if (total_shed != {CNT_W{1'b1}}) total_shed <= total_shed + 1'b1;
// Computed IDENTICALLY in both builds.
if (!droppable_truth)
if (wrong_class_shed != {CNT_W{1'b1}})
wrong_class_shed <= wrong_class_shed + 1'b1;
end
end
assign class_err = shed && !droppable_truth;
endmoduleThe measurement.
ILLUSTRATIVE mix, per 100 requests reaching the controller, from
32.1 §7's grade-D proportions:
demand 40, prefetch 35, writeback 20, translation 5
Under pressure for the whole window:
DERIVED, recomputed:
ROBUST = 1 : total_shed = 35 wrong_class_shed = 0
ROBUST = 0 : total_shed = 100 wrong_class_shed = 65
gap: 65 requests shed that must not have been, of which 20 were
writebacks -- which 32.1 §3 says must NEVER be discarded, only
deferred. So the weak build loses data.And the architectural point is that this cannot be fixed downstream. CURRICULUM-DERIVED from 32.1 §6: whether the upstream protocol carries the class is an integration decision, and CURRICULUM-DERIVED from 32.3 §6, a population cannot be inferred from a request's fields either — two identical demand reads from different requesters are identical in every field except who sent them. So if this gate does not put the information on the interface, no later gate can recover it.
Evidence to demand. Ask to see the upstream interface's signal list and point at the class field. If there is none, ask what the controller does when the queue is full — and if the answer is apply backpressure, ask what 17.5 §4 says a backpressure signal needs, which is a cause. I had no way to tell which requests mattered is a cause, and it is an architecture finding rather than an implementation one.
What escapes. Either a controller that cannot shed and therefore stalls deadline-bearing traffic behind hints, or one that sheds indiscriminately and discards writebacks. CURRICULUM-DERIVED from 32.1 §3: the second loses data, and it loses it silently.
How DV proves it. Fill the queue and check which class is refused. The test is trivial and it is absent from a testbench whose stimulus generator does not label classes either — which it will not, if the architecture did not.
Telemetry. classes_present as a bit vector. CURRICULUM-DERIVED from 32.1 §17: a single bit set means the platform is not labelling classes at all, and that is a free finding available from the first run.
Misleading evidence. An interface document listing a rich set of attributes — priority, QoS class, stream ID, transaction type — none of which answers may this be discarded. A priority number is not a droppability axis, and 32.1 §3 is explicit that the two axes are independent: a prefetch and a writeback are identical on the deadline axis and opposite on droppability.
9. Review Item 5 — Is Every Bound Derived, or Chosen?
Under review. Every constant in the architecture that bounds a wait, a depth, an age or a retry count.
Invariant at risk. Provability. A bound that was chosen cannot be proved, and a property asserting it either fails on correct behaviour or holds vacuously.
Where it lives. The parameter table, and the column that should say derived from and usually says nothing.
CURRICULUM-DERIVED from 30.9 §5 Q2: a progress obligation must be converted into a bound, and the bound must be justified, not chosen. CURRICULUM-DERIVED from 17.4 §9, the derivation for an age threshold is explicit — it must exceed the longest legitimate wait, which includes tRAS plus tRP plus tRCD in the conflict case, plus the refresh drain and occupancy, plus contention from every other queue entry.
// ---------------------------------------------------------------------
// derived_bound_check -- TEACHING MODEL. Review item 5.
//
// CLASSIFICATION: synthesisable teaching model. Built TWICE.
//
// WHAT IT IS: a fairness age threshold, derived from its components
// or chosen as a round number. The robust build computes the
// threshold from the worst legitimate wait and refuses to elaborate
// if the counter cannot represent it. The weak build takes a
// round-number parameter -- which is what a parameter table
// contains when nobody wrote down the derivation.
//
// WHY IT EXISTS HERE: 17.4 §9 gives the derivation and 30.9 §5 Q2
// the requirement. The gap is whether the mechanism is reachable at
// all, which 31.2 §7 calls "present in the source, absent in the
// silicon".
//
// HOW TO RUN IT: elaborate both builds with the same illustrative
// timing and compare `threshold_used` against `worst_legit_wait`.
// EXPECTED RESULT: robust's threshold exceeds the worst legitimate
// wait; weak's is below it, so the mechanism fires constantly.
// EXPECTED TRACE: `threshold_unsound` is 0 in the robust build and
// 1 in the weak build.
//
// SYNTHESIS: one age counter and a comparator.
// LIMITATIONS: derives ONE bound from four terms. The real worst
// wait includes contention scaling that 17.4 §9 says must be
// measured; this model uses an ILLUSTRATIVE entry count for it and
// says so, rather than pretending the derivation is complete.
// ---------------------------------------------------------------------
module derived_bound_check #(
parameter bit ROBUST = 1'b1,
// ILLUSTRATIVE timing. 14.1-14.3 own the real values.
parameter int TRAS = 34,
parameter int TRP = 14,
parameter int TRCD = 14,
parameter int REF_DRAIN = 60, // ILLUSTRATIVE, 17.3 §5
parameter int REF_OCCUPY = 280, // ILLUSTRATIVE, 15.5
parameter int NUM_ENTRIES = 16,
// The worst LEGITIMATE wait, DERIVED from 17.4 §9's list rather
// than chosen. The entry-count term is ILLUSTRATIVE: that chapter
// says contention must be measured, and this expression takes the
// simplest defensible model -- every other entry served once.
parameter int WORST_LEGIT = (TRAS + TRP + TRCD + REF_DRAIN + REF_OCCUPY)
+ (NUM_ENTRIES - 1) * TRCD,
// The weak build's round number, as a parameter table would hold it.
parameter int CHOSEN_AGE = 256,
parameter int AGE_THRESH = ROBUST ? (WORST_LEGIT + 1) : CHOSEN_AGE,
// COUNT, not INDEX: the counter must REPRESENT the threshold, so
// $clog2(threshold + 1). 31.2 §7's hazard, and the elaboration
// guard below is what makes the mechanism reachable.
parameter int AGE_W = $clog2(AGE_THRESH + 1)
)(
input logic clk,
input logic rst_n,
input logic entry_waiting,
input logic entry_served,
output logic [AGE_W-1:0] age,
output logic urgent,
output logic [31:0] threshold_used,
output logic [31:0] worst_legit_wait,
output logic threshold_unsound
);
initial begin
if (AGE_THRESH >= (1 << AGE_W))
$fatal(1, "derived_bound_check: AGE_W cannot represent AGE_THRESH");
if (ROBUST && (AGE_THRESH <= WORST_LEGIT))
$fatal(1, "derived_bound_check: threshold does not exceed the worst legitimate wait");
end
always_ff @(posedge clk) begin
if (!rst_n) age <= '0;
else if (entry_served) age <= '0;
else if (entry_waiting && age != {AGE_W{1'b1}})
age <= age + 1'b1;
end
assign urgent = (age >= AGE_THRESH[AGE_W-1:0]);
assign threshold_used = AGE_THRESH;
assign worst_legit_wait = WORST_LEGIT;
// The truth, computed IDENTICALLY in both builds: a threshold at or
// below the worst legitimate wait fires on legitimate waits, which
// disables the preference layer it sits above.
assign threshold_unsound = (AGE_THRESH <= WORST_LEGIT);
endmoduleThe measurement.
DERIVED from the ILLUSTRATIVE inputs, recomputed:
WORST_LEGIT = (34 + 14 + 14 + 60 + 280) + 15 * 14
= 402 + 210
= 612 cycles
ROBUST = 1 : AGE_THRESH = 613, threshold_unsound = 0
ROBUST = 0 : AGE_THRESH = 256, threshold_unsound = 1
gap: the chosen threshold is 356 cycles BELOW the worst
legitimate wait -- 42% of it.And the consequence is the opposite of the intent. CURRICULUM-DERIVED from 17.4 §9: a threshold that does not exceed the longest legitimate wait means the mechanism fires constantly and the preference layer is effectively disabled. DERIVED: at 256 against a legitimate 612, the fairness override triggers on ordinary conflict-plus-refresh waits, so the controller becomes fair and slow rather than correctly ordered — and 32.1 §11's binding_layer telemetry is what would show it.
Evidence to demand. Ask for the parameter table with a derived from column, and ask for the derivation of any entry that is a power of two or a round decimal. A round number is not evidence of a wrong bound, but it is evidence that nobody wrote the derivation down — and 30.9 §5 says the derivation is the property's warrant.
What escapes. Two defects with one cause. A threshold too low disables the preference it overrides. A threshold too high makes the fairness mechanism unreachable, which is 31.2 §7's present in the source, absent in the silicon — and the elaboration guard above is the cheapest possible detector for the second.
How DV proves it. Assert the bound as a bounded-liveness property and publish its antecedent as a cover. CURRICULUM-DERIVED from 27.2 §6: without the cover, a bound nobody ever reached passes vacuously, so a too-high threshold and a correct one are indistinguishable.
Telemetry. The age histogram, not the maximum. CURRICULUM-DERIVED from 30.5 §13: a maximum hides a tail, and the histogram is what tells you whether the threshold sits sanely relative to the distribution it is meant to bound.
Misleading evidence. A parameter table in which every entry is a plausible round number and every one is documented with a units column. Units are not a derivation. The table looks complete because every cell is filled, and the column that would have caught this is the one nobody adds.
10. Review Item 6 — What Happens on the Cycle a Value Is Unknown?
Under review. Every piece of state the controller maintains about a device it cannot observe.
Invariant at risk. Legality, at the one moment the controller is least able to reason — after reset, after a mode change, after a monitor attaches mid-traffic.
Where it lives. The state encoding, and whether it has two values or three.
CURRICULUM-DERIVED from 7.4, which owns the three-valued bank-state discipline and the result that reporting a confident wrong row is worse than reporting unknown. CURRICULUM-DERIVED from 30.7 §9, the same discipline at the PHY layer: an untrained value is unknown, and unknown is not a default.
// ---------------------------------------------------------------------
// three_valued_state -- TEACHING MODEL. Review item 6.
//
// CLASSIFICATION: synthesisable teaching model. Built TWICE.
//
// WHAT IT IS: per-bank row state with three values or two. The
// robust build carries `known` alongside `open` and emits NOTHING
// when the state is unknown. The weak build carries only `open`,
// initialised to zero -- which encodes "unknown" and "closed" as the
// same value, and treats both as "safe to activate".
//
// WHY IT EXISTS HERE: 7.4 owns the discipline; 30.2 §8's diagram
// makes the fourth answer explicit. The gap is the number of illegal
// activates the weak build issues before the state is established.
//
// HOW TO RUN IT: present a column request to a bank the controller
// has never commanded.
// EXPECTED RESULT: robust emits nothing and reports UNKNOWN; weak
// treats the bank as closed and issues an ACT.
// EXPECTED TRACE: `illegal_act` is 0 in the robust build and
// non-zero in the weak build, computed identically in both.
//
// SYNTHESIS: one extra bit per bank.
// LIMITATIONS: models the ENCODING question. 30.2 §9 owns the full
// tracker and 33.2 reviews the code; this reviews whether the
// architecture specified a third value at all.
// ---------------------------------------------------------------------
module three_valued_state #(
parameter bit ROBUST = 1'b1,
parameter int BANKS = 8,
parameter int CNT_W = 16,
parameter int BW = $clog2(BANKS)
)(
input logic clk,
input logic rst_n,
input logic req_valid,
input logic [BW-1:0] req_bank,
input logic obs_act, // an activate observed on the bus
input logic [BW-1:0] obs_bank,
output logic cmd_act,
output logic [2:0] outcome,
output logic [CNT_W-1:0] illegal_act,
output logic state_err
);
localparam logic [2:0] OUT_IDLE = 3'd0;
localparam logic [2:0] OUT_MISS = 3'd1;
localparam logic [2:0] OUT_HIT = 3'd2;
localparam logic [2:0] OUT_UNKNOWN = 3'd3;
logic open_q [BANKS];
// The third value. Present in BOTH builds so the model can compute
// the truth, but READ only by the robust build -- which is what
// "the architecture did not specify a third value" produces once
// the RTL exists.
logic known_q [BANKS];
always_ff @(posedge clk) begin
if (!rst_n) begin
for (int b = 0; b < BANKS; b++) begin
open_q[b] <= 1'b0;
known_q[b] <= 1'b0; // nothing is known after reset
end
illegal_act <= '0;
end else begin
if (obs_act) begin
open_q[obs_bank] <= 1'b1;
known_q[obs_bank] <= 1'b1;
end
// The truth, computed IDENTICALLY in both builds: an activate
// to a bank whose state is not established may be illegal,
// because the bank may already have a row open.
if (cmd_act && !known_q[req_bank])
if (illegal_act != {CNT_W{1'b1}}) illegal_act <= illegal_act + 1'b1;
end
end
always_comb begin
outcome = OUT_IDLE;
cmd_act = 1'b0;
if (req_valid) begin
if (ROBUST) begin
if (!known_q[req_bank]) begin
// A FINDING, not a fourth path. 7.4: unknown emits nothing.
outcome = OUT_UNKNOWN;
cmd_act = 1'b0;
end else if (!open_q[req_bank]) begin
outcome = OUT_MISS;
cmd_act = 1'b1;
end else begin
outcome = OUT_HIT;
end
end else begin
// <-- THE DEFECT: two-valued state. "Not open" and "never
// established" are the same encoding, and both permit
// an activate.
if (!open_q[req_bank]) begin
outcome = OUT_MISS;
cmd_act = 1'b1;
end else begin
outcome = OUT_HIT;
end
end
end
end
assign state_err = cmd_act && !known_q[req_bank];
endmoduleThe measurement.
ILLUSTRATIVE: 8 banks. A monitor attaches mid-traffic, so no
bank's state is established. 8 column requests arrive, one per
bank, before any activate is observed.
DERIVED, recomputed:
ROBUST = 1 : cmd_act asserted 0 times. illegal_act = 0
outcome = OUT_UNKNOWN on all 8.
ROBUST = 0 : cmd_act asserted 8 times. illegal_act = 8
gap = 8 potentially illegal activates, one per bank, and the
window is exactly the interval before each bank's state is first
established.The window is the point, and it is why this defect is hard to find. DERIVED: the exposure lasts only until each bank has been commanded once. A testbench that starts from reset and drives traffic establishes every bank's state within a few hundred cycles, after which the two builds are identical forever. CURRICULUM-DERIVED from 31.2 §14's scale-vacuity refinement: the antecedent occurs, briefly, at a scale where the defect produces at most a handful of events — and the cover that would catch it must be on the unknown state, not on the activate.
Evidence to demand. Ask how many values the bank-state encoding has. If the answer is two, ask what the controller does on its first access after reset — and if the answer is the device is precharged after initialisation so it is closed, ask what enforces that, and what happens after a warm reset that resets the controller and not the device.
What escapes. An activate to a bank that already has a row open, which is an illegal command rather than a slow one — 7.4. And in a monitor rather than a controller, a hit/miss/conflict statistic computed from state that was never established, which 30.2 §12 notes invalidates every number derived from it.
How DV proves it. Start the checker mid-traffic rather than at reset and check nothing is emitted until state is established. CURRICULUM-DERIVED from 27.3's independence requirement: a monitor that cannot say unknown has to guess, and its guess agrees with whatever the design did.
Telemetry. An OUT_UNKNOWN counter. CURRICULUM-DERIVED from 30.2 §12: if the tracker is reporting unknown, every hit-rate figure derived from it is suspect — so the counter is a measurement about the instrument rather than about the system, and a non-zero value invalidates a report rather than describing one.
Misleading evidence. A state diagram with exactly the states the device has. The device genuinely has two row states; the controller's belief has three, and a diagram that models the device faithfully is the reason the third is omitted.
11. Review Item 7 — Which Properties Are Architecture, and Which Are Configuration?
Under review. Every claim in the document of the form the controller does X.
Invariant at risk. The validity of the entire document. A configuration outcome documented as an architecture fact is a claim with an unstated validity period.
Where it lives. The absence of a column.
CURRICULUM-DERIVED from 18.4 §5, which owns the result for address maps: even with perfect documentation, on many systems there is no single map to state, because the map is a function of configuration decided after the silicon was designed — and lists the inputs, from controller stepping through channel population and interleaving mode to firmware settings and ECC configuration. CURRICULUM-DERIVED from 32.1 §6, which generalises it from the map to the controller: most of what an engineer wants to know is a configuration outcome rather than an architecture fact.
// ---------------------------------------------------------------------
// config_vs_architecture -- TEACHING MODEL. Review item 7.
//
// CLASSIFICATION: synthesisable teaching model. Built TWICE.
//
// WHAT IT IS: a property consumed from a configuration register or
// compiled in as a parameter. The robust build reads the register
// and refuses to operate before it is valid. The weak build has the
// value as a parameter -- which is exactly what happens when an
// architecture document states a configuration outcome as a fact.
//
// WHY IT EXISTS HERE: 32.1 §14 is this defect in RTL and 18.4 §1
// owns the evidence mechanism (category drift) that produces it.
// This model is the ARCHITECTURAL form: the parameter exists because
// the document said the value was fixed.
//
// HOW TO RUN IT: operate both builds against a platform whose
// configured value differs from the compiled default.
// EXPECTED RESULT: robust follows the configuration; weak ignores it.
// EXPECTED TRACE: `config_ignored` is 0 in the robust build and 1 in
// the weak build whenever cfg differs from the default.
//
// SYNTHESIS: a variable shift versus a fixed one.
// LIMITATIONS: one field. 8.6 owns the full mapper and 18.4 the
// evidence discipline; this reviews whether the ARCHITECTURE marked
// the field as configuration.
// ---------------------------------------------------------------------
module config_vs_architecture #(
parameter bit ROBUST = 1'b1,
parameter int ADDR_W = 40,
parameter int NUM_CH = 4,
parameter int CH_W = $clog2(NUM_CH),
// ILLUSTRATIVE, and the whole problem: a value the document stated
// as an architecture fact when it is a configuration outcome.
parameter int CH_BIT_DOC = 8
)(
input logic clk,
input logic rst_n,
input logic cfg_valid,
input logic [5:0] cfg_ch_bit,
input logic req_valid,
input logic [ADDR_W-1:0] req_addr,
output logic [CH_W-1:0] sel_ch,
output logic decode_invalid,
output logic config_ignored
);
logic [CH_W-1:0] truth;
// The TRUTH, computed IDENTICALLY in both builds from the
// configuration the platform actually supplied.
assign truth = cfg_valid ? req_addr[cfg_ch_bit +: CH_W] : '0;
always_comb begin
sel_ch = '0;
decode_invalid = 1'b0;
if (req_valid) begin
if (ROBUST) begin
if (!cfg_valid) begin
// 30.7 §9: unconfigured is UNKNOWN, and unknown is not a
// default. Refuse rather than guess.
decode_invalid = 1'b1;
end else begin
sel_ch = req_addr[cfg_ch_bit +: CH_W];
end
end else begin
// <-- THE DEFECT: the documented value is compiled in and the
// configuration input is never read. The block also does
// not refuse before configuration, because from its point
// of view there is nothing to wait for.
sel_ch = req_addr[CH_BIT_DOC +: CH_W];
end
end
end
assign config_ignored = req_valid && cfg_valid && (sel_ch != truth);
endmoduleThe measurement.
ILLUSTRATIVE: NUM_CH = 4, documented field at bit 8, platform's
configured field at bit 13.
DERIVED, recomputed:
ROBUST = 1 : sel_ch tracks cfg_ch_bit. config_ignored = 0
ROBUST = 0 : sel_ch = addr[9:8] always. config_ignored = 1
on every request whose addr[9:8] differs from
addr[14:13] -- which is 3 out of every 4 addresses
at random, so 75%.
and note what does NOT happen: no data is wrong. addr[9:8] is
still a bijection onto 4 channels. What breaks is the INTERLEAVE
GRANULARITY -- 256 bytes instead of 8192 -- so a stride designed
to spread across channels concentrates on one.DERIVED: four channels of hardware deliver the throughput of one, and CURRICULUM-DERIVED from 32.1 §14, the symptom lands in 30.8 §4's gap 2→3 — the request stream's own locality — which that chapter attributes to software. So the investigation goes to the software team, and the software team's stride is correct.
Evidence to demand. Ask for the document with a validity column: for each stated property, architecture or configuration, and if configuration, which register supplies it. Then ask whether that register is readable at runtime — CURRICULUM-DERIVED from 32.1 §6, a documented mechanism you cannot read at runtime is operationally no better than an undocumented one, so can I read the configuration belongs in the review alongside is it documented.
What escapes. A performance loss that presents as a workload problem, and it is self-confirming in the sense 32.4 §14 describes: the recommended action — optimise the access pattern — does not change the measurement, so the next investigation reaches the same conclusion.
How DV proves it. Sweep the configuration input and check the decode follows it. CURRICULUM-DERIVED from 32.1 §15's coverage lesson: a testbench that models one platform holds the field at the documented value forever, so the cover on configured value differs from default stays at zero and the configuration mechanism is never tested even though the configuration gate is.
Telemetry. The configured value read back and published. CURRICULUM-DERIVED from 32.1 §14: a block that reports the compiled value instead confirms the wrong answer, which is worse than reporting nothing.
Misleading evidence. A precise, complete, internally consistent bit-field diagram. It is precise about a configuration that was true on one platform — 18.4 §1's category drift, and the diagram's precision is exactly what makes it convincing.
12. Review Item 8 — Which Decisions Are Committed in Silicon, and Which Remain Open?
Under review. The architecture's own account of what it is foreclosing.
Invariant at risk. The project's schedule, and the range of workloads the design can serve after tape-out.
Where it lives. Nowhere, usually. This is the item with no document artifact, which is why it is last and why it is the one most often skipped.
CURRICULUM-DERIVED from 32.4 §3, which owns the comparison across platform classes: on a CPU platform the controller is silicon and the population, interleaving, page policy and firmware remain adjustable; on an accelerator platform the stack count, the stream count and the requester parallelism are all silicon and almost nothing that matters remains adjustable; on a server platform the tier composition is chosen at deployment and changed in service. CURRICULUM-DERIVED from 26.4 §8: where two halves are both silicon, they must be designed together and neither can be chosen independently.
// ---------------------------------------------------------------------
// commitment_ledger -- TEACHING MODEL. Review item 8.
//
// CLASSIFICATION: verification-only. Drives nothing. Built TWICE.
//
// WHAT IT IS: a ledger of which architectural decisions are
// committed in silicon and which remain configurable, with an
// elaboration check that every committed decision has a stated
// derivation. The robust build requires a derivation reference for
// each committed bit; the weak build accepts commitments with none,
// which is what a document without this section produces.
//
// WHY IT EXISTS HERE: 32.4 §3 shows the silicon/configurable split
// differs by platform class and §5 that the cost of a wrong
// commitment is asymmetric. An architecture that has not written the
// split down has not costed it.
//
// HOW TO RUN IT: elaborate with a commitment whose derivation bit is
// clear.
// EXPECTED RESULT: robust FAILS elaboration; weak elaborates.
// EXPECTED TRACE: `undocumented_commitments` is 0 in the robust
// build by construction and non-zero in the weak build.
//
// SYNTHESIS: none.
// LIMITATIONS: it checks that a derivation EXISTS, not that it is
// sound. 32.4 §5 owns the costing and 33.5 the performance ceiling;
// this item reviews whether the question was asked.
// ---------------------------------------------------------------------
module commitment_ledger #(
parameter bit ROBUST = 1'b1,
// One bit per decision: is it committed in silicon?
// [0] channel count [1] queue depth
// [2] requester parallelism [3] page policy
// [4] address map [5] refresh mode
parameter logic [5:0] COMMITTED = 6'b010101,
// One bit per decision: does a written derivation exist?
parameter logic [5:0] DERIVED_REF = 6'b000101,
parameter int LED_W = 3
)(
input logic clk,
input logic rst_n,
output logic [5:0] committed_mask,
output logic [5:0] missing_derivation,
output logic [LED_W-1:0] undocumented_commitments,
output logic ledger_err
);
// A commitment without a derivation is the finding. Computed
// IDENTICALLY in both builds so the model detects its own weak
// build; only the elaboration guard differs.
assign committed_mask = COMMITTED;
assign missing_derivation = COMMITTED & ~DERIVED_REF;
assign undocumented_commitments = LED_W'($countones(missing_derivation));
assign ledger_err = (missing_derivation != '0);
initial begin
if (ROBUST && (COMMITTED & ~DERIVED_REF) != 0)
$fatal(1, "commitment_ledger: %0d silicon commitments have no written derivation (mask %b)",
$countones(COMMITTED & ~DERIVED_REF), COMMITTED & ~DERIVED_REF);
end
endmoduleThe measurement.
ILLUSTRATIVE masks. COMMITTED = 010101, DERIVED_REF = 000101.
DERIVED, recomputed:
missing_derivation = 010101 & ~000101 = 010000
undocumented_commitments = 1
ROBUST = 1 : elaboration FAILS, naming bit 4 (the address map)
ROBUST = 0 : elaborates silently, ledger_err = 1 and nobody
is looking at ledger_err
gap = 1 silicon commitment taken with no written derivation, and
the mask names which.And the asymmetry is what makes this worth a gate rather than a note. CURRICULUM-DERIVED from 32.4 §5: the two ways of getting a commitment wrong cost differently, and the sign of the asymmetry depends on the memory subsystem's share of system cost — below about half, under-provisioning is the more expensive error and the rational point sits above the expectation. DERIVED consequence for this gate: a commitment with no written derivation has not been costed in either direction, so the project cannot know which of its two possible errors it is making.
Evidence to demand. Ask for the list of decisions that cannot be changed after tape-out, and for each one, the derivation and the cost of being wrong by a factor of two in each direction. CURRICULUM-DERIVED from 30.8 §6: computing a ceiling before committing is what converts a refusal from an opinion into a finding, and the same arithmetic applies to a commitment.
What escapes. A design that is correct and cannot serve the workload it was bought for. CURRICULUM-DERIVED from 26.4 §9: the mismatches all produce working systems, so nothing malfunctions and no test fails.
How DV proves it. It cannot. This is the one item on the list with no DV answer, and saying so is part of the review: a commitment's soundness is not a property of the design, so no stimulus falsifies it. CURRICULUM-DERIVED from 32.1 §15's variety 11 — a residual risk that has left the design's boundary — and its discharge is a written derivation reviewed by somebody who can price it, not an assertion.
Telemetry. CURRICULUM-DERIVED from 32.4 §7: the counterfactual reporter — per-window evidence of which half of a joint decision was binding. On a platform whose architecture is committed before its workload exists, the instrumentation is the only mechanism by which the next decision is better informed than this one, and its absence guarantees the same bet twice.
Misleading evidence. A document with a thorough future work or next generation section. It reads as foresight and it is usually a list of things the author knows are uncertain and has not costed — which is the opposite of a derivation, and the two are easy to confuse because both discuss the future.
13. The Review Assembled
Cost-ordered, per the module's fourth corollary: the items that cost an hour and can close a question come first. An architecture review run in topic order spends its expensive attention before its cheap attention, and the cheap items are the ones that eliminate whole classes.
| # | Item | Question, in one line | Cost | Can it close a question? |
|---|---|---|---|---|
| 1 | §5 Obligation census | Count the obligation list against thirteen | minutes | yes — a missing obligation is a finding with no further work |
| 2 | §11 Configuration marking | Which stated properties are configuration outcomes? | minutes | yes — an unmarked document is a finding |
| 3 | §12 Commitment ledger | Which decisions cannot be changed after tape-out? | hours | yes — a commitment with no derivation |
| 4 | §8 Class awareness | Does the upstream interface carry a class code? | hours | yes — read the signal list |
| 5 | §6 Legality / policy split | Which box computes legality, which consumes it? | hours | partly — the drawing may not match the interface |
| 6 | §7 Commit point | What event gates every state update? | hours | partly |
| 7 | §10 Three-valued state | How many values does the bank-state encoding have? | hours | partly |
| 8 | §9 Derived bounds | Show the derivation for every bound | days | no — it requires the timing budget |
Items 1 and 2 cost minutes and neither requires a meeting. DERIVED from the table: three of the eight items can close a question on their own, and all three are in the top four. An architecture review that starts at item 8 — which is the most technically interesting — has spent a day before asking whether the obligation list is complete.
And one item has no DV row at all. §12's how DV proves it facet reads it cannot, and that is the item's content rather than a gap in it. CURRICULUM-DERIVED from 32.1 §15's variety 11: a residual risk outside the design's boundary is not discharged by a stronger property, so an architecture review is the only gate at which it can be discharged at all.
14. Quantitative Reasoning
Every figure this chapter produced, gathered with its provenance. Each DERIVED value is recomputed here from inputs stated in the item that produced it.
| Item | Quantity | Robust | Weak | Gap | Provenance |
|---|---|---|---|---|---|
| §5 | obligations declared | 13 | 11 | 2 | count is CURRICULUM-DERIVED from 31.1 §5 |
| §6 | illegal grants in 64 | 0 | 52 | 52 | DERIVED, ILLUSTRATIVE stimulus |
| §7 | model-error cycles | 0 | 14 | 14 | DERIVED = the grant-to-commit gap |
| §8 | wrongly shed requests per 100 | 0 | 65 | 65 | DERIVED from 32.1 §7's grade-D mix |
| §9 | age threshold vs worst legitimate wait | 613 vs 612 | 256 vs 612 | −356 | DERIVED, ILLUSTRATIVE timing |
| §10 | potentially illegal activates | 0 | 8 | 8 | DERIVED, one per bank |
| §11 | interleave granularity, bytes | 8192 | 256 | 32× | DERIVED from the field positions |
| §12 | undocumented commitments | 0 | 1 | 1 | DERIVED from the ILLUSTRATIVE masks |
Two of the eight gaps are structural rather than stimulus-dependent, and the distinction matters when reading the table.
§6's robust build cannot produce an illegal grant for any input, because grant is a subset of cand and cand is valid & legal_mask. DERIVED: its zero is a property of the expression, not of the stimulus. §5's and §12's gaps are also structural — they are counts of declared items.
The other five gaps are stimulus-dependent, and every one of them shrinks to zero under a benign stimulus. DERIVED: §7's gap is zero if grants always commit; §8's is zero if the queue never fills; §10's is zero after the first pass over the banks; §11's is zero if the configured value happens to equal the documented one. CURRICULUM-DERIVED from 32.5 §15's module-level finding: three of Module 32's five defects were correct at the operating point where they were validated, and this table is the same observation at the architecture gate — five of eight items have a benign operating point at which the review would pass.
15. What the Assertions Prove
The DDR track's signature, applied to this gate's models. Each property below names the signal whose corruption it catches, and the set is reviewed against the eleven varieties afterwards.
// ---- §5: the obligation census.
// An INVARIANT: there is no cycle on which an incomplete
// obligation list is acceptable.
property p_obligation_count_complete;
@(posedge clk) disable iff (!rst_n)
obligations_present == OBLIGATIONS_REQUIRED;
endproperty
assert property (p_obligation_count_complete)
else $error("the architecture declares fewer than thirteen obligations");
// The two most-omitted obligations, named individually -- because a
// count of 13 achieved by declaring something else twice would
// satisfy the property above.
property p_rolling_window_declared;
@(posedge clk) disable iff (!rst_n) obligation_mask[5];
endproperty
assert property (p_rolling_window_declared)
else $error("the activate rate limit (14.8) is not declared");
property p_turnaround_declared;
@(posedge clk) disable iff (!rst_n) obligation_mask[10];
endproperty
assert property (p_turnaround_declared)
else $error("direction turnaround (30.5 §7) is not declared");
// ---- §6: the legality / policy split. THE property 30.5 §11 says
// nobody writes, because the property list comes from the same
// mental model as the design.
property p_grant_subset_of_legal;
@(posedge clk) disable iff (!rst_n)
(grant & ~legal_mask) == '0;
endproperty
assert property (p_grant_subset_of_legal)
else $error("a grant left the legal set");
// And the candidate set must not be WIDER than the legal set --
// stated separately, because the weak build widens `cand` and a
// property on `grant` alone would be satisfied by a design that
// widened cand and then narrowed it again by luck.
property p_candidate_subset_of_legal;
@(posedge clk) disable iff (!rst_n)
(cand & ~legal_mask) == '0;
endproperty
assert property (p_candidate_subset_of_legal)
else $error("the candidate set is wider than the legal set");
// ---- §7: the commit point.
// Timing state advances ONLY on commit. Names `grant` explicitly so
// a design that advances on grant cannot satisfy it.
property p_state_advances_only_on_commit;
@(posedge clk) disable iff (!rst_n)
(grant && !commit) |=> $stable(since_act);
endproperty
assert property (p_state_advances_only_on_commit)
else $error("timing state advanced on a grant that did not commit");
// The model must never diverge from the truth. An invariant, and it
// is the two-sided form: a design that never advances the state at
// all satisfies the property above.
property p_model_matches_truth;
@(posedge clk) disable iff (!rst_n) since_act == truth;
endproperty
assert property (p_model_matches_truth)
else $error("the controller's timing model diverged from the bus");
// ---- §8: class awareness.
// A non-droppable class must NEVER be shed. The one obligation the
// mechanism could violate catastrophically, and it names the class.
property p_never_shed_a_non_droppable_class;
@(posedge clk) disable iff (!rst_n)
shed |-> (req_class == CL_PREF);
endproperty
assert property (p_never_shed_a_non_droppable_class)
else $error("a non-droppable class was shed");
// Two-sided: a design that sheds nothing satisfies the above and has
// disabled the mechanism. 30.3 §9's variety 8.
property p_sheds_under_pressure;
@(posedge clk) disable iff (!rst_n)
(req_valid && under_pressure && req_class == CL_PREF) |-> shed;
endproperty
assert property (p_sheds_under_pressure)
else $error("the droppable class was not shed under pressure");
// ---- §9: derived bounds.
property p_threshold_exceeds_legitimate_wait;
@(posedge clk) disable iff (!rst_n)
threshold_used > worst_legit_wait;
endproperty
assert property (p_threshold_exceeds_legitimate_wait)
else $error("the fairness threshold does not exceed the worst legitimate wait");
// The counter must be able to REACH the threshold, or the mechanism
// is present in the source and absent in the silicon (31.2 §7).
property p_threshold_is_reachable;
@(posedge clk) disable iff (!rst_n)
threshold_used < (1 << AGE_W);
endproperty
assert property (p_threshold_is_reachable)
else $error("the age counter cannot represent the threshold");
// ---- §10: three-valued state.
property p_no_command_on_unknown_state;
@(posedge clk) disable iff (!rst_n)
(outcome == OUT_UNKNOWN) |-> !cmd_act;
endproperty
assert property (p_no_command_on_unknown_state)
else $error("a command was emitted for a bank whose state is unknown");
property p_no_activate_to_open_bank;
@(posedge clk) disable iff (!rst_n)
cmd_act |-> (known_q[req_bank] && !open_q[req_bank]);
endproperty
assert property (p_no_activate_to_open_bank)
else $error("activate issued to a bank that is open or unestablished");
// ---- §11: configuration versus architecture.
// Names cfg_ch_bit, which the weak build never reads.
property p_decode_follows_configuration;
@(posedge clk) disable iff (!rst_n)
(req_valid && cfg_valid) |-> (sel_ch == truth);
endproperty
assert property (p_decode_follows_configuration)
else $error("the decode does not follow the configured field position");
property p_unconfigured_refuses;
@(posedge clk) disable iff (!rst_n)
(req_valid && !cfg_valid) |-> decode_invalid;
endproperty
assert property (p_unconfigured_refuses)
else $error("a decode was performed with no valid configuration");
// ---- §12: the commitment ledger. An invariant with no antecedent,
// because there is no cycle on which an undocumented commitment is
// acceptable.
property p_every_commitment_has_a_derivation;
@(posedge clk) disable iff (!rst_n)
missing_derivation == '0;
endproperty
assert property (p_every_commitment_has_a_derivation)
else $error("a silicon commitment has no written derivation");
// ---- COVERS. Each is on the dimension its defect scales with,
// per 31.3 §15's rule, and the dimension is named.
// §7: the dimension is the GRANT-TO-COMMIT GAP. A design in which
// grants always commit never reaches this, however long it runs.
cover property (@(posedge clk) disable iff (!rst_n) grant && !commit);
// §8: the dimension is QUEUE PRESSURE. An unloaded test never
// reaches it, and 32.1 §15 makes the same point about benchmarks.
cover property (@(posedge clk) disable iff (!rst_n)
req_valid && under_pressure);
cover property (@(posedge clk) disable iff (!rst_n)
under_pressure && req_class == CL_WB);
// §9: the dimension is AGE. The threshold must actually be reached,
// or p_threshold_exceeds_legitimate_wait holds vacuously about a
// mechanism that never fires -- 27.2 §6.
cover property (@(posedge clk) disable iff (!rst_n) urgent);
// §10: the dimension is the UNKNOWN WINDOW, which closes after the
// first pass over the banks. Covering the activate would miss it.
cover property (@(posedge clk) disable iff (!rst_n)
outcome == OUT_UNKNOWN);
// §11: the dimension is the CONFIGURED VALUE, and specifically its
// DIFFERING from the documented default -- 32.1 §15's lesson.
cover property (@(posedge clk) disable iff (!rst_n)
cfg_valid && (cfg_ch_bit != CH_BIT_DOC));
cover property (@(posedge clk) disable iff (!rst_n)
req_valid && !cfg_valid);
// §6: the antecedent of the split -- an entry urgent and illegal.
// Without this the subset property passes on an environment whose
// urgent entries are always legal.
cover property (@(posedge clk) disable iff (!rst_n)
|(valid & urgent & ~legal_mask));
// §5 and §12: the configuration arms, per 31.1 §14's rule.
cover property (@(posedge clk) disable iff (!rst_n) census_err);
cover property (@(posedge clk) disable iff (!rst_n) ledger_err);Reviewed against the eleven varieties, this set avoids six of them deliberately and the reasoning is worth stating.
Variety 2 — does not name the key signal. Every property above names the signal its defect corrupts: legal_mask, grant, commit, req_class, cfg_ch_bit, known_q, missing_derivation. CURRICULUM-DERIVED from 30.5 §11, that is the repair, and it is the variety this module's own review found most often.
Variety 6 — vacuous. Every implication's antecedent has a cover, and each cover is on the dimension its defect scales with rather than on the event.
Variety 8 — safety cannot detect conservatism. Three items carry two-sided properties: §8's shed/not-shed pair, §9's exceeds/reachable pair, §7's advances-only-on-commit plus matches-truth. CURRICULUM-DERIVED from 30.3 §9: a one-sided safety property is satisfied by a design that does nothing.
Variety 10 — parameter-conditional soundness. No property above puts ROBUST inside its claim. The parameter selects which build elaborates; every property states the same requirement in both. CURRICULUM-DERIVED from 31.1 §14: the test is whether the parameter feeds the bound or the claim, and here it feeds neither — it selects the design under test, which is what a paired build is for.
Variety 4 — the environment shares a constant. §11's property compares against truth, which is computed from the environment's cfg_ch_bit and not from CH_BIT_DOC. A property written against the documented constant would have been variety 4 and would also have forbidden the fix.
Variety 11 — evidence-grade escape — is NOT avoided, and cannot be. §12's item has no DV row. CURRICULUM-DERIVED from 32.1 §15: a property can prove a mechanism was consulted and cannot prove a commitment was priced correctly, because that correctness is a property of the market rather than of the design. §22 states it as this gate's residual risk.
16. Mutation Testing
Mutations are applied to the robust build, because a mutation run against a build that already fails proves nothing. CURRICULUM-DERIVED from this track's recorded practice: a mutation run needs a passing baseline or every mutation false-kills, and a survivor is often a design finding rather than a test gap.
Baseline: all sixteen assertions pass and all ten covers are non-zero on the robust build with the stimulus each item describes. Only then were mutations injected.
| # | Mutation | Killed by | Survived? |
|---|---|---|---|
| M1 | §5: set mask[O_ACT_RATE] unconditionally | p_obligation_count_complete does not fire — the count is still 13 | SURVIVES — and it is a design finding, see below |
| M2 | §6: change cand & urgent to cand | urgent | p_candidate_subset_of_legal, cycle 1 | killed |
| M3 | §6: change grant to pick before masking | p_grant_subset_of_legal | killed |
| M4 | §7: change if (commit) to if (commit || grant) | p_state_advances_only_on_commit | killed |
| M5 | §7: delete the truth update | p_model_matches_truth | killed |
| M6 | §8: change req_class == CL_PREF to != CL_DEMAND | p_never_shed_a_non_droppable_class on a writeback | killed |
| M7 | §8: tie shed low | p_sheds_under_pressure | killed |
| M8 | §9: change WORST_LEGIT + 1 to WORST_LEGIT | p_threshold_exceeds_legitimate_wait | killed |
| M9 | §9: widen AGE_W by one and raise the threshold past it | p_threshold_is_reachable | killed |
| M10 | §10: drop known_q[req_bank] from the cmd_act guard | p_no_activate_to_open_bank | killed |
| M11 | §11: replace cfg_ch_bit with CH_BIT_DOC | p_decode_follows_configuration only when they differ | killed, by one cover |
| M12 | §12: clear one COMMITTED bit instead of setting its derivation | p_every_commitment_has_a_derivation does not fire | SURVIVES |
DERIVED: ten of twelve mutations killed, two survived, and both survivors are design findings rather than test gaps.
M1's survivor is the obligation census's own weakness. Setting the bit unconditionally makes the count correct while the obligation remains unimplemented — so the census proves a list was written, not that a mechanism exists. That is the item's honest scope and §13's table says so: the census can close a question when it fails, and a pass means only that the list is complete. The mechanism check is 33.2's gate.
M12's survivor is variety 11 again. Clearing a COMMITTED bit makes the ledger consistent by denying that the decision is committed — and no property can detect a false claim about what silicon forecloses. CURRICULUM-DERIVED from 32.1 §15: the discharge is a human review of the ledger, not an assertion.
And M11 is the mutation worth dwelling on. It is killed only by the cover on cfg_ch_bit != CH_BIT_DOC. Without that cover the mutation survives a full regression, because a testbench holding the configuration at its documented value makes the mutated and unmutated builds identical. CURRICULUM-DERIVED from 32.1 §15: the coverage item must be on the configured value differing from the default, and this mutation is the mechanical proof of that requirement.
17. Baseline Defects Found Before Mutation
Three of the eight weak builds were found by reading rather than by running, and recording which is part of the review's honesty. CURRICULUM-DERIVED from 30.9 §3: lint and elaboration prove structural facts, and a structural fact should be proved by the cheapest tool that can prove it.
| Item | Found by | What was visible without running anything |
|---|---|---|
| §8 | reading the port list | req_class is declared and the weak build's shed expression does not mention it — the seventh instance of the declared-and-never-read tell in this curriculum |
| §11 | reading the port list | cfg_ch_bit declared, CH_BIT_DOC used — the same tell, and 32.1 §14 is the identical defect one module earlier |
| §9 | elaboration | the robust build's $fatal fires immediately when the threshold does not exceed the derived wait; no stimulus required |
| §5 | counting | eleven against thirteen, by hand, in under a minute |
| §12 | elaboration | the robust build's $fatal names the mask bit |
| §6 | running | the subset property needs a cycle on which an entry is urgent and illegal |
| §7 | running | the divergence needs a dropped grant |
| §10 | running | the unknown window needs an access before state is established |
DERIVED: five of eight items are findable without simulation — two by reading a port list, two by elaboration, one by counting. Three require stimulus, and all three require stimulus of a specific shape that a benign test does not produce.
That ratio is the argument for running this gate at all. An architecture review that produces five findings before a testbench exists has paid for itself, and the three that need stimulus become 33.4's coverage requirements rather than this gate's failures.
18. Silicon Observability
Every item's escape needs a post-tapeout observable, and this table is a design deliverable rather than a wish list. CURRICULUM-DERIVED from 30.10 §13, which owns the argument that a debug register's value is exactly the set of recovery actions it survives, and that its cost is measured in reproduction hours — or, at this gate, in silicon revisions.
| Item | Observable required | What it distinguishes |
|---|---|---|
| §5 | rolling-window occupancy; turnaround-cycle count | an unimplemented obligation from a workload that never provokes it |
| §6 | cycles with a non-empty legal mask and no commit; empty-mask cycles by binding rule | policy failing to choose from nothing being legal — 30.5 §13 |
| §7 | grants that did not commit | the grant/commit collapse, and a non-zero count contradicts a design claiming grants always commit |
| §8 | classes_present bit vector; per-class shed counts | an unlabelled interface from a working one, free on the first run |
| §9 | age histogram, not the maximum; urgent firing rate | a threshold too low (fires constantly) from one too high (never fires) |
| §10 | OUT_UNKNOWN counter | a report that is invalid from a system that is broken |
| §11 | the configured field position, read back | 32.1 §14's defect, in one register read |
| §12 | the counterfactual reporter of 32.4 §11 | which half of a joint commitment was binding |
Two rows are worth more than the others and for the same reason: they make a claim falsifiable.
§7's grants-that-did-not-commit counter contradicts a specification claim. An architecture asserting that grants always commit, with a non-zero counter, has an internal inconsistency visible in one number — and that is a stronger artifact than a passing test, because it does not depend on the stimulus having reached the case.
§10's unknown counter invalidates a report rather than describing a system. CURRICULUM-DERIVED from 30.2 §12: if the tracker is reporting unknown, every hit-rate number derived from it is suspect — so the counter's job is to tell you when to stop trusting the other counters.
19. Common Wrong Answers
“The architecture is sound — we reviewed it.” §2. “The architecture was reviewed” is bit 0. The review is the eight items, and three of them can close a question in minutes.
“The scheduler will not issue illegal commands.” Opening. That is a requirement with no named enforcement. What mechanism, and what happens on the cycle it is absent?
“All the timing obligations are in the block diagram.” §5. Eleven of thirteen are, because eleven are per-bank counters and fit a row of per-bank boxes. The rolling activate window and direction turnaround do not.
“The diagram shows legality and policy as separate blocks.” §6. Ask whether the policy block can read the timing state. If it can, the separation is a drawing convention — and 17.4 §3 calls deciding legality in the arbiter the inverse error, which is worse.
“Give the urgent request a high enough priority.” §6. A large enough weight outvotes legality. Legality is not a layer; it is the set the layers work inside.
“State updates when the command is selected.” §7. On the commit — 17.1 §7. A model updated on the grant diverges from the bus by exactly the grant-to-commit gap.
“Grants always commit in our design.” §7. Then ask what happens when refresh occupancy closes the gate: 17.3 §2 says normal commands are illegal during occupancy, not deprioritised.
“The interface carries a priority field, so we can distinguish requests.” §8. Priority is not droppability. Chapter 32.1 §3's two axes are independent — a prefetch and a writeback are identical on deadline and opposite on droppability.
“We can add class awareness later.” §8. It is an integration property. If this gate does not put it on the interface, no later gate recovers it — and a population cannot be inferred from a request's fields at all.
“Under pressure we apply backpressure.” §8. Chapter 17.5 §4 requires backpressure to have a cause. I could not tell which requests mattered is a cause, and it is an architecture finding.
“The age threshold is 256 — a sensible round number.” §9. Round numbers are not evidence of a wrong bound; they are evidence that nobody wrote the derivation. Here 256 is 42% of the worst legitimate wait.
“A bigger threshold is safer.” §9. Past the counter's width the comparison is unreachable and the mechanism is present in the source and absent in the silicon — 31.2 §7.
“The parameter table is complete — every cell has units.” §9. Units are not a derivation. The missing column is derived from.
“The bank state is open or closed — the device has two states.” §10. The device has two; the controller's belief has three. A diagram that models the device faithfully is why the third is omitted.
“After initialisation every bank is precharged, so closed is safe.” §10. Ask what enforces it, and what happens after a warm reset that resets the controller and not the device.
“Here is the address map.” §11, and 18.4 §5 owns the answer: often a category error, because the map is a function of configuration decided after the silicon was designed.
“It is documented, so we know the value.” §11. A documented mechanism tells you to read the configuration. And a mechanism you cannot read at runtime is operationally undocumented — 32.1 §6.
“The next-generation section covers what we are unsure about.” §12. A list of uncertainties is the opposite of a derivation, and the two are easy to confuse because both discuss the future.
“We will measure it in silicon and fix it next time.” §12. Only if the instrumentation exists. Chapter 32.4 §7: its absence guarantees the same bet is placed twice.
“All sixteen assertions pass.” §15, §16. On which build, and with which covers non-zero? M11 survives a full regression unless the configured value differs from the documented one.
“Mutation coverage is 100%.” §16. Ten of twelve killed. Both survivors are design findings — one shows the census proves a list rather than a mechanism, the other is variety 11 and no assertion can reach it.
20. Self-Check
-
State the review question this gate turns on, and say why it cannot be is this architecture correct.
-
Name the eight facets. Say which is hardest at this gate and why it is harder here than at the seven that follow.
-
Give the obligation count, its source, and the two obligations most often omitted — with the structural reason both are omitted together.
-
Explain why deciding legality inside the arbiter is worse than re-checking it there, citing the chapter that owns the distinction.
-
Compute §7's model error for a design in which 10% of grants are dropped and the average grant-to-commit gap is 6 cycles. State what the error means for legality.
-
Give §8's two axes and all four combinations, and explain why a priority field answers neither question.
-
Derive §9's worst legitimate wait from its five terms, then state both failure modes of a wrongly chosen threshold and which tool catches each.
-
Explain why the controller's bank-state belief needs three values when the device has two, and say how long the exposure window lasts.
-
For §11, explain why no data is corrupted and name the quantity that breaks, with the gap.
-
Explain why §12 has no how DV proves it row, name the variety that describes it, and say what discharges it instead.
-
From §14's table, identify the two structural gaps and the five stimulus-dependent ones, and state the benign operating point that hides each of the five.
-
Explain why M11 is killed only by a cover, and state the general rule that the mutation proves.
21. The Eight Gates, Composed
This is the first of eight, so it is the chapter that owes the reader the shape of the whole. The gates are not eight topics — they are eight different kinds of question, and each hands a specific artifact to the next.
| Gate | The kind of question it asks | What it hands forward |
|---|---|---|
| 33.1 this chapter | what mechanism enforces this claim? | the obligation list, the derived bounds, the configuration marking |
| 33.2 | what does this line do under every input? | the code that is, or is not, the specified mechanism |
| 33.3 | can this function be performed at all, and is its value read? | the boundary between what is digital and what is measured |
| 33.4 | what does this assertion actually prove? | the evidence that the first three gates' claims hold |
| 33.5 | which quantity is this, and what is its ceiling? | the numbers, with their rungs and denominators named |
| 33.6 | is this gate's pass criterion stated, and is evidence captured first? | a staged order whose every transition is interpretable |
| 33.7 | what would this observation eliminate, and what does it cost? | a discriminator ordering for when it fails anyway |
| 33.8 | recognised, recalled, or derived? | an audit of your own account of all seven |
Two compositions are worth naming because they are the ones that break when a gate is skipped.
This gate's obligation list is 33.2's input, and §16's M1 survivor is why. A complete list with an unimplemented obligation passes here and fails there — so skipping this gate does not merely defer the finding, it removes the list the next gate checks against, and an RTL review with no obligation list reviews the code against itself.
And this gate's derived bounds are 33.4's input. CURRICULUM-DERIVED from 30.9 §5 Q2: a progress property needs a justified bound, and the justification is produced here. A verification gate handed a chosen bound can write a property that passes or one that fails, and has no way to tell which is correct.
The gates also share one facet, and it is the eight-facet table's last row. Every gate's hardest question is what makes the broken version look correct — a reassuring document here, a reassuring waveform at 33.2, a clean training pass at 33.3, a green regression at 33.4, a good benchmark at 33.5, a passed stage gate at 33.6, a plausible signature at 33.7, and a fluent answer at 33.8. Eight gates, eight forms of reassuring evidence, and the module is organised around the fact that every one of them is trusted.
22. Two Findings Only This Gate Can Produce
Six of the eight items can be re-asked later. Two cannot, and knowing which is what makes the gate worth scheduling rather than merging into the next one.
§8's class awareness is irreversible. CURRICULUM-DERIVED from 32.1 §6, whether the upstream protocol carries a class code is an integration decision — and CURRICULUM-DERIVED from 32.3 §6, a requester population cannot be inferred from a request's fields, because two identical demand reads from different requesters differ in no field except the sender. So an interface frozen without the field forecloses every policy that depends on it, permanently. DERIVED from §8's measurement: the cost is 65 wrongly-shed requests per 100 under pressure, of which 20 are writebacks — and 32.1 §3 says those must never be discarded.
§12's commitment ledger has no later gate at all. It has no how DV proves it row, M12 survives mutation, and CURRICULUM-DERIVED from 32.1 §15 it is variety 11 — a residual risk outside the design's boundary that no stronger property reaches. CURRICULUM-DERIVED from 32.4 §3: on some platform classes almost nothing that matters remains adjustable, so the ledger is the only record of what was bet.
The other six items degrade gracefully and it is worth saying how, because a project that must skip this gate should know what it is buying:
| Item | Re-askable at | What is lost by deferring |
|---|---|---|
| §5 obligations | 33.2, by reading the code | the list the RTL gate checks against |
| §6 legality split | 33.2, as which block reads the timing state | the cheap version — after RTL it is a refactor |
| §7 commit point | 33.2, as what gates this update | little; the code makes it visible |
| §9 derived bounds | 33.5, from the timing budget | the elaboration guard, which is free here |
| §10 three-valued state | 33.2, from the encoding width | little |
| §11 configuration marking | 33.3 and 33.6 | the document's validity, which nobody revisits |
DERIVED: six of eight are recoverable, two are not, and the two that are not are the two with no code to inspect. That is the general shape of an architecture gate's value — it is worth most on exactly the questions that leave no artifact behind.
23. The Residual Risk
What clearing all eight items does not prove, stated because a gate claiming to prove everything proves nothing.
It does not prove the mechanisms exist in the RTL. §16's M1 survivor is the mechanical demonstration: a complete obligation list and an unimplemented obligation are indistinguishable at this gate. Chapter 33.2 is where that is settled, and this gate's output is the list that gate checks against.
It does not prove the bounds are achievable. §9 checks that a bound is derived and representable. Whether the design can meet it is a performance question — 33.5 — and whether it does is a bring-up question — 33.6.
It does not prove the commitments were priced correctly. §12's item has no DV row and M12 survives. CURRICULUM-DERIVED from 32.1 §15's variety 11: the residual risk has left the design's boundary, and no gate in this module can absorb it — its discharge is a written derivation reviewed by somebody who can price it.
And it does not prove the architecture is the right architecture. Every item here checks internal soundness: that claims have mechanisms, that boxes are separated, that bounds are derived. CURRICULUM-DERIVED from 32.5 §21's closing finding — all five platform classes' dominating constraints are properties of the requester rather than of the DRAM — so whether this architecture suits its workload is settled outside this gate, by measurements 32.1 through 32.5 specify.
24. Where This Goes
The first gate is conducted on intent, so every item asks for a mechanism. Count the obligation list against thirteen and expect the rolling window and the turnaround to be missing; require legality and policy in separate boxes with a filter rather than a hint between them; require exactly one commit point and every state update fed by it; require the requester class on the interface, because no later gate can recover it; require every bound to be derived and representable; require a third value for every belief about a device you cannot observe; mark every configuration outcome as configuration; and write down what the silicon forecloses, because that item has no DV answer and never will.
Three results carry forward. Five of the eight items are findable without simulation — two by reading a port list, two by elaboration, one by counting — so this gate pays for itself before a testbench exists. Five of the eight have a benign operating point at which the review would pass, which is 32.5 §15's module-level finding arriving at the architecture gate. And one item has no assertion that can reach it, which is variety 11 and is this gate's residual risk.
Chapter 33.2 takes the list this gate produced and asks whether the code is it. The question changes from what mechanism was specified to what does this line actually do, in every cycle, under every combination of its inputs — including the ones the testbench never drove — and the answer stops being a paragraph and becomes a line of code. The track has eighteen chapters carrying a documented defect of exactly that kind, each with its contract, its trace, and its why it survives; the next gate is those eighteen turned into questions a reviewer asks of code they did not write.
Continue learning
Related tutorials
- Related topic
RTL Review Checklist
Nine questions drawn from the eighteen documented defects this track already carries. Every finding is code that is legal, lint-clean, passes a nominal test and is wrong — and five of the nine are decided by reading a port list.
- Related topic
PHY Responsibilities
The controller decides which DDR operation should happen. The PHY makes it real at a pin boundary whose timing the controller cannot meet — and the line between them is not the same in any two implementations.
- Related topic
UVM Architecture for DDR
Three interfaces that are not variations of each other. They share no clock, no transaction identity, and no notion of what a failure is — and the cross-bank obligations finally need a component.
- Related topic
PHY Review Checklist
A PHY's correctness lives in registers whose contents were measured rather than written, so every item is a question about provenance: what measured this, against what, when, and what happens when that measurement stops being true.
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.
