Advanced SystemVerilog

Concurrent threads, synchronization primitives, SVA assertions, and the Direct Programming Interface.

01 · Threads

fork, join, and concurrent processes

Hardware is inherently concurrent. SystemVerilog gives you four forms of fork to express concurrent threads in stimulus and checking code.

threads.svFORK VARIANTS
fork
  drive_writes();
  drive_reads();
  monitor_responses();
join          // waits for ALL three to finish

fork
  watchdog_timer();
  transaction();
join_any      // finishes when EITHER completes

fork
  background_monitor();
join_none     // continues immediately, monitor runs in bg

fork begin
  // isolated local variables
  automatic int i = 5;
  handle_request(i);
end join_none
The automatic trap
When you spawn N threads from a for-loop, each thread must capture its loop index into a local automatic variable — otherwise they all race on the shared outer i.
02 · Synchronization

Mailboxes, semaphores, and events

Three built-in classes handle inter-thread communication:

  • mailbox — typed FIFO queue. Producer puts, consumer gets. Bounded or unbounded.
  • semaphore — counting signal for resource pools. get(n) blocks until n keys available.
  • event — edge-triggered flag. -> fires it, @(ev) waits for the next fire.
mailbox.svMAILBOX
mailbox #(axi_txn) mbx = new(16);  // bounded, capacity 16

// Producer
task drive();
  axi_txn t;
  forever begin
    t = new();
    assert(t.randomize());
    mbx.put(t);                    // blocks if full
  end
endtask

// Consumer
task check();
  axi_txn t;
  forever begin
    mbx.get(t);                    // blocks if empty
    compare_with_ref_model(t);
  end
endtask
03 · Assertions (SVA)

Declaring properties of correct behavior

SystemVerilog Assertions (SVA) let you state what should happen in declarative form. The simulator checks it on every cycle. Two flavors:

  • Immediate assertions — procedural, evaluated when reached. assert(a == b);
  • Concurrent assertions — temporal, watch over time. property/assert property.
sva.svASSERTION
// "valid must not drop before ready"
property p_valid_stable;
  @(posedge clk) disable iff (!rst_n)
  (awvalid && !awready) |=> awvalid;
endproperty

a_valid_stable: assert property (p_valid_stable)
  else $error("awvalid dropped before awready");
Put SVA in the interface
Protocol-level properties belong in the interface file, not scattered through the DUT or testbench. They document the protocol and catch violations from either side.
04 · Direct Programming Interface

Calling C from SystemVerilog (and vice versa)

The DPI lets SystemVerilog call C functions and C call SystemVerilog tasks. Used for reference models, scoreboards backed by C libraries, and CRC/encryption routines that already exist in C.

dpi.svDPI
import "DPI-C" function int c_crc32(input byte data[]);

task check_packet(byte payload[]);
  int expected = c_crc32(payload);
  if (expected != pkt.crc)
    `uvm_error("CRC", $sformatf("crc mismatch: exp=%0h got=%0h",
                                  expected, pkt.crc))
endtask

Pure and context functions

Mark a DPI import pure if the C function has no side effects — the simulator can optimize calls. Mark it context if the C function needs to call back into SystemVerilog.