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
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
    • Callbacks, Command Line, Seeds and Versions
      • Callbacks Done Right
      • The Command Line in Full
      • Random Stability and Seeds
      • UVM 1.2 to IEEE 1800.2: The Delta Table
      • Performance at Scale
    • Synchronisation and Reporting
    • Testbenches at Scale
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

‹Callbacks, Command Line, Seeds and Versions
  1. Topics
  2. UVM Verification
  3. Advanced UVM in Practice
  4. Callbacks, Command Line, Seeds and Versions
  5. UVM 1.2 to IEEE 1800.2: The Delta Table

Part 10 · Advanced Topics · Intermediate

UVM 1.2 to IEEE 1800.2: The Delta Table

A concrete table of API and behaviour differences between UVM 1.2 and IEEE 1800.2 as implemented by the 2020.3 reference library, compile probes, the silent deltas, version macros and migration switches, and how to write code that compiles on both.

On this page

    A VIP moves from UVM 1.2 to a 1800.2 library. It compiles on the first try, the regression is green, and the team relaxes. Three months later a register test that used to fail on a slave error passes, and a sequence that used to report a response-queue overflow is silent. Nothing broke the compile; the library changed what the same code does. Which differences stop the compile, which change behaviour without a word, and how do you write code that cannot be caught by either?

    Three things called UVM

    UVM 1.2 (2014) is an Accellera library: code. IEEE 1800.2 (2017, revised 2020) is a standard: a document that defines the API and ships no code. Reference libraries implement the standard: Accellera's 2020.3 line, which this course runs (Accellera:1800.2:UVM:2020.3.2), and the libraries simulator vendors ship. The overview, with the history, is in UVM 1.2 vs IEEE 1800.2 at a glance; this lesson is the detailed table.

    Think of a rulebook's new edition and a publisher's printing of it. The edition dropped some old rules. The publisher kept many of them in an appendix so old games still work, and marked them "for compatibility". If you learn from that printing, old habits keep working, until you play with someone who has a different printing. The 2020.3 library's appendix is large: its source carries 155 @uvm-compat marks, API kept for 1.2 or 1.1d code that the standard does not define.

    The layers

    Flowchart: UVM 1.2 leads to the IEEE 1800.2-2017 standard, then the 2020 standard, which is implemented by Accellera's 2020.3 reference library and by vendor libraries. The reference library adds @uvm-compat API and a separate uvm_compat_pkg.
    The standard removed the API that 1.2 had deprecated. The reference library put much of it back, marked @uvm-compat, and ships a separate compatibility package for the changes that could not coexist. Vendor libraries make their own choices.

    The delta table

    Every "2020.3 library" entry was checked in the library source, and the compile column by probe files compiled against it with Verilator.

    API

    UVM 1.2

    2020.3 library (IEEE 1800.2)

    Portable code

    starting_phase field

    Deprecated

    Not in the standard; kept as @uvm-compat (compiles)

    get_starting_phase(), or set_automatic_phase_objection(1) plus set_starting_phase(phase)

    uvm_top variable

    Documented

    Kept as @uvm-compat (compiles)

    uvm_root::get() or uvm_coreservice_t::get().get_root()

    Global factory variable

    Deprecated

    Gone: Can't find definition of scope/variable: 'factory'

    uvm_factory::get() or cs.get_factory()

    set_config_int/string/object, get_config_*

    Deprecated

    Not in the standard; kept as @uvm-compat (compiles)

    uvm_config_db#(T)::set/get

    uvm_test_done, global_stop_request()

    Deprecated

    Gone (only a compat uvm_test_done_objection class remains)

    Phase objections; phase_ready_to_end for drain

    uvm_sequence_base, uvm_sequence instances

    Concrete classes

    Abstract: Illegal to call 'new' using an abstract virtual class

    Extend them; uvm_compat_proxy_sequence if code needs an instance

    Abstract registration

    None

    uvm_object_abstract_utils, uvm_component_abstract_utils

    Only in 1800.2-only code

    uvm_do family

    uvm_do, uvm_do_with, uvm_do_on, uvm_do_pri...

    Standard: one uvm_do(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS) with defaults; the library still ships the old names from src/deprecated/macros

    start_item, randomize, finish_item

    Automatic config

    build() always calls apply_config_settings()

    Only if use_automatic_config() returns 1 (the default)

    Call super.build_phase(); override the hook only on purpose

    Response queue overflow

    UVM_ERROR

    Report starts disabled: overflowing responses are dropped silently

    item_done() with no argument, or get_response() per item; set_response_queue_error_report_disabled(0) works on both

    Bus error and the register mirror

    do_predict updates the mirror even on UVM_NOT_OK

    do_predict skips it and warns PREDICT_NOK

    Filter errored transfers in pre_predict or a custom predictor

    Big-endian register maps

    Endianness orders bus beats only

    Also byte-reverses each access (perform_accesses)

    Avoid big-endian maps, or test the byte order on your library

    Register door names

    uvm_path_e, UVM_DEFAULT_PATH, get_default_path()

    uvm_door_e, UVM_DEFAULT_DOOR, get_default_door(); old names compat

    The old names compile on both today

    Event callbacks

    uvm_event::add_callback()

    uvm_callbacks#(...)::add; add_callback kept as compat

    add_callback compiles on both

    Packer stream format

    1.2 layout

    Reworked; round trips hold but streams differ

    uvm_compat_pkg::uvm_compat_packer when bytes matter

    Field automation

    Field macros generate __m_uvm_field_automation

    Field macros generate __m_uvm_execute_field_op, called through do_execute_op(uvm_field_op) and the policy classes

    Hand-written do_copy/do_compare work on both

    Build it: code that compiles on both

    Most portable code is simply code that avoids the left column. Where a call really differs, guard it with the version macros. Accellera 1800.2 libraries define UVM_VERSION_POST_2017 (and the 2020.3 library UVM_VERSION_POST_2020_2_0 and later); UVM 1.2 defines neither.

    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
    // snippet: compiles on UVM 1.2 and IEEE 1800.2
    class dma_cfg_seq extends uvm_sequence #(apb_item);
      `uvm_object_utils(dma_cfg_seq)
      function new(string name = "dma_cfg_seq");
        super.new(name);
        set_automatic_phase_objection(1);          // instead of starting_phase in pre_body
        set_response_queue_error_report_disabled(0); // 1.2 name; the 2020 library keeps it, so both report overflows
      endfunction
      task body();
        apb_item it = apb_item::type_id::create("it");
        start_item(it);                            // instead of the uvm_do_with family
        if (!it.randomize() with { addr == LEN; write == 1; })
          `uvm_fatal("RAND", "apb_item randomize failed")
        finish_item(it);
      endtask
    endclass
    
    // In a component: the root and the factory without globals
    //   uvm_root::get().print_topology();
    //   uvm_factory::get().print();
    `ifdef UVM_VERSION_POST_2017
    //   1800.2-only code goes here, for example a component that returns 0 from use_automatic_config()
    `endif

    Watch it run: the compile probes

    Each line below is one small probe file compiled against the course's 2020.3.2 library. The probes that compile are the dangerous ones: they hide 1.2 habits that a stricter library would reject.

    Diagram
    compiles   uvm_top.print_topology();
    compiles   set_config_int("*", "x", 1);                         (in a component)
    compiles   if (starting_phase != null) starting_phase.raise_objection(this);
    compiles   `uvm_do_with(i, {a == 1;})
    compiles   uvm_path_e p = UVM_DEFAULT_PATH;
    compiles   e.add_callback(cb);
    fails      factory.print();            Can't find definition of scope/variable: 'factory'
    fails      uvm_test_done.raise_objection(null);  Can't find definition of scope/variable: 'uvm_test_done'
    fails      global_stop_request();      Can't find definition of task/function: 'global_stop_request'
    fails      uvm_sequence_base sb = new("sb");   Illegal to call 'new' using an abstract virtual class 'uvm_sequence_base'

    Migration switches: what they do on which library

    • UVM 1.2: +define+UVM_NO_DEPRECATED compiles the deprecated API out. Code that builds clean with it is on the path to 1800.2. This is the cheapest portability check you can run.

    • Earlier 1800.2 reference releases (2017-1.x): +define+UVM_ENABLE_DEPRECATED_API brought some old API back. In the 2020.3 kit that define appears only in a readme (src/deprecated/readme.important): the compatibility API is compiled unconditionally and marked @uvm-compat. On 2020.3, a clean compile proves nothing about portability.

    • The compatibility package, uvm_compat_pkg (shipped beside the 2020.3 library in compat/) supplies the 1.2 packer behaviour and a concrete proxy sequence for changes that could not coexist in uvm_pkg.

    A migration plan that holds up: compile against UVM 1.2 with UVM_NO_DEPRECATED and against the target 1800.2 library; grep for the left column of the table; then run the same seeds on both libraries and diff the logs. The diff finds the behaviour rows, which no compiler will.

    What breaks: the migration that deleted an error

    Take the hook's response-queue symptom. A driver calls item_done(rsp) for every write, but the write sequence never calls get_response(). On UVM 1.2, the ninth write overflows the default queue of 8 and the library reports UVM_ERROR, which a team usually notices and fixes. On the 2020 reference library the same overflow is dropped silently, because the report flag starts disabled. Migrating did not fix the bug; it removed the only message that pointed at it. If a later sequence does call get_response() for its read data, it can receive a stale write response and read the wrong value.

    The register row is the same kind of trap in reverse: a write that the slave answers with PSLVERR leaves the mirror changed on 1.2 and unchanged on 1800.2, so a mirror(UVM_CHECK) that failed on one library passes on the other. Both are on the fact sheet for a reason. The defence is the dual-library regression diff above, plus code that does not depend on either default: item_done() without an argument when the data travels in the request, and an explicit pre_predict filter when a bus error must not reach the mirror.

    Interview

    "You are porting a UVM 1.2 VIP to an IEEE 1800.2 library. What do you check?"

    A weak answer: "Fix the compile errors; 1800.2 is basically 1.2." The compile is the easy part, and on the 2020.3 library most 1.2 code compiles anyway.

    A strong answer: "Three passes. First, compile on 1.2 with UVM_NO_DEPRECATED and on the target library, and replace the removed API: the global factory, uvm_test_done and global_stop_request, new on uvm_sequence_base, plus starting_phase, set_config_* and the old uvm_do variants, which the reference library still accepts as compat but the standard does not define. Second, check the behaviour deltas by name: the response-queue overflow report, do_predict on UVM_NOT_OK, big-endian maps, use_automatic_config, packer streams. Third, run the same seeds on both libraries and diff the logs."

    Follow-ups: How do you make one source tree support both? (write to the common subset; guard the rest with ifdef UVM_VERSION_POST_2017) and why does starting_phase compile on your 2020 library but not on the vendor's? (it is @uvm-compat in the Accellera library, not part of the standard; vendors differ).

    Check yourself A team's VIP compiles cleanly on the Accellera 2020.3 library. They conclude it is 1800.2-compliant. What is wrong with that conclusion, and what would test it?

    The 2020.3 library compiles a large compatibility layer unconditionally (155 @uvm-compat marks), including starting_phase, set_config_*, uvm_top and the old uvm_do macros. A clean compile there says nothing about a stricter library. Compile on UVM 1.2 with UVM_NO_DEPRECATED defined, and grep for the API the standard does not define.

    Check yourself A register test writes a read-only register; the APB slave answers PSLVERR. On UVM 1.2 the next mirror(UVM_CHECK) reports a mismatch; on the 2020 library it does not. Which library is right?

    Both follow their own code. The stock predictor passes the transfer to do_predict in both; 1.2's do_predict updates the mirror regardless of status, so the model now holds the rejected value, while 1800.2's skips the update on UVM_NOT_OK and warns PREDICT_NOK. Decide what the mirror should do and make it explicit with a pre_predict filter, so the result does not depend on the library.

    Check yourself Code calls uvm_sequence_base seq = new("seq") to make a placeholder sequence for a start_item call. Why does it fail on the 2020 library, and what is the portable replacement?

    1800.2 made uvm_sequence_base and uvm_sequence abstract (virtual class), so new on them is illegal. Declare a small concrete subclass registered with uvm_object_utils, or use uvm_compat_pkg::uvm_compat_proxy_sequence on libraries that ship the compatibility package.

    Next: the library is settled; now make it fast. Performance at scale measures where a UVM bench spends its time.

    Related topics

    • UVM 1.2 vs IEEE 1800.2 at a glance

    • Sequences and objections

    • Responses and pipelined drivers

    • Prediction modes

    Previous

    172 / 280

    Next: Performance at Scale

    Up next

    Up nextPerformance at Scale

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Callbacks Done Right
    • The Command Line in Full