Skip to content
VLSI Mentor

DDR · Module 27

JEDEC Compliance

A compliance claim has a structure: an enumerated rule list, a result per rule, and a residual. This chapter builds the structure — and refuses to invent the rule list, because JEDEC would not serve it.

Chapter 1.7 names this chapter's subject twice, and the second time it is blunt. Listing the ways engineers get DDR wrong, it describes “treating the standard as an implementation detail” — building a controller against one device's observed behaviour, verifying against a single vendor's model, and treating the specification as documentation. The stated consequence is “a design that interoperates with the part it was developed against and fails with another — found at qualification with a second supplier, which is late and expensive.” The prescription is equally direct:

“verify against the specification and against multiple vendor models, and treat compliance as a deliverable. Module 27's subject.

And earlier, in the same chapter: all of it must be verified against a specification written by someone else. Interoperability is the point of R6, which means compliance is a real obligation rather than an internal quality bar.”

Those two sentences are this chapter's mandate, and they contain three distinct claims worth separating: a compliance test has a different purpose from a functional test, a different counterparty, and a different completeness argument. §1, §2 and §7 take them in turn.

1. A Compliance Test Is Not a Functional Test

The two look identical in a waveform and differ in every other respect.

Functional testCompliance test
Question askeddoes my design do what I intended?does my design obey a rule someone else wrote?
Authority for the answerthe design specificationthe standard
Who is harmed by a missthe productthe counterparty — §3
When a failure is foundduring developmentat qualification, often with a second supplier
Passing meansthe feature worksthe design is interoperable

The load-bearing row is the second. A functional test's correct answer is whatever the design team decided; a compliance test's correct answer is fixed outside the project and is not negotiable by it.

That has a consequence for how a failure is triaged. A functional test failure admits two resolutions — fix the design, or change the specification, because the team owns both. A compliance failure admits one. The standard does not move, so the design does.

And it changes what a test's absence means. A missing functional test is untested intent, which the team can weigh against its own risk appetite. A missing compliance test is an unverified obligation to a party who will discover it for you — and §7 is about why that asymmetry makes the completeness argument the hard part.

2. The Counterparty Is Not Your Team

Chapter 1.7 frames interoperability as the point, and interoperability is a relationship between parties. Naming them is what makes the obligation concrete.

CounterpartyWhat they rely onWhat they will do about a violation
The device vendorthat your controller drives their part legallynothing — their part misbehaves and it looks like theirs
A second device vendorthe same, for a part you never testedqualification failure, late
The module vendorthat your platform meets the module's assumptionsfield returns attributed to the module
A future integratorthat your IP behaves per the standarda bug report against IP you have shipped

None of them is in the room when the test is written, and that is the structural difference from functional verification.

Two consequences, and the second is the reason §6 organises suites the way it does.

A compliance suite must be legible to someone who did not write it. A functional test can be justified by a conversation; a compliance test has to carry its own justification, because the person asking “did you check this?” will be external and will be asking after a failure.

And the obligation survives the team. Chapter 1.7's failure mode — “found at qualification with a second supplier” — happens months or years after the controller was written, typically to different people. So provenance is not documentation hygiene; it is the mechanism by which the obligation remains checkable at all, and §5 specifies what it must record.

3. Why One Vendor Model Is Not Enough

Chapter 1.7's prescription says “multiple vendor models”, and it is worth establishing why that is a requirement rather than diligence.

The specification permits a range; a model implements a point in it. Wherever a standard says a parameter has a minimum, a vendor may sit anywhere above it. Wherever it permits an optional feature, a vendor may or may not have it. So a single model is one legal sample from a space of legal devices, and a controller verified against it has been verified against that sample.

DERIVED under a stated model, to show the shape rather than to claim a probability. Suppose a design has some latent assumption that happens to hold for a fraction f of legal devices, and it is verified against n independent vendor models:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   probability the assumption survives verification  =  f^n

ILLUSTRATIVE values, recomputed:

Fraction of devices where the bad assumption holdsn = 1n = 2n = 3
0.90.9000.8100.729
0.50.5000.2500.125
0.30.3000.0900.027

Read the middle row. An assumption that is wrong for half of all legal devices survives single-model verification half the time — and a suite that passes has told you nothing about which half you are in.

Two honest caveats, because this is a model and not a measurement.

Vendor models are not independent. They implement the same standard, often follow the same reference behaviour, and may share the same ambiguity readings. So f^n is optimistic, and the real benefit of a second model is smaller than the table suggests.

And a model is not a device. It is a vendor's encoding of their part's behaviour, which can itself be wrong or incomplete. Agreement between two models is evidence about the models, and §13's block reports exactly that rather than claiming more.

4. What This Curriculum's Own Checking Actually Looks Like

Before prescribing how to organise checks, it is worth measuring the ones this curriculum has already written — because it is the largest body of DDR checking available to this chapter, and it was written without a compliance frame.

MEASURED, by extracting every SystemVerilog code block from every live DDR chapter and counting assert property and cover property:

ModulesAssertionsCoversChapters
1–13343075
14–191497433
20–2635232532
Total844399142

Three results, and all three bear on §6.

Covers appear only from Module 14 onward. The first thirteen modules — eighty-four chapters — contain zero cover property. MEASURED, and it is a striking gap in a body of work that was otherwise assertion-rich from the start.

The cover-to-assertion ratio rises steeply. DERIVED from the table: Modules 14–19 sit at 74/149 = 0.50; Modules 20–26 at 325/352 = 0.92. The later work writes nearly as many covers as assertions.

And assertion density per chapter roughly quadruples. DERIVED: Modules 1–13 average 343/75 = 4.6 assertions per chapter; Modules 20–26 average 352/32 = 11.0.

5. What a Rule's Provenance Must Record

§2 established that the obligation outlives the team and must be legible externally. That turns provenance into a data structure with required fields.

A rule record must answer five questions, and each one corresponds to a question an external party will ask after a failure:

FieldThe question it answers
Rule identitywhich obligation is this?
Source citationwhere in the standard does it come from?
Interpretationwhat did we take it to mean, in our own words?
Checkwhat artefact verifies it — assertion, test, review?
Statusverified, waived, unverifiable, or not yet attempted?

The third and fifth fields are the ones usually missing, and they are the ones that matter most.

Interpretation must be recorded separately from the citation. A standard's sentence and a team's reading of it are different objects, and the gap between them is where interoperability failures live. A record that cites without interpreting cannot be reviewed — a reader can check the citation exists but not whether the team understood it.

And “unverifiable” must be a distinct status from “not attempted”. A rule that cannot be checked in the available environment — because it concerns electrical behaviour, or a condition the testbench cannot create — is a permanent known gap requiring a different mitigation. A rule nobody has got to yet is a schedule item. Collapsing them loses the distinction between a risk you have accepted and a task you have forgotten, and §11's registry keeps them apart for that reason.

6. Organise Around Rules, Not Tests

Here is the structural prescription, and §4's census is the argument for it.

A test-organised suite answers “what do we run?” It is a list of stimuli and checks, grows by addition, and its completeness question is “have we written enough tests?” — which has no answer.

A rule-organised suite answers “what do we owe?” It is a list of obligations, each with a status, and its completeness question is “is every rule accounted for?” — which has an answer, even when the answer is partly no.

Test-organisedRule-organised
Primary artefacta testa rule record
Grows bywriting testsenumerating rules
Completeness questionunanswerableanswerable
A gap appears asnothinga rule with status not attempted
Many-to-manyone test covers many rulestracked explicitly — §11

The relationship is many-to-many and that is the implementation difficulty. One test can discharge several rules, and one rule may need several tests. So the mapping is a table, not a naming convention — and a suite that encodes coverage in test names cannot represent a test that half-covers two rules.

Note what this does not claim. Rule organisation does not make a suite more complete; it makes the suite's incompleteness visible. §4's curriculum census is locally excellent and globally silent, and rule organisation is the change that would make it speak.

7. Arguing Completeness Without the Specification

The hardest part, and the part this chapter must be most careful about.

A completeness argument over an enumerable specification is a coverage measurement. Count the rules, count the discharged ones, report the fraction. This chapter cannot do that — the opening callout records that the document is unobtainable, so the rule set cannot be enumerated here.

But the argument's structure does not depend on having the list, and it has three parts that can be stated independently:

Enumeration is itself a deliverable with its own status. “We have extracted 400 rules” is a claim about the extraction, not about the standard, and it can be wrong in two directions — missed rules and invented ones. So the enumeration needs review by someone who reads the standard independently, and its own completeness is unprovable from inside.

Coverage of the enumerated set is measurable and is not the whole claim. 100% of extracted rules discharged is exactly as strong as the extraction, which is the same structure 22.4 and 25.4 found for error detection: a mechanism is only as good as the fault model behind it.

And the residual must be stated, not implied. Rules known to be unverifiable, rules waived with a reason, and rules deferred are three different residuals, and a suite that reports only a percentage has hidden all three.

8. What Compliance Does Not Buy

Stating the limits is part of the deliverable, because a compliance pass is routinely over-read.

It does not buy performance. Module 23 establishes at length that a legal controller can be a slow one. Every rule can be obeyed by a design that achieves a fraction of achievable bandwidth, and no compliance test would notice.

It does not buy interoperability with a specific part. It buys interoperability with the standard, which is a claim about a population. §3's arithmetic is the reason: a legal design meeting a legal device can still expose an assumption neither party violated.

It does not buy correctness of your own features. §1's first row — compliance asks whether you obey someone else's rule, not whether you do what you intended. A design can be fully compliant and functionally wrong, and the two suites are not substitutes.

And it does not buy electrical soundness. Module 22 establishes that a great deal of a DDR interface's correctness lives outside the digital domain, and 22.3 refuses to model it in RTL for that reason. Digital compliance checking cannot reach it, and §11's registry has an unverifiable status precisely so that gap is recorded rather than silently absent.

9. The Three Quantities at This Level

DecisionCoverageCheckingCost
Enumerate rules before writing testsunchangedbetter — gaps become visibleworse — enumeration is real work
Add a second vendor modelbetterbetter — §3worse — a second environment
Record interpretation per ruleunchangedbetter — reviewableworse — maintenance
Report a percentage instead of a residualappears betterunchangedbetter

The last row is the trap and it is why it is in the table. Reporting a percentage costs less, reads better, and changes neither what was exercised nor what would be caught. A decision that improves only the report is the one to be most suspicious of — and §7's callout is what it looks like in practice.

10. The Compliance Architecture

How a rule-organised compliance suite is structured, in four rows. The top row holds the four inputs: the standard itself which this curriculum could not obtain, the team's interpretation of each rule recorded separately from the citation, the device or vendor models available to check against, and the verification environment. The second row holds the four artefacts: the rule registry which is the primary record, the bindable checkers that verify rules directly in the design, the tests that exercise conditions a checker needs, and the vendor agreement cross-check that compares behaviour across models. The third row holds the three outputs that constitute the deliverable: the discharged rules, the residual of waived unverifiable and deferred rules, and the enumeration review status which bounds every other claim. The bottom row is the compliance claim itself, which is only as strong as all three. Edges run from the standard and the interpretation into the rule registry, from the registry into the checkers and the tests, from the models into the vendor cross-check, from the environment into the tests, from the checkers and tests into the discharged set, from the registry into the residual, and from all three outputs into the claim.The standardunobtainable, 403 — seeaboveInterpretationrecorded separately — §6Vendor modelsplural is required — §3The environmentwhat can be created atallRule registrythe primary artefact — §6Bindable checkersverify in the design —§12Testscreate the conditionsVendor agreementevidence about models —§13Discharged rulesas we extracted them — §7The residualwaived / unverifiable /deferredEnumeration reviewbounds every other claim— §7The compliance claimonly as strong as allthree12

Two things the structure makes visible.

The standard and Interpretation are separate inputs to the registry. §5 argues they are different objects and the diagram enforces it — a registry fed only by the standard would have a citation and no reading, which is the record §5 says cannot be reviewed.

And three arrows reach the claim, not one. A percentage of discharged rules is one of them. The residual and the enumeration review are the other two, and §7's callout is exactly the failure of reporting the first while omitting the second and third.

11. The Rule Registry

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// compliance_rule_registry -- the primary artefact of a rule-organised
// suite: one record per obligation, with the five fields §5 requires.
//
// CLASSIFICATION: educational, SIMULATION-ONLY.
//
// WHAT IT DOES NOT MODEL:
//   - the standard, or any rule's actual content
//   - the design, any device, or any vendor model
//   - whether an interpretation is CORRECT. §5: the gap between a
//     standard's sentence and a team's reading is where
//     interoperability failures live, and no data structure closes it.
//
// WHAT IT WOULD MISS:
//   - a rule that was never enumerated. This is the big one. The
//     registry can report 100% discharged over a set that omits the
//     rule that fails qualification (§7), which is why
//     enumeration_reviewed is a field and not a comment.
//   - a rule enumerated wrongly -- invented, or split, or merged.
//   - anything about the QUALITY of a check. "Discharged by an
//     assertion" says an artefact exists, not that it is adequate.
// ---------------------------------------------------------------------
typedef enum int {
  RULE_NOT_ATTEMPTED = 0,   // a schedule item
  RULE_IN_PROGRESS   = 1,
  RULE_DISCHARGED    = 2,   // an artefact verifies it
  RULE_WAIVED        = 3,   // deliberately not verified, with a reason
  RULE_UNVERIFIABLE  = 4    // cannot be checked in this environment
} rule_status_e;

typedef enum int {
  CHK_NONE      = 0,
  CHK_ASSERTION = 1,        // a bindable property -- 27.2
  CHK_TEST      = 2,        // a directed or random test
  CHK_MONITOR   = 3,        // a passive check -- 27.3
  CHK_SCOREBOARD = 4,       // a data comparison -- 27.4
  CHK_REVIEW    = 5         // a human argument, not a simulation
} check_kind_e;

class compliance_rule extends uvm_object;
  `uvm_object_utils(compliance_rule)

  // ── §5's five required fields. All five, or the record is rejected.
  string        rule_id;          // which obligation
  string        source_citation;  // where in the standard
  string        interpretation;   // what WE took it to mean -- §5
  check_kind_e  check_kind;
  string        check_artefact;   // the name of the thing that checks it
  rule_status_e status;

  // Non-empty only for WAIVED and UNVERIFIABLE. §5: those are
  // different residuals and each needs its own reason.
  string        residual_reason;

  function new(string name = "compliance_rule");
    super.new(name);
    status     = RULE_NOT_ATTEMPTED;
    check_kind = CHK_NONE;
  endfunction

  // A record is well formed when its fields are mutually consistent.
  // Returns "" when valid, else the first problem found.
  function string validate();
    if (rule_id         == "") return "rule_id is empty";
    if (source_citation == "") return "source_citation is empty";
    // §5: a citation without an interpretation cannot be reviewed --
    // a reader can confirm the citation exists but not whether the
    // team understood it. So interpretation is REQUIRED, always.
    if (interpretation  == "") return "interpretation is empty";
    if (status == RULE_DISCHARGED) begin
      if (check_kind == CHK_NONE) return "discharged with no check kind";
      if (check_artefact == "")   return "discharged with no artefact named";
    end
    if (status inside {RULE_WAIVED, RULE_UNVERIFIABLE}) begin
      if (residual_reason == "")
        return "waived or unverifiable with no reason";
      // A residual must NOT claim a check. Doing so would let a rule
      // appear both unverified and covered.
      if (check_kind != CHK_NONE)
        return "residual rule must not name a check";
    end
    if (status == RULE_NOT_ATTEMPTED && check_artefact != "")
      return "not-attempted rule names an artefact";
    return "";
  endfunction
endclass


class compliance_registry extends uvm_component;
  `uvm_component_utils(compliance_registry)

  protected compliance_rule m_rules[string];   // by rule_id
  // §7: the enumeration is itself a deliverable with its own status,
  // and it BOUNDS every other claim this registry can make.
  protected bit    m_enumeration_reviewed;
  protected string m_enumeration_reviewer;
  protected int    m_rejected_records;

  function new(string name, uvm_component parent);
    super.new(name, parent);
    m_enumeration_reviewed = 0;
  endfunction

  // Returns 1 on acceptance. A malformed record is REJECTED, not
  // stored with a warning -- a registry holding invalid records
  // cannot support any completeness claim at all.
  function bit add_rule(compliance_rule r);
    string why;
    if (r == null) begin
      `uvm_error("REG", "null rule record")
      m_rejected_records++;
      return 0;
    end
    why = r.validate();
    if (why != "") begin
      `uvm_error("REG", $sformatf("rule '%s' rejected: %s", r.rule_id, why))
      m_rejected_records++;
      return 0;
    end
    if (m_rules.exists(r.rule_id)) begin
      // Duplicate ids would make the counts meaningless: the same
      // obligation could be discharged and not-attempted at once.
      `uvm_error("REG", $sformatf("duplicate rule_id '%s'", r.rule_id))
      m_rejected_records++;
      return 0;
    end
    m_rules[r.rule_id] = r;
    return 1;
  endfunction

  function void mark_enumeration_reviewed(string reviewer);
    if (reviewer == "") begin
      `uvm_error("REG", "enumeration review needs a named reviewer")
      return;
    end
    m_enumeration_reviewed = 1;
    m_enumeration_reviewer = reviewer;
  endfunction

  function int count_with_status(rule_status_e s);
    int n = 0;
    foreach (m_rules[id]) if (m_rules[id].status == s) n++;
    return n;
  endfunction

  function int total_rules();  return m_rules.size();       endfunction
  function int rejected();     return m_rejected_records;   endfunction
  function bit enumeration_reviewed(); return m_enumeration_reviewed; endfunction

  // §7: the honest statement is a residual, not a percentage. This
  // returns the FOUR numbers a counterparty actually needs, and it
  // deliberately does not compute a single score.
  function void residual(output int discharged, output int waived,
                         output int unverifiable, output int outstanding);
    discharged   = count_with_status(RULE_DISCHARGED);
    waived       = count_with_status(RULE_WAIVED);
    unverifiable = count_with_status(RULE_UNVERIFIABLE);
    outstanding  = count_with_status(RULE_NOT_ATTEMPTED)
                 + count_with_status(RULE_IN_PROGRESS);
  endfunction

  // A claim is only SUPPORTABLE when nothing is outstanding AND the
  // enumeration was reviewed. Note it can be supportable with a large
  // residual -- §7: waived and unverifiable rules are disclosed, not
  // disqualifying.
  function bit claim_supportable();
    int d, w, u, o;
    residual(d, w, u, o);
    return (o == 0) && m_enumeration_reviewed && (m_rejected_records == 0);
  endfunction

  function void report_phase(uvm_phase phase);
    int d, w, u, o;
    residual(d, w, u, o);
    `uvm_info("REG", $sformatf(
      "rules=%0d discharged=%0d waived=%0d unverifiable=%0d outstanding=%0d rejected=%0d enum_reviewed=%0b(%s) supportable=%0b",
      total_rules(), d, w, u, o, m_rejected_records,
      m_enumeration_reviewed, m_enumeration_reviewer, claim_supportable()), UVM_LOW)
  endfunction
endclass

residual() returns four numbers and refuses to compute a percentage. §7's callout establishes that a single figure hides the three residuals, so the method's signature is the argument — a caller that wants a percentage must construct it and choose its own denominator, which makes the choice visible.

And claim_supportable() can be true with a large residual. Waived and unverifiable rules are disclosed, not disqualifying. What makes a claim unsupportable is an outstanding rule, an unreviewed enumeration, or a rejected record — three things the team controls, unlike the residual.

12. The Bindable Rule Checker

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// compliance_rule_checker -- a bindable checker whose every property
// carries a rule identity, so a firing names the obligation it broke.
//
// CLASSIFICATION: educational, synthesisable, BINDABLE.
//
// WHY BINDABLE MATTERS: §2. The counterparty is external and arrives
// after a failure. A checker that reports "assertion 7 failed" needs
// a human to translate; one that reports a RULE ID answers the
// external question directly.
//
// WHAT IT DOES NOT MODEL:
//   - any real rule from any standard. The document was not
//     obtainable, so the rules below are ILLUSTRATIVE structural
//     ones and are NOT presented as JEDEC's.
//   - the array, any timing parameter, or any electrical behaviour
//
// WHAT IT WOULD MISS:
//   - every rule not expressible over the bound signals, which
//     includes all of Module 22's electrical subject matter
//   - a rule nobody enumerated (§7)
// ---------------------------------------------------------------------
module compliance_rule_checker #(
  parameter int BANKS    = 16,
  parameter int BANK_W   = $clog2(BANKS),
  // A COUNT of violations up to N needs clog2(N+1), not clog2(N).
  parameter int CNT_W    = 20
) (
  input  logic              clk,
  input  logic              rst_n,

  // ── Bound command interface. ILLUSTRATIVE encoding.
  input  logic              cmd_valid,
  input  logic [2:0]        cmd_code,      // 0 NOP 1 ACT 2 RD 3 WR 4 PRE 5 REF
  input  logic [BANK_W-1:0] cmd_bank,

  // ── Bound state, observed rather than reconstructed here. 27.3
  //    owns reconstruction; a bindable checker sees the DUT's own.
  input  logic [BANKS-1:0]  bank_open,
  input  logic              init_complete,

  // ── One violation flag per rule, so a firing names its obligation.
  output logic              v_r001_act_on_open_bank,
  output logic              v_r002_access_closed_bank,
  output logic              v_r003_refresh_with_bank_open,
  output logic              v_r004_command_before_init,
  output logic              v_r005_precharge_nothing_open,

  output logic [CNT_W-1:0]  cnt_violations,
  output logic              any_violation,
  // Which rule fired, as a mask, so a consumer can map a cycle onto
  // registry records without re-deriving the conditions.
  output logic [4:0]        rule_mask
);

  localparam logic [2:0] C_NOP = 3'd0, C_ACT = 3'd1, C_RD = 3'd2,
                         C_WR  = 3'd3, C_PRE = 3'd4, C_REF = 3'd5;

  initial begin
    if (BANKS < 2 || (BANKS & (BANKS - 1)) != 0)
      // The >= 2 bound matters: a power-of-two test ALONE accepts 0
      // and 1, and $clog2(1) is 0, which makes [BANK_W-1:0] illegal.
      // Module 24 and Module 26 each shipped this hole once.
      $fatal(1, "compliance_rule_checker: BANKS must be a power of two >= 2");
    if (BANK_W != $clog2(BANKS))
      $fatal(1, "compliance_rule_checker: BANK_W must address BANKS");
  end

  // Declared above the continuous assigns that read them.
  logic is_acc;
  assign is_acc = cmd_valid && ((cmd_code == C_RD) || (cmd_code == C_WR));

  logic bank_is_open;
  assign bank_is_open = bank_open[cmd_bank];

  logic any_open;
  assign any_open = (bank_open != '0);

  // ILLUSTRATIVE rules, each tagged with the identity a registry
  // record would carry. These are structural, not quoted.
  assign v_r001_act_on_open_bank      = cmd_valid && (cmd_code == C_ACT) && bank_is_open;
  assign v_r002_access_closed_bank    = is_acc && !bank_is_open;
  assign v_r003_refresh_with_bank_open = cmd_valid && (cmd_code == C_REF) && any_open;
  assign v_r004_command_before_init   = cmd_valid && (cmd_code != C_NOP) && !init_complete;
  // R005 -- a precharge issued when nothing is open. Harmless
  // electrically and still a rule: it indicates the controller's
  // model of bank state disagrees with the device's, which is the
  // condition that produces a real violation one command later.
  assign v_r005_precharge_nothing_open = cmd_valid && (cmd_code == C_PRE) && !any_open;

  logic [CNT_W-1:0] n_v;
  logic             viol_now;
  assign viol_now = v_r001_act_on_open_bank | v_r002_access_closed_bank
                  | v_r003_refresh_with_bank_open | v_r004_command_before_init
                  | v_r005_precharge_nothing_open;

  assign rule_mask = {v_r005_precharge_nothing_open, v_r004_command_before_init,
                      v_r003_refresh_with_bank_open, v_r002_access_closed_bank,
                      v_r001_act_on_open_bank};

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) n_v <= '0;
    else if (viol_now && (n_v != {CNT_W{1'b1}})) n_v <= n_v + CNT_W'(1);
  end

  assign cnt_violations = n_v;
  assign any_violation  = viol_now;
endmodule

Each violation output names a rule rather than a condition, and that is the block's whole design rationale. §2 establishes the counterparty is external and arrives after a failure; a log line reading v_r003_refresh_with_bank_open maps onto a registry record, while assert_7_failed requires the person who wrote it.

13. The Vendor-Agreement Cross-Check

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// vendor_agreement_check -- runs one stimulus against N vendor models
// and reports where they disagree.
//
// CLASSIFICATION: educational, SIMULATION-ONLY.
//
// WHY IT EXISTS: 1.4 prescribes verifying "against multiple vendor
// models", and §3 shows why -- a single model is one legal sample from
// a space of legal devices.
//
// WHAT IT DOES NOT MODEL:
//   - any vendor's model, or any device
//   - WHICH model is right when two disagree. A disagreement is a
//     finding requiring human adjudication against the standard, and
//     this block escalates rather than resolving.
//
// WHAT IT WOULD MISS:
//   - a CORRELATED error. §3's callout: models implement the same
//     standard, often from the same reference behaviour, and may
//     share an ambiguity reading. Two models agreeing and both being
//     wrong is invisible here, and it is the failure mode that
//     matters most.
//   - any behaviour the stimulus never creates.
// ---------------------------------------------------------------------
class vendor_response extends uvm_object;
  `uvm_object_utils(vendor_response)
  string        model_name;
  logic [63:0]  data;
  bit           has_data;      // some responses carry no data
  bit           flagged_error; // the model reported the stimulus illegal
  function new(string name = "vendor_response"); super.new(name); endfunction

  // Two responses agree when they agree on ALL THREE observable
  // facts. Comparing only data would call "error" and "no error"
  // agreement whenever the data field happened to match.
  function bit agrees_with(vendor_response other);
    if (other == null) return 0;
    if (flagged_error != other.flagged_error) return 0;
    if (has_data      != other.has_data)      return 0;
    if (has_data && (data != other.data))     return 0;
    return 1;
  endfunction
endclass


class vendor_agreement_check extends uvm_component;
  `uvm_component_utils(vendor_agreement_check)

  protected int m_stimuli;
  protected int m_unanimous;
  protected int m_disagreements;
  protected int m_single_model_runs;   // §3: runs that prove nothing
  protected int m_min_models_seen;

  function new(string name, uvm_component parent);
    super.new(name, parent);
    m_min_models_seen = -1;
  endfunction

  // Returns 1 when every model agreed. A run with FEWER THAN TWO
  // models is counted separately and never reported as agreement --
  // §3: one model cannot agree with anything.
  function bit check_stimulus(string stim_id, vendor_response resp[$]);
    bit unanimous = 1;
    m_stimuli++;
    if (resp.size() < 2) begin
      m_single_model_runs++;
      `uvm_warning("VENDOR", $sformatf(
        "stimulus '%s' ran against %0d model(s): agreement is undefined below two",
        stim_id, resp.size()))
      if (m_min_models_seen < 0 || resp.size() < m_min_models_seen)
        m_min_models_seen = resp.size();
      return 0;
    end
    if (m_min_models_seen < 0 || resp.size() < m_min_models_seen)
      m_min_models_seen = resp.size();

    for (int i = 1; i < resp.size(); i++) begin
      if (!resp[0].agrees_with(resp[i])) begin
        unanimous = 0;
        // Escalated, not resolved. Which model is right is a question
        // about the standard, and this block does not have it.
        `uvm_error("VENDOR", $sformatf(
          "stimulus '%s': model '%s' disagrees with '%s' -- adjudicate against the standard",
          stim_id, resp[i].model_name, resp[0].model_name))
      end
    end
    if (unanimous) m_unanimous++;
    else           m_disagreements++;
    return unanimous;
  endfunction

  function int stimuli();          return m_stimuli;           endfunction
  function int unanimous();        return m_unanimous;         endfunction
  function int disagreements();    return m_disagreements;     endfunction
  function int single_model_runs(); return m_single_model_runs; endfunction
  function int min_models();       return m_min_models_seen;   endfunction

  // §3: the strength of an agreement claim is bounded by the SMALLEST
  // number of models any stimulus ran against, not the largest.
  function bit multi_model_claim_supportable();
    return (m_single_model_runs == 0) && (m_min_models_seen >= 2);
  endfunction

  function void report_phase(uvm_phase phase);
    `uvm_info("VENDOR", $sformatf(
      "stimuli=%0d unanimous=%0d disagreements=%0d single_model_runs=%0d min_models=%0d supportable=%0b",
      m_stimuli, m_unanimous, m_disagreements, m_single_model_runs,
      m_min_models_seen, multi_model_claim_supportable()), UVM_LOW)
  endfunction
endclass

The claim is bounded by min_models, not by the largest count. A campaign running most stimuli against three models and a few against one is as strong as the ones against one for those stimuli — so reporting an average would overstate it, and multi_model_claim_supportable() requires that no stimulus ran alone.

And agrees_with compares all three observable facts. Comparing data alone would treat “returned 0 and flagged an error” as agreeing with “returned 0 and flagged nothing” — the case where one model thinks the stimulus was illegal and the other does not, which is exactly the disagreement worth catching.

14. What the Assertions Prove

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Bind unit note: P1-P12 reference compliance_rule_checker's internals.
// P13-P18 are written as immediate assertions over the SIMULATION-ONLY
// registry and cross-check, since those are classes rather than
// modules and carry no clock.

// ── Bindable, over compliance_rule_checker.

// P1 -- FORBIDDEN. An activate to an already-open bank is always
// flagged. ILLUSTRATIVE rule R001, structural not quoted.
property p_r001_always_flagged;
  @(posedge clk) disable iff (!rst_n)
    (cmd_valid && (cmd_code == 3'd1) && bank_open[cmd_bank])
      |-> v_r001_act_on_open_bank;
endproperty
assert property (p_r001_always_flagged);

// P2 -- FORBIDDEN. An access to a closed bank is always flagged.
property p_r002_always_flagged;
  @(posedge clk) disable iff (!rst_n)
    (cmd_valid && ((cmd_code == 3'd2) || (cmd_code == 3'd3))
     && !bank_open[cmd_bank]) |-> v_r002_access_closed_bank;
endproperty
assert property (p_r002_always_flagged);

// P3 -- FORBIDDEN. A refresh with any bank open is always flagged.
property p_r003_always_flagged;
  @(posedge clk) disable iff (!rst_n)
    (cmd_valid && (cmd_code == 3'd5) && (bank_open != '0))
      |-> v_r003_refresh_with_bank_open;
endproperty
assert property (p_r003_always_flagged);

// P4 -- FORBIDDEN. Any non-NOP command before initialisation is
// flagged. The one rule here that does not depend on bank state.
property p_r004_always_flagged;
  @(posedge clk) disable iff (!rst_n)
    (cmd_valid && (cmd_code != 3'd0) && !init_complete)
      |-> v_r004_command_before_init;
endproperty
assert property (p_r004_always_flagged);

// P5 -- no rule flag asserts without a command. A checker that
// flagged on an idle cycle would attribute a violation to a
// command that was never issued.
property p_no_flag_without_command;
  @(posedge clk) disable iff (!rst_n)
    !cmd_valid |-> !any_violation;
endproperty
assert property (p_no_flag_without_command);

// P6 -- INVARIANT. any_violation is exactly the disjunction of the
// five rule flags. An aggregate that could assert alone would be a
// violation with no obligation attached, which §12's design forbids.
property p_aggregate_is_the_disjunction;
  @(posedge clk) disable iff (!rst_n)
    any_violation == (|rule_mask);
endproperty
assert property (p_aggregate_is_the_disjunction);

// P7 -- INVARIANT. The mask's bits are exactly the individual flags,
// in a fixed order. A consumer maps a mask bit onto a registry
// record, so a reordering would silently misattribute violations.
property p_mask_matches_the_flags;
  @(posedge clk) disable iff (!rst_n)
    rule_mask == {v_r005_precharge_nothing_open, v_r004_command_before_init,
                  v_r003_refresh_with_bank_open, v_r002_access_closed_bank,
                  v_r001_act_on_open_bank};
endproperty
assert property (p_mask_matches_the_flags);

// P8 -- FORBIDDEN. R001 and R002 are mutually exclusive, because they
// require different command codes. Both firing at once would mean the
// command decode is ambiguous.
property p_r001_r002_exclusive;
  @(posedge clk) disable iff (!rst_n)
    !(v_r001_act_on_open_bank && v_r002_access_closed_bank);
endproperty
assert property (p_r001_r002_exclusive);

// P9 -- R004 dominates: before initialisation, EVERY non-NOP command
// is flagged regardless of bank state. A checker that let bank state
// suppress R004 would pass traffic issued before the device was ready.
property p_r004_dominates_before_init;
  @(posedge clk) disable iff (!rst_n)
    (cmd_valid && (cmd_code != 3'd0) && !init_complete) |-> any_violation;
endproperty
assert property (p_r004_dominates_before_init);

// P10 -- FORBIDDEN. A precharge with nothing open is always flagged.
// §12: harmless electrically, and evidence the controller's model of
// bank state has diverged from the device's.
property p_r005_always_flagged;
  @(posedge clk) disable iff (!rst_n)
    (cmd_valid && (cmd_code == 3'd4) && (bank_open == '0))
      |-> v_r005_precharge_nothing_open;
endproperty
assert property (p_r005_always_flagged);

// P11 -- the counter advances exactly once per violating cycle,
// however many rules fired in it. Counting rules rather than cycles
// would make one bad command look like several.
property p_counter_counts_cycles_not_rules;
  @(posedge clk) disable iff (!rst_n)
    (any_violation && (cnt_violations != {CNT_W{1'b1}}))
      |=> (cnt_violations == $past(cnt_violations, 1) + CNT_W'(1));
endproperty
assert property (p_counter_counts_cycles_not_rules);

// P12 -- INVARIANT. The counter never decreases. A violation record
// that could unwind would let a passing final state hide a failure.
property p_counter_is_monotone;
  @(posedge clk) disable iff (!rst_n)
    (cnt_violations >= $past(cnt_violations, 1));
endproperty
assert property (p_counter_is_monotone);

// ── Cover, over the bindable checker. Each ILLUSTRATIVE rule must be
// ATTEMPTED or its property is vacuous -- 27.2 §5 measures how much
// of this curriculum's corpus is exposed to exactly that.
cover property (@(posedge clk) disable iff (!rst_n) v_r001_act_on_open_bank);
cover property (@(posedge clk) disable iff (!rst_n) v_r002_access_closed_bank);
cover property (@(posedge clk) disable iff (!rst_n) v_r003_refresh_with_bank_open);
cover property (@(posedge clk) disable iff (!rst_n) v_r004_command_before_init);
cover property (@(posedge clk) disable iff (!rst_n) v_r005_precharge_nothing_open);
// The mask carrying exactly one bit, and more than one -- P11
// distinguishes those cases and a suite must reach both.
cover property (@(posedge clk) disable iff (!rst_n) $onehot(rule_mask));
// A clean run: commands issued, no rule broken. Without this cover a
// suite could be flagging everything and still pass P1-P8.
cover property (@(posedge clk) disable iff (!rst_n) cmd_valid && !any_violation);
// Two rules broken in one cycle -- the case P7 distinguishes.
cover property (@(posedge clk) disable iff (!rst_n)
                  $countones(rule_mask) > 1);
// Commands before and after initialisation, so R004's antecedent is
// reached in both directions.
cover property (@(posedge clk) disable iff (!rst_n) cmd_valid && init_complete);
cover property (@(posedge clk) disable iff (!rst_n) cmd_valid && !init_complete);
// Every bank exercised at the extremes of the index.
cover property (@(posedge clk) disable iff (!rst_n) cmd_valid && (cmd_bank == '0));
cover property (@(posedge clk) disable iff (!rst_n)
                  cmd_valid && (cmd_bank == BANK_W'(BANKS - 1)));

The registry and the cross-check are classes with no clock, so their invariants are immediate assertions in a checker task rather than concurrent properties:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SIMULATION-ONLY. Immediate assertions over the registry's and the
// cross-check's invariants -- the class equivalents of P1-P12.
task automatic check_registry_invariants(compliance_registry reg_h,
                                         vendor_agreement_check va_h);
  int d, w, u, o;
  reg_h.residual(d, w, u, o);

  // P13 -- the four residual categories partition the rule set exactly.
  // A rule in no category, or in two, would make every count wrong.
  assert (d + w + u + o == reg_h.total_rules())
    else $error("P13: residual categories do not partition %0d rules", reg_h.total_rules());

  // P14 -- FORBIDDEN. A claim is never supportable while anything is
  // outstanding. §7: waived and unverifiable are disclosed; an
  // outstanding rule is simply unfinished.
  assert (!(reg_h.claim_supportable() && (o > 0)))
    else $error("P14: claim reported supportable with %0d outstanding rules", o);

  // P15 -- FORBIDDEN. A claim is never supportable without a reviewed
  // enumeration. §7: the extraction bounds every other claim.
  assert (!(reg_h.claim_supportable() && !reg_h.enumeration_reviewed()))
    else $error("P15: claim reported supportable with an unreviewed enumeration");

  // P16 -- a rejected record never enters the counts. A registry
  // holding invalid records cannot support any completeness claim.
  assert (!(reg_h.claim_supportable() && (reg_h.rejected() > 0)))
    else $error("P16: claim supportable with %0d rejected records", reg_h.rejected());

  // P17 -- FORBIDDEN. Agreement is never claimed below two models.
  // §3: one model cannot agree with anything.
  assert (!(va_h.multi_model_claim_supportable() && (va_h.min_models() < 2)))
    else $error("P17: multi-model claim supportable with min_models=%0d", va_h.min_models());

  // P18 -- unanimous and disagreeing runs partition the multi-model
  // stimuli, with single-model runs excluded from both.
  assert (va_h.unanimous() + va_h.disagreements() + va_h.single_model_runs()
          == va_h.stimuli())
    else $error("P18: agreement outcomes do not partition %0d stimuli", va_h.stimuli());
endtask

15. Corner Cases

CaseBehaviourWhy
Rule with a citation and no interpretationRejected§5 — a record without a reading cannot be reviewed
Rule discharged with no artefact namedRejected“Discharged” must point at something
Rule waived with no reasonRejected§5 — each residual needs its own reason
Waived rule that also names a checkRejectedWould appear both unverified and covered
Not-attempted rule naming an artefactRejectedA schedule item cannot have a checker
Duplicate rule_idRejectedOne obligation cannot hold two statuses
Every rule discharged, enumeration unreviewedNot supportableP15 — the extraction bounds the claim
Large residual, nothing outstanding, review doneSupportable§7 — residuals are disclosed, not disqualifying
One rejected record, everything else cleanNot supportableP16
Stimulus run against one modelCounted separately; never agreement§3, P17
Two models agreeing, both wrongUndetectable§13's WHAT IT WOULD MISS
Models differing only in flagged_errorDisagreementagrees_with compares all three facts
Two rules broken in one cycleCounter advances onceP7 — one bad command, not several
Violation flag on an idle cycleP5 firesWould attribute a violation to no command
BANKS of 0 or 1$fatal at elaborationA power-of-two test alone accepts both

Rows seven and eight are the pair this chapter exists to distinguish. A suite with a large disclosed residual can support a claim, and a suite with everything discharged but an unreviewed enumeration cannot — which inverts the intuition that discharging rules is the whole job.

16. DV — Testing the Checkers Themselves

A compliance suite is itself a deliverable, so its own machinery needs testing. The reference here is deliberately a different representation: the registry is an associative array, so the reference is an ordered queue with independent counting.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SIMULATION-ONLY. Independent reference for the registry's
// accounting, holding records in a QUEUE and counting by iteration
// rather than by the DUT's own status tallies -- so agreement is
// evidence rather than a restatement.
class registry_reference;
  typedef struct {
    string        id;
    rule_status_e st;
    bit           has_artefact;
    bit           has_reason;
    bit           has_interp;
  } rec_t;
  rec_t recs[$];

  function bit would_accept(rec_t r);
    if (r.id == "" || !r.has_interp) return 0;
    if (r.st == RULE_DISCHARGED && !r.has_artefact) return 0;
    if (r.st inside {RULE_WAIVED, RULE_UNVERIFIABLE} && !r.has_reason) return 0;
    if (r.st == RULE_NOT_ATTEMPTED && r.has_artefact) return 0;
    foreach (recs[i]) if (recs[i].id == r.id) return 0;   // duplicate
    return 1;
  endfunction

  function void add(rec_t r);
    if (would_accept(r)) recs.push_back(r);
  endfunction

  function int count(rule_status_e s);
    int n = 0;
    foreach (recs[i]) if (recs[i].st == s) n++;
    return n;
  endfunction

  function int total(); return recs.size(); endfunction
endclass
CheckWhat it establishes
Add 200 well-formed records; compare totals against the referenceTwo representations of one accounting
Add a record missing interpretationRejected by both; P13's partition holds
Add a discharged record with no artefactRejected by both
Add a waived record with no reason, then one with a reasonOnly the second accepted
Add a waived record that also names a checkRejected — the both-ways case
Add the same rule_id twiceSecond rejected; total unchanged
Mark every rule discharged, leave the enumeration unreviewedclaim_supportable() false; P15
Review the enumeration; re-queryNow true, with the residual unchanged
Leave one rule IN_PROGRESS and review the enumerationStill false; P18
Inject one rejected record into an otherwise clean registryFalse; P16
Run a stimulus against exactly one modelsingle_model_runs rises; not counted as agreement
Run against three models, all agreeingunanimous rises; supportable while min_models ≥ 2
Run one stimulus against one model in an otherwise three-model campaignmulti_model_claim_supportable() false
Two models identical in data, differing in flagged_errorDisagreement reported
Drive each ILLUSTRATIVE rule violation individually and togetherAll four covers plus the multi-rule cover

The seventh and eighth checks together produce the report worth publishing, because the suite is complete by every measure a percentage would report and still cannot support a claim:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  THE SUITE THAT DISCHARGED EVERY RULE AND PROVES NOTHING

    rules enumerated         412
    discharged               412
    waived                     0
    unverifiable               0
    outstanding                0
    rejected records           0
    enumeration_reviewed       0     <-- nobody checked the extraction

    the percentage a report would quote :  412/412 = 100%
    claim_supportable()                 :  FALSE

    assertions : P13 residual partitions          PASS
                 P14 not supportable if outstanding PASS
                 P15 not supportable if unreviewed  PASS  <-- this one
                 P16 no rejected records            PASS
                 every property                     PASS

    diagnosis : the suite is internally perfect and externally
      unsupported. Every rule the team extracted is discharged, and
      nothing establishes that the extraction resembles the standard.
      §7: five layers of self-selection, and this run has verified
      the inner four while leaving the outermost untouched.

    what makes it dangerous : 100% is the number that gets reported,
      and it is true. The missing field is a boolean nobody asked
      for, and 1.4's qualification failure lives exactly there --
      "found at qualification with a second supplier, which is late
      and expensive."

    the fix : enumeration_reviewed is a REQUIRED input to
      claim_supportable(), not an advisory field. A suite cannot
      review its own extraction, so the check must be a gate rather
      than a metric.

17. Debugging

SymptomLikely causeHow to confirm
Registry totals disagree with per-status countsA record in no category or twoP13; compare against §16's reference
100% discharged, claim not supportableEnumeration unreviewed — §16enumeration_reviewed(); P15
Claim supportable with rules in progressclaim_supportable() ignoring outstandingP18
Records silently missingRejected at add_rule and the return value ignoredrejected(); every add returns a bit
A rule appears both waived and coveredA residual record naming a checkRejected by validate()
Agreement rate looks excellent, qualification still failsCorrelated model error — §13Undetectable here; adjudicate against the standard
Agreement claimed on a single-model campaignmin_models below twoP17; single_model_runs
A violation logged with no commandFlag asserting on an idle cycleP5
One bad command counted as several violationsCounter counting rules, not cyclesP7
Violation count decreased between reportsA counter that unwindsP8
Checker will not elaborateBANKS not a power of two ≥ 2The $fatal message

Row six is the honest limit. A high agreement rate is consistent with a shared misreading, and nothing in this chapter's machinery can distinguish the two — which is why §3's callout states it and §13's header repeats it at the block.

18. Misconceptions

“Compliance is thorough functional verification.” §1. Different question, different authority, different counterparty. A functional failure admits two resolutions; a compliance failure admits one.

“We verified against the vendor's model, so we are compliant.” §3. That model is one legal sample from a space of legal devices, and 1.7 names the resulting failure explicitly.

“Two models agreeing means we are right.” §3's callout, §13. It is evidence about the models. Shared ancestry or a shared ambiguity reading defeats it, and that case is invisible.

“A citation is provenance.” §5. A citation without a recorded interpretation cannot be reviewed — a reader can confirm the citation exists but not whether the team understood it.

“Unverifiable and not-yet-done are both gaps.” §5. One is an accepted risk needing a different mitigation; the other is a schedule item. Collapsing them loses which is which.

“A bigger suite is a more complete suite.” §7. A test-organised suite grows without ever being able to state what it does not check — which §4 measures in this curriculum's own 844 assertions.

“Rule organisation makes a suite more complete.” §7. It makes the incompleteness visible. That is a different and more useful property.

“100% of our compliance suite passes.” §7's callout. True, and it describes the conjunction of five things the team chose. §16 shows a 412-of-412 suite that cannot support a claim.

“A large residual means a weak suite.” §15 rows seven and eight. A disclosed residual with a reviewed enumeration supports a claim; a zero residual with an unreviewed enumeration does not.

“Compliance implies performance.” §8. Module 23 establishes that a fully legal controller can deliver a fraction of achievable bandwidth.

“Compliance covers the electrical rules too.” §8. Module 22 owns that domain and 22.3 refuses to model it in RTL. Those rules take the unverifiable status.

“This chapter lists the JEDEC compliance tests.” The opening callout. It does not, and the reason is recorded: the document returned 403, and inventing a list would be the error 1.7 warns against.

19. Interview Reasoning

What is the difference between a functional test and a compliance test? The authority for the correct answer. A functional test checks intent the team owns; a compliance test checks a rule written elsewhere — so a functional failure can be resolved by changing the specification and a compliance failure cannot.

Who is a compliance suite written for? An external counterparty who is not in the room — another device vendor, a module vendor, a future integrator — and who will ask “did you check this?” after a failure, often years later and to different people.

Why is one vendor model insufficient? The specification permits a range and a model implements a point in it. A latent assumption that holds for half of all legal devices survives single-model verification half the time, and a pass tells you nothing about which half you are in.

What is the catch with multiple models? They are not independent. They implement the same standard, often from the same reference behaviour, so agreement is evidence about the models — and a shared misreading is invisible.

What must a rule record contain? Identity, citation, interpretation, the checking artefact, and status. The interpretation is the field usually missing and the one that makes the record reviewable.

Why distinguish “unverifiable” from “not attempted”? One is a permanent gap needing a different mitigation; the other is unfinished work. A single “gap” category loses the distinction between accepted risk and forgotten task.

Why organise a suite around rules rather than tests? Because “have we written enough tests?” has no answer and “is every rule accounted for?” does. Rule organisation does not add completeness; it makes incompleteness visible.

What is wrong with “we pass 100% of our compliance suite”? Nothing factually, and it describes a suite the team enumerated, interpreted, checked and ran against models it chose. The useful statement is a residual: rules extracted, discharged, waived, unverifiable, and who reviewed the extraction.

Can a suite be complete and unsupportable? Yes, and it is the common case. Every rule discharged with an unreviewed enumeration is exactly the state in which a qualification failure is discovered by someone else.

What does compliance not buy? Performance, correctness of your own features, interoperability with any specific part, and anything electrical.

20. Exercises

  1. Take §3's model and derive the number of independent vendor models needed to reduce the survival probability of a f = 0.7 assumption below 0.1. Then state why the answer is a lower bound.

  2. §4 reports zero cover property in Modules 1–13. Propose the smallest change to a per-chapter structure that would have surfaced that gap, and say what it would cost.

  3. Construct a rule record that passes every check in validate() and is nonetheless useless to an external reviewer. Identify which field carries the weakness.

  4. §5 requires interpretation to be recorded. Design the review process that would catch a wrong interpretation, and state what it needs that a registry cannot provide.

  5. Extend §11's registry with a many-to-many rule-to-test mapping as §6 requires. Show that a naming convention cannot represent a test that half-covers two rules.

  6. §13 cannot detect correlated model error. Design the smallest additional check that would give some evidence about correlation, and state precisely what it would and would not establish.

  7. Remove enumeration_reviewed from claim_supportable() and re-run §16's scenario. Which properties still pass? Explain why P13, P14 and P16 are insufficient on their own.

  8. §8 lists four things compliance does not buy. For each, name the module of this curriculum that owns it and the check that would be needed instead.

21. Where This Goes

Compliance now has a structure rather than a sentiment. A compliance test differs from a functional one in its authority and its counterparty; multiple vendor models are a requirement because a model is one legal sample; a rule record needs five fields of which interpretation is the one usually missing; a suite organised around rules can state its own incompleteness where one organised around tests cannot; and a completeness claim is bounded by an enumeration review that the suite cannot perform on itself.

Four results carry forward. A functional failure has two resolutions and a compliance failure has one — the standard does not move. Agreement between models is evidence about models, and correlated error is the failure mode that matters most and is invisible. A disclosed residual supports a claim and an unreviewed enumeration does not, which inverts the usual intuition about what completeness means. And this curriculum's own 844 assertions and 399 covers are locally excellent and globally silent — MEASURED, with covers entirely absent from its first seventy-five chapters, which is what checking looks like when it grows without a rule inventory.

Two things are left open. The standard was not obtainable — 403 on every attempt, for the fourth module running — so no rule in this chapter is quoted and no test list appears. And the quality of a check is not modelled anywhere. §11's registry records that a rule is discharged by a named artefact; whether that artefact is adequate is a judgement no field captures, and §20's third exercise asks you to construct the record that exposes it.

What this chapter has treated as a primitive is the checking artefact itself. It records that a rule is discharged “by an assertion” and says nothing about what makes an assertion adequate — whether it can fire, whether it fires for the right reason, or whether it is evaluated at all.

Chapter 27.2 takes that up, and it has an unusual amount of evidence to work with: 843 named properties already written across this curriculum, which can be measured rather than theorised about. It turns out that 662 of them are implications and therefore exposed to vacuity, 181 are invariants and cannot be, 91.2% carry a reset guard and 74 do not — and that a property which passes because its antecedent never occurred is the single most common way a suite reports success while checking nothing.

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.