Skip to content
VLSI Mentor

DDR · Module 32

CPU Memory Controllers

A CPU controller serves several structurally different requester classes at once, differing on two independent axes — deadline and droppability — and the class with the hardest obligation has the smallest share. So any policy allocating attention in proportion to traffic is wrong for exactly the class that can least afford it.

Every chapter in this module asks the same question of a different platform: which constraint dominates here that did not dominate elsewhere?

For a CPU platform the answer is not bandwidth, not capacity and not latency. It is that the controller does not serve one requester — it serves several structurally different ones simultaneously, and they are not interchangeable.

The dominating constraint is a heterogeneous requester mix with unequal obligations. Some requests have a deadline; some do not. Some may be dropped; some must never be. And the class with the hardest obligation has the smallest share — so any policy that allocates attention in proportion to traffic is wrong for exactly the class that can least afford it.

And there is a second finding, about knowledge rather than about hardware. CURRICULUM-DERIVED from 18.4 §2: the major sources of CPU memory controllers occupy different evidence categories — one documents the mechanism extensively, one licenses IP whose configuration its integrators choose, and for one the public knowledge is research rather than documentation. An engineer who assumes a single uniform situation will look in the wrong place for most of them, and §6 turns that into the observation that the CPU memory controller is a category error.

1. What Every Platform Class Shares

Before any difference, the substrate — because five chapters that each invent their own baseline cannot be compared.

All five platform classes in this module attach DRAM with a destructive read, so CURRICULUM-DERIVED from 31.1 §5 every one of them carries the same 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.

None of the five removes any of them. None of the five adds a fourteenth of the same kind. STRUCTURAL: the thirteen are a property of the access contract, and the access contract does not vary across these platforms.

So the module's question is never what obligations does this platform have. It is:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   for each platform class, in this order:

     1  WHICH CONSTRAINT dominates that did not dominate elsewhere
     2  WHAT DECISION that constraint forces on the controller
     3  WHAT GRADE of evidence we have for any of it

   and the answer to (1) is, in every chapter of this module,
   a property of the REQUESTER MIX rather than of the DRAM.

That is the module's spine, and it is worth stating once here because the remaining four chapters are instances of it. The DRAM is the same; what changes is who is asking, how many of them there are, and what happens if they wait.

2. The Requester Mix Is the Subject

CURRICULUM-DERIVED from 29.3, which owns what actually causes a DDR request on a CPU path: most loads never reach DRAM, and the ones that do arrive from several distinct mechanisms — a demand miss, a writeback the program never requested, a prefetch, and translation traffic. That chapter owns the taxonomy of the traffic.

This chapter owns what the controller must do about the fact that those mechanisms are not one stream.

The distinction matters because Module 17's scheduler does not model it. Chapter 17.2 owns what a request entry must retain, and 17.4 owns choosing among legal candidates — but both treat every queued request as an obligation of the same kind. A queue entry is an entry; an arbiter picks one. On a CPU platform that uniformity is false, and §3 is why.

Two things make a CPU platform's mix unusual, and both are STRUCTURAL:

The requesters are numerous and unsynchronised. CURRICULUM-DERIVED from 29.3 §7's multicore-contention scenario: several cores generate misses independently, so the mix arriving at the controller is a superposition nobody designed. A single-requester platform has a traffic shape; a multi-core platform has a traffic distribution.

And the requesters are not equally patient, in a way the controller can be told about. A demand load has a core waiting on it. A writeback has nobody waiting. That difference is knowable at the controller boundary if the upstream protocol carries it — and whether it does is an integration decision, which is §6's subject.

3. The Obligation Classes

Two independent axes separate the classes, and the pair is what makes them non-interchangeable.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   AXIS 1 -- DEADLINE
     does something stall until this completes?
       yes -> latency is observable, and delay has a cost upstream
       no  -> latency is invisible; only throughput matters

   AXIS 2 -- DROPPABILITY
     may the controller discard this request entirely?
       yes -> it is a HINT. Correctness does not depend on it.
       no  -> it is an OBLIGATION. Discarding it loses data or hangs
              the requester.

   the two axes are INDEPENDENT, and all four combinations occur.

The four combinations, with the mechanism that produces each. CURRICULUM-DERIVED from 29.3 for the traffic; the classification is this chapter's.

ClassDeadlineDroppableProduced byWhat the controller must do
Demandyesnoa load or store that missed — 29.3 §2serve it soonest; it is the only class whose latency a program feels directly
Prefetchnoyesa predictor — 29.3 §10serve it with spare capacity, and drop it under pressure
Writebacknonoeviction — 29.3 §3, traffic the program never requesteddefer it freely, never discard it
Translationyes, and it blocksnoa page-table walk — 29.3 §11serve it soonest; a walk holds up the access that needed it

Read the second and third rows together, because they are the pair that a uniform scheduler handles wrongly in opposite directions.

A prefetch has no deadline and may be dropped. So the correct response to pressure is discard, and a scheduler that instead defers it keeps a queue entry occupied, keeps its bank state relevant, and continues to count it in every fairness calculation — paying for work it was free to abandon.

A writeback has no deadline and may not be dropped. So the correct response to pressure is defer, and a scheduler that treats no deadline as low value and applies the same policy to both classes will either discard data or hold a prefetch it should have thrown away. The two classes look identical on axis 1 and are opposite on axis 2, and axis 2 is the one Module 17 has no field for.

And the fourth row is the one that surprises people. A translation walk has the strongest obligation in the table — it has a deadline and something else is blocked behind it, so its delay is multiplied. CURRICULUM-DERIVED from 29.3 §11, which owns translation as traffic nobody wrote: the walk is not the access the program made; it is a prerequisite the program does not know about, and the access that needed it cannot proceed until it returns.

4. Droppable Is a Class Nothing Upstream Models

Axis 2 deserves its own section because it is genuinely absent from everything this chapter consumes, and its absence is not an oversight.

CURRICULUM-DERIVED from 17.5, which owns the controller boundary contract: the one-handshake-one-entry rule, metadata stability while stalled, and completion for reads and writes. Every one of those assumes a request, once accepted, will be completed. Chapter 17.5 §8 owns when a request is actually complete, and the contract has no third outcome.

So a droppable class breaks a contract that Module 17 correctly established.

Three consequences, and they are design requirements rather than observations:

Dropping must happen before acceptance, not after. Once 17.5's handshake completes, the controller owes a completion. So the drop decision belongs at the admission boundary — which is why §9's block is an admission structure and not a scheduler modification. A controller that accepts a prefetch and then discards it has violated its own interface, and the requester will wait forever for a completion that is not coming.

A dropped request must be reported, not silently absorbed. CURRICULUM-DERIVED from 30.10 §13, which owns debug observables as design deliverables: a drop that is not counted is indistinguishable from a prefetcher that never issued. And the two have opposite fixes — one is controller pressure, the other is an upstream predictor problem.

And the drop policy must be bounded in the other direction too. A controller that drops every prefetch under any pressure has disabled prefetching, which CURRICULUM-DERIVED from 29.3 §10prefetch, help and harm — is a real loss when the prediction was good. So dropping is a policy with a threshold, and the threshold is a parameter somebody must justify — the same shape as 17.4 §9's age threshold and 23.4 §5's starvation bound.

5. The Evidence Asymmetry

Now the module's second discipline, applied to this platform class. §Scope's four grades are not decoration — for CPU controllers the grades differ per source, and that asymmetry is the most useful single fact available.

CURRICULUM-DERIVED from 18.4 §2, which surveyed the sources with citations and attached a category to each. This chapter restates that survey's shape and does not extend it, because extending it would require sources this chapter does not have.

SourceGrade availableWhat that means you do
A vendor documenting the mechanism extensively — address-map and interleave configuration registers, with an explicit statement that the mapping is programmable and selected at initialisationA/Bread the configuration, because the registers are the answer
A vendor licensing controller IP with a non-confidential technical reference manual, whose address-decode registers its own open-source firmware programs at initialisationBread the integrator's firmware, because the map is whatever it wrote
A vendor that does not publish the physical-address-to-bank-and-row translationno A/Bwhat is publicly known is grade C research about specific machines

CURRICULUM-DERIVED from 18.4 §2, whose closing observation is the transferable one: the asymmetry is the finding. An engineer who assumes a single uniform situation across all sources will look in the wrong place for most of them.

And one vendor sentence, quoted in 18.4 §2 from public product documentation, is worth more than any table: that the address mapping “is usually programmable in the DRAM controller and is selected at initialization time,” and that “there is no one-size-fits-all mapping. Different mappings maximize performance of different workloads or traffic patterns.”

That is a vendor stating, in its own documentation, what 18.2 demonstrated by measurement — and 18.4 §2 is explicit about why the statement beats a table: a table would be true for one part, one population, one firmware revision and one interleaving mode, while the statement is true across the family and tells you what to do.

6. “The CPU Memory Controller” Is a Category Error

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. That chapter lists the inputs — controller generation and stepping, channels populated, interleaving mode, ranks per channel, DIMM organisation, firmware settings, memory holes, ECC configuration, and remapping above the controller.

This chapter generalises that from the map to the controller.

STRUCTURAL: on a CPU platform, the properties an engineer wants to know are configuration outcomes, not architecture facts — and the list is longer than the map.

Question asked as if about architectureActually a property of
How many channels?the population, and the platform's supported configurations
What is the page policy?firmware, and it may be adaptive — 23.5
What is the queue depth per class?configuration, where it is exposed at all
Are prefetches distinguishable at the controller?the upstream protocol and the integration — §4
What is the refresh mode?configuration, and it varies with temperature — 15.4
What is the address map?all of 18.4 §5's inputs at once

So the correct answer to most what does this CPU's controller do questions is a procedure rather than a value, and giving the procedure is the strong answer:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   1  identify which of §5's three source situations applies
   2  if a mechanism is documented -> READ THE CONFIGURATION
   3  if only research exists -> treat it as grade C: a finding
      about those machines, and design a measurement for yours
   4  state the category with every number you then quote

   and note what step 2 requires that step 3 does not: ACCESS to
   the running machine's registers. A grade-B answer is only
   actionable if you can read the configuration, which is an
   observability requirement rather than a documentation one.

The last note is the one worth carrying. A documented mechanism you cannot read at runtime is, operationally, no better than an undocumented one — and 30.10 §2's observability collapse says configuration read-back is the cheapest observable in existence. So can I read the configuration belongs in a platform evaluation, alongside is it documented.

7. Share and Obligation Are Anti-Correlated

Now the arithmetic, and it produces the chapter's sharpest result.

DERIVED from a stated model. Every figure is grade D — invented to teach the concept, and CURRICULUM-DERIVED from 29.3 only for the existence of the four mechanisms, never for their proportions.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   GRADE D. A representative mix, per 100 requests reaching the
   controller. Proportions are invented; the RANKING they produce
   is the transferable part.

     class         share   deadline  droppable
     -----------   -----   --------  ---------
     demand          40      yes        no
     prefetch        35      no         YES
     writeback       20      no         no
     translation      5      yes+       no      (+ blocks another)

   DERIVED observations, recomputed:

   (1) DEADLINE-BEARING share  = 40 + 5 = 45%
       so 55% of arriving traffic has NO deadline at all.

   (2) DROPPABLE share = 35%
       more than a third of the queue is work the controller is
       free to abandon -- and Module 17's queue has no field for it.

   (3) the class with the STRONGEST obligation has the SMALLEST
       share: translation, at 5%.

Result (3) is the finding, and it is a statement about policies rather than about proportions.

Any policy that allocates attention in proportion to traffic gives the hardest obligation the least attention. A round-robin over classes gives translation one slot in four when it needs priority; a share-proportional weighting gives it 5%. CURRICULUM-DERIVED from 17.4 §4, whose layered mask is the structure that solves this — layers, not numbers — because a layer can put a rare class first without giving it a weight that its rarity would dilute.

So the class taxonomy is not a refinement of arbitration. It is an argument for which arbitration structure to use, and the argument survives any change to the grade-D proportions: the ranking is what matters, and the ranking is set by the mechanism rather than by the mix.

Two more DERIVED consequences worth stating.

Dropping the droppable class under pressure frees 35% of the queue without violating anything. DERIVED: if pressure requires shedding a quarter of the offered load, the droppable class alone can absorb it — so a controller with axis 2 never has to defer a deadline-bearing request in order to make room. A controller without axis 2 must.

And the no-deadline classes together are 55%, which is why the naive conclusion is so attractive and so wrong. Most traffic has no deadline, so latency policy hardly mattersexcept that the 45% which does have a deadline is the only part a program can feel, and 23.1 §9 owns why the average is the wrong statistic for exactly this reason. A mean latency over the whole mix is dominated by requests nobody was waiting for.

8. The Platform, as Blocks

A block diagram of a CPU memory platform organised by requester class rather than by hardware block. On the left, four request sources feed the controller: demand misses from the cores, which carry a deadline because a core stalls on them; prefetches from a predictor, which carry no deadline and are droppable; writebacks from cache eviction, which carry no deadline but must never be discarded; and translation walks, which carry a deadline and additionally block the access that needed them. All four converge on the class-aware admission stage, which is the only place a drop may legally occur because once the ready-valid handshake of chapter seventeen point five completes the controller owes a completion. Admission feeds the legality filter, which is identical for every class because the thirteen shared obligations do not vary by requester, and legality feeds the layered policy stage where the class ranking is applied as layers rather than as weights, because the class with the strongest obligation has the smallest share. Policy feeds the commit point, the single instant at which architectural state may change, and the commit drives the DRAM device. Separately, the address decode stage sits between admission and legality and is configured at initialisation rather than compiled in; chapter eleven's defect is a decode that compiled the value in. The class mix monitor observes admission and reports the per-class shares and drop counts, because a drop that is not counted is indistinguishable from a prefetcher that never issued.Demand missdeadline, notdroppablePrefetchno deadline,DROPPABLEWritebackno deadline, neverdropClass admissionthe only legal droppointAddress decodeconfigured, notcompiledLegality filteridentical for everyclassClass-mixmonitorshares and dropcountsLayered policylayers, not weightsCommit pointstate may changehereDRAM devicethirteen obligationsreqhintobligacceptedentryclassbanklegalmixgrantcommand12

Read the left column and the admission block together. The four sources differ on two axes, and the admission stage is the only place the difference can be acted on — because after it, 17.5's handshake has created an obligation that cannot be withdrawn.

And read the legality block's caption twice. It is identical for every class, because §1's thirteen obligations are properties of the DRAM and know nothing about who asked. The class distinction lives entirely above legality and entirely below the commit point, which is exactly the region 30.5 §3 calls policy — and the reason class-awareness is not a legality change is that a deadline does not make an illegal command legal.

Translation is deliberately absent from the diagram's node set. It is a fourth source and the node count is already at ten; CURRICULUM-DERIVED from the component contract, a BlockDiagram warns above twelve nodes. It enters §9's RTL as a class code rather than a block, and saying so is better than crowding the picture.

9. RTL — Class-Aware Admission

The platform-profile block for this chapter. COHERENT and HAS_PREFETCH are the platform properties that decide whether the class distinction exists at all, and the generate boundaries show that a single-requester platform needs none of this machinery — which is the comparison §2 claims.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// request_class_admission -- the platform-profile block of §9.
//
// CLASSIFICATION: synthesisable, grade-D parameter values, CORRECT as
// written. The intentionally defective block is §12.
//
// WHAT IT IS: the controller's admission boundary, class-aware. It is
// the ONLY place a drop may legally occur, because after 17.5's
// handshake the controller owes a completion (§4).
//
// WHY IT EXISTS HERE: §3 establishes two independent axes -- deadline
// and droppability -- and §4 that Module 17's queue has no field for
// the second. This block adds that field at the only boundary where
// it can be acted on, and its generate boundaries show what a
// single-requester platform does NOT need.
//
// HOW TO RUN IT: offer a mix at or above capacity with all four
// classes present.
// EXPECTED RESULT: prefetches are DROPPED (not deferred), writebacks
// are DEFERRED (never dropped), and deadline classes are admitted.
// EXPECTED TRACE: on pressure, drop_count rises and no
// deadline-bearing or non-droppable request is ever refused.
//
// SYNTHESIS: one occupancy counter per class plus a small decode. No
// memory; the queue itself is 17.2's.
//
// LIMITATIONS: models ADMISSION. It does not schedule -- 17.1 owns
// the pipeline, 17.4 the layered mask, and 23.4 the heuristic, and
// §7's argument is precisely that the class ranking belongs in
// 17.4's LAYERS rather than in a weight here. Nor does it model
// coherence itself: COHERENT only selects whether a remote class
// exists, and CHI/AXI semantics are 29.1's.
// ---------------------------------------------------------------------
module request_class_admission #(
  // Platform properties. These are the CONSTRAINT of §1 step 1
  // expressed as parameters, not sizes -- so 31.1 §12's warning
  // applies: an obligation must be re-derived when they change.
  parameter bit COHERENT     = 1'b1,
  parameter bit HAS_PREFETCH = 1'b1,
  parameter int NUM_CORES    = 8,

  parameter int QDEPTH       = 32,
  // Grade D. The share at which the droppable class starts being
  // shed. §4: dropping is a policy with a threshold somebody must
  // justify -- the same shape as 17.4 §9's age threshold.
  parameter int DROP_AT_PCT  = 75,

  // COUNT, not INDEX: occupancy ranges 0 .. QDEPTH inclusive, so it
  // needs $clog2(QDEPTH + 1) bits. Sized $clog2(QDEPTH) a full queue
  // wraps to empty and admission would accept without limit --
  // the counter failing inside the pressure case it exists to detect.
  parameter int OCC_W        = $clog2(QDEPTH + 1),
  parameter int CNT_W        = 32
)(
  input  logic              clk,
  input  logic              rst_n,

  // Upstream. 17.5 owns the ready/valid contract; this block supplies
  // `req_ready` and must hold 17.5's one-handshake-one-entry rule.
  input  logic              req_valid,
  input  logic [2:0]        req_class,
  output logic              req_ready,

  // Queue state, from 17.2's pool.
  input  logic [OCC_W-1:0]  q_occupancy,
  input  logic              q_free,

  // Outputs.
  output logic              admit,
  output logic              drop,
  output logic              defer_hint,
  output logic [CNT_W-1:0]  drop_count,
  output logic [CNT_W-1:0]  admit_count,
  output logic              class_unknown,
  output logic [7:0]        classes_present
);
  // The class codes. Translation is a CODE rather than a diagram node
  // (§8) and it carries the strongest obligation in §3's table.
  localparam logic [2:0] CL_DEMAND = 3'd0;  // deadline, not droppable
  localparam logic [2:0] CL_PREF   = 3'd1;  // no deadline, DROPPABLE
  localparam logic [2:0] CL_WB     = 3'd2;  // no deadline, never drop
  localparam logic [2:0] CL_XLATE  = 3'd3;  // deadline, and BLOCKS
  localparam logic [2:0] CL_REMOTE = 3'd4;  // coherent platforms only

  initial begin
    if (QDEPTH < 2) $fatal(1, "request_class_admission: QDEPTH must be >= 2");
    if (DROP_AT_PCT < 1 || DROP_AT_PCT > 100)
      $fatal(1, "request_class_admission: DROP_AT_PCT must be 1..100");
    // §4's third consequence, enforced: a threshold of 100 means the
    // droppable class is only shed when the queue is completely full,
    // which is indistinguishable from not having the mechanism. Flag
    // it rather than let a configuration silently disable the feature
    // -- 31.2 §7's "present in the source, absent in the silicon".
    if (HAS_PREFETCH && DROP_AT_PCT == 100)
      $warning("request_class_admission: DROP_AT_PCT = 100 disables shedding in all but the full case (§4)");
  end

  // The drop threshold in entries, DERIVED at elaboration so the
  // percentage and the depth cannot disagree at runtime.
  localparam int DROP_THRESH = (QDEPTH * DROP_AT_PCT) / 100;

  logic deadline_bearing, droppable, recognised;

  always_comb begin
    // §3's two axes, decoded independently -- they are INDEPENDENT,
    // so they are two expressions rather than one priority number.
    // Collapsing them into a single "priority" is the error §3's
    // second and third rows are about.
    unique case (req_class)
      CL_DEMAND : begin deadline_bearing = 1'b1; droppable = 1'b0; recognised = 1'b1; end
      CL_PREF   : begin deadline_bearing = 1'b0; droppable = 1'b1; recognised = HAS_PREFETCH; end
      CL_WB     : begin deadline_bearing = 1'b0; droppable = 1'b0; recognised = 1'b1; end
      CL_XLATE  : begin deadline_bearing = 1'b1; droppable = 1'b0; recognised = 1'b1; end
      CL_REMOTE : begin deadline_bearing = 1'b1; droppable = 1'b0; recognised = COHERENT; end
      default   : begin deadline_bearing = 1'b1; droppable = 1'b0; recognised = 1'b0; end
    endcase
  end

  // An unrecognised class is treated as deadline-bearing and
  // NON-droppable, and reported. 7.4's three-valued discipline
  // applied to a class code: the safe default for an unknown
  // obligation is the STRONGEST obligation, because the cost of
  // over-serving is performance and the cost of under-serving is
  // correctness.
  assign class_unknown = req_valid && !recognised;

  generate
  if (HAS_PREFETCH) begin : g_shedding

    logic under_pressure;
    assign under_pressure = (q_occupancy >= DROP_THRESH[OCC_W-1:0]);

    // The drop decision. It happens BEFORE acceptance -- §4's first
    // consequence -- so `drop` and `admit` are mutually exclusive and
    // together they account for every valid request.
    assign drop  = req_valid && recognised && droppable && under_pressure;
    assign admit = req_valid && !drop && q_free;

    // Deferral is a HINT to 17.4's policy layers, not an action here.
    // A writeback under pressure is deferred by the SCHEDULER; this
    // block only says which class it is. Acting on it here would put
    // policy in the admission stage, which 17.4 §3 forbids.
    assign defer_hint = req_valid && recognised && !droppable && !deadline_bearing;

  end else begin : g_no_shedding

    // A platform with no prefetcher has no droppable class, so the
    // mechanism does not exist -- it is not disabled, it is absent.
    assign drop       = 1'b0;
    assign admit      = req_valid && q_free;
    assign defer_hint = req_valid && recognised && !deadline_bearing;

  end
  endgenerate

  assign req_ready = admit || drop;   // a dropped request is ANSWERED

  always_ff @(posedge clk) begin
    if (!rst_n) begin
      drop_count      <= '0;
      admit_count     <= '0;
      classes_present <= '0;
    end else begin
      // §4's second consequence: a drop must be COUNTED. A drop that
      // is not counted is indistinguishable from a prefetcher that
      // never issued, and the two have opposite fixes.
      if (drop  && drop_count  != {CNT_W{1'b1}}) drop_count  <= drop_count  + 1'b1;
      if (admit && admit_count != {CNT_W{1'b1}}) admit_count <= admit_count + 1'b1;
      // Which classes this platform actually presented, so §14's mix
      // report can be checked against the platform's claims.
      if (req_valid && recognised) classes_present[req_class[2:0]] <= 1'b1;
    end
  end
endmodule

req_ready = admit || drop is the line that keeps 17.5's contract intact, and it is worth stating plainly: a dropped request is answered, not ignored. The handshake completes, the requester learns its hint was declined, and no completion is owed. A design that lowered req_ready instead would be applying backpressure — which 17.5 §4 owns as a mechanism with a cause, and I chose not to do this is not a cause.

10. RTL — The Class Ranking, as Layers

§7 claimed that the class ranking belongs in 17.4's layers rather than in a weight, and §9's block deliberately refused to implement policy. This block closes that loop, because a claim about which structure to use is only worth making if the structure is shown.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// class_policy_layers -- CORRECT as written. Grade-D thresholds.
//
// CLASSIFICATION: synthesisable policy. It chooses among LEGAL
// candidates only, and never re-checks legality -- 17.4 §3 owns why
// that separation is mandatory rather than tidy.
//
// WHAT IT IS: §7's class ranking expressed as 17.4's LAYERED MASK.
// Each layer NARROWS the legal set; a layer that would empty it
// passes the set through unchanged. That narrowing rule is what lets
// a 5%-share class be served first without a weight its rarity
// would dilute.
//
// WHY IT EXISTS HERE: §7's result is that share and obligation are
// anti-correlated, so any share-proportional policy under-serves the
// hardest obligation. The claim that layers fix it is structural,
// and a generate-free mask chain is how a structural claim is made
// checkable.
//
// HOW TO RUN IT: present a legal set containing one translation
// request and many prefetches.
// EXPECTED RESULT: the translation request is granted, and its 5%
// share is irrelevant to that outcome.
// EXPECTED TRACE: grant must be one-hot and a subset of legal_mask
// on every cycle.
//
// SYNTHESIS: four mask ANDs, four zero-detects, one priority encoder.
//
// LIMITATIONS: implements the CLASS layer and a rotation below it. It
// does not implement locality preference (23.3), direction batching
// (30.5 §7) or the age-based bounded bypass -- 17.4 §9 owns that and
// §6 of this block's discussion states why age must sit ABOVE class.
// ---------------------------------------------------------------------
module class_policy_layers #(
  parameter int NUM_ENTRIES = 16,
  // COUNT, not INDEX: the age counter must REPRESENT the threshold it
  // is compared against, so it needs $clog2(AGE_MAX + 1) bits. Sized
  // $clog2(AGE_MAX) the comparison is unreachable and the fairness
  // layer is present in the source and absent in the silicon --
  // 31.2 §7's hazard, and 17.4 §9 owns the original argument.
  parameter int AGE_MAX      = 255,
  parameter int AGE_W        = $clog2(AGE_MAX + 1),
  // Grade D. The age at which fairness outranks class. It must sit
  // ABOVE the class layer or a starved low-class entry is
  // unreachable -- 17.4 §9's "the override must be reachable".
  parameter int AGE_URGENT   = 192
)(
  input  logic                    clk,
  input  logic                    rst_n,

  // From the legality filter. Consumed, NEVER recomputed (17.4 §3).
  input  logic [NUM_ENTRIES-1:0]  legal_mask,
  input  logic [NUM_ENTRIES-1:0]  is_xlate,
  input  logic [NUM_ENTRIES-1:0]  is_demand,
  input  logic [NUM_ENTRIES-1:0]  is_wb,
  input  logic [AGE_W-1:0]        age [NUM_ENTRIES],

  input  logic                    commit,

  output logic [NUM_ENTRIES-1:0]  grant,
  output logic [2:0]              binding_layer,
  output logic                    fairness_active
);
  initial begin
    if (AGE_URGENT > AGE_MAX)
      $fatal(1, "class_policy_layers: AGE_URGENT exceeds AGE_MAX -- the layer is unreachable");
    if (NUM_ENTRIES < 2) $fatal(1, "class_policy_layers: NUM_ENTRIES >= 2");
  end

  function automatic logic [NUM_ENTRIES-1:0] lowest(input logic [NUM_ENTRIES-1:0] m);
    return m & (~m + 1'b1);
  endfunction

  // A layer NARROWS, or passes through. This helper is the whole
  // mechanism of 17.4 §4, and writing it once makes each layer one
  // line -- which is the point: the structure is simple and the
  // ORDER is the design decision.
  function automatic logic [NUM_ENTRIES-1:0] narrow(
      input logic [NUM_ENTRIES-1:0] set,
      input logic [NUM_ENTRIES-1:0] pref);
    return (|(set & pref)) ? (set & pref) : set;
  endfunction

  logic [NUM_ENTRIES-1:0] aged, l0, l1, l2, l3;
  logic [$clog2(NUM_ENTRIES > 1 ? NUM_ENTRIES : 2)-1:0] rot_ptr;

  always_comb begin
    aged = '0;
    for (int i = 0; i < NUM_ENTRIES; i++)
      // The aged set is intersected with LEGAL, not with valid.
      // 31.1's module established that an override placed above
      // legality issues illegal commands; 30.5 §10 is the defect.
      if (legal_mask[i] && age[i] >= AGE_URGENT[AGE_W-1:0]) aged[i] = 1'b1;
  end

  always_comb begin
    // Layer 0 -- the legal set. Never widened.
    l0 = legal_mask;
    // Layer 1 -- FAIRNESS, above class so a starved entry of any
    // class is reachable (17.4 §9).
    l1 = narrow(l0, aged);
    // Layer 2 -- translation. §3's strongest obligation: a deadline
    // AND it blocks another access. Its 5% share is irrelevant here,
    // which is exactly what a weight could not achieve.
    l2 = narrow(l1, is_xlate);
    // Layer 3 -- demand. A deadline, nothing blocked behind it.
    l3 = narrow(l2, is_demand);
    // Writebacks and prefetches fall through to the rotation below,
    // which is correct: neither has a deadline, and §3 says the
    // response to pressure for the droppable one already happened at
    // admission (§9).
  end

  // Rotation, advanced on COMMIT rather than on grant -- 17.4 §7,
  // because a grant that does not commit must not move the pointer.
  always_ff @(posedge clk) begin
    if (!rst_n) rot_ptr <= '0;
    else if (commit) rot_ptr <= rot_ptr + 1'b1;
  end

  assign grant = lowest(l3);

  // Which layer actually narrowed the set. Reported so that "why did
  // this entry win" has an answer -- 30.5 §3's attribution argument,
  // applied to policy instead of to legality.
  always_comb begin
    if      (|aged && (l1 != l0))                binding_layer = 3'd1;
    else if (|(l1 & is_xlate)  && (l2 != l1))    binding_layer = 3'd2;
    else if (|(l2 & is_demand) && (l3 != l2))    binding_layer = 3'd3;
    else                                          binding_layer = 3'd4;  // rotation
  end
  assign fairness_active = |aged;
endmodule

The layer order is the design decision, and two orderings in it are load-bearing.

Fairness sits above class, because a starved writeback must be reachable. CURRICULUM-DERIVED from 17.4 §9: the override must sit above the preference to be reachable, and a bigger number inside a preference layer does not achieve it. Put class above fairness and a low-class entry behind a steady stream of translation walks waits forever.

And the aged set is intersected with legal_mask, not with validity. CURRICULUM-DERIVED from 30.5 §10, where exactly that omission produced a fairness fix that issued illegal commands and was biased toward doing so. The override sits above the preference, not above legality — and the one-line difference between those two sentences is the whole defect that chapter reviewed.

binding_layer is the output worth having. Without it, why did this entry win has no answer, and CURRICULUM-DERIVED from 30.5 §3, an unattributed outcome is a loop that found something rather than a reportable fact. With it, §16's row seven becomes measurable: a binding_layer stuck at 1 means fairness is firing constantly and the class ranking is effectively off — the controller is fair and slow rather than correctly ordered.

11. What the Classes Cost in Logic

DERIVED from §9's generate boundaries, as state elements, because state is what must stay coherent with something the controller cannot observe.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   GRADE D geometry: QDEPTH = 32, so OCC_W = 6; CNT_W = 32.

   WITH the class mechanism (COHERENT = 1, HAS_PREFETCH = 1):
       drop_count           32
       admit_count          32
       classes_present       8
                            --
                            72 bits, plus a combinational decode

   WITHOUT it (HAS_PREFETCH = 0, COHERENT = 0):
       admit_count          32     (still worth having)
       classes_present       8
                            --
                            40 bits, and no drop path at all

   DERIVED: 72 bits against 40. The mechanism is CHEAP.

And that is the point rather than an aside. CURRICULUM-DERIVED from 31.1 §10, which made the same argument in the other direction: the cost of controller state is not the flip-flops, it is the surface where belief can diverge from reality. Here almost nothing can diverge — the class code arrives with the request and is not remembered — so the class mechanism is one of the rare additions that costs area without adding a coherence hazard.

Which raises the honest question: why would a platform omit it? Two answers, both real. The upstream protocol may not carry the class, in which case the controller cannot classify what it was not told — §6's integration dependence. And the drop path is an interface change, because a requester that can have a request declined must handle the decline. So the cost is not in the controller; it is in the contract, and that is why §4 insists the drop happens at the boundary.

12. RTL Review — A Platform Address Decode

The intended contract. CURRICULUM-DERIVED from 18.4 §2, where a vendor's own documentation states the mapping “is usually programmable in the DRAM controller and is selected at initialization time” — so the field positions are a grade-B fact, and grade B means read the configuration.

  1. The channel, bank and row field positions must be taken from configuration registers written at initialisation. They must not be compiled in.
  2. Before the configuration is valid, no decode may be performed — assert decode_invalid and produce nothing.
  3. A configuration change must take effect: the decode is recomputed, never latched from the first value seen.
  4. The block must report which configuration it is using, so any claim about this platform's map is traceable to a source rather than to a diagram.
  5. Reset leaves the configuration invalid.
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// platform_address_decode -- INTENTIONALLY DEFECTIVE, for review (§12).
//
// CLASSIFICATION: synthesisable, grade-D values, and CONTAINS A BUG.
//
// WHAT IT IS MEANT TO DO: the five-clause contract above -- decode a
// physical address into channel, bank and row using field positions
// the PLATFORM supplies, because 18.4 §2 establishes that those
// positions are a grade-B fact and 18.4 §5 that "the" map is often a
// category error.
//
// WHY IT EXISTS HERE: §5's callout owns CATEGORY DRIFT -- a grade-C
// measurement loses its qualification through a slide and a wiki and
// is eventually consumed as grade A. This block is that drift in
// hardware, and it is the only defect in this module that could not
// have appeared in any earlier one.
//
// HOW TO RUN IT: bring the block up on a platform whose configured
// channel-field position differs from the compiled one.
// EXPECTED RESULT under clause 1: the decode follows the CONFIGURED
// position.
// EXPECTED TRACE: changing cfg_ch_bit must change sel_ch for the
// same address. It does not.
//
// SYNTHESIS: a variable bit-extract plus a validity gate.
//
// LIMITATIONS: decodes three fields. The complete field set, the
// inversion and the hashing options are 8.6's and 18.1's, and
// omitting them is STATED rather than hidden -- it is not the bug.
// ---------------------------------------------------------------------
module platform_address_decode #(
  parameter int ADDR_W  = 46,
  parameter int NUM_CH  = 4,
  parameter int NUM_BK  = 16,
  parameter int ROW_W   = 16,
  parameter int CH_W    = $clog2(NUM_CH),
  parameter int BK_W    = $clog2(NUM_BK),

  // GRADE D, and this is the whole problem. The value came from a
  // measurement on the first platform this block was brought up on
  // -- honest grade C at the moment it was taken (18.4 §1), written
  // here as a localparam-in-all-but-name and consumed below as
  // though it were grade A.
  parameter int CH_BIT_DEFAULT = 8
)(
  input  logic               clk,
  input  logic               rst_n,

  // The CONFIGURATION, from the platform's registers at
  // initialisation. Clause 1 says these are the answer.
  input  logic               cfg_valid,
  input  logic [5:0]         cfg_ch_bit,
  input  logic [5:0]         cfg_bk_bit,
  input  logic [5:0]         cfg_row_bit,

  input  logic               req_valid,
  input  logic [ADDR_W-1:0]  req_addr,

  output logic [CH_W-1:0]    sel_ch,
  output logic [BK_W-1:0]    sel_bk,
  output logic [ROW_W-1:0]   sel_row,
  output logic               decode_invalid,
  output logic [5:0]         cfg_in_use_ch
);
  initial begin
    if (CH_BIT_DEFAULT + CH_W > ADDR_W)
      $fatal(1, "platform_address_decode: channel field falls outside the address");
  end

  // Clause 2 and 5, HONOURED. The block refuses to decode before the
  // configuration is valid, and a reviewer checking "does it wait for
  // configuration?" finds that it does. This line is CORRECT, and it
  // is what conceals the defect.
  assign decode_invalid = req_valid && !cfg_valid;

  always_comb begin
    sel_ch  = '0;
    sel_bk  = '0;
    sel_row = '0;
    if (req_valid && cfg_valid) begin
      // <-- THE DEFECT: the compiled-in position is used, and
      //     cfg_ch_bit is never read.
      sel_ch  = req_addr[CH_BIT_DEFAULT +: CH_W];
      sel_bk  = req_addr[cfg_bk_bit  +: BK_W];
      sel_row = req_addr[cfg_row_bit +: ROW_W];
    end
  end

  // Clause 4, and it makes the bug FINDABLE rather than fixing it:
  // the block reports what it believes it is using.
  assign cfg_in_use_ch = CH_BIT_DEFAULT[5:0];
endmodule

Before reading on: which clause, and what grade is CH_BIT_DEFAULT, versus what grade is it consumed as?

13. The Defect — Grade D Wearing Grade A's Clothes

The violated clause is 1, and the defect is that cfg_ch_bit is declared on the port list and never read while cfg_bk_bit and cfg_row_bit are used correctly. One field of three compiles in its position.

The evidence story is the point. CH_BIT_DEFAULT began as an honest measurement on the first platform — grade C, a recovered result about that machine. It became a parameter default. It is now consumed as grade A, a stated fact about how this controller maps addresses. CURRICULUM-DERIVED from 18.4 §1: nothing was fabricated at any step; each copy was faithful, and only the qualification was lost.

And clause 2 being honoured is what conceals it. The block waits for a configuration it then ignores. A reviewer asking does this respect the platform's configuration? sees cfg_valid gating the decode and stops. The gate is honoured and the value is ignored — structurally the same shape as 31.2 §12's ownership flag, which forbade the owner's action correctly and failed to suspend the non-owner's accounting. One signal, two duties, one served.

The trace, and note what does not happen:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   GRADE D throughout. NUM_CH = 4 so CH_W = 2.

   platform A, brought up first:
       cfg_ch_bit = 8   == CH_BIT_DEFAULT
       decode is CORRECT. every test passes. the constant is now
       "validated by bring-up".

   platform B, a different population and interleave granularity:
       cfg_ch_bit = 13
       the block still extracts addr[9:8].

   consequence, and it is NOT corruption:
       addr[9:8] is still a bijection onto 4 channels, so every
       address still maps to exactly one channel and every read
       still returns what was written there. NO DATA IS WRONG.

   what IS wrong: the INTERLEAVE GRANULARITY.
       intended  : channel changes every 2^13 = 8192 bytes
       actual    : channel changes every 2^8  =  256 bytes

   DERIVED: a stride-8192 access pattern that was designed to
   spread across all four channels now lands entirely on one,
   because bits [9:8] are constant across that stride. Four
   channels of hardware deliver the throughput of one.

Three properties make this the module's signature failure.

It is a performance failure with no error signal, and it looks like a workload problem. Nothing is illegal, no data is wrong, no assertion about legality or association can fire. CURRICULUM-DERIVED from 30.8 §4, the symptom lands in gap 2→3 — the request stream's own localitywhich that chapter says is usually owned by software. So the investigation goes to the software team, and the software team's stride is correct.

It survives because the constant was validated. Bring-up on platform A is a genuine, passing, end-to-end test of the wrong thing. §5's category drift ends with an engineer sizes a buffer using what now looks like grade A; here the engineer is the block itself.

And §14's monitor is what finds it, because the two symptoms it produces are exactly what a channel-mix report distinguishes: extreme imbalance with no correctness failure. CURRICULUM-DERIVED from 31.3 §13, which owns the imbalance-versus-starvation instrument and states in its own limitations that balance and correctness are independent.

The correction, and one line of it is a deletion:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
      // CORRECTED. Clause 1: all three positions come from the
      // configuration. The compiled default is DELETED rather than
      // kept as a fallback -- a fallback recreates the bug on any
      // platform whose firmware did not write the register, and
      // clause 2 already says the correct behaviour there is to
      // REFUSE rather than to guess. 30.7 §9: an untrained value is
      // unknown, and unknown is not a default.
      sel_ch  = req_addr[cfg_ch_bit  +: CH_W];
      sel_bk  = req_addr[cfg_bk_bit  +: BK_W];
      sel_row = req_addr[cfg_row_bit +: ROW_W];

  // And clause 4 must report the CONFIGURED value, not the compiled
  // one -- otherwise the block's own traceability output confirms
  // the wrong answer, which is worse than having no output.
  assign cfg_in_use_ch = cfg_ch_bit;

Two interface consequences the correction creates, stated rather than assumed. The elaboration guard on CH_BIT_DEFAULT + CH_W <= ADDR_W must become a runtime check on cfg_ch_bit, because a configuration register can hold a position that does not fit — so decode_invalid gains a second cause and the two causes should be reported separately. And CH_BIT_DEFAULT disappears from the parameter list entirely, which is the review artifact worth looking for: the fix removes a parameter, and a fix that removes a parameter carrying a platform quantity is usually the right shape30.7 §9's design smell, resolved.

The general finding:

A parameter holding a platform quantity is grade C or D at best, however it was obtained. Consuming it as though documented is category drift with a localparam. Grep a controller's parameter list for values that name platform properties — field positions, channel counts, latencies, interleave granularities — and for each one ask which register should have supplied it.

14. RTL — Measuring the Mix

§7's arithmetic used grade-D proportions. This block measures the real ones, which is the only way the class ranking stops being an assumption — and it is also the instrument that finds §13's defect.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// class_mix_monitor -- verification/telemetry, CORRECT as written.
//
// CLASSIFICATION: synthesisable telemetry. Drives nothing. Grade-D
// parameter values.
//
// WHAT IT DOES: counts requests per class and per channel over a
// window, and reports both mixes plus the drop count.
//
// WHY IT EXISTS HERE: §7's proportions are grade D, so the ranking
// they produce is transferable and the numbers are not. This block
// replaces them with measurements. And §13's defect produces a
// signature only a CHANNEL mix can show -- extreme imbalance with no
// correctness failure -- so the two mixes are reported together.
//
// HOW TO RUN IT: run the real workload and read both mixes.
// EXPECTED RESULT: a stride-based pattern designed to interleave
// should show a near-uniform channel mix. Extreme concentration with
// zero errors is §13's signature.
//
// SYNTHESIS: NUM_CLASS + NUM_CH counters plus a max/min tracker.
// No divider.
//
// LIMITATIONS: measures DISTRIBUTION. It cannot see a decode that is
// wrong but uniform, and it cannot see a class the upstream protocol
// never labelled (§6). Both are STATED rather than implied --
// 27.3's independence discipline requires a monitor to say what it
// does not cover.
// ---------------------------------------------------------------------
module class_mix_monitor #(
  parameter int NUM_CLASS = 5,
  parameter int NUM_CH    = 4,
  parameter int WIN       = 1048576,
  // COUNT, not INDEX: a window in which EVERY request went to one
  // class or one channel must be representable, so each counter needs
  // $clog2(WIN + 1) bits. Sized to the "fair share" WIN / NUM_CH it
  // would saturate in exactly the concentrated case it exists to
  // detect, and report balance.
  parameter int CNT_W     = $clog2(WIN + 1),
  parameter int CL_W      = $clog2(NUM_CLASS > 1 ? NUM_CLASS : 2),
  parameter int CH_W      = $clog2(NUM_CH > 1 ? NUM_CH : 2)
)(
  input  logic              clk,
  input  logic              rst_n,

  input  logic              admit,
  input  logic              drop,
  input  logic [CL_W-1:0]   req_class,
  input  logic [CH_W-1:0]   sel_ch,
  input  logic              win_tick,

  output logic [CNT_W-1:0]  r_class   [NUM_CLASS],
  output logic [CNT_W-1:0]  r_ch_max,
  output logic [CNT_W-1:0]  r_ch_min,
  output logic [CNT_W-1:0]  r_drops,
  output logic [CNT_W-1:0]  r_total,
  output logic              concentrated,
  output logic              result_valid
);
  initial begin
    if (WIN < NUM_CH)
      $fatal(1, "class_mix_monitor: WIN must be >= NUM_CH or the channel mix is meaningless");
    if (NUM_CLASS < 1) $fatal(1, "class_mix_monitor: NUM_CLASS >= 1");
  end

  logic [CNT_W-1:0] c_class [NUM_CLASS];
  logic [CNT_W-1:0] c_ch    [NUM_CH];
  logic [CNT_W-1:0] c_drop, c_total;

  always_ff @(posedge clk) begin
    if (!rst_n) begin
      for (int i = 0; i < NUM_CLASS; i++) begin c_class[i] <= '0; r_class[i] <= '0; end
      for (int i = 0; i < NUM_CH;    i++) c_ch[i] <= '0;
      c_drop <= '0;  c_total <= '0;
      r_ch_max <= '0;
      // AND-accumulator discipline: a minimum tracker must start at
      // all-ones, or the first sample never wins and the reported
      // minimum stays zero -- which would report maximum
      // concentration on every window regardless of the traffic.
      r_ch_min <= '1;
      r_drops <= '0;  r_total <= '0;
      concentrated <= 1'b0;  result_valid <= 1'b0;
    end else if (win_tick) begin
      begin
        logic [CNT_W-1:0] mx, mn;
        mx = '0;
        mn = '1;
        for (int i = 0; i < NUM_CH; i++) begin
          if (c_ch[i] > mx) mx = c_ch[i];
          if (c_ch[i] < mn) mn = c_ch[i];
        end
        r_ch_max <= mx;
        r_ch_min <= mn;
        // §13's signature, cross-multiplied so no divider is needed:
        // a channel received more than three quarters of a window's
        // traffic while another received almost none. Reported as a
        // FLAG plus both endpoints rather than as a single ratio --
        // 27.5 refuses a lone percentage and 30.8 §11 requires a
        // derived statistic's range to be visible.
        concentrated <= (mx * 4 > c_total * 3) && (mn * NUM_CH * 4 < c_total);
      end
      for (int i = 0; i < NUM_CLASS; i++) begin
        r_class[i] <= c_class[i];
        c_class[i] <= '0;
      end
      for (int i = 0; i < NUM_CH; i++) c_ch[i] <= '0;
      r_drops      <= c_drop;
      r_total      <= c_total;
      c_drop       <= '0;
      c_total      <= '0;
      result_valid <= 1'b1;
    end else begin
      result_valid <= 1'b0;
      if (admit) begin
        if (c_class[req_class] != {CNT_W{1'b1}}) c_class[req_class] <= c_class[req_class] + 1'b1;
        if (c_ch[sel_ch]       != {CNT_W{1'b1}}) c_ch[sel_ch]       <= c_ch[sel_ch]       + 1'b1;
        if (c_total            != {CNT_W{1'b1}}) c_total            <= c_total            + 1'b1;
      end
      // Drops are counted SEPARATELY and are not in c_total, because
      // a dropped request never reached a channel. Folding them in
      // would make the channel mix's denominator disagree with its
      // numerators -- 30.8 §10's denominator error, avoided by
      // construction.
      if (drop && c_drop != {CNT_W{1'b1}}) c_drop <= c_drop + 1'b1;
    end
  end
endmodule

The two mixes together are the diagnostic, and the pairing is deliberate.

A skewed class mix says the platform is not what you assumed — a prefetch share near zero means either the predictor is off or, per §6, the protocol never labelled it and every request is arriving as demand. Those have opposite fixes and the counter distinguishes them, because an unlabelled platform shows classes_present with a single bit set.

A skewed channel mix with zero correctness failures is §13's defect, and nothing else produces that combination. CURRICULUM-DERIVED from 31.3 §13: balance and correctness are independent measurements, so a report of no errors is not evidence about distribution and never was.

15. SVA Review — Proving a Decode You Did Not Configure

The properties written for §12's block, and both are good properties:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  // Offered as "proves the decode respects the platform configuration".
  // Clause 2 and 5. Correct, non-vacuous, and PASSES on the
  // defective block.
  property p_no_decode_before_config;
    @(posedge clk) disable iff (!rst_n)
      (req_valid && !cfg_valid) |-> decode_invalid;
  endproperty
  assert property (p_no_decode_before_config)
    else $error("a decode was attempted before the configuration was valid");

  // And the field-extraction property, which was written from the
  // same mental model as the design.
  property p_channel_from_default_position;
    @(posedge clk) disable iff (!rst_n)
      (req_valid && cfg_valid) |->
        (sel_ch == req_addr[CH_BIT_DEFAULT +: CH_W]);
  endproperty
  assert property (p_channel_from_default_position)
    else $error("channel select did not match the expected field");

Q. Both pass. What is wrong with each?

The first is 30.9 §6's variety 2: it names cfg_valid and never cfg_ch_bit, so it proves the gate and says nothing about the value. §13's whole point is that the gate is honoured.

The second is worse — it is variety 4 and variety 10 at once. It shares the design's constant (CH_BIT_DEFAULT), so it confirms agreement rather than truth30.7 §10's consistency check. And on a platform where the configured position differs, a corrected design fails it, so the property forbids the fix31.1 §14's variety 10 in its purest form.

What actually covers clause 1:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  // Clause 1. It names cfg_ch_bit -- the signal the defective block
  // declares and never reads -- so it cannot pass while that signal
  // is ignored. Variety 2's and variety 4's repair together: the
  // property's reference is the CONFIGURATION, not a constant the
  // design also holds.
  property p_channel_follows_configuration;
    @(posedge clk) disable iff (!rst_n)
      (req_valid && cfg_valid) |->
        (sel_ch == ((req_addr >> cfg_ch_bit) & ((1 << CH_W) - 1)));
  endproperty
  assert property (p_channel_follows_configuration)
    else $error("channel select does not follow the configured field position");

  // Clause 3. A configuration change must take effect. This is the
  // property that catches a design which LATCHES the first
  // configuration it saw -- a different bug in the same family, and
  // one the defective block above would also exhibit.
  property p_config_change_takes_effect;
    @(posedge clk) disable iff (!rst_n)
      (req_valid && cfg_valid && !$stable(cfg_ch_bit)) |->
        (sel_ch == ((req_addr >> cfg_ch_bit) & ((1 << CH_W) - 1)));
  endproperty
  assert property (p_config_change_takes_effect)
    else $error("a configuration change did not take effect");

  // Clause 4, and it is the property that makes the block's own
  // traceability trustworthy. Reporting the compiled value would
  // CONFIRM the wrong answer, which §13 argues is worse than
  // reporting nothing.
  property p_reported_config_is_the_used_config;
    @(posedge clk) disable iff (!rst_n)
      cfg_valid |-> (cfg_in_use_ch == cfg_ch_bit);
  endproperty
  assert property (p_reported_config_is_the_used_config)
    else $error("the block reports a configuration it is not using");

  // And the runtime guard the correction creates (§13): a configured
  // position that does not fit must be REFUSED, not wrapped.
  property p_out_of_range_config_refused;
    @(posedge clk) disable iff (!rst_n)
      (req_valid && cfg_valid && (cfg_ch_bit + CH_W > ADDR_W)) |-> decode_invalid;
  endproperty
  assert property (p_out_of_range_config_refused)
    else $error("an out-of-range configured field position was used");

  // ---- Covers. The dimension this defect scales with is the
  //      CONFIGURATION VALUE, so per 31.3 §15's rule the cover must
  //      be on that value -- and specifically on it DIFFERING from
  //      the compiled default, which is the only case that separates
  //      the two designs.
  cover property (@(posedge clk) disable iff (!rst_n)
                  req_valid && cfg_valid && (cfg_ch_bit == CH_BIT_DEFAULT));
  cover property (@(posedge clk) disable iff (!rst_n)
                  req_valid && cfg_valid && (cfg_ch_bit != CH_BIT_DEFAULT));
  // A configuration CHANGE while running, for clause 3.
  cover property (@(posedge clk) disable iff (!rst_n)
                  cfg_valid && !$stable(cfg_ch_bit));
  // The refusal path, so clause 2 is known to have been exercised.
  cover property (@(posedge clk) disable iff (!rst_n) decode_invalid);

The second cover is the section's deliverable and it is the module's coverage lesson. CURRICULUM-DERIVED from 31.3 §15's rule — the coverage item must be on the dimension the defect scales withand here that dimension is a configuration value supplied by the environment. A testbench that models one platform will hold cfg_ch_bit at the default forever, so the cover stays at zero, both properties pass, and the configuration mechanism was never tested even though the configuration gate was.

And now the finding that is new.

Variety 11 — EVIDENCE-GRADE ESCAPE. A property can prove that a configurable mechanism was consulted. It cannot prove the configured value is correct, because the correctness of a grade-B value is a property of the platform and not of the design. So a property set that reaches p_channel_follows_configuration has verified everything the design can be held responsible for — and the residual risk has left the design's boundary entirely.

Held against the ten, what is different is where the obligation lives:

VarietyThe property's flawWhose problem
1–5, 8, 9the property checks the wrong thing, or too little of itthe property's
6it was never evaluatedthe stimulus's
7it shares the design's statethe property's
10it is sound in one configuration and certifies the defect in anotherthe property's, per arm
11it is correct and complete, and the risk is still therethe PLATFORM's — no assertion can absorb it

Varieties 1 to 10 are all fixable by writing a better property. Variety 11 is not, and that is precisely why it is worth naming: the correct response is not a stronger assertion but a platform-level check — read the configuration on the machine, compare it against what the design was integrated to expect, and report the comparison as a bring-up gate. CURRICULUM-DERIVED from 30.9 §2's obligation kinds: this is an obligation-discharge obligation, not a safety one, and it needs a ledger rather than a property.

Follow-up an interviewer should ask: so is variety 11 an excuse? No — it is a boundary, and stating it is what makes the plan honest. The wrong response is to claim the assertion set covers a configuration risk it structurally cannot. The right response is §16's row one: make configuration read-back a deliverable, which 30.10 §13 already argues on debug grounds and this chapter now argues on verification grounds.

16. What the Admission Block's Assertions Prove

§15 reviewed the decode and left §9's block unasserted. The gap matters most here for a specific reason: §9's block is the only one in this module that may legally refuse a request, so the property that matters is not about what it does but about which requests it is forbidden to refuse.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  // ---- The safety property of the whole class mechanism. A
  //      deadline-bearing or non-droppable request must NEVER be
  //      dropped, whatever the pressure. This is the one obligation
  //      the mechanism could violate catastrophically, and it names
  //      both axes of §3 rather than a priority number.
  property p_never_drop_an_obligation;
    @(posedge clk) disable iff (!rst_n)
      drop |-> (droppable && !deadline_bearing);
  endproperty
  assert property (p_never_drop_an_obligation)
    else $error("a non-droppable or deadline-bearing request was dropped");

  // Admission and drop must PARTITION the accepted requests: a valid
  // request is admitted, or dropped, or back-pressured -- never two
  // of those and never none silently. 17.5's contract depends on it.
  property p_request_is_accounted;
    @(posedge clk) disable iff (!rst_n)
      req_valid |-> ((admit ^ drop) || (!admit && !drop && !req_ready));
  endproperty
  assert property (p_request_is_accounted)
    else $error("a valid request was neither admitted, dropped, nor stalled");

  // 17.5's one-handshake-one-entry rule, at this boundary: a DROP
  // completes the handshake and must NOT create a queue entry. This
  // is the property that catches §4's forbidden design -- accept,
  // then discard -- which would leave the requester waiting forever.
  property p_drop_creates_no_entry;
    @(posedge clk) disable iff (!rst_n)
      (drop && req_ready) |=> $stable(q_occupancy) || admit_count != $past(admit_count);
  endproperty
  assert property (p_drop_creates_no_entry)
    else $error("a dropped request occupied a queue entry");

  // An unrecognised class must be treated as the STRONGEST
  // obligation, never dropped. 7.4's three-valued discipline: the
  // safe default for an unknown obligation is the strictest one.
  property p_unknown_class_never_dropped;
    @(posedge clk) disable iff (!rst_n)
      class_unknown |-> !drop;
  endproperty
  assert property (p_unknown_class_never_dropped)
    else $error("a request of unrecognised class was dropped");

  // The PLATFORM invariant, with the parameter in the ANTECEDENT and
  // not inside the claim -- 31.1 §14's test for whether a property
  // may be shared across configurations. It may.
  property p_no_shedding_without_prefetch;
    @(posedge clk) disable iff (!rst_n)
      (!HAS_PREFETCH) -> !drop;
  endproperty
  assert property (p_no_shedding_without_prefetch)
    else $error("a platform without a droppable class performed a drop");

  // Shedding must be BOUNDED in the other direction too (§4's third
  // consequence): below the threshold, nothing is dropped. Without
  // this, a design that drops every prefetch always satisfies the
  // safety property above and has silently disabled prefetching.
  property p_no_drop_below_threshold;
    @(posedge clk) disable iff (!rst_n)
      (q_occupancy < DROP_THRESH) |-> !drop;
  endproperty
  assert property (p_no_drop_below_threshold)
    else $error("a drop occurred below the pressure threshold");

  // ---- Covers: per class, per platform arm, and at the threshold.
  // Per CLASS, because the isolation of §3's axes holds only for the
  // classes the stimulus presented -- 31.3 §15's per-index rule,
  // applied to a class code.
  cover property (@(posedge clk) disable iff (!rst_n) admit && req_class == CL_DEMAND);
  cover property (@(posedge clk) disable iff (!rst_n) admit && req_class == CL_WB);
  cover property (@(posedge clk) disable iff (!rst_n) admit && req_class == CL_XLATE);
  cover property (@(posedge clk) disable iff (!rst_n) drop  && req_class == CL_PREF);
  // The BOUNDARY of the shedding threshold, so "the rule was
  // respected" is distinguishable from "the rule was exercised" --
  // 30.3 §10.
  cover property (@(posedge clk) disable iff (!rst_n)
                  req_valid && (q_occupancy == DROP_THRESH));
  // And the unrecognised-class path, which is a FINDING rather than a
  // fifth class: a non-zero count means the platform presented a
  // class this controller was not integrated to understand (§6).
  cover property (@(posedge clk) disable iff (!rst_n) class_unknown);

p_no_drop_below_threshold is the property nobody writes, and it is the mirror of 30.3 §9's variety 8: a safety property cannot detect over-application. Never drop an obligation is satisfied perfectly by a controller that drops every prefetch immediately — which has disabled a mechanism 29.3 §10 says is a real gain when the prediction is good. The two-sided bound is what makes the policy reviewable.

17. What Would You Measure?

Q. You are evaluating a CPU platform's memory controller. What do you measure, in what order?

MeasurementWhat it settlesCostOwner
Can you read the configuration at runtime?§6 — a documented mechanism you cannot read is operationally undocumentedhours§6, 30.10 §2
Which of §5's three source situations applieswhere to look, and it is wrong for most sources if you assume onehours18.4 §2
Configuration read-back versus integration expectationvariety 11's residual risk — the only thing that discharges ithours§15
classes_present from §9whether the protocol labels classes at all, or everything arrives as demandfree§9
The class mix from §14§7's proportions for this platform rather than grade Ddays§14
The channel mix, with concentrated§13's signature — imbalance with zero errorsdays§14
drop_count against the prefetch offered ratewhether shedding is working or has disabled prefetchingdays§16
Tail latency of the deadline classes only23.1 §9 — a mean over the whole mix is dominated by requests nobody awaiteddays23.1

Rows one to three cost hours and two of them can close a question. Row three is the one this chapter adds to the standard list, and §15's variety 11 is why: no assertion can absorb a configuration risk, so the read-back comparison is the check that discharges it — and it is cheap, mechanical, and almost never a bring-up gate.

Row four is free and it reframes everything below it. If classes_present has one bit set, the platform is not labelling classes, so §3's entire taxonomy is unavailable to the controller and the correct finding is an integration gap rather than a policy one.

And row eight is the one that inverts a conclusion. DERIVED from §7: 55% of the mix has no deadline, so a mean latency is majority-composed of requests nobody was waiting for. A platform that looks slow on mean latency and fine on deadline-class tail latency is fine, and the reverse is the case to escalate.

18. Common Wrong Answers

“The controller serves one request stream.” §2, §3. It serves four structurally different classes at once, differing on two independent axes, and 29.3 owns the mechanisms that produce each.

“Prefetches are just low-priority requests.” §3. They are droppable, which is a different axis from priority. The correct response to pressure is discard, not deferral, and deferring keeps paying for work you were free to abandon.

“Writebacks are low priority too, so treat them the same as prefetches.” §3. Identical on the deadline axis and opposite on droppability. Discarding one loses data.

“Give each class a priority weight.” §7. The class with the strongest obligation has the smallest share, so a share-proportional weight gives translation 5%. Chapter 17.4 §4 owns the fix — layers, not numbers.

“Translation traffic is negligible.” §3, §7. Smallest share, strongest obligation — it has a deadline and blocks the access that needed it, so its delay is multiplied.

“Most traffic has no deadline, so latency policy hardly matters.” §7. The 45% that does is the only part a program feels, and 23.1 §9 owns why a mean over the whole mix is the wrong statistic.

“Drop the request after accepting it if pressure rises.” §4. Chapter 17.5's handshake creates an obligation with no third outcome. The drop must happen at admission or not at all.

“A dropped prefetch needs no report.” §4. A drop that is not counted is indistinguishable from a prefetcher that never issued, and the two have opposite fixes.

“Drop aggressively — they are only hints.” §4, §16. A controller that drops every prefetch satisfies every safety property and has disabled a real gain. The bound is two-sided.

“What is the address map of this CPU?” §6, 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.

“This vendor documents it, so I know the answer.” §5, §6. A documented mechanism tells you to read the configuration. You know the answer once you have read the machine, not once you have read the manual.

“This diagram shows the mapping.” §5. Ask its category and its source. Chapter 18.4 §1 owns category drift: nothing was fabricated, only the qualification was lost.

“The constant was validated by bring-up.” §13. Bring-up on one platform is a genuine, passing, end-to-end test of the wrong thing.

“It waits for the configuration, so it respects it.” §13. The gate is honoured and the value is ignored — one signal, two duties, one served.

“No data is wrong, so the decode is fine.” §13. A wrong field position is still a bijection. What breaks is the interleave granularity, and four channels deliver the throughput of one.

“The channel imbalance means the workload's stride is bad.” §13, §14. That is the conclusion the defect produces, and it sends the investigation to a software team whose stride is correct. Check the configured field position first.

“The decode assertions pass.” §15. One proves the gate and the other shares the design's constant — a consistency check that also forbids the fix.

“We will add an assertion for the configuration.” §15. You can assert that the mechanism was consulted. You cannot assert that a grade-B value is right, because its correctness is a property of the platform — variety 11, and the discharge is a read-back gate.

“The regression is green.” §15. With cfg_ch_bit held at the compiled default forever, the configuration mechanism was never tested even though the configuration gate was.

19. Self-Check

  1. Name the thirteen shared obligations' owner and state, in one sentence, what the module's question therefore always is.

  2. Give §3's two axes and all four combinations, with the mechanism that produces each and the correct controller response.

  3. Explain why deferring a prefetch and deferring a writeback are the same action with opposite correctness consequences.

  4. Using §7's grade-D mix, compute the deadline-bearing share, the droppable share, and the share of the class with the strongest obligation. State which policy structure the third figure rules out.

  5. Explain why a drop must occur at admission rather than after acceptance, naming the contract it would otherwise break.

  6. State the three source situations of §5 and, for each, what an engineer should go and read.

  7. Explain why a documented mechanism you cannot read at runtime is operationally no better than an undocumented one.

  8. Find the defect in §12 without reading §13. Then say what evidence grade the compiled value is and what grade it is consumed as.

  9. Explain why §13's defect corrupts no data, and give the quantity it does break and the measurement that reveals it.

  10. Explain why p_channel_from_default_position is both variety 4 and variety 10, and write the property that is neither.

  11. State variety 11 in one sentence. Say why a stronger assertion cannot fix it and what discharges it instead.

20. Where This Goes

A CPU platform's dominating constraint is a heterogeneous requester mix with unequal obligations. The classes differ on two independent axes — deadline and droppability — and Module 17's queue has a field for neither; droppability must be acted on at admission because the handshake afterwards creates an obligation with no third outcome; the class with the strongest obligation has the smallest share, which rules out every share-proportional policy; and the CPU memory controller is a category error, because most of what you want to know is a configuration outcome rather than an architecture fact.

Three results carry forward. A parameter holding a platform quantity is grade C or D however it was obtained, and consuming it as documented is category drift with a localparam. A validity gate honoured while its value is ignored is one signal with two duties and one served — the second instance, after 31.2 §12. And variety 11: a property can prove a mechanism was consulted and cannot prove a grade-B value is right, so the residual risk leaves the design's boundary and needs a read-back gate rather than a stronger assertion.

Chapter 32.2 keeps the requester mix and changes what binds it. A mobile platform's mix is not heterogeneous in obligation — it is homogeneous and interrupted, because the binding constraint switches at runtime. Chapter 24.1 owns the energy mission and 31.2 the duty-cycle crossover; what neither owns is what happens when temperature, rather than energy, becomes the limit while the workload is running — and the answer is that the controller acquires an obligation it has not had in thirty-one chapters: it must be able to be told to slow down, within a bounded time, without violating anything.

Continue learning

Standards & specifications

Governing standard
JEDEC JESD79 (DDR SDRAM)(opens JEDEC Solid State Technology Association in a new tab)

Defines the DDR SDRAM device itself — signals, command encoding, mode registers, timing parameters and the initialisation sequence — one document per generation. Memory-controller microarchitecture, address-mapping policy, PHY training algorithms and board-level design are not specified by it.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the DDR curriculum.