Classes model behavior that changes at runtime; modules and interfaces model structure fixed at elaboration. The virtual interface is the one bridge between the two worlds. Each answer below is the short version with a link to the lesson.
A module is a static container fixed at elaboration. A class is a dynamic object created with new, with inheritance, polymorphism and randomization. Testbenches need runtime flexibility, so they use classes; DUTs stay modules because hardware is static structure with timing.
Taught in: Class Declaration & Objects.
Level | What happens | When it bites |
|---|---|---|
Handle assignment ( | One object, two names | Editing through either name changes both |
Shallow copy ( | Two objects sharing nested ones | Editing the copy payload corrupts the original |
Deep copy (hand-written | Fully independent objects | Monitors must use it before reusing a transaction |
Taught in: Handles vs Objects, Shallow vs Deep Copy.
A virtual method dispatches on the object type, not the handle type. Components hold base handles while tests inject derived objects, and the driver is never edited. Without virtual the base version runs and the override is silently ignored.
Taught in: Virtual dispatch.
`$cast`: a checked downcast. As a function it returns 0 on failure so code can branch; as a task it raises a run-time error. It also converts an integral value to an enum. See Casting with $cast.
`static`: one copy shared by all instances. Good for transaction IDs and counters, but it is global state in disguise, so never use it as a configuration back-channel. See Static Properties & Methods.
Parameterized classes: written once, specialized per type, and each specialization is a distinct type. Use a non-parameterized base class for a common handle. See Parameterized Classes.
An interface bundles a signal group into one named port, and protocol assets travel with it: clocking blocks, modports, assertions and tasks. Modports are compile-time direction contracts: the compiler rejects a module driving a signal its modport declares as input. Code holding the raw interface bypasses the contract.
Taught in: Interface Basics, Modports.
input #1step samples in the Preponed region, the value just before the edge, exactly what a flop captures. output with a small delay drives past the hold window. #0 samples after the edge may have updated, so it can read post-edge values.
CLOCKING BLOCK TIMING
setup edge hold
────────────────┬──┬──┬────────────────────► time
│ ▲ │
input #1step ──┘ │ └── output #2ns drives here
samples here │ (after hold window)
(Preponed: value clk
before the edge) risesTaught in: Clocking Blocks.
Classes have no elaboration-time existence, so they cannot have ports. A virtual interface is a runtime handle to a real interface instance, the one sanctioned bridge into the module world. With many agents, each needs its own handle bound to its own instance; binding all of them to instance zero shows triple traffic on port zero and silence elsewhere. Assert the handle is non-null before the run starts.
Taught in: Why Virtual Interfaces Exist, Multi-Instance & Parameterized vifs.
virtual, a base handle holds a derived object and calls the overridden method. Which version runs?The base version. Dispatch follows the declared handle type, silently ignoring the override with no warning.
Triple traffic on port zero and nothing on the other ports. Each agent needs its own handle bound to its own instance.