Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
  • Factory & Configuration15
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
    • Environment Architecture
      • The Environment and Its Config Object
      • Vertical Reuse: From Block to Subsystem
      • Integrating Third-Party VIP
      • Where the Virtual Sequencer Lives (and Whether You Need One)
    • Tests: Base Classes, Selection and Startup
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

‹Environment Architecture
  1. Topics
  2. UVM Verification
  3. Environment & Test Classes
  4. Environment Architecture
  5. Integrating Third-Party VIP

Part 7 · Environment & Tests · Intermediate

Integrating Third-Party VIP

Wrapping a commercial VIP agent: an adapter subscriber that turns its transactions into the bench's, mapping its configuration from the env config, demoting its noise with report catchers, version pinning, and what to ask the vendor, shown with the APB monitor standing in for vendor VIP.

On this page

    Your team has bought a commercial APB VIP. Its monitor publishes vnd_apb_txn, not the bench's apb_item, so dma_scoreboard cannot listen to it. Its configuration class has forty fields with names unlike yours. It prints a warning on every transfer because your APB has no PPROT signal, and the next release lands next quarter. Wire it in naively and the vendor's names spread into every test, the warning count becomes meaningless, and the upgrade touches fifty files. How do you integrate it so that none of that leaks?

    The idea: the VIP is a black box with three adapters

    Treat third-party VIP as a sealed component and put three small pieces of your own around it. A transaction adapter converts its transactions into yours, so your scoreboards never see the vendor's types. A config map translates your env config into its configuration, so tests never touch vendor fields. A message policy, built from report catchers or severity overrides, decides which of its messages count. Around all of it, compile isolation and a pinned version keep upgrades a one-file change.

    A travel power adapter is the picture. You do not rewire the hotel, and you do not open your laptop's charger. A small adapter between the two converts one plug shape into the other, and when you travel to a different country you change only the adapter.

    The picture

    Diagram: the env config is mapped into the vendor config; the vendor monitor's transactions go through an adapter subscriber that publishes apb_item to the scoreboard; the vendor's warnings pass through a report catcher to the report server.
    The VIP stays sealed. The env config is translated into the vendor's config; the vendor's transactions are converted into the bench's items by an adapter; its messages pass through a catcher before they are counted.

    Build it on the bench

    To make this concrete without a licence, the examples treat the bench's APB monitor as if a vendor had shipped it under the names vnd_apb_agent, vnd_apb_monitor, vnd_apb_txn and vnd_apb_cfg. Those names, and their fields, are invented; a real VIP's documentation gives you the real ones. The vendor transaction has its own field names and enums: kind (VND_READ, VND_WRITE), a 32-bit address, wdata, rdata and resp (VND_OKAY, VND_SLVERR).

    1. The transaction adapter

    A uvm_subscriber is a component with one analysis export and a write method you implement. Connect the vendor monitor's analysis port to it, convert each transaction into a fresh apb_item, and publish that on your own port. Your scoreboard connects to the adapter exactly as it would to your own monitor.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // snippet
    class apb_vip_adapter extends uvm_subscriber #(vnd_apb_txn);
      `uvm_component_utils(apb_vip_adapter)
      uvm_analysis_port #(apb_item) ap;
    
      function new(string name, uvm_component parent);
        super.new(name, parent);
        ap = new("ap", this);
      endfunction
    
      // Called by the vendor monitor. Convert at once into a new object; never keep t.
      function void write(vnd_apb_txn t);
        apb_item it = apb_item::type_id::create("it");
        it.addr   = t.address[7:0];
        it.write  = (t.kind == VND_WRITE);
        it.data   = t.wdata;
        it.rdata  = t.rdata;
        it.slverr = (t.resp == VND_SLVERR);
        ap.write(it);
      endfunction
    endclass
    
    // In the env's connect_phase:
    //   apb_vip.monitor.item_collected_port.connect(adapt.analysis_export);
    //   adapt.ap.connect(sb.apb_export);

    The adapter is also where you handle mismatches between the two models: a 32-bit vendor address cut to the bench's 8 bits, an error response mapped to slverr, or a vendor burst split into several of your items. Keep the conversion lossless for everything your checkers read, and document what is dropped.

    2. The config map

    One function in the env translates your env config into the vendor's configuration object, sets it where the vendor's documentation says the VIP will look for it, and is the only code in the bench that names vendor fields.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // snippet
    // In the env's build_phase, before creating the VIP agent.
    function void map_vip_cfg();
      vnd_apb_cfg vcfg = vnd_apb_cfg::type_id::create("vcfg");
      vcfg.is_master  = (cfg.apb_active == UVM_ACTIVE);   // our knob, their field
      vcfg.addr_width = 8;
      vcfg.has_pprot  = 0;                                // our APB has no PPROT
      uvm_config_db#(vnd_apb_cfg)::set(this, "apb_vip.*", "cfg", vcfg);
    endfunction

    Tests set cfg.apb_active, a field of your env config, and never see vnd_apb_cfg. If the vendor is replaced, or renames a field in a new release, this function and the adapter are the whole change.

    3. The message policy

    The first tool is the built-in one: set_report_severity_id_override(UVM_WARNING, "VND_APB_PPROT", UVM_INFO) on the vendor component turns one message ID into an info for that component. Use a report catcher when the decision depends on the message itself (only for one address, only before reset ends) or must span many components. A catcher is an object whose catch() method sees every message from the objects it is attached to, and may change it or swallow it.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // snippet
    class vnd_apb_demoter extends uvm_report_catcher;
      `uvm_object_utils(vnd_apb_demoter)
      int unsigned n_demoted;
    
      function new(string name = "vnd_apb_demoter");
        super.new(name);
      endfunction
    
      function action_e catch();
        if (get_severity() == UVM_WARNING && get_id() == "VND_APB_PPROT") begin
          set_severity(UVM_INFO);       // still in the log, no longer counted as a warning
          n_demoted++;
        end
        return THROW;                   // pass every message on; CAUGHT would drop it
      endfunction
    endclass
    
    // In the env's connect_phase, scoped to the vendor's monitor only:
    //   demoter = vnd_apb_demoter::type_id::create("demoter");
    //   uvm_report_cb::add(apb_vip.monitor, demoter);
    • Scope it. uvm_report_cb::add(obj, catcher) attaches to one object; add(null, catcher) attaches to every report object, and runs for every message in the simulation. A global catcher matching a common ID can silence your own components.

    • Demote, do not drop. Changing severity keeps the message in the log for the day it matters. Never demote errors from a VIP's protocol checker without a written waiver.

    • Count what you demote and print the count in report_phase, so a sudden jump is visible.

    4. Version pinning and compile isolation

    • Never edit vendor source. Workarounds go in the wrapper; bugs go to the vendor as tickets. An edited VIP cannot be upgraded.

    • Pin the version in one place, the path or manifest your compile scripts read, and record it in every log. If the vendor exports a version constant, check it in the env's build and fatal on a mismatch.

    • Compile it as its own package (often its own library), and prefix your own package and macro names. A vendor apb_pkg and yours cannot both exist; neither can two ` define APB_DATA_W ``.

    • Match the UVM version. A VIP delivered for UVM 1.2 and a bench on an IEEE 1800.2 library, or the reverse, is a compile matrix to check before the purchase, not after. Encrypted VIP also ties you to the simulator versions the vendor supports.

    5. What to ask the vendor

    Ask

    Why it matters

    Which UVM versions and simulators, and which releases of each?

    Your bench's library and tools must be on the list.

    Does the monitor publish a new object per transaction?

    If it reuses one, every subscriber must copy on write (see below).

    Does anything in the VIP raise objections?

    Monitors should not; a VIP that objects can hold your test open.

    What are the message IDs, and which are protocol errors?

    You need the list to write a message policy and waivers.

    Are protocol checks SVA or class code, and can each be disabled?

    Errors you inject on purpose must not fail the test.

    Active and passive modes, reset in mid-transfer, coverage model?

    Vertical reuse needs passive mode; reset tests need clean recovery.

    Source or encrypted, release cadence, compatibility policy?

    Decides how painful each upgrade will be.

    Watch it run

    This is a real run of the smoke test with a scratch variant of dma_env that adds the stand-in VIP monitor, the adapter, the demoter and a second scoreboard fed only through the adapter. The vendor monitor warns on every transfer because has_pprot is 0:

    Diagram
    adapt                    apb_vip_adapter         -     @338
          apb_vip                  vnd_apb_agent           -     @330
            monitor                vnd_apb_monitor         -     @580
          vip_sb                   dma_scoreboard          -     @364
    ...
    UVM_INFO dma_vip_demo_tb.sv(56) @ 75000: uvm_test_top.env.apb_vip.monitor [VND_APB_PPROT] PPROT not connected: assuming 3'b000
    ...
    UVM_INFO dma_tb.sv(411) @ 655000: uvm_test_top.env.sb [SB] 8 words matched, 0 mismatched
    UVM_INFO dma_tb.sv(411) @ 655000: uvm_test_top.env.vip_sb [SB] 8 words matched, 0 mismatched
    UVM_INFO dma_vip_demo_tb.sv(174) @ 655000: uvm_test_top.env [VIP] demoted 6 vendor warnings
    --- UVM Report catcher Summary ---
    Number of demoted UVM_WARNING reports:    6
    --- UVM Report Summary ---
    UVM_WARNING :    2
    UVM_ERROR :    0
    • vip_sb matched the same 8 words as the bench's own scoreboard, but learned KEY only through the vendor monitor and the adapter. The adapter is lossless for what the scoreboard reads.

    • The six VND_APB_PPROT messages appear as UVM_INFO. The library prints its own catcher summary, a useful audit line. Without the catcher the same run reports UVM_WARNING : 8; the 2 that remain come from the UVM library in this Verilator build.

    What breaks: the subscriber that kept the vendor's handle

    Some VIP monitors fill and publish one transaction object, over and over, which the stand-in monitor above also does. An engineer writes a quick coverage collector that stores the vendor's handles in a queue and samples them at the end of the test. In the same run, it reports this:

    Diagram
    UVM_INFO dma_vip_demo_tb.sv(119) @ 655000: uvm_test_top.env.store [STORE] 6 transfers stored, addresses: 04 04 04 04 04 04

    The bus really carried writes to 0C, 08 and 00, then accesses to 04. Every stored handle points to the same object, which holds the last transfer. The adapter is immune because it converts each transaction into a new apb_item inside write, before the monitor overwrites it. The fix for the collector is the same: copy or convert in write, never store the handle. And it goes on the vendor question list: a monitor that publishes a fresh object per transaction is the convention for a reason.

    Interview

    "You're integrating a vendor VIP into an existing environment. How do you do it?"

    A weak answer: "Instantiate their agent in the env and connect its monitor to the scoreboard." The scoreboard then depends on the vendor's types, and every test sooner or later sets vendor fields.

    A strong answer: "I wrap it. An adapter subscriber converts its transactions into ours, copying in write because some VIPs reuse one object, so our scoreboards and coverage are vendor-neutral. One config-map function translates our env config into theirs; tests never touch vendor fields. A message policy uses severity overrides or a scoped report catcher to demote known noise, and counts it. It compiles as its own package with our names prefixed, the version is pinned and logged, and nothing in the vendor tree is edited. Before buying I check UVM and simulator support, passive mode, objections, reset behaviour and the message-ID list."

    Follow-ups: Where would you put a workaround for a vendor bug? (in the wrapper or adapter, with a ticket number, never in vendor source). Catcher or set_report_severity_id_override? (the override for a fixed ID on a known component; a catcher when the decision depends on content or spans components).

    Check yourself The vendor's monitor reports read data in a field that is valid only for reads, and leaves garbage in it for writes. Where do you handle that, and why there?

    In the adapter: map rdata only when kind == VND_READ, and set it to 0 otherwise. The adapter is the one place that knows both models, so the bench's checkers keep seeing clean apb_items, and the quirk is documented next to the conversion instead of being rediscovered by every subscriber.

    Check yourself A colleague attaches the demoter with uvm_report_cb::add(null, demoter) to save a line. What is the risk?

    A null object attaches the catcher to every report object in the simulation, so it runs on every message and demotes any VND_APB_PPROT warning from anywhere, including a future component that reuses the ID for something real. Scoping it to the vendor monitor makes it cheap and makes its effect predictable.

    Next: the env now holds your agents and a vendor's. Something has to coordinate them, and Where the Virtual Sequencer Lives decides who owns the handles to their sequencers.

    Related topics

    • Where the Virtual Sequencer Lives

    • VIP versioning and delivery

    • Analysis connectivity patterns

    • Reporting and verbosity

    Previous

    117 / 280

    Next: Where the Virtual Sequencer Lives (and Whether You Need One)

    Up next

    Up nextWhere the Virtual Sequencer Lives (and Whether You Need One)

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The Environment and Its Config Object