Part 10 · Advanced Topics · Intermediate

Compatibility Layer: What It Preserves and What It Hides

How compatibility wrappers keep UVM 1.2 code running, and where strict-mode behavior exposes hidden debt.

The compatibility contract

Compatibility layers are not random helper piles; they are intentional bridges. Their job is to preserve productivity for existing code while the ecosystem converges on standardized naming and semantics.

The bridge usually includes alias methods, retained macros, and convenience wrappers. These features reduce immediate breakage, but they can also hide migration debt if teams never test strict mode.

diagram
Legend: [UVM] [ADV]

               Legacy 1.2-style calls
                        │
                        ▼
          +----------------------------------+
          | [ADV] compatibility wrappers     |
          |  alias names, convenience APIs   |
          +----------------------------------+
                        │ forwards to
                        ▼
          +----------------------------------+
          | [UVM] IEEE-oriented core API     |
          +----------------------------------+
  • Compatibility is a transition mechanism, not a permanent architecture goal.

  • Strict mode intentionally removes or tightens parts of this bridge.

  • Run both modes to distinguish breakage from genuine DUT/testbench issues.


Strict vs compatibility mode behaviors

Many teams only validate one simulator default mode and assume they are portable. A better approach is explicit mode control in every CI job so behavior differences become deterministic and reviewable.

diagram
[UVM] mode behavior matrix

  Area                     Compatibility mode                  Strict mode
  --------------------------------------------------------------------------------
  Legacy aliases           Usually accepted                    Often rejected
  Deprecated helpers       Usually present                     May warn/error
  Diagnostics              Familiar 1.2 style                 Standard-focused wording
  Migration signal         Low (debt hidden)                  High (debt exposed)
  Portability confidence   Medium                             High when passing
bash
# Pseudo flow for CI (vendor flags differ by simulator)
# lane A: permissive compatibility
make sim MODE=compat TEST=smoke

# lane B: strict 1800.2 expectations
make sim MODE=strict TEST=smoke
  • Keep testlists identical between lanes to isolate mode effects.

  • Collect mode-specific log signatures to simplify triage ownership.

  • Avoid debugging functional failures until mode-mismatch failures are classified.


Compatibility anti-patterns

Compatibility makes short-term delivery easier, which can unintentionally create long-term debt. The most common anti-pattern is new code adopting old helper calls because they are still accepted.

  1. Copying old examples that rely on alias APIs into new VIP.

  2. Using permissive mode in all lanes because strict mode is noisy.

  3. Treating strict failures as tooling defects without root-cause labeling.

  4. Refactoring only failing files while allowing unaffected files to retain legacy style.

diagram
[ADV] debt growth curve

  Quarter  Strict failures   New legacy callsites added   Net migration progress
  -------------------------------------------------------------------------------
  Q1       120               85                           negative
  Q2       90                70                           near-zero
  Q3       55                15                           positive
  Q4       18                3                            strong positive

  Interpretation:
    Reducing failures is not enough if new debt keeps landing.

Hardening strategy for compatibility usage

The safest strategy is two-speed governance: legacy code can pass through controlled migration queues, but new code must be strict-clean from day one. This stops debt growth while existing debt is retired.

systemverilog
// Example policy helper: fail fast in strict-only branch
function void pre_run_policy_check();
  if ($test$plusargs("STRICT_1800_2_REQUIRED")) begin
    // Project-specific policy hooks, e.g. check forbidden macros list
    `uvm_info("POLICY", "strict policy enabled", UVM_LOW)
  end
endfunction
diagram
[UVM] policy checklist

  New file policy:
    - must pass strict lane
    - must avoid compatibility-only aliases
    - must include migration-safe reporting/factory usage

  Legacy file policy:
    - allowed in compat lane
    - strict failures tracked with owner + ETA
    - touched lines converted opportunistically

Key takeaways

  • Compatibility layers should buy time, not define your end state.

  • Dual-lane CI (compat + strict) turns hidden debt into actionable work.

  • Stop debt growth by requiring strict-clean standards for new code.

Common pitfalls

  • Leaving strict mode disabled because initial failure volume is high.

  • Allowing copy-paste of compatibility-only patterns into new modules.

  • Tracking migration as anecdotes instead of lane metrics.