SystemVerilog Hands-On
Get fluent in the verification language interviewers actually probe: dynamic data structures, OOP for reusable testbench components, constrained randomization, interfaces and clocking blocks, processes and IPC, and finally SystemVerilog assertions and functional coverage.
By the end you can
- Model transactions with classes, deep copy and polymorphism
- Write constrained-random stimulus with solve-before and distributions
- Drive a DUT through an interface with a clocking block
- Specify behavior with SVA and measure it with functional coverage
0 / 25 assignments done
Move each assignment through the stages — progress saves automatically.
Data types & structures
0/6The containers testbenches live on — queues, dynamic and associative arrays, packed structs/unions — plus packages and a DPI call.
Queues, dynamic and associative arrays
Model a small scoreboard store three ways: a queue used as a FIFO of expected items, a dynamic array you grow at runtime, and an associative array keyed by an address. Add, look up, and delete entries and print the contents.
Requirements
- Queue push_back/pop_front used as an ordered expected-list
- Dynamic array sized at runtime with new[]
- Associative array keyed by a wide address with exists()/delete()
- A short demo that adds, finds and removes entries
You'll be able to
- Pick the right SV container for a verification task
- Use queue, dynamic and associative array methods correctly
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Packed struct and union for a packet header
Define a packed struct for a protocol header (fields like addr, len, opcode, parity) and a union that views the same bits as a raw vector. Pack a header, corrupt one bit through the union view, and detect it.
Requirements
- A packed struct with named bit-fields
- A union giving a raw [N-1:0] view of the same storage
- Round-trip: struct → bits → struct is lossless
- A parity field computed and checked
You'll be able to
- Use packed structs/unions for bit-accurate modeling
- Reason about layout and byte/bit ordering
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Package and a DPI-C helper
Put shared typedefs and a parameter in a package, import it into two modules, and import one C function via DPI to compute a reference checksum. Call the C function from SystemVerilog and use its result.
Requirements
- A package with at least one typedef and one parameter
- Two consumers importing the package
- One import "DPI-C" function with a matching C signature
- The DPI result used in a comparison
You'll be able to
- Share definitions cleanly with packages
- Call external C reference models through DPI
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Array locator and reduction methods
Given a queue of transactions, use the built-in array methods with a `with` clause instead of hand-written loops: find and find_index the reads, sum the lengths, get min/max address, and sort/rsort by address.
Requirements
- find/find_index with a `with` predicate
- sum/min/max reductions with `with`
- sort and rsort using a key expression
- No manual loop where a built-in method exists
You'll be able to
- Use SystemVerilog array methods idiomatically
- Replace loops with locators and reductions
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
String parsing and formatting
Parse a command line such as WR 0x40 12 into an opcode, address and length using $sscanf, then build a formatted log line with $sformatf. Reject a malformed line without crashing.
Requirements
- Convert hex/decimal text to numeric values
- Use string methods (len, substr, toupper) where useful
- Format output with $sformatf including zero-padded hex
- A malformed line is rejected gracefully
You'll be able to
- Process and format strings in SystemVerilog
- Convert between text and numeric values
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Streaming operators for pack/unpack
Serialize a packed header struct into a byte queue and reconstruct it using the streaming operators. Show that a round trip is lossless and how the streaming direction changes byte order.
Requirements
- Pack a struct to a byte queue with the >> stream
- Unpack back into an identical struct
- Demonstrate << reversing the order
- A round-trip equality check
You'll be able to
- Serialize and deserialize with streaming operators
- Reason about bit and byte ordering
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Object-oriented testbench building blocks
0/6The class patterns every UVM component is built on — a transaction with deep copy and compare, and a base/derived hierarchy using polymorphism.
Transaction class with deep copy and compare
Write a transaction class with rand fields, plus copy(), clone(), compare() and a display() method. Demonstrate that a deep copy is independent of the original (mutating one doesn't change the other), unlike a handle assignment.
Requirements
- rand fields plus a constructor
- copy() performs a field-by-field deep copy
- compare() returns a match result and a diff message
- A demo proving handle-assignment aliases but copy() does not
You'll be able to
- Distinguish shallow (handle) copy from deep copy
- Provide the copy/compare/print methods components rely on
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Inheritance and polymorphism: base and derived driver
Create a base driver class with a virtual drive() method and two derived drivers that override it. Store them through base handles in an array and call drive() polymorphically so the correct override runs.
Requirements
- A base class with a virtual method
- Two subclasses overriding that method
- Base-handle array holding derived objects
- A loop calling the virtual method (dynamic dispatch)
You'll be able to
- Use virtual methods for run-time polymorphism
- Explain why 'virtual' is required for the override to run
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Parameterized generic container class
Write a parameterized stack class with a type parameter and push/pop/size/is_empty, then specialize it for an int and for a transaction handle to show the same code is type-safe for both.
Requirements
- A type parameter with a sensible default
- Type-safe push/pop/size/is_empty
- Two specializations (a scalar and a class handle)
- A short demo exercising both
You'll be able to
- Write reusable parameterized classes
- Specialize a generic class for multiple types
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Static members: a transaction counter
Add a static counter and a per-object unique id to a transaction class so every object is numbered and you can query how many were created, plus a static method that reports the count.
Requirements
- A static count incremented in the constructor
- A per-object unique id derived from the static
- A static reporting method
- A demo showing the count is shared across instances
You'll be able to
- Use static members for shared state
- Give each object a unique id
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Abstract class and a simple factory
Define an abstract base transaction with a pure virtual method, two concrete subclasses, and a factory function that returns the right subclass by an enum — the pattern UVM's factory formalizes.
Requirements
- A virtual (abstract) class with a pure virtual method
- Two concrete subclasses implementing it
- A factory function returning a base handle by kind
- Polymorphic use of the returned objects
You'll be able to
- Use abstract classes and pure virtual methods
- Build a type-selecting factory
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Safe downcasting with $cast
Downcast a base handle to a derived handle with $cast, handling both the success and failure cases, and explain why a direct assignment from base to derived doesn't compile.
Requirements
- A successful $cast when the object is the derived type
- A handled failure when it is not
- An explanation of why the direct assign is illegal
- No run-time crash on the failing path
You'll be able to
- Downcast safely with $cast
- Explain compile-time vs run-time type checks
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Randomization, constraints & interfaces
0/6Generate legal, interesting stimulus with constraints, then hand it to a DUT through an interface and a clocking block.
Constrained-random packet with solve-before and dist
Build a packet class whose length and address are constrained (e.g. aligned addresses, length weighted toward small packets, no crossing a boundary). Use solve-before where an ordering dependency exists and a dist for weighting.
Requirements
- At least three interacting constraints
- A dist clause to weight a field
- A solve-before to control a dependent field's distribution
- A short randomize() loop showing the legal spread
You'll be able to
- Write realistic constrained-random stimulus
- Control ordering and weighting with solve-before and dist
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Classic constraints: sum-to-N and all-unique
Solve two staple interview constraints: randomize an array of K elements that sums to exactly N, and randomize an array whose elements are all unique within a range. Prove both hold over many randomizations.
Requirements
- An array-sum constraint producing a total of exactly N
- A uniqueness constraint (no repeats) over a bounded range
- A checker that fails loudly if either property is violated
- Runs cleanly for many seeds with no solver failures
You'll be able to
- Express aggregate and relational constraints on arrays
- Use the unique construct and array reductions
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Interface, clocking block and virtual interface
Bundle a DUT's pins into an interface with a clocking block and a testbench modport, then drive and sample the DUT from a class through a virtual interface — with no race between the driver and the DUT.
Requirements
- An interface grouping the DUT signals
- A clocking block with input/output skews
- A modport for the testbench side
- A class driving/sampling via a virtual interface handle
You'll be able to
- Connect class-based stimulus to RTL cleanly
- Avoid driver/DUT races with clocking-block skews
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Inline constraints and rand/constraint_mode
Override a class's constraints for a single call with randomize() with {}, then use rand_mode(0) to freeze a field and constraint_mode(0) to switch off a constraint block at run time — showing the effect of each.
Requirements
- An inline randomize() with {} that tightens a field
- rand_mode(0) freezing a field at its current value
- constraint_mode(0) disabling a named constraint
- A demonstration of each toggle's effect
You'll be able to
- Steer randomization per call
- Enable and disable fields and constraints at run time
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
pre_randomize and post_randomize hooks
Use post_randomize() to compute a derived field (a parity or CRC over the randomized data) so the object is always self-consistent after randomize(), and pre_randomize() to set up a guard the constraints depend on.
Requirements
- pre_randomize sets up dependent state
- post_randomize computes a derived field
- The derived field is correct after every randomize()
- A check across several randomizations
You'll be able to
- Use the randomize hooks correctly
- Compute fields that depend on randomized values
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
randc and weighted distributions
Use randc to cycle through all values of a field with no repeats until the range is exhausted, and a dist with := and :/ weights to bias another field. Tally many draws to show randc's no-repeat property.
Requirements
- A randc field cycling its full range before repeating
- A dist-weighted rand field
- A tally proving no repeats within a randc cycle
- A note on rand vs randc cost
You'll be able to
- Use randc for exhaustive cycling
- Weight randomization with dist
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Processes, assertions & functional coverage
0/7Concurrency and synchronization, then the two ways interviews check you can specify and measure behavior: SVA and covergroups.
fork/join, mailbox and semaphore
Build a tiny producer/consumer: a producer thread generates items into a mailbox, a consumer thread drains them, and a semaphore guards a shared resource. Show fork/join_any and fork/join_none behavior and terminate cleanly.
Requirements
- A mailbox passing items between two threads
- A semaphore protecting a shared section
- A demonstration of join, join_any and join_none differences
- Clean shutdown with no hung threads
You'll be able to
- Coordinate concurrent threads with mailboxes and semaphores
- Choose the right fork/join variant
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
SVA: assert a request/grant handshake
Write concurrent assertions for a simple handshake: every req must eventually get an ack within N cycles, ack must not appear without a pending req, and a captured value must be stable while req is high. Use implication, $rose and $past.
Requirements
- An overlapping/non-overlapping implication where appropriate
- A bounded-response property (ack within N cycles)
- Use of $rose/$fell and $past
- Both an assert and a matching cover for one property
You'll be able to
- Specify temporal behavior with SVA
- Use implication and sampled-value functions correctly
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
SVA sequences with consecutive repetition
Specify a multi-cycle protocol fragment with a named sequence: a start pulse, then a burst of exactly K back-to-back valid beats, then done. Use consecutive repetition [*K] and compose sequences.
Requirements
- A named sequence using [*K] consecutive repetition
- Sequence composition with ##1 / within
- An assertion that the full pattern holds after start
- A cover to prove the pattern is exercised
You'll be able to
- Build reusable named sequences
- Use repetition operators to describe bursts
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Functional coverage: covergroup, bins and cross
Write a covergroup for a transaction: coverpoints for opcode and length with explicit bins (including illegal/ignore bins), and a cross between opcode and a length range. Sample it from stimulus and report coverage.
Requirements
- Coverpoints with explicit, illegal and ignore bins
- A cross of two coverpoints
- Sampling triggered on a real event
- A note on what 100% of this covergroup would prove
You'll be able to
- Model functional intent with covergroups
- Use bins, illegal_bins and crosses correctly
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Events: trigger, wait and wait_order
Synchronize threads with named events: one triggers with ->, others wait with @ or wait(ev.triggered), and enforce an ordering with wait_order. Show why @ can miss an event that wait(triggered) catches.
Requirements
- -> to trigger and @ to wait
- wait(ev.triggered) to avoid a missed-edge race
- wait_order enforcing a required sequence
- A demonstration of the @ vs triggered difference
You'll be able to
- Synchronize threads with events
- Avoid missed-event races
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Coverage: transition bins and cross filtering
Extend a covergroup with transition bins on an FSM state coverpoint (A then B then C) and a cross that uses binsof/intersect with ignore_bins to drop illegal combinations, then read which transitions were missed.
Requirements
- Transition bins on a state coverpoint
- A cross filtered with binsof/intersect
- ignore_bins removing illegal combinations
- An interpretation of the missed transitions
You'll be able to
- Cover state transitions, not just states
- Filter illegal cross combinations
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Assertions: local variables and disable iff
Write a property that captures the request's data into a local variable and checks the response carries the same value N cycles later, with disable iff(!rst_n) so a reset in the middle doesn't cause a false failure.
Requirements
- A local variable captured on the antecedent
- A check that the response matches the captured value
- disable iff for reset
- A cover proving the scenario is exercised
You'll be able to
- Carry values through a property with local variables
- Guard properties against reset
Submitting your solution link marks this assignment done.
A full worked solution with a step-by-step walkthrough — included with the domain pack and All-Access. Try it yourself first.
Put it to work
Drill the matching interview questions, then see where this module sits in the full Design Verification roadmap.