Advanced SystemVerilog
Concurrent threads, synchronization primitives, SVA assertions, and the Direct Programming Interface.
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.
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
automatic variable — otherwise they all race on the shared outer i.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 #(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
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.
// "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");
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.
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.