HomeProblemsTheoryUVM
Advanced4 min readChapter 15

Advanced UVM Patterns

Production-grade patterns — layered sequences, synchronization, response handlers, and test organization.

Advanced UVM Patterns

This chapter covers production-grade patterns used in real-world semiconductor verification environments.


1. Layered Sequences

Build complex scenarios by composing simple, reusable sequences:

systemverilog
// Layer 1: Atomic operation class single_write extends uvm_sequence #(apb_txn); `uvm_object_utils(single_write) rand bit [31:0] addr; rand bit [31:0] data; function new(string name = "single_write"); super.new(name); endfunction task body(); apb_txn txn = apb_txn::type_id::create("txn"); start_item(txn); txn.randomize() with { write == 1; txn.addr == local::addr; txn.data == local::data; }; finish_item(txn); endtask endclass // Layer 2: Scenario (initialize all registers) class init_sequence extends uvm_sequence #(apb_txn); `uvm_object_utils(init_sequence) function new(string name = "init_sequence"); super.new(name); endfunction task body(); single_write wr; for (int i = 0; i < 8; i++) begin wr = single_write::type_id::create($sformatf("wr_%0d", i)); wr.addr = i * 4; wr.data = 32'h0; wr.start(m_sequencer); end endtask endclass // Layer 3: Full test flow class full_test_seq extends uvm_sequence #(apb_txn); `uvm_object_utils(full_test_seq) function new(string name = "full_test_seq"); super.new(name); endfunction task body(); init_sequence init; traffic_sequence traffic; cleanup_sequence cleanup; init = init_sequence::type_id::create("init"); traffic = traffic_sequence::type_id::create("traffic"); cleanup = cleanup_sequence::type_id::create("cleanup"); init.start(m_sequencer); // Phase 1 traffic.start(m_sequencer); // Phase 2 cleanup.start(m_sequencer); // Phase 3 endtask endclass

2. Event-Based Synchronization

Coordinate components using UVM events:

systemverilog
class my_env extends uvm_env; `uvm_component_utils(my_env) uvm_event reset_done; uvm_event config_done; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); reset_done = new("reset_done"); config_done = new("config_done"); endfunction endclass // In the reset sequence: task body(); // ... perform reset ... `uvm_info("RST", "Reset complete", UVM_NONE) p_sequencer.env.reset_done.trigger(); endtask // In the main test sequence: task body(); // Wait for reset to finish before proceeding p_sequencer.env.reset_done.wait_trigger(); `uvm_info("MAIN", "Starting main traffic", UVM_NONE) // ... run test ... endtask

3. Response Handler Pattern

Process drive requests and responses in separate threads:

systemverilog
class my_driver extends uvm_driver #(my_txn); `uvm_component_utils(my_driver) virtual my_if vif; function new(string name, uvm_component parent); super.new(name, parent); endfunction task run_phase(uvm_phase phase); fork drive_requests(); collect_responses(); join endtask task drive_requests(); my_txn req; forever begin seq_item_port.get_next_item(req); // Drive request to DUT @(posedge vif.clk); vif.valid <= 1; vif.addr <= req.addr; vif.data <= req.data; @(posedge vif.clk); vif.valid <= 0; seq_item_port.item_done(); end endtask task collect_responses(); forever begin @(posedge vif.clk); if (vif.resp_valid) begin // Process async response from DUT `uvm_info("DRV", $sformatf( "Response: data=0x%h", vif.resp_data ), UVM_HIGH) end end endtask endclass

4. Test Library Pattern

Organize tests with a common base and specialized overrides:

systemverilog
// Base test: common setup for all tests class base_test extends uvm_test; `uvm_component_utils(base_test) my_env env; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); env = my_env::type_id::create("env", this); endfunction function void check_phase(uvm_phase phase); // Common end-of-test checks endfunction endclass // Smoke test: basic functionality class smoke_test extends base_test; `uvm_component_utils(smoke_test) function new(string name, uvm_component parent); super.new(name, parent); endfunction task run_phase(uvm_phase phase); smoke_vseq vseq; phase.raise_objection(this); vseq = smoke_vseq::type_id::create("vseq"); vseq.start(env.v_sqr); phase.drop_objection(this); endtask endclass // Stress test: high-volume traffic class stress_test extends base_test; `uvm_component_utils(stress_test) function new(string name, uvm_component parent); super.new(name, parent); endfunction task run_phase(uvm_phase phase); stress_vseq vseq; phase.raise_objection(this); vseq = stress_vseq::type_id::create("vseq"); vseq.start(env.v_sqr); phase.drop_objection(this); endtask endclass

Select from the command line:

bash
vsim +UVM_TESTNAME=smoke_test vsim +UVM_TESTNAME=stress_test

5. UVM Heartbeat — Detect Hangs

systemverilog
class watchdog_env extends uvm_env; `uvm_component_utils(watchdog_env) uvm_heartbeat hb; uvm_event hb_event; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); hb_event = new("hb_event"); hb = new("hb", this, hb_event); endfunction function void connect_phase(uvm_phase phase); uvm_component comps[$]; comps.push_back(agent.driver); comps.push_back(agent.monitor); hb.set_mode(UVM_ANY_ACTIVE); hb.add(comps); endfunction endclass

If no registered component raises an objection within the heartbeat window, UVM issues a fatal error — catching hangs early.


Key Takeaways

PatternWhen to Use
Layered sequencesComplex multi-step test scenarios
Event synchronizationCross-component coordination
Response handlerAsync request/response protocols
Test libraryOrganized, maintainable test suite
HeartbeatLong-running simulations that may hang

🎉 Congratulations! You've completed the full UVM tutorial series — from basics to production-grade patterns!