Skip to content
VLSI Mentor

Wishbone · Module 26

UVM Concepts

You have already built a monitor, a reference model, a scoreboard and a coverage collector. UVM is a vocabulary for those roles — it supplies no protocol knowledge and no bins.

This chapter does not start UVM from the beginning. It starts from something you already have.

Chapters 26.1 through 26.5 built a complete verification environment: a protocol checker with activation counts, a passive monitor, an independent reference model, a scoreboard and a functional coverage model, all executing against a real Wishbone subsystem. UVM is a set of names and conventions for exactly those roles.

UVM does not make verification rigorous. The architecture does. What UVM supplies is a standard vocabulary, a standard component hierarchy, and reusable plumbing — so that the environment you built by hand can be assembled from parts other people recognise.

1. The Mapping

what you builtUVM namefile
the transaction recorduvm_sequence_itemwb_monitor.sv fields
the stimulus in tb_*.svuvm_sequencethe op() tasks
the request-driving logicuvm_driverwb_master_fsm + op()
wb_monitoruvm_monitorunchanged in role
driver + sequencer + monitor, bundleduvm_agent
wb_refmodel + wb_scoreboarduvm_scoreboard (+ predictor)unchanged in role
wb_coverageuvm_subscriberunchanged in role
wb_ver_envuvm_envunchanged in role
tb_env.svuvm_test

Nine rows, and eight of them are a rename. That is the honest summary of what this chapter has to teach.

The standard UVM component hierarchy applied to a Wishbone environment. A test instantiates an environment. The environment contains an agent, a scoreboard and a coverage subscriber. The agent contains a sequencer that supplies transaction items, a driver that converts them into Wishbone pin activity, and a monitor that passively observes the same pins and reconstructs transactions. The monitor publishes those transactions through an analysis port to both the scoreboard and the coverage subscriber, neither of which drives anything.sqruvm_sequencerdrvuvm_drivermonuvm_monitoragentuvm_agentsbuvm_scoreboardcovuvm_subscriberenvuvm_envtest_baseuvm_test

2. The Transaction Becomes A Class

Your monitor's fields, as a uvm_sequence_item:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── REPRESENTATIVE UVM CODE — NOT COMPILED IN THIS MODULE ───────────
// No UVM library or UVM-capable simulator is present in this
// environment. This is published as a mapping, not as evidence.
class wishbone_item extends uvm_sequence_item;
  rand bit [11:0] adr;
  rand bit [31:0] wdat;
  rand bit [3:0]  sel;
  rand bit        we;
       bit [31:0] rdat;
       term_e     term;   // ACK / ERR / RTY
       int        waits;

  `uvm_object_utils_begin(wishbone_item)
    `uvm_field_int(adr,  UVM_ALL_ON)
    `uvm_field_int(wdat, UVM_ALL_ON)
    `uvm_field_int(sel,  UVM_ALL_ON)
    `uvm_field_int(we,   UVM_ALL_ON)
  `uvm_object_utils_end
endclass

Compare that field list against the one you already wrote:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
//   adr    which location            sel    which byte lanes
//   we     direction                 wdat   what was written
//   rdat   what was read             term   ACK / ERR / RTY
//   waits  clocks presented unanswered - the endpoint's cost
//   seq    monotonic attempt number - makes ordering checkable

The same decisions, in a class instead of a port list. The hard part — deciding that term and waits must be carried — is done before UVM enters the picture.

3. The Monitor Keeps Its Rules

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── REPRESENTATIVE UVM CODE — NOT COMPILED IN THIS MODULE ───────────
class wishbone_monitor extends uvm_monitor;
  uvm_analysis_port #(wishbone_item) ap;

  task run_phase(uvm_phase phase);
    forever begin
      @(posedge vif.clk);
      // THE SAME RULE AS wb_monitor.sv: emit on the completion event,
      // never merely because STB is high.
      if (vif.cyc && vif.stb && (vif.ack || vif.err || vif.rty)) begin
        wishbone_item t = wishbone_item::type_id::create("t");
        t.adr  = vif.adr;
        t.rdat = vif.dat_i;          // qualified NOW - RULE 3.65
        t.term = vif.rty ? RTY : (vif.err ? ERR : ACK);
        ap.write(t);
      end
    end
  endtask
endclass

UVM does not know about RULE 3.60 or RULE 3.65. The emit condition and the sampling clock are exactly the decisions Chapter 26.3 made, and a UVM monitor written with if (vif.stb) duplicates transactions in precisely the same way — for precisely the same reason.

A UVM monitor publishing to multiple subscribers through one analysis port. The monitor reconstructs a transaction from pin activity and writes it to its analysis port. The port broadcasts to every connected subscriber independently: a scoreboard that compares against a prediction, and a coverage collector that records which situations were reached. Neither subscriber can affect the monitor or the design, and adding a subscriber requires no change to the monitor.monitorreconstructs txnanalysis_portwrite(txn)scoreboardanalysis_impcoverageanalysis_impap.write(txn)write()write()12

The analysis port is the one genuinely new idea in this chapter. Your environment wired the monitor's outputs to the scoreboard and the coverage collector by hand:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  wb_scoreboard #(.AW(AW),.DW(DW),.SW(SW)) u_sb (
    .obs_valid_i(t_valid),.obs_adr_i(t_adr),.obs_we_i(t_we),

An analysis port makes that one-to-many broadcast rather than point-to-point wiring, so a third subscriber costs nothing in the monitor.

4. Active And Passive Agents

agentcontainswhen
active mastersequencer + driver + monitoryou are generating the traffic
passivemonitor onlysomething else is generating it
active slavesequencer + driver + monitoryou are emulating a responder

Your environment has one of each in spirit. wb_master_fsm driven by op() is an active master agent; wb_vplan_checker, wb_monitor and wb_coverage are passive observers; and the register slave and memory are real RTL rather than emulated responders.

The passive distinction matters for a reason that is not about UVM: a passive agent can be attached to a design you did not write, in a system you do not control, without changing its behaviour. That is the same property Chapter 26.3 insisted on when it gave the monitor no outputs.

5. The Scoreboard Keeps Its Independence

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── REPRESENTATIVE UVM CODE — NOT COMPILED IN THIS MODULE ───────────
class wishbone_scoreboard extends uvm_scoreboard;
  `uvm_analysis_imp_decl(_obs)
  uvm_analysis_imp_obs #(wishbone_item, wishbone_scoreboard) obs_imp;

  function void write_obs(wishbone_item t);
    wishbone_item exp = predictor.predict(t);   // INDEPENDENT model
    if (t.term != exp.term)
      `uvm_error("SB", "termination class mismatch")
    else if (!t.we && (t.rdat !== exp.rdat))
      `uvm_error("SB", $sformatf("data: exp %0h got %0h", exp.rdat, t.rdat))
  endfunction
endclass

The independence rule survives the translation unchanged:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// A scoreboard whose expected value came from the DUT is asking the
// suspect to write its own alibi. Module 25 made that point about a DMA;
// here it is architecture.

UVM will happily let you write a scoreboard that reads DUT internals through a virtual interface. It has no opinion. The discipline is yours, and Chapter 26.4 showed what it buys: a design with zero protocol violations returning wrong data on four of nine transactions.

6. Coverage Becomes A Subscriber

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── REPRESENTATIVE UVM CODE — NOT COMPILED IN THIS MODULE ───────────
class wishbone_coverage extends uvm_subscriber #(wishbone_item);
  wishbone_item t;

  covergroup cg;
    op:     coverpoint t.we      { bins rd = {0}; bins wr = {1}; }
    term:   coverpoint t.term    { bins ack = {ACK}; bins err = {ERR};
                                   bins rty = {RTY}; }
    waitc:  coverpoint t.waits   { bins zero = {0}; bins short = {[1:3]};
                                   bins lng = {[4:$]}; }
    selc:   coverpoint t.sel     { bins full = {4'hF};
                                   bins partial = default; }
    op_x_wait:  cross op, waitc;
    wr_x_sel:   cross op, selc;
  endgroup

  function void write(wishbone_item t_in);
    t = t_in;
    cg.sample();
  endfunction
endclass

That is the same bin model Chapter 26.5 built as counters, expressed in the syntax a commercial tool understands. The dimensions, the crosses and the reasons for them are identical — and so is the hard part:

covergroup will compute a percentage for a bin model that excludes every interesting case. Choosing the bins, justifying the exclusions, and knowing that hitting a bin is not the same as being sensitive to its bug — none of that is supplied by the language.

7. What UVM Does Not Do

Correcting the misconceptions directly, against the evidence in this module:

claimwhat this module measured
"UVM is what makes verification rigorous"the rigour is in the architecture; UVM renames it
"UVM replaces assertions"it has no protocol knowledge at all — RULE 3.60 is still yours to write
"UVM replaces scoreboards"uvm_scoreboard is a base class, not a comparison
"UVM automatically provides functional coverage"covergroup is a language feature; the bins are yours
"a UVM monitor can emit whenever STB is high"it duplicates exactly as DUPLICATE_MONITOR did — 15 transactions for 5 completions
"UVM code is verified because it is UVM"verification code is software; Chapter 26.4's REF_IGNORES_SEL was a testbench bug with a DUT-bug symptom

8. Sequence To Pins, And Back

The one structural thing UVM adds that your hand-built environment did not have is a separation between deciding what to send and knowing how to send it.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
    sequence          "write 0x1122_3344 to offset 1, lane 1 only"
        ↓  sequence_item
    sequencer         arbitrates between sequences

    driver            drives CYC, STB, ADR, SEL, WE and holds them
        ↓             still until a termination arrives (RULE 3.60)
    Wishbone pins

    DUT

    monitor           reconstructs on the completion event
        ↓  analysis port
    scoreboard + coverage

In tb_env.sv those first three roles are one op() task plus wb_master_fsm:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  task automatic op(input logic we, input [AW-1:0] a,
                    input [DW-1:0] d, input [SW-1:0] s);

Splitting them buys reuse: the same driver serves any sequence, and the same sequence runs against any driver implementing the same item. It costs indirection, which is why a teaching environment is clearer without it and a production one is not.

The driver inherits an obligation the sequence knows nothing about. RULE 3.60 requires the request to be held still until answered — a sequence says what to transfer, and the driver is where "and do not move it while waiting" lives. A driver that re-drove its outputs from a fresh item each clock would reproduce Chapter 26.2's MOVING_REQUEST exactly.

9. Why The Analysis Port Is Not Just Wiring

Transaction-level communication between UVM components. A producer component publishes transaction objects through a port; a consumer component receives them through an implementation port. The connection carries whole transactions rather than individual signals, so the two components share no timing relationship and either can be replaced without changing the other.produceranalysis_portsubscriber Aanalysis_impsubscriber Banalysis_impsubscriber Canalysis_impwrite(txn)write(txn)write(txn)12

Your environment connected the monitor to the scoreboard with a bundle of signals:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
    .obs_valid_i(t_valid),.obs_adr_i(t_adr),.obs_we_i(t_we),
    .obs_rdat_i(t_rdat),.obs_term_i(t_term),

Adding the coverage collector meant adding another bundle. An analysis port makes that a broadcast — one publisher, any number of subscribers, none of which the publisher knows about. Adding a third consumer changes no existing code.

It also changes what is communicated: a transaction object rather than a set of concurrent signals, so the subscriber has no timing relationship with the monitor at all. That is the "transaction-level" in TLM, and it is the reason a scoreboard can be written without knowing how many clocks anything took.

10. Honest Scope

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── REPRESENTATIVE UVM CODE — NOT COMPILED IN THIS MODULE ───────────
// No UVM library or UVM-capable simulator is present in this
// environment. This is published as a mapping, not as evidence.

None of the UVM code in this chapter was compiled or executed. The executable proof of this module is Chapters 26.1–26.5, which ran twelve simulations against real RTL in a real simulator. This chapter maps that proof onto UVM's vocabulary and stops there.

Deliberately out of scope, and owned by the dedicated UVM curriculum:

  • the factory and type overrides
  • uvm_config_db
  • the phase mechanism beyond run_phase
  • objections and end-of-test
  • virtual sequences and sequence arbitration
  • the register abstraction layer (RAL)

Six pages do not make anyone a UVM expert, and this chapter does not pretend otherwise. What it should leave you with is the opposite of intimidation: the components have names you now recognise, because you built every one of them before you learned what UVM calls it.

11. Where Module 26 Ends

Five verification components, twelve simulations, eight defects and a discrimination matrix in which every defect was caught by the layer the plan nominated and the other layers stayed quiet:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
      intended detections            8 of 8
      missed intended detections     0
      unexpected protocol detections 0
      false positives (correct rig)  0

The single most transferable result is the one this module opened with and closed with: four of those eight defects — two in the design, one in the monitor, one in the reference model — kept the bus perfectly legal. A conformance suite passes all four.


Module 27 takes up debugging: what to do when one of these layers fires and you do not yet know which model is wrong.

Continue learning

Standards & specifications

Governing standard
Wishbone SoC Interconnection Architecture (OpenCores)(opens OpenCores in a new tab)

Defines the Wishbone signal set, the bus cycles built from it and the interface rules a portable IP core must follow. It deliberately leaves interconnect topology, address map and arbitration policy to the integrator, so those are system decisions rather than requirements of the specification.

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 Wishbone curriculum.