Skip to content
VLSI Mentor

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.

ComponentWhat it doesThis module's version
Bus-functional modeldrives or responds on the DDR interfacenot built here — the UVM track's driver
Monitorreconstructs transactions from pins27.3
Reference modelholds what should be at each address27.4 §10
Scoreboardcompares observed against expected27.4 §12
Protocol checkerasserts the timing and legality rules27.2 §11
Coverage modelrecords which situations occurred27.5 §12
Configuration objectspeed grade, geometry, timing set27.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 stepEffortWhere it goes wrong
Bind the interfacemechanicalnaming and direction, caught at elaboration
Build the configuration objectmechanical§8 — silently wrong values
Connect analysis portsmechanicalnothing
Set the operating modesmall§6 — the wrong side gets tested
Determine what it reportsunbounded§4, §5 — the subject of this chapter
Determine what it does notunbounded§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.

JudgementThis module's answerThe other answer, which also works
A monitor's unresolvable state — 27.3 §6three-valued: report unknownassume a default and report a value
A scoreboard's ambiguous expectation — 27.4 §3a set, compared by membershipmodel the controller's ordering; compare exactly
A read with no expected value — 27.4 §2a third outcome, counted apartfold it into passes
A coverage denominator — 27.5 §4four numbers, no percentageone 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 necessaryHow to determine it
Per-field resolution state on a transactionInspect the transaction class — is there such a field at all?
Behaviour when a monitor attaches mid-trafficStart the VIP late; read what it reports for the first access
Whether an ambiguous expectation is a setIssue overlapping writes to one address; see if it errors
Whether unchecked reads are counted apartRead before writing; see whether the pass count rises
Whether its coverage denominator excludes unreachable binsRead the model's bin count against §4 of 27.5
Whether its properties report antecedent counts27.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 observeWhat it proves
The checker fires on a violation you injectedthat rule is implemented
The checker is silent on legal trafficnothing
The checker is silent on a violation you injectedthat rule is absent or unreached
The checker is silent on traffic you did not shapenothing 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.

ModeThe VIP isUnder test isWhat it can check
Memory model (reactive)the deviceyour controllercommand legality, timing, refresh obligations
Controller (active)the hostyour device or PHYdevice response, data return, training
Passive monitor onlyan observerwhatever drives the busprotocol 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

A DDR verification IP at its integration boundary, in four rows. The top row holds your environment, the VIP boundary itself, your design under test, and the configuration surface. The second row holds the four components inside the boundary that this module built on its own: their monitor, their reference model, their coverage model, and their assertions. The third row separates what those components report from what they do not report, and places your own monitor from chapter 27.3 alongside as the independent instrument. The bottom row is the cross-check that compares your monitor against theirs, which is the only procedure that can detect a component agreeing with you for a shared reason rather than an independent one. Edges run from your environment, your design and the configuration surface into the VIP boundary; from the boundary into each of the four internal components; from their monitor, coverage and assertions into what is reported; from their reference model and coverage into what is not reported; and from what is reported, what is not, and your own monitor into the cross-check.Your environmentsequences, testsVIP boundarythe line you cannot seepastYour DUTcontroller, device or PHY— §6Config surfacegeometry, timing set — §8Their monitor27.3's job, theirjudgementTheir ref model27.4's job, theirjudgementTheir coverage27.5's job, theirdenominatorTheir assertions27.2's job, unenumerable— §5What they reportdeterminable byexperiment — §4What they don'tthe four judgements — §3Your monitor27.3 — the independentoneCross-checkagreement is not evidence— §1112

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 itemWrong value's symptomWhy it is dangerous
Geometry — banks, rows, columnsoften nonethe VIP models a different device; addresses alias
Speed grade / timing setoften noneits checker enforces different minimums
Burst lengthusually loudmismatched data phases fail quickly
Refresh modenone for a short testModule 15's obligations differ
Command timing (1N / 2N)none27.5 §8AT_MIN becomes unreachable
On-die ECC enablednone, ever25.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 inputWhy it correlatesConsequence of a shared error
The same specification documentboth authors read the same textboth implement the same misreading
The same configuration object§8 — one source of geometry and timingboth model the wrong device identically
The same interpretation of an ambiguitya spec's unclear clause has a conventional readingboth take the conventional reading
Your DUT's own behaviourif either was tuned against itagreement 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

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// 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
endclass

record() 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

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// 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);
endmodule

Twelve 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

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// 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
endclass

agreement_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.

ComponentKeep yours?Why
Bus-functional modeldelete yoursnever built here; no independence to lose
Monitor — 27.3keep, as a cross-check§12 — the only instrument that can detect divergence
Reference model — 27.4 §10depends on §6's modewith a memory-model VIP, keeping both verifies nothing
Scoreboard — 27.4 §12keepits five totals are §3's row three and four judgements
Protocol checker — 27.2 §11keep§5 — theirs is unenumerable, yours is known
Coverage model — 27.5 §12keep§5's denominator is unaudited; yours is reviewed
Configuration objectshare, 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.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------
// 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
endclass

The 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

CaseBehaviourWhy
A capability declared but never determinedStays CAP_UNKNOWN§4 — the default must be honest
A status recorded with no methodRefused§4 — an experiment nobody can describe was not run
A status recorded with EV_NONERefused§10 — a status without evidence is an assertion
CAP_PROVIDED on documentation onlyRecorded, not demonstrated§5 — a datasheet is not a stimulus
Every capability provided, enumeration unreviewedReport not supportable27.1 §5 — the enumeration problem
A checker silent on legal trafficProves nothing§5, row two
A checker silent on an injected violationThat rule is absent or unreached§5, row three — the only negative result
A passive VIP driving the busAssertion fires — p_mode_respected§6
Traffic before configurationAssertion fires§8 — the silent-wrong-geometry case
Configuration changed while lockedAssertion fires§8 — derived figures go stale mid-test
BANKS = 1Elaboration fails$clog2(1) is 0; the index would be [-1:0]
A VIP configured slower than the deviceNo symptom — checking is weaker§8 — the worst row
A VIP configured stricterFails legal traffic; investigated correctly§8 — noisy and safe
Both monitors agree, one shared inputagreement_is_evidence() false§9 — correlated
Both monitors agree, no shared input, none divergedEvidence§12 — the only configuration that is
A field neither monitor resolvedCounted inconclusive27.3 §6 — not agreement
A transaction only one monitor sawA finding about the other§12 — the more informative result
A memory-model VIP plus your own ref modelVerifies 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

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 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
CheckWhat it establishes
Declare 40 capabilities in both; compare all countsTwo representations of one register
Record a status with no method in bothBoth refuse
Record a status with EV_NONE in bothBoth refuse
Record CAP_PROVIDED with EV_DOCCounted provided, not demonstrated
Declare 40, determine 39integration_report_supportable() false
Determine all 40, skip the review flagStill false — 27.1 §5
Determine all 40 by document onlyFalse — §5's demonstration requirement
Determine all 40 by experiment, reviewSupportable — the only configuration that is
Drive VIP_ACTIVE=0 and assert vip_drivesp_mode_respected fires
Issue a command with cfg_valid lowp_config_before_traffic fires
Toggle cfg_valid while cfg_lockedp_config_stable fires
Drive cmd_bank = BANKSp_bank_in_range fires
Drive both vip_drives and env_drivesp_never_both_drive fires
Elaborate with BANKS = 1$fatal at elaboration
Run with the VIP disconnectedAll 12 asserts pass; all 12 covers empty
Cross-check with no shared input, no divergenceagreement_is_evidence() true
Record one shared inputImmediately false
Feed a field neither monitor resolvedinconclusive() 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  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

SymptomLikely causeHow to confirm
Everything passes, nothing was testedThe VIP is not connected — report (A)The twelve covers' hit counts
Checking weaker than expectedA slower speed grade configured — §8Compare the configured timing set against the device's
Address aliasing under a sweepGeometry mismatch — §8 row onep_bank_in_range; sweep beyond the modelled size
Legal traffic failingConfigured stricter than the device — §8The inverse of the row above; noisy and safe
A resolution flag always set§3 row one, or genuinely never neededThe !mon_resolved cover; §4's row-two experiment
Two models agree perfectlyPossibly a shared input — §9shared_inputs(); agreement_is_evidence()
Your reference model validated, device notMemory-model VIP plus your own model — §6Ask what drove the bus
A rule you expected checked is silent§5 rows two and fourInject the violation; silence then means absent
Integration report not supportableUnknowns, or unreviewed enumerationresidual()'s four numbers
Elaboration fails at BANKSThe BANKS >= 2 guard — §11The $fatal message
Agreement rate high, confidence lowInconclusive comparisons — §12inconclusive() 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

  1. §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.

  2. §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.

  3. §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.

  4. §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.

  5. §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.

  6. §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.

  7. §12's agreement_is_evidence() returns false whenever a shared input exists. Argue for and against softening this to a warning, then decide.

  8. 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

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.