UVM Test

The top-level component that instantiates the environment and starts sequences.

The UVM Test: The Movie Director

Think of your entire UVM Testbench as a Movie Production.

  • The Environment (Env): This is the movie set. It has cameras (monitors), actors (drivers), and props (data). The set is usually the same every day.
  • The Sequences: These are the scripts. One script might be an action scene, another might be a drama.
  • The Test: This is the Director. The Director decides which script we are filming today and which actors should be on set.

The Test doesn't build the cameras or the actors—it just tells the Factory to create them and then tells them when to say "Action!"

Why keep the Test separate from the Env?

Beginners often ask: "Why can't I just put everything in the Environment?"

The reason is Reusability. If you glue your test scenario inside your Environment, you can never change it. By keeping the Test separate, you can have 100 different Tests (Error Test, Reset Test, Performance Test) all using the exact same Environment.

The Environment is the "Machine," and the Test is the "Operator" who decides which buttons to push today.

Common Mistakes (Troubleshooting)

1. The "Blink of an Eye" Simulation

The Problem: You start the simulation, and it finishes in 0 nanoseconds with no errors, but no data was sent.

The Cause: You forgot to Raise an Objection. In UVM, if the Director doesn't say "I'm busy!" (Raise Objection), the simulation thinks everyone is done and closes the curtains immediately.

2. Connecting Ports in the Test

Mistake: Trying to connect the Driver to the Monitor inside the Test class.

Correction: The Test should never worry about wires. Connecting components is the job of the Env or the Agent. The Test should stay "High Level."

The Orchestrator Role

What is the Test Class?

The Simple Version: The Test is the "Brain" of your verification. While other components like Drivers and Monitors are the "Body Parts," the Test decides what the body actually does.

The uvm_test class is the "Brain" of the verification environment. While other components (Drivers, Monitors) are fixed in their structure, the Test is dynamic—it decides which environment to build, how to configure it, and what stimulus to apply.

1. The base_test Pattern

In the real world, you don't write a brand new test from scratch every time. Instead, you create a Base Test. This is your "Template". It sets up the boring stuff (clock, reset, standard environment). Then, for your actual tests, you just copy (extend) this Base Test and add the special sauce for that specific scenario.

Pro Tip:
  • Base Test: The foundation. Has connection code, timeout settings, and default config.
  • Derived Test: The specific test. "Base Test + Error Injection" or "Base Test + Long Delay".
Example: Professional Base Test

class base_test extends uvm_test;
    `uvm_component_utils(base_test)
    my_env env;
    function void build_phase(uvm_phase phase);
        // Create the environment using the factory
        env = my_env::type_id::create("env", this);
        // Pass standard configurations to the agents
        uvm_config_db#(int)::set(this, "env.agt*", "is_active", UVM_ACTIVE);
    endfunction
    // Catch-all timeout for safety
    function void start_of_simulation_phase(uvm_phase phase);
        uvm_top.set_timeout(1ms);
    endfunction
endclass
                            

Dynamic Variation: Overrides

A derived test leverages factory overrides to change the behavior of sub-components without touching the structural code of the environment.

Example: Error Injection Test

class err_inj_test extends base_test;
    `uvm_component_utils(err_inj_test)
    function void build_phase(uvm_phase phase);
        // Step 1: Request the factory to swap the standard driver
        // This MUST happen before super.build_phase()!
        my_driver::type_id::set_type_override(error_driver::get_type());
        // Step 2: Now call base build (which creates the env)
        super.build_phase(phase);
    endfunction
endclass
                            

Stimulus Control

The Test is responsible for starting sequences. This is typically done in the run_phase using the start() method on the sequencer handle.


task run_phase(uvm_phase phase);
    my_seq seq = my_seq::type_id::create("seq");
    phase.raise_objection(this, "Starting Main Stimulus");
    seq.start(env.agt.sqr);
    phase.drop_objection(this, "Stimulus Finished");
endtask
                            

Command Line execution

To run your simulation with a specific test, use the following simulator switch:

+UVM_TESTNAME=err_inj_test