Verification

SystemVerilog interfaces and modports

By CourseTron Team ·  3 min read ·  Updated Oct 2026 💬 𝕏 in f
Table of Contents
    ? Print / Save as PDF

    In short: A SystemVerilog interface bundles related signals into one named connection, and a modport then slices that bundle into directional views (input/output) per port, while a virtual interface is the handle that lets a class-based testbench reach into those physical wires.

    Why interfaces exist

    Before SystemVerilog, a Verilog module port list for a modern bus could run to dozens of signals. A simple memory handshake needs clk, rst_n, addr, wdata, rdata, req, gnt and valid — eight signals you had to repeat identically in the DUT port list, the driver, the monitor and every .name(name) connection in between. One typo in width, one swapped order, and you spent an afternoon in the waveform viewer. Interfaces collapse that repetition into a single first-class object you declare once and pass around as a unit.

    interface mem_if #(parameter AW = 32, DW = 32) (input logic clk, rst_n);
      logic [AW-1:0] addr;
      logic [DW-1:0] wdata, rdata;
      logic          req, gnt, valid, we;
    endinterface

    Instantiate it once and hand the same instance to both sides. The DUT and the verification components now share a single source of truth for connectivity.

    A width change made in the interface (say DW from 32 to 64) propagates to every connected module and testbench component automatically — no edits scattered across five files.

    One interface instance shared by both sides DUT (RTL) mem_if addrwdata / rdatareq / gntvalid / weclk / rst_n Testbench (driver / monitor) CourseTron · coursetron.com
    One interface instance is the single physical bundle shared by the design and the verification environment.

    Modports: giving each side a directional view

    A bare interface has no direction — addr is just a wire. But the DUT drives rdata and gnt while sampling addr and req; the driver does the exact opposite. A modport (module port) defines a named, direction-qualified view so each connected module only sees the correct input/output sense. This is what gives you compile-time protection against driving a signal from the wrong end.

    interface mem_if (input logic clk, rst_n);
      logic [31:0] addr, wdata, rdata;
      logic        req, gnt, valid, we;
    
      modport dut (input  addr, wdata, req, we,
                   output rdata, gnt, valid,
                   input  clk, rst_n);
    
      modport tb  (output addr, wdata, req, we,
                   input  rdata, gnt, valid, clk, rst_n);
    endinterface

    The DUT declares its port as mem_if.dut d_if and the testbench uses mem_if.tb. If RTL accidentally writes d_if.req <= 1, a simulator such as Synopsys VCS, Cadence Xcelium or Siemens Questa flags it as a write to an input — caught during elaboration, not three weeks into a regression. Modports can also carry import declarations for tasks and functions, so a bus-functional model exported from the interface is callable only through the view that imports it.

    ConstructPurposeDeclared in
    interfaceBundle a set of signals as one objectCompilation unit / package
    modportDirectional slice of the bundle for one connecting moduleInside the interface
    virtual interfaceClass handle pointing to a physical interface instanceInside a class (UVM driver/monitor)
    clocking blockSynchronous, skew-controlled sampling/drivingInside the interface

    Modports pair naturally with a clocking block, which adds input/output skew so the testbench samples and drives relative to a clock edge instead of racing the DUT.

    Same wires, opposite directions per modport modport dutaddrinputwdatainputreqinputweinputrdataoutputgntoutputvalidoutputmodport tbaddroutputwdataoutputreqoutputweoutputrdatainputgntinputvalidinput CourseTron · coursetron.com
    The dut and tb modports expose the same signals with opposite input/output senses.

    Virtual interfaces: the class-to-wire bridge

    Here is the subtlety that trips up most engineers moving into UVM. Interfaces are static — they are elaborated once and live for the whole simulation, like modules. Classes (your driver, monitor, sequence) are dynamic — they are constructed at run time with new(). A static interface cannot be instantiated inside a dynamic class. The bridge is a virtual interface: a handle (a pointer) to an already-elaborated physical instance.

    class mem_driver;
      virtual mem_if.tb vif;       // handle, not an instance
      function new(virtual mem_if.tb vif);
        this.vif = vif;
      endfunction
      task run();
        @(posedge vif.clk);
        vif.addr <= 32'hA000;
        vif.req  <= 1'b1;
      endtask
    endclass

    In a UVM environment the physical instance is placed in the uvm_config_db at the top level and retrieved by name inside each component — decoupling the class hierarchy from the structural hookup. Note the virtual mem_if.tb form: you can type a virtual interface against a specific modport so the class is held to the same directional contract the RTL enjoys.

    A null virtual interface is the single most common UVM startup failure. If uvm_config_db::get never found the handle, the first vif.clk dereferences null and the simulator reports a fatal "null object access" — always guard the handle in build_phase.

    req / gnt handshake, then a data beat req gnt data data beat travels DUT → TB CourseTron · coursetron.com
    Driver raises req; after the DUT asserts gnt, a data beat moves across the bundled interface each clock.

    Practical guidelines and gotchas

    • Keep interfaces synthesizable-neutral. Put clocking blocks and assertions in the interface for verification, but gate them behind a modport the RTL never uses, so the design side stays clean.
    • One modport per role, not per module. A master/slave/monitor triad covers most buses; the monitor modport makes every signal an input so a passive monitor physically cannot drive the bus.
    • Parameterize once. Width and depth parameters on the interface flow to all consumers — essential when you reuse the same AXI-lite interface across a 32-bit and 64-bit instance in one SoC.
    • Virtual interface arrays let a single agent drive N identical channels — index the handle rather than cloning components.

    Teams building full UVM environments usually pair interface design with sequence and scoreboard architecture; our UVM testbench architecture guide walks through that end to end. If you are moving from functional verification into actual RTL-to-GDSII work, the physical-design specialists at Avecas design services handle the back-end hand-off.

    Want to write a complete interface-driven UVM agent from scratch, with modports, clocking blocks and virtual-interface wiring that elaborates clean on VCS and Questa? Our CourseTron Verification track builds it live, lab by lab.

    Frequently asked questions

    What is the difference between an interface and a modport?

    An interface is the container that bundles signals; a modport is a directional view of that container. The interface holds the wires, the modport decides who drives and who samples each wire for a particular connection.

    Why can't I use a physical interface directly inside a UVM driver?

    UVM components are dynamic classes created with new() during the build phase, while interfaces are static and elaborated at time zero. You cannot instantiate a static interface inside a class, so you store a virtual interface handle that points to the already-elaborated physical instance.

    Can a modport change signal directions at run time?

    No. Modport directions are resolved at elaboration and are fixed for the simulation. If a signal is bidirectional, you model that with separate signals or by choosing the appropriate modport per connection, not by flipping direction dynamically.

    Do interfaces and modports cost anything in synthesis?

    The signal bundle itself synthesizes to ordinary nets — there is no hardware overhead. Verification-only members such as clocking blocks and assertions are ignored by synthesis tools, so a well-structured interface is safe to carry into the RTL.

    Advertisement