DDR · Module 27
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.
Chapters 27.1 through 27.5 built the parts of a DDR verification environment: a compliance obligation with an honest residual, a property set that reports its own antecedents, a monitor with a three-valued resolution flag, a distributed scoreboard with five separate totals, and a coverage model with a defensible denominator.
Almost nobody builds them. A DDR verification IP arrives with a monitor, a reference model, a coverage model and an assertion set already written — and integrating one is a day's work at the interface.
The integration question is therefore not how to connect it. It is what you are now unable to see. A component you did not write reports what its author chose to report, and every judgement the previous five chapters made about what to report — the resolution flag, the legal-set size, the unchecked total, the reviewed denominator — is a judgement somebody else has already made on your behalf, and has usually not published.
1. What a DDR VIP Is, Structurally
Strip away the packaging and a DDR verification IP is a small number of components, each of which this module has already built.
| Component | What it does | This module's version |
|---|---|---|
| Bus-functional model | drives or responds on the DDR interface | not built here — the UVM track's driver |
| Monitor | reconstructs transactions from pins | 27.3 |
| Reference model | holds what should be at each address | 27.4 §10 |
| Scoreboard | compares observed against expected | 27.4 §12 |
| Protocol checker | asserts the timing and legality rules | 27.2 §11 |
| Coverage model | records which situations occurred | 27.5 §12 |
| Configuration object | speed grade, geometry, timing set | 27.5 §8's surface |
So a VIP is not a new kind of thing. It is these seven components with the boundary drawn around them instead of through them — and the boundary is what changes.
Two structural facts follow, and the second is the chapter. Because the components exist, the integration is mechanical: an interface, a configuration object, and one or more analysis ports. And because the boundary is around them, every internal judgement is now invisible — which is the difference between using a component and having built it.
2. The Integration Question Is Not Connection
Connection is a solved problem, and stating what it involves is worth one table so the rest of the chapter can be about the part that is not solved.
| Integration step | Effort | Where it goes wrong |
|---|---|---|
| Bind the interface | mechanical | naming and direction, caught at elaboration |
| Build the configuration object | mechanical | §8 — silently wrong values |
| Connect analysis ports | mechanical | nothing |
| Set the operating mode | small | §6 — the wrong side gets tested |
| Determine what it reports | unbounded | §4, §5 — the subject of this chapter |
| Determine what it does not | unbounded | §5 — and it cannot be asked directly |
Rows one through four fail at elaboration or in the first simulation. They are cheap because they are loud.
Rows five and six never fail. An environment with a VIP whose monitor silently treats an unresolvable bank state as “row 0” runs, passes, and reports coverage — and 27.3 §6 establishes exactly why that is worse than reporting nothing. The integration is complete, correct, and blind in a way no test will surface.
3. The Four Judgements Somebody Else Made
The previous five chapters each arrived at a reporting decision that was not obvious and was argued for at length. Each one is now a decision the VIP's author made, and in each case both answers produce a working component.
| Judgement | This module's answer | The other answer, which also works |
|---|---|---|
| A monitor's unresolvable state — 27.3 §6 | three-valued: report unknown | assume a default and report a value |
| A scoreboard's ambiguous expectation — 27.4 §3 | a set, compared by membership | model the controller's ordering; compare exactly |
| A read with no expected value — 27.4 §2 | a third outcome, counted apart | fold it into passes |
| A coverage denominator — 27.5 §4 | four numbers, no percentage | one percentage of the naive product |
Every right-hand answer yields a component that compiles, runs, and reports success. That is what makes the column dangerous: none of these choices produces a symptom.
And the right-hand column is the cheaper implementation in all four rows, which is a real argument that it is the more common one. Assuming a default is less code than a three-valued flag; exact comparison is less code than set membership; one percentage is less code than an audited denominator. CURRICULUM-DERIVED from 27.4 §8 and 27.5 §9: in both chapters the cheapest option was also the one that destroyed the thing being measured.
So the integration contract has to ask about these four specifically, and §4 is the procedure for doing that without documentation.
4. The Observability Contract
You cannot ask a component what it fails to report. You can determine it by construction, and the procedure is the same one 27.1 §5 used for a compliance obligation: enumerate what must be reported, then record the status of each item as provided, absent, or unknown.
| Capability the previous chapters proved necessary | How to determine it |
|---|---|
| Per-field resolution state on a transaction | Inspect the transaction class — is there such a field at all? |
| Behaviour when a monitor attaches mid-traffic | Start the VIP late; read what it reports for the first access |
| Whether an ambiguous expectation is a set | Issue overlapping writes to one address; see if it errors |
| Whether unchecked reads are counted apart | Read before writing; see whether the pass count rises |
| Whether its coverage denominator excludes unreachable bins | Read the model's bin count against §4 of 27.5 |
| Whether its properties report antecedent counts | 27.2 §7 — look for cover statements beside the asserts |
| Which rules its checker actually implements | §5 — usually undeterminable |
Rows two, three and four are experiments, not documentation questions, and that is the important structural point. Each is a stimulus whose result distinguishes the two answers in §3's table, and each takes an afternoon.
Row seven is the one that cannot be resolved, and §5 is about it.
The result is a three-valued register, and unknown must stay unknown. Chapter 27.1 §9's residual refused to compute a percentage of an unenumerated obligation for precisely this reason: a capability register with unknown silently counted as provided is an integration report that claims coverage nobody established. §10's registry therefore refuses to do it.
5. What a VIP Cannot Tell You About Itself
One question has no experimental answer, and it is the same question 27.1 could not answer about JEDEC.
“Which rules does your checker implement?” A VIP that asserts protocol compliance is making 27.1 §3's claim — and that chapter established that the claim is unenumerable from outside, because a checker that implements 400 of 600 rules and one that implements all 600 are indistinguishable on any test that violates none of the missing 200.
CURRICULUM-DERIVED from 27.1 §4: the asymmetry is total. A checker firing proves a rule is implemented. A checker staying silent proves nothing — the rule may be implemented and satisfied, implemented and not reached, or absent.
| What you observe | What it proves |
|---|---|
| The checker fires on a violation you injected | that rule is implemented |
| The checker is silent on legal traffic | nothing |
| The checker is silent on a violation you injected | that rule is absent or unreached |
| The checker is silent on traffic you did not shape | nothing at all |
Row three is the only negative result available, and it requires knowing which violation to inject. So the enumeration problem reappears exactly: to determine which rules are missing you must already have the rule list, which is the thing 27.1 could not obtain.
What this leaves is an honest procedure rather than a solution. For every rule you can enumerate — from this curriculum's own chapters, from your own specification reading, from a failure you have previously seen — inject the violation and record whether the checker fired. The result is a lower bound on the checker's coverage and never an upper one, and §10's registry records it as exactly that.
6. Passive and Active — Which Side You Are Testing
A DDR VIP can sit on either side of the interface, and the choice determines what is under test. Getting it wrong produces a working environment that tests the VIP.
| Mode | The VIP is | Under test is | What it can check |
|---|---|---|---|
| Memory model (reactive) | the device | your controller | command legality, timing, refresh obligations |
| Controller (active) | the host | your device or PHY | device response, data return, training |
| Passive monitor only | an observer | whatever drives the bus | protocol conformance, nothing about data |
The third mode is the one worth dwelling on, because it is the only one that composes with the components this module built. A passive VIP monitor produces transactions and checks protocol rules without responding, so it can sit alongside 27.3's monitor and 27.4's scoreboard rather than replacing them.
And it is the mode in which §11's correlated-failure risk is lowest, because a passive monitor that disagrees with yours is an actual finding — whereas a memory model that agrees with your scoreboard may be agreeing for a shared reason.
The failure that makes this section necessary: using a memory-model VIP and then also writing your own reference model. The environment now has two models of the array, and 27.4 §7's independence argument applies — but in the wrong direction. Your scoreboard compares reads against your model; the VIP returns data from its model; the two agree because the device was the VIP. You have verified that your reference model matches theirs, which is a real result and is not the result anyone wanted.
7. The Structure of the Integration
Two things the structure makes visible.
Their coverage feeds both What they report and What they don't. That is not a drafting error. A coverage model reports a number and does not report its denominator's justification — so the same component is the source of a result and of an unaudited assumption, which 27.5 §4 shows is the difference between 2.5% and 41%.
And Your monitor sits outside the boundary with an edge into the cross-check. §11 argues that this is the only instrument capable of detecting a supplied component agreeing with you for a shared reason — and it is also the one an integration is most tempted to delete, since the VIP already has a monitor.
8. The Configuration Surface
Chapter 27.5 §8 established that reachability is a function of configuration and that an exclusion list written once goes stale. With a VIP, the configuration object is the entire surface through which you can affect any of it — and it is the one part of the integration that is both mechanical and silently wrong.
| Configuration item | Wrong value's symptom | Why it is dangerous |
|---|---|---|
| Geometry — banks, rows, columns | often none | the VIP models a different device; addresses alias |
| Speed grade / timing set | often none | its checker enforces different minimums |
| Burst length | usually loud | mismatched data phases fail quickly |
| Refresh mode | none for a short test | Module 15's obligations differ |
| Command timing (1N / 2N) | none | 27.5 §8 — AT_MIN becomes unreachable |
| On-die ECC enabled | none, ever | 25.4 §4 — a corrected error is invisible |
Rows one, two, four, five and six produce no symptom, and row two is the worst of them. A VIP configured with a slower speed grade than your device enforces looser minimums — so its checker passes traffic that violates your device's actual timing. The environment is green and the checking is weaker than it appears, which is 27.2 §2's vacuity problem arriving through a configuration field.
And the inverse produces noise rather than silence. A VIP configured stricter than your device fails legal traffic, an engineer investigates, and the investigation ends correctly. The same asymmetry 27.5 §6 established for illegal_bins applies here: when unsure, configure strict.
9. The Correlated-Failure Problem
Chapter 27.1 §13 named this in the context of a vendor model, and a VIP is where it actually bites.
Two independent models agreeing is evidence. Two models with a shared input agreeing is not. And a VIP and your own environment share more inputs than is comfortable:
| Shared input | Why it correlates | Consequence of a shared error |
|---|---|---|
| The same specification document | both authors read the same text | both implement the same misreading |
| The same configuration object | §8 — one source of geometry and timing | both model the wrong device identically |
| The same interpretation of an ambiguity | a spec's unclear clause has a conventional reading | both take the conventional reading |
| Your DUT's own behaviour | if either was tuned against it | agreement by construction — 27.3 §9 |
Row two is the mechanical one and it is easy to miss. Feeding your reference model and the VIP from one configuration object is good engineering — it removes a class of mismatch bug. And it guarantees that a wrong geometry is wrong in both, so the cross-check in §7's diagram cannot detect it.
Row four is the fatal one and it has a name in this module. Chapter 27.3 §9 called it the monitor that cannot fail; 27.4 §7 found the subtler form where only the ordering comes from the design. A VIP whose reference model was validated against a previous generation of your own design is in that category, and nothing at the interface reveals it.
What remains possible is bounding the correlation rather than removing it. Enumerate the shared inputs, and for each one say what a shared error would look like: a wrong geometry shows up as address aliasing under a directed sweep; a shared misreading shows up only against a third party's behaviour. §12's cross-check therefore reports the shared inputs alongside the agreement rate, because an agreement rate with no shared-input list is the number this section exists to distrust.
10. The Capability Registry
// ---------------------------------------------------------------------
// vip_capability_registry -- §4's observability contract, executable.
//
// CLASSIFICATION: educational, SIMULATION-ONLY.
//
// WHY unknown IS A FIRST-CLASS VALUE (§4): you cannot ask a component
// what it fails to report. A register where unknown silently counts
// as provided is an integration report claiming coverage nobody
// established -- and 27.1 §9's residual() refused to compute a
// percentage for exactly this reason.
//
// WHY A LOWER BOUND ONLY (§5): a checker firing proves a rule is
// implemented; a checker staying silent proves nothing. So the
// determinable result is a LOWER bound on capability, never an upper
// one, and this class will not report otherwise.
//
// WHAT IT DOES NOT MODEL:
// - any product, vendor implementation, or real capability list
//
// WHAT IT WOULD MISS:
// - every capability nobody enumerated. 27.1 §5's enumeration
// problem, which is why review is a flag and not a computation.
// ---------------------------------------------------------------------
typedef enum { CAP_PROVIDED, // an experiment demonstrated it
CAP_ABSENT, // an experiment demonstrated its absence
CAP_UNKNOWN // not determined -- the default
} cap_status_e;
// §4's table: how the status was established. A capability asserted
// from documentation is weaker evidence than one demonstrated, and
// the registry keeps them distinct rather than averaging them.
typedef enum { EV_NONE, // nothing was done
EV_DOC, // the supplier's documentation says so
EV_EXPERIMENT // stimulus demonstrated it
} evidence_e;
class vip_capability extends uvm_object;
`uvm_object_utils(vip_capability)
string id;
string requirement; // which chapter established the need
cap_status_e status;
evidence_e evidence;
string how; // the experiment, or why none exists
function new(string name = "vip_capability");
super.new(name);
status = CAP_UNKNOWN;
evidence = EV_NONE;
endfunction
// §5: documentation is not a demonstration. A capability believed
// present on documentation alone is reported separately, because
// the whole subject of this chapter is the gap between what a
// component claims and what it reports.
function bit demonstrated();
return (status == CAP_PROVIDED) && (evidence == EV_EXPERIMENT);
endfunction
endclass
class vip_capability_registry extends uvm_object;
`uvm_object_utils(vip_capability_registry)
protected vip_capability m_cap[string];
protected bit m_enumeration_reviewed;
function new(string name = "vip_capability_registry");
super.new(name);
endfunction
function void declare(string id, string requirement);
vip_capability c;
if (id == "" || requirement == "") begin
`uvm_error("VIPREG",
"a capability needs an id and the requirement it answers")
return;
end
if (m_cap.exists(id)) return; // idempotent
c = vip_capability::type_id::create(id);
c.id = id; c.requirement = requirement;
m_cap[id] = c; // status stays CAP_UNKNOWN
endfunction
// Recording a determination requires saying HOW. §4: rows two,
// three and four of its table are experiments, and an experiment
// nobody can describe was not run.
function void record(string id, cap_status_e status,
evidence_e evidence, string how);
if (!m_cap.exists(id)) begin
`uvm_error("VIPREG", $sformatf("unknown capability '%s'", id))
return;
end
if (status != CAP_UNKNOWN && how == "") begin
`uvm_error("VIPREG", $sformatf(
"determination of '%s' refused: no method given", id))
return;
end
if (status != CAP_UNKNOWN && evidence == EV_NONE) begin
`uvm_error("VIPREG", $sformatf(
"determination of '%s' refused: status without evidence", id))
return;
end
m_cap[id].status = status;
m_cap[id].evidence = evidence;
m_cap[id].how = how;
endfunction
function void mark_enumeration_reviewed();
m_enumeration_reviewed = 1;
endfunction
function int total(); return m_cap.size(); endfunction
function int count_with(cap_status_e s);
int n = 0;
foreach (m_cap[k]) if (m_cap[k].status == s) n++;
return n;
endfunction
function int count_demonstrated();
int n = 0;
foreach (m_cap[k]) if (m_cap[k].demonstrated()) n++;
return n;
endfunction
// 27.1 §9's refusal, in this chapter's terms. Four numbers, and NO
// percentage -- because a percentage of an enumeration nobody has
// reviewed is a percentage of a number nobody chose.
function void residual(output int declared, output int provided,
output int absent, output int unknown_n);
declared = m_cap.size();
provided = count_with(CAP_PROVIDED);
absent = count_with(CAP_ABSENT);
unknown_n = count_with(CAP_UNKNOWN);
endfunction
// §4: unknown must stay unknown. An integration report is only
// supportable when nothing is undetermined, the enumeration was
// reviewed, and every PROVIDED status was demonstrated rather than
// read in a document.
function bit integration_report_supportable();
if (m_cap.size() == 0) return 0; // nothing enumerated
if (!m_enumeration_reviewed) return 0; // 27.1 §5
if (count_with(CAP_UNKNOWN) != 0) return 0; // §4
if (count_demonstrated() != count_with(CAP_PROVIDED)) return 0; // §5
return 1;
endfunction
// §5: what is established about a supplied checker is a LOWER
// bound. This method exists so nothing downstream can mistake it
// for a completeness figure.
function int rules_demonstrated_lower_bound();
return count_demonstrated();
endfunction
function void report_phase(uvm_phase phase);
int d, p, a, u;
residual(d, p, a, u);
`uvm_info("VIPREG", $sformatf(
"declared=%0d provided=%0d (demonstrated=%0d) absent=%0d unknown=%0d reviewed=%0b supportable=%0b",
d, p, count_demonstrated(), a, u, m_enumeration_reviewed,
integration_report_supportable()), UVM_LOW)
endfunction
endclassrecord() refuses a determination with no stated method. §4's procedure is experimental — start the VIP late, issue overlapping writes, read before writing — and an experiment nobody can describe was not run. This is the same refusal 27.5 §11's exclude() makes for an unjustified exclusion, and for the same reason.
And demonstrated() separates documentation from experiment rather than averaging them. The entire subject of this chapter is the gap between what a component claims and what it reports, so a registry that treated a datasheet line and a stimulus result as equivalent evidence would have erased its own subject.
11. The Boundary Property Set
// ---------------------------------------------------------------------
// vip_boundary_check -- CLASSIFICATION: synthesisable, BINDABLE.
//
// Bound at the interface between your environment and a VIP, this set
// checks the INTEGRATION's assumptions rather than the protocol's
// rules. 27.2 §11 owns protocol spacing; this owns the boundary.
//
// WHY BINDABLE AND NOT A CLASS: §7's diagram places this outside the
// VIP boundary deliberately. A check that consumed the VIP's own
// analysis port would inherit its author's judgement, which is the
// correlated-failure problem of §9. These properties see pins only.
//
// Every property is guarded by `disable iff (!rst_n)` -- 27.2's
// census measured 769 of 843 named properties with such a guard and
// 74 without, and the 74 are where reset-time noise comes from.
// ---------------------------------------------------------------------
module vip_boundary_check #(
parameter int BANKS = 16,
parameter int VIP_ACTIVE = 0, // §6: 1 when the VIP drives
parameter int ECC_ENABLED = 0 // §8's last row
)(
input logic clk,
input logic rst_n,
input logic cmd_valid,
input logic [3:0] cmd_code,
input logic [$clog2(BANKS)-1:0] cmd_bank,
input logic vip_drives, // the VIP owns the bus
input logic env_drives, // your env owns it
input logic cfg_valid, // §8's config applied
input logic cfg_locked,
input logic rsp_valid,
input logic rsp_error,
input logic mon_txn_valid, // VIP's monitor output
input logic mon_resolved // and its resolution flag
);
// BANKS < 2 would make $clog2(BANKS) zero and cmd_bank illegal.
// The sibling guard in 24.3 accepted 0 and 1; this one does not.
initial begin
if (BANKS < 2)
$fatal(1, "vip_boundary_check: BANKS must be at least 2 (got %0d)", BANKS);
end
// ---- §6: exactly one side drives. Both is contention; neither
// during a command is a floating bus.
property p_single_driver;
@(posedge clk) disable iff (!rst_n)
cmd_valid |-> (vip_drives ^ env_drives);
endproperty
assert property (p_single_driver)
else $error("boundary: both or neither side driving during a command");
// ---- §6: an ACTIVE VIP drives; a passive one must never.
property p_mode_respected;
@(posedge clk) disable iff (!rst_n)
(VIP_ACTIVE == 0) |-> !vip_drives;
endproperty
assert property (p_mode_respected)
else $error("boundary: a passive VIP drove the bus");
// ---- §8: no command before the configuration is applied. A VIP
// modelling a default device is the silent-wrong-geometry case.
property p_config_before_traffic;
@(posedge clk) disable iff (!rst_n)
cmd_valid |-> cfg_valid;
endproperty
assert property (p_config_before_traffic)
else $error("boundary: traffic before the configuration was applied");
// ---- §8: and the configuration must not change under traffic,
// which would make every derived timing figure stale mid-test.
property p_config_stable;
@(posedge clk) disable iff (!rst_n)
cfg_locked |=> $stable(cfg_valid);
endproperty
assert property (p_config_stable)
else $error("boundary: configuration changed while locked");
// ---- The bank index must be in range. A VIP modelling a smaller
// device aliases silently -- §8's first row.
property p_bank_in_range;
@(posedge clk) disable iff (!rst_n)
cmd_valid |-> (cmd_bank < BANKS);
endproperty
assert property (p_bank_in_range)
else $error("boundary: bank index outside the configured geometry");
// ---- A response requires a command to have been issued. This is
// an IMPLICATION and must be: rsp_valid is the only thing that makes
// the claim meaningful, so there is no invariant form. 27.2's census
// put 78.53% of this curriculum's properties in this category, which
// is why the cover statements below are not optional.
property p_no_unsolicited_response;
@(posedge clk) disable iff (!rst_n)
rsp_valid |-> $past(cmd_valid, 1) || $past(cmd_valid, 2)
|| $past(cmd_valid, 3);
endproperty
assert property (p_no_unsolicited_response)
else $error("boundary: a response with no recent command");
// ---- §4: a monitor transaction must carry a resolution flag. If
// the VIP has no such concept the input is tied, and this property
// is the experiment that demonstrates it.
property p_resolution_flag_present;
@(posedge clk) disable iff (!rst_n)
mon_txn_valid |-> !$isunknown(mon_resolved);
endproperty
assert property (p_resolution_flag_present)
else $error("boundary: monitor output with no resolution flag");
// ---- A monitor output requires traffic to have occurred. A VIP
// reporting transactions with no commands is modelling, not
// observing -- 27.3 §9's cannot-fail monitor at the boundary.
property p_monitor_observes;
@(posedge clk) disable iff (!rst_n)
mon_txn_valid |-> $past(cmd_valid, 1) || $past(cmd_valid, 2)
|| $past(cmd_valid, 3) || $past(cmd_valid, 4);
endproperty
assert property (p_monitor_observes)
else $error("boundary: a monitor transaction with no preceding command");
// ---- §8's last row: with ECC enabled, a response error is not a
// data error, and an integration treating it as one is wrong.
// 25.4 §4 owns why a corrected error is invisible.
property p_ecc_error_not_data;
@(posedge clk) disable iff (!rst_n)
(ECC_ENABLED == 1) && rsp_error |-> rsp_valid;
endproperty
assert property (p_ecc_error_not_data)
else $error("boundary: an error flag outside a valid response");
// ---- INVARIANT, not an implication -- the ONE property in this set
// that is. The two drive signals are never both high, at any time,
// command or not, so this property has no antecedent to fail to arm
// and is the only one here structurally immune to vacuity.
property p_never_both_drive;
@(posedge clk) disable iff (!rst_n)
!(vip_drives && env_drives);
endproperty
assert property (p_never_both_drive)
else $error("boundary: bus contention");
// ---- IMPLICATION, and it cannot be an invariant: cmd_code is
// don't-care while cmd_valid is low, so an ungated form would fire on
// idle-cycle noise. A command code outside the configured set is a
// configuration mismatch, not a protocol violation.
property p_cmd_code_known;
@(posedge clk) disable iff (!rst_n)
cmd_valid |-> (cmd_code <= 4'd7);
endproperty
assert property (p_cmd_code_known)
else $error("boundary: command code outside the configured set");
// ---- IMPLICATION, and it cannot be an invariant: mon_resolved is
// meaningless when no transaction is being reported. An unresolved
// output is permitted; a monitor that is NEVER unresolved across a
// whole run is the §3 row-one case -- a component assuming a default.
// That cannot be asserted, so it is COVERED below instead.
property p_resolved_is_boolean;
@(posedge clk) disable iff (!rst_n)
mon_txn_valid |-> (mon_resolved inside {1'b0, 1'b1});
endproperty
assert property (p_resolved_is_boolean)
else $error("boundary: resolution flag neither 0 nor 1");
// ---- 27.2 §7: publish the antecedents so a silent pass is
// distinguishable from a property that never armed. Without these
// the twelve asserts above are 78.53%-style vacuity risks.
cover property (@(posedge clk) disable iff (!rst_n) cmd_valid);
cover property (@(posedge clk) disable iff (!rst_n) rsp_valid);
cover property (@(posedge clk) disable iff (!rst_n) mon_txn_valid);
cover property (@(posedge clk) disable iff (!rst_n) cfg_locked);
cover property (@(posedge clk) disable iff (!rst_n) vip_drives);
cover property (@(posedge clk) disable iff (!rst_n) env_drives);
// ---- §3, row one, as coverage rather than assertion: a monitor
// that reports UNRESOLVED at least once has the three-valued
// concept. One that never does may simply never have needed it --
// which is why this is a cover and not an assert.
cover property (@(posedge clk) disable iff (!rst_n)
mon_txn_valid && !mon_resolved);
cover property (@(posedge clk) disable iff (!rst_n)
mon_txn_valid && mon_resolved);
// ---- §8: traffic under a locked configuration, which is the only
// configuration state in which a derived timing figure is sound.
cover property (@(posedge clk) disable iff (!rst_n)
cmd_valid && cfg_locked);
// ---- §6: the passive mode actually exercised.
cover property (@(posedge clk) disable iff (!rst_n)
(VIP_ACTIVE == 0) && cmd_valid && env_drives);
// ---- §8's ECC row reached at all.
cover property (@(posedge clk) disable iff (!rst_n)
(ECC_ENABLED == 1) && rsp_valid);
// ---- And a response arriving with no error, so the error path's
// silence is distinguishable from an absent error path.
cover property (@(posedge clk) disable iff (!rst_n)
rsp_valid && !rsp_error);
endmoduleTwelve properties and twelve covers, and the pairing is the point. Chapter 27.2 measured 662 of 843 named properties in this curriculum as implications — 78.53% vacuity-exposed — and its remedy was publishing antecedent counts. A boundary check with no covers would be a silent pass that proves the VIP was never connected.
Only one of the twelve is an invariant, and that is worth stating plainly rather than glossing. p_never_both_drive holds at every cycle, so it has no antecedent to fail to arm — it belongs to the 21.47% of 27.2's census that is structurally immune to vacuity. The other eleven are implications and cannot be anything else, because the signals they constrain are don't-care when their antecedent is low: an ungated claim about cmd_code or mon_resolved would fire on idle-cycle values that mean nothing. So this set is 91.7% vacuity-exposed — worse than the curriculum's 78.53% — and the twelve cover statements are the only thing standing between it and §15's report (A).
And the resolution-flag question is a cover, not an assert. §3's first row cannot be asserted: a monitor that never reports unresolved may have no such concept, or may simply never have needed it. The two covers distinguish them over a run, which is the honest instrument for a question with no single-cycle answer.
12. The Cross-Check
// ---------------------------------------------------------------------
// vip_cross_check -- compares your monitor against theirs, and
// reports the SHARED INPUTS beside the agreement rate.
//
// CLASSIFICATION: educational, SIMULATION-ONLY.
//
// WHY THE SHARED INPUTS ARE PART OF THE RESULT (§9): two independent
// models agreeing is evidence; two models with a shared input
// agreeing is not. An agreement rate published alone invites exactly
// the inference §9 exists to refuse.
//
// WHAT IT DOES NOT MODEL:
// - either monitor's internals
//
// WHAT IT WOULD MISS:
// - every divergence both monitors make identically. A shared
// misreading of a spec clause produces perfect agreement, and
// all this class can do is report that the clause is shared.
// ---------------------------------------------------------------------
class vip_cross_check extends uvm_component;
`uvm_component_utils(vip_cross_check)
protected int m_compared;
protected int m_agreed;
protected int m_diverged;
protected int m_ours_only;
protected int m_theirs_only;
// §9's table, recorded rather than assumed.
protected string m_shared_input[$];
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void note_shared_input(string what);
if (what == "") begin
`uvm_error("XCHK", "a shared input must be named")
return;
end
foreach (m_shared_input[i]) if (m_shared_input[i] == what) return;
m_shared_input.push_back(what);
endfunction
// Compare one pair of observations. 27.3 §6: a field either
// monitor could not resolve is NOT a divergence -- it is an
// absence of evidence, and counting it either way is wrong.
function void compare(bit ours_valid, bit theirs_valid,
bit ours_resolved, bit theirs_resolved,
longint ours_addr, longint theirs_addr);
if (!ours_valid && !theirs_valid) return;
if (ours_valid && !theirs_valid) begin m_ours_only++; return; end
if (!ours_valid && theirs_valid) begin m_theirs_only++; return; end
// Both saw it. If either could not resolve the address, there is
// nothing to compare -- and this is NOT agreement.
if (!ours_resolved || !theirs_resolved) begin
m_compared++; // a comparison was attempted
return; // and neither agreed nor diverged
end
m_compared++;
if (ours_addr == theirs_addr) m_agreed++;
else begin
m_diverged++;
`uvm_error("XCHK", $sformatf(
"monitors disagree: ours %0h theirs %0h", ours_addr, theirs_addr))
end
endfunction
function int compared(); return m_compared; endfunction
function int agreed(); return m_agreed; endfunction
function int diverged(); return m_diverged; endfunction
function int ours_only(); return m_ours_only; endfunction
function int theirs_only(); return m_theirs_only; endfunction
function int shared_inputs(); return m_shared_input.size(); endfunction
// Attempted comparisons that resolved to neither outcome. §9: this
// is the number that stops a high agreement rate from being read
// as a high confidence.
function int inconclusive();
int n = m_compared - m_agreed - m_diverged;
return (n < 0) ? 0 : n;
endfunction
// §9: agreement is only evidence to the extent the inputs are
// independent. This is deliberately NOT a confidence figure.
function bit agreement_is_evidence();
if (m_compared == 0) return 0; // nothing compared
if (m_shared_input.size() != 0) return 0; // §9 -- correlated
return (m_diverged == 0);
endfunction
// One-sided observation is the more informative result: a
// transaction only one monitor saw is a finding about the other.
function bit one_sided_findings_present();
return (m_ours_only + m_theirs_only) > 0;
endfunction
function void report_phase(uvm_phase phase);
`uvm_info("XCHK", $sformatf(
"compared=%0d agreed=%0d diverged=%0d inconclusive=%0d ours_only=%0d theirs_only=%0d shared_inputs=%0d evidence=%0b",
m_compared, m_agreed, m_diverged, inconclusive(),
m_ours_only, m_theirs_only, m_shared_input.size(),
agreement_is_evidence()), UVM_LOW)
foreach (m_shared_input[i])
`uvm_info("XCHK", $sformatf(" shared input: %s", m_shared_input[i]),
UVM_LOW)
endfunction
endclassagreement_is_evidence() returns false the moment any shared input is recorded, and that is the whole of §9 in one method. A perfect agreement rate between two components reading the same specification clause is not a confidence figure — and a method that returned one would be the instrument this chapter is warning against.
And an unresolvable field on either side is counted as neither agreement nor divergence. Chapter 27.3 §6 establishes that the third value is the absence of knowledge; folding it into the agreement count would inflate confidence with silence, which is the same error 27.4 §2 refuses for unchecked reads.
13. What to Delete and What to Keep
§1's table pairs every VIP component with the one this module built. So the integration forces seven decisions about duplication, and the tempting answer — delete yours, the VIP has one — is right for some rows and destroys the environment in others.
| Component | Keep yours? | Why |
|---|---|---|
| Bus-functional model | delete yours | never built here; no independence to lose |
| Monitor — 27.3 | keep, as a cross-check | §12 — the only instrument that can detect divergence |
| Reference model — 27.4 §10 | depends on §6's mode | with a memory-model VIP, keeping both verifies nothing |
| Scoreboard — 27.4 §12 | keep | its five totals are §3's row three and four judgements |
| Protocol checker — 27.2 §11 | keep | §5 — theirs is unenumerable, yours is known |
| Coverage model — 27.5 §12 | keep | §5's denominator is unaudited; yours is reviewed |
| Configuration object | share, and record it | §9 row two — sharing is right and correlating |
Row three is the only row whose answer is conditional, and §6 is why. With a passive VIP the device is your device, so two reference models are two independent predictions and keeping both is 27.4 §7's independence argument working as intended. With a memory-model VIP the device is the VIP — so your model and theirs are predicting each other, and the comparison has no subject.
Rows five and six are the ones an integration deletes and should not. A supplied checker is a lower bound you cannot measure (§5) and a supplied coverage model reports a number whose denominator nobody reviewed (27.5 §4). Replacing a known instrument with an unmeasurable one is a loss of information that presents as a simplification — which is the form every mistake in this chapter takes.
And row seven is the row with no clean answer. Sharing one configuration object is correct engineering and is also §9's second correlation. The resolution is not to duplicate it; it is to record the sharing, so the cross-check's agreement rate is read with the correlation visible.
// ---------------------------------------------------------------------
// vip_overlap_plan -- records the seven duplication decisions of this
// section and refuses the ones that leave no independent instrument.
//
// CLASSIFICATION: educational, SIMULATION-ONLY.
//
// WHY A COMPONENT AND NOT A CHECKLIST: the two refusals below are
// structural, not stylistic. Deleting your monitor removes §12's
// cross-check entirely, and deleting your reference model under a
// memory-model VIP leaves the VIP predicting itself. Both present as
// simplifications, which is the form every mistake in this chapter
// takes -- so they are refused rather than documented.
//
// WHAT IT DOES NOT MODEL:
// - any VIP, any implementation, or the cost of keeping a component
//
// WHAT IT WOULD MISS:
// - a decision recorded correctly and never implemented. This
// checks the PLAN; §15's report (A) is what an unimplemented
// plan looks like at the boundary.
// ---------------------------------------------------------------------
typedef enum { OWN_KEPT, // yours stays, as an instrument
OWN_DELETED, // yours goes, the VIP's is sole
OWN_SHARED // one object, used by both -- §9
} overlap_e;
typedef enum { VIP_PASSIVE, // §6: the device is your device
VIP_MEMORY, // §6: the device IS the VIP
VIP_CONTROLLER // §6: the host is the VIP
} vip_mode_e;
class vip_overlap_plan extends uvm_object;
`uvm_object_utils(vip_overlap_plan)
protected overlap_e m_decision[string];
protected string m_reason[string];
protected vip_mode_e m_mode;
protected bit m_mode_set;
function new(string name = "vip_overlap_plan");
super.new(name);
endfunction
function void set_mode(vip_mode_e mode);
m_mode = mode;
m_mode_set = 1;
endfunction
// Every decision carries its reason, for the same cause §10's
// record() demands a method: a decision nobody can justify is
// indistinguishable from one nobody made.
function bit decide(string component, overlap_e d, string reason);
if (!m_mode_set) begin
`uvm_error("OVERLAP", "the VIP mode must be set first -- §6")
return 0;
end
if (component == "" || reason == "") begin
`uvm_error("OVERLAP", "a decision needs a component and a reason")
return 0;
end
// REFUSAL 1 -- deleting your monitor removes §12's cross-check,
// and with it the only instrument that can detect a supplied
// component diverging from an independent observation.
if (component == "monitor" && d == OWN_DELETED) begin
`uvm_error("OVERLAP", $sformatf(
"refused: deleting your monitor removes the cross-check (§12)"))
return 0;
end
// REFUSAL 2 -- under a memory-model VIP, keeping BOTH reference
// models compares two predictions of each other. The device is
// the VIP, so there is no third party for either to be right
// about.
if (component == "ref_model" && d == OWN_KEPT
&& m_mode == VIP_MEMORY) begin
`uvm_error("OVERLAP", $sformatf(
"refused: two reference models with a memory-model VIP have no subject (§6)"))
return 0;
end
m_decision[component] = d;
m_reason[component] = reason;
return 1;
endfunction
function bit decided(string component);
return m_decision.exists(component);
endfunction
function int count_with(overlap_e d);
int n = 0;
foreach (m_decision[k]) if (m_decision[k] == d) n++;
return n;
endfunction
// §9 row two: a shared object is right AND correlating, so the
// plan reports how many shares exist rather than hiding them.
function int shared_count(); return count_with(OWN_SHARED); endfunction
// At least one instrument must remain yours, or §12 has nothing
// independent to compare against and the whole environment's
// findings come from components you did not write.
function bit independent_instrument_remains();
return count_with(OWN_KEPT) > 0;
endfunction
// The plan is complete only when all seven rows of this section's
// table have an answer. A missing row is an undecided duplication,
// which resolves itself by accident at integration time.
function bit complete(ref string missing[$]);
string rows[$] = '{"bfm", "monitor", "ref_model", "scoreboard",
"checker", "coverage", "config"};
missing.delete();
foreach (rows[i])
if (!m_decision.exists(rows[i])) missing.push_back(rows[i]);
return missing.size() == 0;
endfunction
function void report_phase(uvm_phase phase);
string missing[$];
void'(complete(missing));
`uvm_info("OVERLAP", $sformatf(
"mode_set=%0b kept=%0d deleted=%0d shared=%0d undecided=%0d independent=%0b",
m_mode_set, count_with(OWN_KEPT), count_with(OWN_DELETED),
shared_count(), missing.size(),
independent_instrument_remains()), UVM_LOW)
foreach (missing[i])
`uvm_warning("OVERLAP", $sformatf("undecided duplication: %s", missing[i]))
endfunction
endclassThe two refusals are structural rather than stylistic. Deleting your monitor is not a style choice — it removes §12's cross-check, and every finding in the environment then comes from components you did not write. Keeping both reference models under a memory-model VIP is not redundancy — it is two predictions of each other with no third party either can be right about.
And complete() reports undecided rows as warnings rather than deriving a default. An undecided duplication resolves itself at integration time by whichever component happened to get connected, which is the one way this plan can be followed exactly and still produce the wrong environment.
14. Corner Cases
| Case | Behaviour | Why |
|---|---|---|
| A capability declared but never determined | Stays CAP_UNKNOWN | §4 — the default must be honest |
| A status recorded with no method | Refused | §4 — an experiment nobody can describe was not run |
A status recorded with EV_NONE | Refused | §10 — a status without evidence is an assertion |
CAP_PROVIDED on documentation only | Recorded, not demonstrated | §5 — a datasheet is not a stimulus |
| Every capability provided, enumeration unreviewed | Report not supportable | 27.1 §5 — the enumeration problem |
| A checker silent on legal traffic | Proves nothing | §5, row two |
| A checker silent on an injected violation | That rule is absent or unreached | §5, row three — the only negative result |
| A passive VIP driving the bus | Assertion fires — p_mode_respected | §6 |
| Traffic before configuration | Assertion fires | §8 — the silent-wrong-geometry case |
| Configuration changed while locked | Assertion fires | §8 — derived figures go stale mid-test |
BANKS = 1 | Elaboration fails | $clog2(1) is 0; the index would be [-1:0] |
| A VIP configured slower than the device | No symptom — checking is weaker | §8 — the worst row |
| A VIP configured stricter | Fails legal traffic; investigated correctly | §8 — noisy and safe |
| Both monitors agree, one shared input | agreement_is_evidence() false | §9 — correlated |
| Both monitors agree, no shared input, none diverged | Evidence | §12 — the only configuration that is |
| A field neither monitor resolved | Counted inconclusive | 27.3 §6 — not agreement |
| A transaction only one monitor saw | A finding about the other | §12 — the more informative result |
| A memory-model VIP plus your own ref model | Verifies your model against theirs | §6 — the wrong result |
Row eleven is worth stating explicitly because it is a recurring hazard in this curriculum. A bare $clog2(BANKS) is zero at BANKS = 1, making cmd_bank a [-1:0] vector; a sibling guard in 24.3 once accepted both 0 and 1 for the same reason. §11's guard requires BANKS >= 2 rather than testing a property that both degenerate values satisfy.
15. DV — Testing the Integration
// SIMULATION-ONLY. Independent reference for §10's registry: a
// QUEUE of records scanned linearly rather than an associative array,
// so agreement between the two is evidence rather than a restatement.
class capability_reference;
typedef struct { string id; int status; int evidence; } rec_t;
rec_t recs[$];
function void declare(string id);
rec_t r; r.id = id; r.status = 2; r.evidence = 0; // 2 = UNKNOWN
recs.push_back(r);
endfunction
function bit record(string id, int status, int evidence, string how);
if (status != 2 && (how == "" || evidence == 0)) return 0;
foreach (recs[i])
if (recs[i].id == id) begin
recs[i].status = status; recs[i].evidence = evidence;
return 1;
end
return 0;
endfunction
function int count(int status);
int n = 0;
foreach (recs[i]) if (recs[i].status == status) n++;
return n;
endfunction
function int demonstrated();
int n = 0;
foreach (recs[i]) if (recs[i].status == 0 && recs[i].evidence == 2) n++;
return n;
endfunction
endclass| Check | What it establishes |
|---|---|
| Declare 40 capabilities in both; compare all counts | Two representations of one register |
| Record a status with no method in both | Both refuse |
Record a status with EV_NONE in both | Both refuse |
Record CAP_PROVIDED with EV_DOC | Counted provided, not demonstrated |
| Declare 40, determine 39 | integration_report_supportable() false |
| Determine all 40, skip the review flag | Still false — 27.1 §5 |
| Determine all 40 by document only | False — §5's demonstration requirement |
| Determine all 40 by experiment, review | Supportable — the only configuration that is |
Drive VIP_ACTIVE=0 and assert vip_drives | p_mode_respected fires |
Issue a command with cfg_valid low | p_config_before_traffic fires |
Toggle cfg_valid while cfg_locked | p_config_stable fires |
Drive cmd_bank = BANKS | p_bank_in_range fires |
Drive both vip_drives and env_drives | p_never_both_drive fires |
Elaborate with BANKS = 1 | $fatal at elaboration |
| Run with the VIP disconnected | All 12 asserts pass; all 12 covers empty |
| Cross-check with no shared input, no divergence | agreement_is_evidence() true |
| Record one shared input | Immediately false |
| Feed a field neither monitor resolved | inconclusive() rises; agreed() does not |
The fifteenth check is the report worth publishing, and it is this chapter's version of a suite that proves nothing:
TWO PASSING BOUNDARY REPORTS
(A) the VIP was never connected
stimulus : the environment runs; the VIP's interface is
present but nothing drives it
p_single_driver PASS
p_mode_respected PASS
p_config_before_traffic PASS
p_bank_in_range PASS
p_no_unsolicited_response PASS
p_resolution_flag_present PASS
p_monitor_observes PASS
... all 12 properties PASS
--------------------------------------------
cover cmd_valid 0 hits
cover rsp_valid 0 hits
cover mon_txn_valid 0 hits
cover cfg_locked 0 hits
eleven of the twelve properties are implications, so with no
command they never arm. 27.2's census put 78.53% of this
curriculum's properties in that category, and this is what
that number looks like when the antecedent is absent
entirely. The single INVARIANT also passes, correctly -- there
was no contention because there was no traffic.
(B) the VIP was connected and the integration is still blind
stimulus : full random traffic, VIP passive, all 12 covers hit
all 12 properties PASS
all 12 covers HIT
--------------------------------------------
cover mon_txn_valid && !mon_resolved 0 hits
cover mon_txn_valid && mon_resolved 2,041,883 hits
every boundary check passes and every antecedent armed. And
the VIP's monitor reported RESOLVED on every one of two
million transactions -- which is either a monitor that never
needed the third value, or §3 row one: a component that
assumes a default and reports a confident wrong answer.
27.3 §6 says those are not equivalent, and the boundary
cannot tell them apart.
diagnosis : (A) is the vacuity case -- the covers are the only
thing separating a passing boundary from an unconnected one.
(B) is §3: the covers all hit, and the ONE cover that would
have distinguished a three-valued monitor from a defaulting
one is empty.
the fix : (A) needs the covers read, not just the asserts. (B)
needs §4's row-two experiment -- attach the VIP mid-traffic and
see what it reports for the first access. That is a stimulus
question, and no property at the boundary can answer it.16. Debugging
| Symptom | Likely cause | How to confirm |
|---|---|---|
| Everything passes, nothing was tested | The VIP is not connected — report (A) | The twelve covers' hit counts |
| Checking weaker than expected | A slower speed grade configured — §8 | Compare the configured timing set against the device's |
| Address aliasing under a sweep | Geometry mismatch — §8 row one | p_bank_in_range; sweep beyond the modelled size |
| Legal traffic failing | Configured stricter than the device — §8 | The inverse of the row above; noisy and safe |
| A resolution flag always set | §3 row one, or genuinely never needed | The !mon_resolved cover; §4's row-two experiment |
| Two models agree perfectly | Possibly a shared input — §9 | shared_inputs(); agreement_is_evidence() |
| Your reference model validated, device not | Memory-model VIP plus your own model — §6 | Ask what drove the bus |
| A rule you expected checked is silent | §5 rows two and four | Inject the violation; silence then means absent |
| Integration report not supportable | Unknowns, or unreviewed enumeration | residual()'s four numbers |
Elaboration fails at BANKS | The BANKS >= 2 guard — §11 | The $fatal message |
| Agreement rate high, confidence low | Inconclusive comparisons — §12 | inconclusive() against compared() |
Row eight has no instrument and cannot have one. §5's asymmetry is total: a silent checker is consistent with the rule being implemented, unreached, or absent — and distinguishing them requires the rule list that 27.1 could not obtain.
17. Misconceptions
“Integrating a VIP is about connecting it.” §2. Connection fails at elaboration and is therefore cheap. What it reports and what it does not never fails at all.
“A VIP saves you from understanding the protocol.” §3. It relocates four judgements about what to report — and in each case the cheaper implementation is the one that destroys the measurement.
“You can read the documentation to learn what it checks.” §5. A checker's rule list is unenumerable from outside, exactly as 27.1 found for JEDEC's. Documentation is evidence, not demonstration.
“A silent checker means the traffic was legal.” §5. It means the rule is implemented and satisfied, implemented and unreached, or absent. Only an injected violation distinguishes them.
“A VIP that claims compliance is compliant.” §5. That is 27.1 §3's unenumerated claim with a different author.
“Use the VIP's memory model and your own scoreboard.” §6. Then the device is the VIP, and you have verified that your reference model matches theirs.
“Sharing one configuration object is straightforwardly good.” §9. It removes a mismatch bug and guarantees a wrong geometry is wrong in both, which the cross-check cannot detect.
“Two models agreeing is strong evidence.” §9, §12. Only to the extent their inputs are independent. agreement_is_evidence() returns false the moment a shared input is recorded.
“A high agreement rate is a confidence figure.” §12. Not while comparisons are inconclusive — a field neither monitor resolved is not agreement.
“Configuring the VIP conservatively is over-cautious.” §8. Configured loose, it passes traffic your device would fail, silently. Configured strict, it fails legal traffic loudly. When unsure, strict.
“The boundary assertions prove the integration works.” §15, report (A). Eleven of the twelve are implications; with the VIP disconnected they never arm and all twelve pass.
18. Interview Reasoning
What is the hard part of integrating a DDR VIP? Not connection — that fails at elaboration. It is determining what the component reports and what it silently does not, because neither ever fails.
Name a reporting judgement a VIP author made for you. Whether a monitor reports an unresolvable state as unknown or assumes a default. Both produce a working monitor; only one is honest, and the cheaper one is the default-assuming version.
How do you find out what a VIP reports? By experiment, not documentation. Attach it mid-traffic and read the first access; issue overlapping writes to one address; read before writing and watch whether the pass count rises.
A VIP's checker is silent on your traffic. What have you learned? Nothing. Silence is consistent with the rule being implemented and satisfied, implemented and unreached, or absent.
What is the only negative result available about a checker? Injecting a violation and observing silence. That proves the rule is absent or unreached — and it requires already knowing which violation to inject.
Why is a memory-model VIP plus your own reference model a mistake? The VIP is then the device. Your scoreboard compares reads against your model, the data came from theirs, and you have verified that two models agree.
When is agreement between two models evidence? When their inputs are independent. Sharing a specification document, a configuration object, or an interpretation of an ambiguous clause makes agreement expected rather than informative.
Which configuration error is most dangerous and why? A speed grade slower than the device. The VIP's checker then enforces looser minimums, so it passes traffic that violates the real timing — with no symptom at all.
Your boundary assertions all pass. What do you check next? The cover statements. Eleven of the twelve boundary properties are implications, so a disconnected VIP passes every assertion and hits no cover.
What can you never establish about a supplied checker? An upper bound on what it checks. Every experiment gives a lower bound, and the enumeration needed for an upper bound is the thing that is unavailable.
19. Exercises
-
§3 lists four judgements with two viable answers each. Derive how many distinct reporting behaviours that permits, then say how many of them an integration test could distinguish.
-
§4's table has three experimental rows. Write the stimulus for one of them precisely enough that a colleague could run it, and state the result that would distinguish the two answers.
-
§5 argues a checker's rule list is unenumerable. Construct the strongest bound you could establish with a month of effort, and say what it still does not license.
-
§8's second row has no symptom. Design the check that would detect a slower-than-device speed grade, and state where it has to live.
-
§9 lists four shared inputs. Rank them by how hard a shared error would be to detect, and justify the ranking with the detection method for each.
-
§11's set has twelve properties and twelve covers. Remove the covers and describe precisely which of §15's two reports becomes indistinguishable from success.
-
§12's
agreement_is_evidence()returns false whenever a shared input exists. Argue for and against softening this to a warning, then decide. -
A colleague proposes deleting 27.3's monitor because the VIP has one. Identify what §7's diagram loses, and state the class of bug that becomes undetectable.
20. Where This Goes
A DDR VIP is the seven components of a verification environment with the boundary drawn around them instead of through them. Connection is mechanical and fails loudly; what a supplied component reports is determinable by experiment; what its checker implements is unenumerable from outside; the configuration surface is the whole of your influence and its worst errors are silent; and agreement between a supplied model and your own is evidence only to the extent their inputs are independent.
Four results carry forward. The four judgements of §3 each have a cheaper wrong answer, which is a real argument about which is more common. AT_MIN for a checker is the injected violation — the only negative result about a supplied checker, and it needs the rule list nobody has. When unsure, configure strict, the same asymmetry 27.5 §6 established for illegal_bins. And an agreement rate with no shared-input list is not a confidence figure.
Two things stay open. The rule list remains unavailable, so every statement here about a supplied checker is a lower bound — 27.1's residual in a second setting. And the always-resolved monitor of §15's report (B) cannot be diagnosed at the boundary: a component that never needed the third value and one that assumes a default are identical at the pins, and separating them takes a stimulus experiment rather than a property.
Six chapters have now produced parts: an obligation, a property set, a monitor, a scoreboard, a coverage model, and an integration contract. Nothing has said how they go together.
Chapter 27.7 takes that up, and the DDR-specific answer is not one agent. The UVM track owns agent-architecture and multi-agent-systems — what an agent is, when to make it active or passive, how several coordinate. What it does not cover is that a DDR environment has at least three interfaces that are not variations of each other: a host-side request interface where transactions have addresses and ordering, a DDR-side command interface where there are only pins and timing, and a sideband interface that is a different protocol entirely. They do not share a clock, a transaction, or a notion of what a failure is — and 27.4 §6's cross-bank gap, left unowned by every chapter since, finally needs a component.
Continue learning
Related tutorials
- Related topic
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.
- 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
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.
