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 test | Compliance test | |
|---|---|---|
| Question asked | does my design do what I intended? | does my design obey a rule someone else wrote? |
| Authority for the answer | the design specification | the standard |
| Who is harmed by a miss | the product | the counterparty — §3 |
| When a failure is found | during development | at qualification, often with a second supplier |
| Passing means | the feature works | the 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.
| Counterparty | What they rely on | What they will do about a violation |
|---|---|---|
| The device vendor | that your controller drives their part legally | nothing — their part misbehaves and it looks like theirs |
| A second device vendor | the same, for a part you never tested | qualification failure, late |
| The module vendor | that your platform meets the module's assumptions | field returns attributed to the module |
| A future integrator | that your IP behaves per the standard | a 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:
probability the assumption survives verification = f^nILLUSTRATIVE values, recomputed:
| Fraction of devices where the bad assumption holds | n = 1 | n = 2 | n = 3 |
|---|---|---|---|
| 0.9 | 0.900 | 0.810 | 0.729 |
| 0.5 | 0.500 | 0.250 | 0.125 |
| 0.3 | 0.300 | 0.090 | 0.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:
| Modules | Assertions | Covers | Chapters |
|---|---|---|---|
| 1–13 | 343 | 0 | 75 |
| 14–19 | 149 | 74 | 33 |
| 20–26 | 352 | 325 | 32 |
| Total | 844 | 399 | 142 |
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:
| Field | The question it answers |
|---|---|
| Rule identity | which obligation is this? |
| Source citation | where in the standard does it come from? |
| Interpretation | what did we take it to mean, in our own words? |
| Check | what artefact verifies it — assertion, test, review? |
| Status | verified, 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-organised | Rule-organised | |
|---|---|---|
| Primary artefact | a test | a rule record |
| Grows by | writing tests | enumerating rules |
| Completeness question | unanswerable | answerable |
| A gap appears as | nothing | a rule with status not attempted |
| Many-to-many | one test covers many rules | tracked 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
| Decision | Coverage | Checking | Cost |
|---|---|---|---|
| Enumerate rules before writing tests | unchanged | better — gaps become visible | worse — enumeration is real work |
| Add a second vendor model | better | better — §3 | worse — a second environment |
| Record interpretation per rule | unchanged | better — reviewable | worse — maintenance |
| Report a percentage instead of a residual | appears better | unchanged | better |
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
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
// ---------------------------------------------------------------------
// 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
endclassresidual() 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
// ---------------------------------------------------------------------
// 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;
endmoduleEach 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
// ---------------------------------------------------------------------
// 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
endclassThe 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
// 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:
// 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());
endtask15. Corner Cases
| Case | Behaviour | Why |
|---|---|---|
| Rule with a citation and no interpretation | Rejected | §5 — a record without a reading cannot be reviewed |
| Rule discharged with no artefact named | Rejected | “Discharged” must point at something |
| Rule waived with no reason | Rejected | §5 — each residual needs its own reason |
| Waived rule that also names a check | Rejected | Would appear both unverified and covered |
| Not-attempted rule naming an artefact | Rejected | A schedule item cannot have a checker |
Duplicate rule_id | Rejected | One obligation cannot hold two statuses |
| Every rule discharged, enumeration unreviewed | Not supportable | P15 — the extraction bounds the claim |
| Large residual, nothing outstanding, review done | Supportable | §7 — residuals are disclosed, not disqualifying |
| One rejected record, everything else clean | Not supportable | P16 |
| Stimulus run against one model | Counted separately; never agreement | §3, P17 |
| Two models agreeing, both wrong | Undetectable | §13's WHAT IT WOULD MISS |
Models differing only in flagged_error | Disagreement | agrees_with compares all three facts |
| Two rules broken in one cycle | Counter advances once | P7 — one bad command, not several |
| Violation flag on an idle cycle | P5 fires | Would attribute a violation to no command |
BANKS of 0 or 1 | $fatal at elaboration | A 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.
// 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| Check | What it establishes |
|---|---|
| Add 200 well-formed records; compare totals against the reference | Two representations of one accounting |
Add a record missing interpretation | Rejected by both; P13's partition holds |
| Add a discharged record with no artefact | Rejected by both |
| Add a waived record with no reason, then one with a reason | Only the second accepted |
| Add a waived record that also names a check | Rejected — the both-ways case |
Add the same rule_id twice | Second rejected; total unchanged |
| Mark every rule discharged, leave the enumeration unreviewed | claim_supportable() false; P15 |
| Review the enumeration; re-query | Now true, with the residual unchanged |
Leave one rule IN_PROGRESS and review the enumeration | Still false; P18 |
| Inject one rejected record into an otherwise clean registry | False; P16 |
| Run a stimulus against exactly one model | single_model_runs rises; not counted as agreement |
| Run against three models, all agreeing | unanimous rises; supportable while min_models ≥ 2 |
| Run one stimulus against one model in an otherwise three-model campaign | multi_model_claim_supportable() false |
Two models identical in data, differing in flagged_error | Disagreement reported |
| Drive each ILLUSTRATIVE rule violation individually and together | All 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:
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
| Symptom | Likely cause | How to confirm |
|---|---|---|
| Registry totals disagree with per-status counts | A record in no category or two | P13; compare against §16's reference |
| 100% discharged, claim not supportable | Enumeration unreviewed — §16 | enumeration_reviewed(); P15 |
| Claim supportable with rules in progress | claim_supportable() ignoring outstanding | P18 |
| Records silently missing | Rejected at add_rule and the return value ignored | rejected(); every add returns a bit |
| A rule appears both waived and covered | A residual record naming a check | Rejected by validate() |
| Agreement rate looks excellent, qualification still fails | Correlated model error — §13 | Undetectable here; adjudicate against the standard |
| Agreement claimed on a single-model campaign | min_models below two | P17; single_model_runs |
| A violation logged with no command | Flag asserting on an idle cycle | P5 |
| One bad command counted as several violations | Counter counting rules, not cycles | P7 |
| Violation count decreased between reports | A counter that unwinds | P8 |
| Checker will not elaborate | BANKS not a power of two ≥ 2 | The $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
-
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. -
§4 reports zero
cover propertyin Modules 1–13. Propose the smallest change to a per-chapter structure that would have surfaced that gap, and say what it would cost. -
Construct a rule record that passes every check in
validate()and is nonetheless useless to an external reviewer. Identify which field carries the weakness. -
§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.
-
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.
-
§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.
-
Remove
enumeration_reviewedfromclaim_supportable()and re-run §16's scenario. Which properties still pass? Explain why P13, P14 and P16 are insufficient on their own. -
§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
Related tutorials
- Related topic
DDR Assertions
662 of this curriculum's 843 named properties are implications, so 78.53% can pass by never arming. Built on the measured census, not on advice.
- Related topic
DDR VIP Usage
A DDR verification IP arrives with its own monitor, reference model, coverage model and assertions. Connecting it is a day's work. Knowing what it does not report is the whole problem.
- Related topic
UVM Architecture for DDR
Three interfaces that are not variations of each other. They share no clock, no transaction identity, and no notion of what a failure is — and the cross-bank obligations finally need a component.
- Related topic
Senior Verification Strategy
Use UVM, add assertions, add coverage names three tools and zero obligations. Start from what must be true, then ask what evidence each kind of truth admits — and hold the eight reasons a green assertion proves nothing.
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.
