SystemVerilog Complete Cheat Sheet

Quick Reference Guide for SystemVerilog

Your one-stop SystemVerilog reference for rapid development

Table of Contents

  1. Data Types
  2. Operators
  3. Arrays
  4. Control Structures
  5. Procedural Blocks
  6. Modules and Ports
  7. Always Blocks
  8. Functions and Tasks
  9. Classes and OOP
  10. Interfaces
  11. Constraints
  12. Coverage
  13. Assertions
  14. Common Patterns
  15. Quick Reference

1. Data Types

Two-State vs Four-State

// TWO-STATE (0, 1) - Faster simulation
bit           single_bit;      // 1-bit
bit [7:0]     byte_val;        // 8-bit vector
byte          signed_byte;     // 8-bit signed (-128 to 127)
shortint      short_val;       // 16-bit signed
int           int_val;         // 32-bit signed
longint       long_val;        // 64-bit signed

// FOUR-STATE (0, 1, X, Z) - Hardware modeling
logic         logic_bit;       // Can be X or Z
logic [7:0]   logic_byte;
reg  [31:0]   reg_val;         // Same as logic
wire [7:0]    wire_val;        // For connections

// REAL NUMBERS
real          real_val;        // 64-bit floating point
shortreal     short_real;      // 32-bit floating point

// STRING
string        text = "Hello";  // Dynamic string

// TIME
time          sim_time;        // 64-bit time value
realtime      real_time;       // Real time value

User-Defined Types

// Typedef
typedef bit[7:0] byte_t;
typedef logic[31:0] word_t;

byte_t my_byte = 8'hAA;
word_t my_word = 32'hDEAD_BEEF;

// Enum
typedef enum logic[1:0] {
  IDLE   = 2'b00,
  ACTIVE = 2'b01,
  WAIT   = 2'b10,
  DONE   = 2'b11
} state_t;

state_t current_state, next_state;

// Enum with auto increment
typedef enum {RED, GREEN, BLUE} color_t;  // RED=0, GREEN=1, BLUE=2

// Struct (packed)
typedef struct packed {
  bit [7:0] opcode;
  bit [3:0] dest;
  bit [3:0] src;
} instruction_t;

instruction_t inst;
inst.opcode = 8'h42;

// Struct (unpacked)
typedef struct {
  int addr;
  int data;
  bit write;
} transaction_t;

transaction_t txn;
txn.addr = 100;

// Union (packed)
typedef union packed {
  bit [31:0] word;
  bit [15:0] half[2];
  bit [7:0]  byte[4];
} data_union_t;

data_union_t data;
data.word = 32'hDEAD_BEEF;
// Can also access as: data.byte[0] = 0xEF

2. Operators

Arithmetic

a + b        // Addition
a - b        // Subtraction
a * b        // Multiplication
a / b        // Division
a % b        // Modulus
a ** b       // Power (a^b)

a++          // Post-increment
++a          // Pre-increment
a--          // Decrement
a += b       // a = a + b
a -= b       // a = a - b
a *= b       // a = a * b

Bitwise

a & b        // Bitwise AND
a | b        // Bitwise OR
a ^ b        // Bitwise XOR
~a           // Bitwise NOT
a ~& b       // NAND
a ~| b       // NOR
a ~^ b       // XNOR

a << b       // Logical left shift
a >> b       // Logical right shift
a <<< b      // Arithmetic left shift
a >>> b      // Arithmetic right shift (sign extend)

Reduction

&data        // AND all bits
|data        // OR all bits
^data        // XOR all bits (parity)
~&data       // NAND all bits
~|data       // NOR all bits
~^data       // XNOR all bits

Comparison

// Numeric
a == b       // Equal
a != b       // Not equal
a < b        // Less than
a > b        // Greater than
a <= b       // Less than or equal
a >= b       // Greater than or equal

// Case equality (checks X and Z)
a === b      // Equal (4-state)
a !== b      // Not equal (4-state)

// Wildcard equality (? = don't care)
a ==? b      // Wildcard equal
a !=? b      // Wildcard not equal

// Examples
if (data === 8'bXXXX_0000)  // Matches X in upper nibble
if (opcode ==? 4'b10??)     // Matches 1000, 1001, 1010, 1011

Logical

a && b       // Logical AND
a || b       // Logical OR
!a           // Logical NOT

a ? b : c    // Conditional (ternary)

// Example
result = (sel) ? data_a : data_b;
mux = (sel == 2'b00) ? in0 :
      (sel == 2'b01) ? in1 :
      (sel == 2'b10) ? in2 : in3;

Special

{a, b}       // Concatenation: {4'h5, 4'hA} = 8'h5A
{n{a}}       // Replication: {8{1'b1}} = 8'hFF

a inside {[m:n], val}   // Range/set check
// if (addr inside {[0:127], 256})

$bits(var)   // Width of variable
$countones(data)  // Number of 1s
$onehot(val) // Exactly one bit is 1
$onehot0(val) // At most one bit is 1
$clog2(n)    // Ceiling log2

3. Arrays

Static Arrays

// Packed array (single vector)
bit [7:0] byte_val;          // 8-bit vector
byte_val[3] = 1'b1;          // Access individual bit

// Unpacked array (separate elements)
int memory[256];             // 256 integers
memory[10] = 42;

// Multi-dimensional
bit [7:0] mem[256];          // 256 bytes
int matrix[4][8];            // 4 rows, 8 columns
mem[10] = 8'hAA;
matrix[2][3] = 100;

Dynamic Arrays

// Dynamic array
int dyn_arr[];

// Allocate
dyn_arr = new[10];           // 10 elements
dyn_arr[5] = 100;

// Resize (copies old data)
dyn_arr = new[20](dyn_arr);

// Delete
dyn_arr.delete();

// Size
int size = dyn_arr.size();

Associative Arrays

// Associative array (sparse)
int assoc[string];           // String index
int mem[bit[31:0]];          // Address index

// Access
assoc["apple"] = 10;
assoc["orange"] = 20;
mem[32'h1000] = 42;

// Methods
if (assoc.exists("apple"))   // Check existence
  $display("Found");

assoc.delete("apple");       // Delete entry
int count = assoc.num();     // Number of entries

// Iterate
string key;
if (assoc.first(key))        // Get first key
  do begin
    $display("%s => %0d", key, assoc[key]);
  end while (assoc.next(key));  // Get next key

Queues

// Queue (dynamic, indexed)
int q[$];                    // Unbounded queue
int bounded_q[$:15];         // Max 16 elements (0-15)

// Operations
q.push_back(10);             // Add to end
q.push_front(5);             // Add to front
int val = q.pop_back();      // Remove from end
int val2 = q.pop_front();    // Remove from front

q.insert(2, 99);             // Insert at index 2
q.delete(3);                 // Delete index 3
q.delete();                  // Delete all

int size = q.size();         // Get size

// Initialize
int q[$] = {1, 2, 3, 4, 5};

Array Methods

int arr[5] = '{10, 20, 30, 40, 50};

// Reduction
int sum = arr.sum();         // 150
int prod = arr.product();    // 12000000
int max_val = arr.max();     // 50
int min_val = arr.min();     // 10

// Manipulation
arr.reverse();               // Reverse order
arr.sort();                  // Ascending sort
arr.rsort();                 // Descending sort
arr.shuffle();               // Random order

// Locator methods (return queue)
int q[$];
q = arr.find with (item > 25);           // {30, 40, 50}
q = arr.find_index with (item > 25);     // {2, 3, 4} (indices)
q = arr.find_first with (item > 25);     // {30}
q = arr.find_last with (item < 45);      // {40}

// Unique
q = arr.unique();            // Remove duplicates

4. Control Structures

Conditional Statements

// If-else
if (condition) begin
  // Code
end else if (other_condition) begin
  // Code
end else begin
  // Code
end

// Single line (no begin-end needed)
if (a > b) result = a;
else result = b;

// Ternary operator
result = (condition) ? true_val : false_val;

// Unique/Priority if
unique if (a) action_a();    // Warns if multiple true
else if (b) action_b();

priority if (a) action_a();  // First true wins
else if (b) action_b();

Case Statements

// Case
case (select)
  2'b00: out = in0;
  2'b01: out = in1;
  2'b10: out = in2;
  2'b11: out = in3;
  default: out = 0;
endcase

// Case inside (range matching)
case (data) inside
  [0:63]:   $display("Low");
  [64:127]: $display("Mid");
  [128:255]: $display("High");
endcase

// Casex (X and Z are don't cares)
casex (opcode)
  4'b0000: nop();
  4'b001X: read();   // Matches 0010, 0011
  4'b01XX: write();  // Matches 0100-0111
endcase

// Casez (Z is don't care)
casez (grant)
  4'b0001: master0();
  4'b001?: master1();  // Matches 0010, 0011
  4'b01??: master2();  // Matches 0100-0111
endcase

// Unique case (warns if overlap or not all covered)
unique case (state)
  IDLE: next = ACTIVE;
  ACTIVE: next = DONE;
  DONE: next = IDLE;
endcase

// Priority case (first match wins)
priority case (cmd)
  4'b0000: nop();
  4'b001?: read();   // Has priority
  4'b01??: write();
endcase

Loops

// For loop
for (int i = 0; i < 10; i++) begin
  $display("i = %0d", i);
end

// While loop
while (count < 100) begin
  count++;
end

// Do-while
do begin
  count++;
end while (count < 100);

// Repeat
repeat (10) begin
  @(posedge clk);
end

// Foreach (arrays)
int arr[5] = '{1, 2, 3, 4, 5};
foreach (arr[i]) begin
  $display("arr[%0d] = %0d", i, arr[i]);
end

// Forever
forever begin
  @(posedge clk);
  // Process
end

// Loop control
break;       // Exit loop
continue;    // Next iteration
return;      // Exit function/task

5. Procedural Blocks

Always Blocks

// Combinational logic
always_comb begin
  sum = a + b;
  product = a * b;
end

// Sequential logic (flip-flops)
always_ff @(posedge clk or negedge reset_n) begin
  if (!reset_n)
    q <= 0;
  else
    q <= d;
end

// Latch (avoid!)
always_latch begin
  if (enable)
    q <= d;
end

// Initial (runs once at time 0)
initial begin
  clk = 0;
  reset_n = 0;
  #100ns reset_n = 1;
end

// Final (runs at end of simulation)
final begin
  $display("Simulation complete");
  $display("Total errors: %0d", error_count);
end

Fork-Join

// fork-join: Wait for ALL threads
fork
  #10ns process1();
  #20ns process2();
  #15ns process3();
join
// Continues at 20ns (when all complete)

// fork-join_any: Wait for FIRST thread
fork
  #10ns process1();
  #20ns process2();
join_any
// Continues at 10ns (when first completes)

// fork-join_none: Don't wait
fork
  #10ns process1();
  #20ns process2();
join_none
// Continues immediately

// Disable fork (kill all threads)
fork
  forever #10ns $display("Thread 1");
  forever #20ns $display("Thread 2");
join_none

#100ns;
disable fork;  // Kill all forked processes

// Wait fork (wait for all forked to complete)
wait fork;

6. Modules and Ports

Module Definition

module adder #(
  parameter WIDTH = 8
)(
  input  logic             clk,
  input  logic             reset_n,
  input  logic [WIDTH-1:0] a,
  input  logic [WIDTH-1:0] b,
  output logic [WIDTH-1:0] sum
);

  always_ff @(posedge clk or negedge reset_n) begin
    if (!reset_n)
      sum <= 0;
    else
      sum <= a + b;
  end

endmodule

// Instantiation
adder #(.WIDTH(16)) adder_inst (
  .clk(clk),
  .reset_n(reset_n),
  .a(data_a),
  .b(data_b),
  .sum(result)
);

// Implicit port connection (.*)
adder #(.WIDTH(16)) adder_inst (.*);
// Connects ports with same names

Port Types

// Input/Output/Inout
input  logic [7:0] data_in;
output logic [7:0] data_out;
inout  logic [7:0] data_bidir;

// Output types
output logic data;       // Can be driven in procedural
output wire  data;       // Continuous assignment only

// Ref port (pass by reference)
module check(ref logic[7:0] data);
  // Can read/write original data (no copy)
endmodule

7. Always Blocks Deep Dive

Always_comb

// Combinational logic (auto-sensitivity)
always_comb begin
  y = a & b;
  z = c | d;
  // Automatically sensitive to a, b, c, d
end

// Can read from arrays
logic [7:0] rom[256];
logic [7:0] addr, data;

always_comb begin
  data = rom[addr];  // Legal in always_comb!
end

// Must assign in all branches
always_comb begin
  case (sel)
    2'b00: out = in0;
    2'b01: out = in1;
    2'b10: out = in2;
    2'b11: out = in3;
    // Must cover all cases or use default
  endcase
end

Always_ff

// D Flip-Flop
always_ff @(posedge clk) begin
  q <= d;
end

// With async reset
always_ff @(posedge clk or negedge reset_n) begin
  if (!reset_n)
    q <= 0;
  else
    q <= d;
end

// With sync reset
always_ff @(posedge clk) begin
  if (!reset_n)
    q <= 0;
  else
    q <= d;
end

// Multiple clock domains
always_ff @(posedge clk_a) begin
  data_a <= input_a;
end

always_ff @(posedge clk_b) begin
  data_b <= input_b;
end

Blocking vs Non-Blocking

// Non-blocking (<=) for sequential logic
always_ff @(posedge clk) begin
  a <= b;
  c <= a;  // Uses OLD value of a
end

// Blocking (=) for combinational logic
always_comb begin
  temp = a + b;
  result = temp * 2;  // Uses NEW value of temp
end

// RULE: Use <= in always_ff, = in always_comb

8. Functions and Tasks

Functions

// Function (no time delay, returns value)
function int add(int a, int b);
  return a + b;
endfunction

int result = add(5, 3);

// Automatic function (re-entrant)
function automatic int factorial(int n);
  if (n <= 1)
    return 1;
  else
    return n * factorial(n-1);
endfunction

// Void function (no return)
function void print_data(int data);
  $display("Data: %0d", data);
endfunction

// Default arguments
function int add_with_default(int a, int b = 10);
  return a + b;
endfunction

result = add_with_default(5);     // 15 (uses default b=10)
result = add_with_default(5, 20); // 25

Tasks

// Task (can have time delay, no return value)
task wait_cycles(int n);
  repeat(n) @(posedge clk);
endtask

wait_cycles(10);

// Task with output
task read_memory(input int addr, output int data);
  @(posedge clk);
  data = mem[addr];
endtask

int read_data;
read_memory(32'h100, read_data);

// Automatic task (re-entrant)
task automatic drive_transaction(transaction_t txn);
  @(posedge clk);
  bus.addr = txn.addr;
  bus.data = txn.data;
endtask

// Ref argument (pass by reference)
task modify_data(ref int data);
  data = data * 2;  // Modifies original
endtask

9. Classes and OOP

Basic Class

class packet;
  
  // Properties
  rand bit [7:0]  addr;
  rand bit [31:0] data;
  rand bit        write;
  
  // Constructor
  function new(string name = "packet");
    $display("Creating %s", name);
  endfunction
  
  // Methods
  function void display();
    $display("addr=%h, data=%h, write=%b", addr, data, write);
  endfunction
  
  task send();
    #10ns;
    $display("Sending packet");
  endtask
  
endclass

// Usage
packet pkt;
pkt = new("my_packet");
pkt.addr = 8'h10;
pkt.display();

Inheritance

// Base class
class base_packet;
  rand bit [7:0] addr;
  
  function void display();
    $display("Base: addr=%h", addr);
  endfunction
endclass

// Derived class
class extended_packet extends base_packet;
  rand bit [31:0] data;
  
  // Override method
  function void display();
    super.display();  // Call parent method
    $display("Extended: data=%h", data);
  endfunction
  
  // New method
  function void process();
    $display("Processing...");
  endfunction
endclass

// Polymorphism
extended_packet ext = new();
base_packet base = ext;  // Upcast
base.display();          // Calls extended version if virtual

Virtual Methods

class base;
  virtual function void show();
    $display("Base");
  endfunction
endclass

class derived extends base;
  function void show();
    $display("Derived");
  endfunction
endclass

// Polymorphism
base b;
derived d = new();
b = d;
b.show();  // Prints "Derived" (dynamic binding)

Static Members

class counter;
  static int count = 0;  // Shared across all instances
  int id;                // Unique per instance
  
  function new();
    count++;
    id = count;
  endfunction
  
  static function int get_count();
    return count;
  endfunction
endclass

counter c1 = new();  // count=1, id=1
counter c2 = new();  // count=2, id=2
$display("Total: %0d", counter::get_count());  // 2

10. Interfaces

Basic Interface

interface apb_if(input logic pclk);
  
  logic        preset_n;
  logic [31:0] paddr;
  logic        psel;
  logic        penable;
  logic        pwrite;
  logic [31:0] pwdata;
  logic [31:0] prdata;
  logic        pready;
  
  // Modport (view)
  modport master (
    input  pclk, preset_n, prdata, pready,
    output paddr, psel, penable, pwrite, pwdata
  );
  
  modport slave (
    input  pclk, preset_n, paddr, psel, penable, pwrite, pwdata,
    output prdata, pready
  );
  
  // Tasks in interface
  task write_transfer(input bit[31:0] addr, data);
    @(posedge pclk);
    paddr = addr;
    pwdata = data;
    pwrite = 1;
    psel = 1;
    penable = 0;
    @(posedge pclk);
    penable = 1;
    wait(pready);
    @(posedge pclk);
    psel = 0;
    penable = 0;
  endtask
  
endinterface

// Module using interface
module apb_master(apb_if.master bus);
  always @(posedge bus.pclk) begin
    bus.psel <= 1;
  end
endmodule

// Instantiation
apb_if bus(clk);
apb_master master(bus);

Virtual Interface

// For use in classes
class driver;
  virtual apb_if vif;  // Virtual interface handle
  
  function new(virtual apb_if v);
    vif = v;
  endfunction
  
  task drive(bit[31:0] addr, data);
    @(posedge vif.pclk);
    vif.paddr = addr;
    vif.pwdata = data;
  endtask
endclass

// Usage
apb_if bus(clk);
driver drv = new(bus);
drv.drive(32'h100, 32'hDEAD);

11. Constraints and Randomization

Basic Constraints

class packet;
  rand bit [7:0] addr;
  rand bit [31:0] data;
  rand bit write;
  
  // Constraint block
  constraint addr_range {
    addr inside {[0:127]};
  }
  
  constraint data_nonzero {
    data != 0;
  }
  
  // Distribution
  constraint write_dist {
    write dist {0 := 30, 1 := 70};  // 30% read, 70% write
  }
endclass

// Randomize
packet pkt = new();
assert(pkt.randomize());

Advanced Constraints

class advanced;
  rand bit [7:0] addr;
  rand bit [31:0] data;
  rand bit [7:0] len;
  rand bit [7:0] arr[];
  
  // Implication
  constraint impl {
    (len > 10) -> (addr < 100);  // If len>10, then addr<100
  }
  
  // If-else
  constraint cond {
    if (addr < 128)
      data < 1000;
    else
      data < 2000;
  }
  
  // Foreach
  constraint array_constraint {
    arr.size() == len;
    foreach(arr[i]) {
      arr[i] inside {[0:100]};
      if (i > 0)
        arr[i] > arr[i-1];  // Increasing
    }
  }
  
  // Unique
  constraint unique_elements {
    unique {arr};  // All elements unique
  }
  
  // Solve-before
  constraint solve_order {
    solve len before arr;
  }
  
  // Soft (can be overridden)
  constraint soft_default {
    soft addr == 0;
  }
endclass

// Inline constraints
assert(pkt.randomize() with {
  addr < 50;
  data inside {[100:200]};
  write == 1;
});

// Constraint control
pkt.addr_range.constraint_mode(0);  // Disable
pkt.addr_range.constraint_mode(1);  // Enable

// Pre/Post randomize
class smart_packet;
  rand bit[7:0] addr;
  
  function void pre_randomize();
    $display("Before randomization");
  endfunction
  
  function void post_randomize();
    addr[1:0] = 2'b00;  // Force alignment
    $display("After: addr=%h", addr);
  endfunction
endclass

Random Functions

// $urandom - Random 32-bit unsigned
data = $urandom();

// $urandom_range - Random in range [min:max]
data = $urandom_range(0, 100);  // 0 to 100 inclusive
data = $urandom_range(10, 20);

// Randomize variables directly
int addr, data;
assert(std::randomize(addr, data) with {
  addr < 256;
  data != 0;
});

// Randcase (weighted random selection)
randcase
  10: action_a();  // 10/(10+20+70) = 10%
  20: action_b();  // 20%
  70: action_c();  // 70%
endcase

12. Functional Coverage

Covergroup Essentials

class transaction;
  rand bit [7:0] addr;
  rand bit [31:0] data;
  rand bit write;
  
  // Covergroup
  covergroup cg;
    
    // Simple coverpoint
    addr_cp: coverpoint addr {
      bins low  = {[0:63]};
      bins mid  = {[64:127]};
      bins high = {[128:255]};
    }
    
    // Auto bins
    write_cp: coverpoint write {
      bins read  = {0};
      bins write = {1};
    }
    
    // Bins with expression
    data_cp: coverpoint data {
      bins even[] = {[0:255]} with (item % 2 == 0);
      bins odd[]  = {[0:255]} with (item % 2 == 1);
    }
    
    // Cross coverage
    addr_write_cross: cross addr_cp, write_cp;
    
    // Transition coverage
    state_cp: coverpoint state {
      bins trans1 = (IDLE => ACTIVE);
      bins trans2 = (ACTIVE => DONE);
      bins sequence = (IDLE => ACTIVE => DONE);
    }
    
    // Ignore/Illegal bins
    cmd_cp: coverpoint cmd {
      bins valid = {[0:10]};
      ignore_bins reserved = {11, 12};
      illegal_bins invalid = {[13:15]};
    }
    
  endgroup
  
  function new();
    cg = new();
  endfunction
  
  function void post_randomize();
    cg.sample();
  endfunction
endclass

// Query coverage
real cov = pkt.cg.get_coverage();
$display("Coverage: %0.2f%%", cov);

Coverage Options

covergroup cg_opts;
  option.per_instance = 1;     // Separate per instance
  option.at_least = 10;        // Each bin ≥ 10 hits
  option.auto_bin_max = 64;    // Max auto bins
  option.goal = 95;            // Coverage goal %
  
  coverpoint addr {
    option.weight = 5;         // Weight in total coverage
    bins values[] = {[0:255]};
  }
endgroup

13. Assertions

Immediate Assertions

// In procedural code
always @(posedge clk) begin
  assert (data < 256) 
    else $error("Data overflow!");
  
  assert (count >= 0 && count <= MAX)
    else $fatal("Count out of bounds!");
end

// In functions
function void check_valid(bit[7:0] val);
  assert (val inside {[0:200]})
    else $warning("Value out of range: %0d", val);
endfunction

Concurrent Assertions

// Property definition
property req_gnt;
  @(posedge clk) disable iff (!reset_n)
    req |=> gnt;
endproperty

// Assert property
assert property (req_gnt)
  else $error("Grant missing!");

// Cover property
cover property (req_gnt)
  $display("Request-Grant occurred");

// Assume property (for formal)
assume property (req_gnt)
  else $error("Input constraint violated!");

Assertion Operators

// Implication
req |-> ack      // Overlapping (same cycle)
req |=> ack      // Non-overlapping (next cycle)

// Delay
##3              // Exactly 3 cycles
##[1:5]          // 1 to 5 cycles
##[1:$]          // Eventually (1 or more)

// Repetition
a[*3]            // Exactly 3 consecutive
a[*2:5]          // 2-5 consecutive
a[*]             // 0 or more consecutive
a[+]             // 1 or more consecutive
a[->3]           // 3 occurrences (non-consecutive)
a[=3]            // 3 occurrences, match after last

// Examples
property p1;
  @(posedge clk) disable iff (!reset_n)
    req |-> ##[1:5] gnt;  // Grant within 1-5 cycles
endproperty

property p2;
  @(posedge clk) disable iff (!reset_n)
    busy[*3] ##1 done;    // Busy for 3 cycles, then done
endproperty

property p3;
  @(posedge clk) disable iff (!reset_n)
    req[->3] |=> ack;     // After 3 requests, ack next cycle
endproperty

// System functions in assertions
$rose(signal)    // Rising edge
$fell(signal)    // Falling edge
$stable(signal)  // Value unchanged
$past(signal,N)  // Value N cycles ago
$onehot(signal)  // Exactly one bit

// Example
property p_rose;
  @(posedge clk) disable iff (!reset_n)
    $rose(req) |-> gnt;
endproperty

Local Variables in Assertions

property addr_preserved;
  logic [7:0] captured_addr;
  @(posedge clk) disable iff (!reset_n)
    (start, captured_addr = addr_in) |-> 
    ##[1:10] (done && (addr_out == captured_addr));
endproperty

assert property (addr_preserved)
  else $error("Address mismatch!");

14. Common Patterns

14.1 Clock and Reset

// Simple clock
logic clk = 0;
always #5ns clk = ~clk;  // 10ns period, 100MHz

// Clock with duty cycle
logic clk = 0;
always begin
  #3ns clk = 1;  // High for 3ns
  #7ns clk = 0;  // Low for 7ns
end

// Reset generation
logic reset_n;
initial begin
  reset_n = 0;
  #100ns reset_n = 1;
end

// Synchronous reset
logic reset;
initial begin
  reset = 1;
  repeat(5) @(posedge clk);
  reset = 0;
end

14.2 Memory Model

module memory #(
  parameter DEPTH = 256,
  parameter WIDTH = 32
)(
  input  logic              clk,
  input  logic              wr_en,
  input  logic              rd_en,
  input  logic [7:0]        addr,
  input  logic [WIDTH-1:0]  wr_data,
  output logic [WIDTH-1:0]  rd_data
);

  logic [WIDTH-1:0] mem [DEPTH];
  
  // Write
  always_ff @(posedge clk) begin
    if (wr_en)
      mem[addr] <= wr_data;
  end
  
  // Read
  always_ff @(posedge clk) begin
    if (rd_en)
      rd_data <= mem[addr];
  end

endmodule

14.3 FSM Pattern

typedef enum logic [1:0] {
  IDLE   = 2'b00,
  ACTIVE = 2'b01,
  WAIT   = 2'b10,
  DONE   = 2'b11
} state_t;

state_t state, next_state;

// State register
always_ff @(posedge clk or negedge reset_n) begin
  if (!reset_n)
    state <= IDLE;
  else
    state <= next_state;
end

// Next state logic
always_comb begin
  next_state = state;  // Default: stay in current state
  
  case (state)
    IDLE: begin
      if (start)
        next_state = ACTIVE;
    end
    
    ACTIVE: begin
      if (done)
        next_state = WAIT;
      else if (error)
        next_state = IDLE;
    end
    
    WAIT: begin
      if (ready)
        next_state = DONE;
    end
    
    DONE: begin
      next_state = IDLE;
    end
  endcase
end

// Output logic
always_comb begin
  busy = (state != IDLE);
  complete = (state == DONE);
end

14.4 Handshake Protocols

// 2-phase handshake (valid-ready)
task send_data(bit[7:0] data);
  valid = 1;
  data_out = data;
  @(posedge clk iff ready);  // Wait for ready
  @(posedge clk);
  valid = 0;
endtask

// 4-phase handshake (req-ack)
task four_phase(bit[7:0] data);
  req = 1;
  data_out = data;
  wait(ack == 1);
  req = 0;
  wait(ack == 0);
endtask

// Pipelined handshake
always_ff @(posedge clk) begin
  if (valid && ready) begin
    data_reg <= data_in;
    // Transfer occurs
  end
end

14.5 FIFO Template

module fifo #(
  parameter DEPTH = 16,
  parameter WIDTH = 32
)(
  input  logic              clk,
  input  logic              reset_n,
  input  logic              wr_en,
  input  logic              rd_en,
  input  logic [WIDTH-1:0]  wr_data,
  output logic [WIDTH-1:0]  rd_data,
  output logic              full,
  output logic              empty
);

  logic [WIDTH-1:0] mem [DEPTH];
  logic [$clog2(DEPTH):0] count;
  logic [$clog2(DEPTH)-1:0] wr_ptr, rd_ptr;
  
  assign full = (count == DEPTH);
  assign empty = (count == 0);
  
  // Write
  always_ff @(posedge clk or negedge reset_n) begin
    if (!reset_n)
      wr_ptr <= 0;
    else if (wr_en && !full) begin
      mem[wr_ptr] <= wr_data;
      wr_ptr <= wr_ptr + 1;
    end
  end
  
  // Read
  always_ff @(posedge clk or negedge reset_n) begin
    if (!reset_n) begin
      rd_ptr <= 0;
      rd_data <= 0;
    end else if (rd_en && !empty) begin
      rd_data <= mem[rd_ptr];
      rd_ptr <= rd_ptr + 1;
    end
  end
  
  // Count
  always_ff @(posedge clk or negedge reset_n) begin
    if (!reset_n)
      count <= 0;
    else begin
      case ({wr_en && !full, rd_en && !empty})
        2'b10: count <= count + 1;
        2'b01: count <= count - 1;
        default: count <= count;
      endcase
    end
  end

endmodule

15. Quick Reference

Data Type Quick Ref

TypeBitsStateRangeUse
bit1+20,1Fast simulation
logic1+40,1,X,ZHardware modeling
byte82-128..127Signed byte
shortint162-32K..32KSigned short
int322-2G..2GSigned integer
longint642LargeSigned long
real642FloatReal numbers
stringN/A2TextStrings

Array Type Quick Ref

TypeDeclarationSizeIndexUse
Packedbit[7:0]Fixed[n]Single vector
Unpackedint arr[10]Fixed[n]Separate elements
Dynamicint arr[]Runtime[]Growing/shrinking
Associativeint a[string]Sparse[type]Sparse/large
Queueint q[$]Dynamic[$]FIFO-like

Operator Precedence (High to Low)

1.  ()  []  ::  .
2.  +  -  !  ~  (unary)
3.  **
4.  *  /  %
5.  +  -  (binary)
6.  <<  >>  <<<  >>>
7.  <  <=  >  >=  inside
8.  ==  !=  ===  !==  ==?  !=?
9.  &  ~&
10. ^  ~^
11. |  ~|
12. &&
13. ||
14. ?:

System Tasks

// Display
$display("Format", args);    // Print with newline
$write("Format", args);      // Print without newline
$monitor("expr=%d", expr);   // Print on change
$strobe("val=%d", val);      // Print at end of timestep

// Format specifiers
%b  // Binary
%d  // Decimal
%h  // Hex
%o  // Octal
%t  // Time
%s  // String
%0d // No leading spaces

// Simulation control
$finish;     // End simulation
$stop;       // Pause simulation
$exit;       // Exit current process

// Time
$time;       // Current simulation time
$realtime;   // Real time
#10ns;       // Delay 10ns

// File I/O
$fopen("file.txt", "w");
$fclose(fd);
$fdisplay(fd, "data=%h", data);
$readmemh("file.hex", mem);
$writememh("out.hex", mem);

// Random
$urandom();                  // Random 32-bit
$urandom_range(min, max);    // Range [min:max]

// VCD dump
$dumpfile("waves.vcd");
$dumpvars(0, top);
$dumpon; $dumpoff;

// Assertion control
$assertoff; $asserton;
$assertkill;

Common Idioms

// Wait for condition
wait(done == 1);
@(posedge clk iff ready);

// Edge detection
@(posedge clk);   // Wait for rising edge
@(negedge clk);   // Wait for falling edge
@(clk);           // Wait for any edge

// Delay
#10ns;            // Absolute delay
#(2*CLK_PERIOD);  // Calculated delay
repeat(5) @(posedge clk);  // 5 clock cycles

// Default values
int data = 0;
logic [7:0] addr = 8'h00;

// Array initialization
int arr[5] = '{1, 2, 3, 4, 5};           // Positional
int arr2[5] = '{default: 0};             // All zeros
int arr3[10] = '{0:99, 5:55, default:0}; // Specific + default

// Structure assignment
typedef struct {int a; int b;} pair_t;
pair_t p = '{a: 10, b: 20};
pair_t p2 = '{default: 0};

// Bit manipulation
data[3] = 1'b1;              // Set bit 3
data = data | (1 << n);      // Set bit n
data = data & ~(1 << n);     // Clear bit n
data = data ^ (1 << n);      // Toggle bit n

// Swap
{a, b} = {b, a};

// Multiple assign
{high, low} = {data[15:8], data[7:0]};

Complete Examples

Example 1: Simple Counter

module counter #(
  parameter WIDTH = 8
)(
  input  logic             clk,
  input  logic             reset_n,
  input  logic             enable,
  output logic [WIDTH-1:0] count
);

  always_ff @(posedge clk or negedge reset_n) begin
    if (!reset_n)
      count <= 0;
    else if (enable)
      count <= count + 1;
  end

endmodule

Example 2: Mux

module mux4to1 #(parameter WIDTH = 8)(
  input  logic [1:0]       sel,
  input  logic [WIDTH-1:0] in0, in1, in2, in3,
  output logic [WIDTH-1:0] out
);

  always_comb begin
    case (sel)
      2'b00: out = in0;
      2'b01: out = in1;
      2'b10: out = in2;
      2'b11: out = in3;
    endcase
  end

endmodule

Example 3: Testbench

module tb;
  
  logic clk = 0;
  logic reset_n;
  logic [7:0] data_in, data_out;
  
  // Clock generation
  always #5ns clk = ~clk;
  
  // DUT instantiation
  dut dut_inst(
    .clk(clk),
    .reset_n(reset_n),
    .data_in(data_in),
    .data_out(data_out)
  );
  
  // Test stimulus
  initial begin
    reset_n = 0;
    data_in = 0;
    
    #100ns reset_n = 1;
    
    repeat(100) begin
      @(posedge clk);
      data_in = $urandom();
    end
    
    #100ns;
    $finish;
  end
  
  // Monitor
  always @(posedge clk) begin
    if (reset_n)
      $display("Time=%0t: in=%h, out=%h", $time, data_in, data_out);
  end
  
endmodule

Example 4: Class-Based Testbench

class transaction;
  rand bit [7:0] addr;
  rand bit [31:0] data;
  
  constraint addr_c {
    addr inside {[0:127]};
  }
  
  function void display();
    $display("addr=%h, data=%h", addr, data);
  endfunction
endclass

class driver;
  virtual dut_if vif;
  
  function new(virtual dut_if v);
    vif = v;
  endfunction
  
  task drive(transaction txn);
    @(posedge vif.clk);
    vif.addr <= txn.addr;
    vif.data <= txn.data;
  endtask
endclass

module tb;
  dut_if bus(clk);
  driver drv;
  
  initial begin
    transaction txn;
    drv = new(bus);
    
    repeat(100) begin
      txn = new();
      assert(txn.randomize());
      drv.drive(txn);
    end
    
    $finish;
  end
endmodule

SystemVerilog in One Page

//=============================================================================
// SYSTEMVERILOG COMPLETE SYNTAX
//=============================================================================

// DATA TYPES
bit [7:0] b;              // 2-state
logic [7:0] l;            // 4-state
int i; byte by; shortint si; longint li;
real r; string s;

// ARRAYS
int arr[10];              // Static
int dyn[];                // Dynamic: dyn = new[10]
int assoc[string];        // Associative
int q[$];                 // Queue

// OPERATORS
// Arithmetic: + - * / % **
// Bitwise: & | ^ ~ << >> <<< >>>
// Reduction: &vec |vec ^vec
// Logical: && || !
// Compare: == != < > <= >= === !== ==?
// Concat: {a,b}  Replicate: {n{a}}

// PROCEDURAL
always_comb   y = a & b;        // Combinational
always_ff @(posedge clk) q <= d; // Sequential
always_latch if(en) q <= d;     // Latch
initial begin end               // Once at t=0
final begin end                 // At end

// CONTROL
if (c) {} else if {} else {}
case (x) endcase
for (int i=0; i<n; i++) {}
while (c) {}
foreach (arr[i]) {}
repeat (n) @(posedge clk);

// FUNCTIONS/TASKS
function int add(int a, b);
  return a + b;
endfunction

task wait_cycles(int n);
  repeat(n) @(posedge clk);
endtask

// CLASSES
class packet;
  rand bit[7:0] addr;
  constraint c {addr < 128;}
  function new(); endfunction
endclass

packet p = new();
assert(p.randomize());

// INTERFACE
interface bus_if(input clk);
  logic [7:0] data;
  modport master(output data);
  modport slave(input data);
endinterface

// COVERAGE
covergroup cg;
  coverpoint addr;
  cross addr, write;
endgroup

// ASSERTIONS
property p1;
  @(posedge clk) req |=> gnt;
endproperty
assert property (p1);

// SYSTEM TASKS
$display, $write, $monitor
$finish, $stop, $time
$urandom, $urandom_range
$readmemh, $writememh

Quick Lookup Tables

Signal Initialization

PatternExampleResult
Default allarr[5] = ‘{default: 0}All = 0
Positionalarr = ‘{1,2,3}arr[0]=1, arr[1]=2, arr[2]=3
Namedarr = ‘{0:10, 2:20, default:0}arr[0]=10, arr[2]=20, rest=0
Replicatearr = ‘{4{8’hFF}}First 4 = 0xFF

Process Control

StatementMeaning
@(posedge clk)Wait for rising edge
@(negedge clk)Wait for falling edge
@(clk)Wait for any edge
@(*)Combinational sensitivity
#10nsWait 10 nanoseconds
wait(condition)Wait for condition true
->eventTrigger event
@(event)Wait for event
fork-joinWait for all threads
fork-join_anyWait for first thread
fork-join_noneDon’t wait
disable forkKill all threads
wait forkWait for all forked

Severity Levels

TaskWhen to UseEffect
$fatalCritical errorTerminates simulation
$errorFunctional errorReport, continue
$warningUnexpected conditionReport, continue
$infoInformationalReport, continue
$displayGeneral outputPrint message

For Hardware Engineers

Log File Parser

module log_parser;
  
  int fd;
  string line;
  int errors = 0;
  int warnings = 0;
  
  initial begin
    fd = $fopen("sim.log", "r");
    
    while (!$feof(fd)) begin
      $fgets(line, fd);
      
      if (line.match("ERROR"))
        errors++;
      
      if (line.match("WARNING"))
        warnings++;
      
      // Extract hex values
      if (line.match("Data: 0x([0-9A-Fa-f]+)")) begin
        // Process hex data
      end
    end
    
    $fclose(fd);
    $display("Errors: %0d, Warnings: %0d", errors, warnings);
  end
  
endmodule

Stimulus Generation

module stimulus_gen;
  
  logic clk;
  logic [7:0] data;
  logic valid;
  
  // Random stimulus
  initial begin
    valid = 0;
    repeat(100) begin
      @(posedge clk);
      data = $urandom_range(0, 255);
      valid = $urandom_range(0, 1);
    end
  end
  
  // Pattern generation
  initial begin
    // Walking ones
    for (int i = 0; i < 8; i++) begin
      @(posedge clk);
      data = (1 << i);
    end
    
    // Walking zeros
    for (int i = 0; i < 8; i++) begin
      @(posedge clk);
      data = ~(1 << i);
    end
    
    // All zeros
    @(posedge clk); data = 8'h00;
    
    // All ones
    @(posedge clk); data = 8'hFF;
    
    // Alternating
    @(posedge clk); data = 8'hAA;
    @(posedge clk); data = 8'h55;
  end
  
endmodule

Protocol Checker

module apb_checker(
  input logic pclk,
  input logic preset_n,
  input logic psel,
  input logic penable,
  input logic pready
);

  // Protocol assertions
  property setup_access;
    @(posedge pclk) disable iff (!preset_n)
      (psel && !penable) |=> (psel && penable);
  endproperty
  
  a_protocol: assert property (setup_access)
    else $error("APB: Setup not followed by access!");
  
  property pready_timeout;
    @(posedge pclk) disable iff (!preset_n)
      (psel && penable) |-> ##[0:15] pready;
  endproperty
  
  a_timeout: assert property (pready_timeout)
    else $error("APB: PREADY timeout!");
  
  // Coverage
  covergroup apb_cg @(posedge pclk);
    state_cp: coverpoint {psel, penable} {
      bins idle   = {2'b00};
      bins setup  = {2'b10};
      bins access = {2'b11};
      illegal_bins invalid = {2'b01};
    }
    
    transitions_cp: coverpoint {psel, penable} {
      bins idle_setup = (2'b00 => 2'b10);
      bins setup_access = (2'b10 => 2'b11);
      bins access_idle = (2'b11 => 2'b00);
    }
  endgroup
  
  apb_cg cg = new();
  
endmodule

Comparison Tables

Blocking vs Non-Blocking

AssignmentUse InExecutionExample
=always_combSequentialtemp = a + b;
<=always_ffParallel (scheduled)q <= d;

Rule: Use <= in always_ff, use = in always_comb

Array Comparison

FeaturePackedUnpackedDynamicAssociativeQueue
Declarationbit[7:0]int a[10]int a[]int a[string]int q[$]
SizeFixedFixedRuntimeSparseDynamic
AllocationStaticStaticnew[n]AutoAuto
Access[n][n][n][key][n]
UseVectorArrayGrowingSparse/HashFIFO

Always Block Types

BlockUseSensitivityBlocking
always_combCombinationalAutomatic=
always_ffSequential@(edge)<=
always_latchLatchAutomatic= or <=
always @(*)Comb (legacy)Automatic=
always @(posedge)Seq (legacy)Explicit<=

Best Practices

✅ DO

## Quick Reference Guide for SystemVerilog

*Your one-stop SystemVerilog reference for rapid development*

---

## 1. Data Types

```systemverilog
// TWO-STATE (0, 1) - Faster
bit           b;           // 1-bit
bit [7:0]     byte_val;    // 8-bit
byte          sb;          // 8-bit signed (-128..127)
shortint      si;          // 16-bit signed
int           i;           // 32-bit signed
longint       li;          // 64-bit signed

// FOUR-STATE (0, 1, X, Z) - Hardware
logic         l;           // Can be X, Z
logic [7:0]   lv;
reg  [31:0]   r;           // Same as logic
wire [7:0]    w;

// OTHER
real          f;           // 64-bit float
string        s = "text";  // Dynamic string
time          t;           // 64-bit time

// USER-DEFINED
typedef bit[7:0] byte_t;

typedef enum logic[1:0] {
  IDLE, ACTIVE, WAIT, DONE
} state_t;

typedef struct packed {
  bit [7:0] opcode;
  bit [7:0] data;
} instruction_t;

2. Arrays

// PACKED (single vector)
bit [7:0] byte_val;          // 8-bit
byte_val[3] = 1'b1;          // Bit access

// UNPACKED (separate elements)
int memory[256];             // 256 integers
int matrix[4][8];            // 4x8 matrix

// DYNAMIC
int dyn[];
dyn = new[10];               // Allocate 10
dyn = new[20](dyn);          // Resize, copy
dyn.delete();                // Free

// ASSOCIATIVE (sparse)
int assoc[string];           // String key
assoc["key"] = 100;
if (assoc.exists("key")) ...
assoc.delete("key");

// QUEUE (FIFO-like)
int q[$];                    // Unbounded
q.push_back(10);
q.push_front(5);
int val = q.pop_back();
int val2 = q.pop_front();

// INITIALIZATION
int arr[5] = '{1, 2, 3, 4, 5};              // Positional
int arr2[10] = '{default: 0};               // All zeros
int arr3[10] = '{0:99, 5:55, default:0};    // Named + default

// METHODS
sum = arr.sum();
arr.reverse();
arr.sort();
arr.shuffle();
q = arr.find with (item > 5);

3. Operators

// ARITHMETIC
+ - * / % **                 // a ** b = a^b

// BITWISE
& | ^ ~ ~& ~| ~^            // AND OR XOR NOT NAND NOR XNOR
<< >> <<< >>>               // Shift

// REDUCTION
&data  |data  ^data         // AND/OR/XOR all bits

// COMPARISON
== != < > <= >=             // Numeric
=== !==                     // 4-state (checks X, Z)
==? !=?                     // Wildcard (? = don't care)

// LOGICAL
&& || !                     // AND OR NOT

// SPECIAL
{a, b}                      // Concatenate
{n{a}}                      // Replicate: {8{1'b1}} = 8'hFF
a ? b : c                   // Conditional
inside {[m:n], val}         // Range check

// USEFUL FUNCTIONS
$bits(var)                  // Width
$countones(data)            // Number of 1s
$onehot(val)                // Exactly one bit
$clog2(n)                   // Ceiling log2
$urandom()                  // Random 32-bit
$urandom_range(min, max)    // Random in range

4. Procedural Blocks

// COMBINATIONAL
always_comb begin
  y = a & b;
end

// SEQUENTIAL
always_ff @(posedge clk or negedge reset_n) begin
  if (!reset_n)
    q <= 0;
  else
    q <= d;
end

// INITIAL (once at t=0)
initial begin
  clk = 0;
  #100ns reset_n = 1;
end

// FINAL (at end)
final begin
  $display("Done");
end

// FORK-JOIN
fork
  #10ns task1();
  #20ns task2();
join          // Wait all
join_any      // Wait first
join_none     // Don't wait

disable fork; // Kill all
wait fork;    // Wait all forked

5. Control Structures

// IF-ELSE
if (a > b) result = a;
else result = b;

// TERNARY
result = (a > b) ? a : b;

// CASE
case (sel)
  2'b00: out = in0;
  2'b01: out = in1;
  default: out = 0;
endcase

// CASE INSIDE
case (data) inside
  [0:63]: low();
  [64:127]: mid();
endcase

// LOOPS
for (int i = 0; i < 10; i++) {}
while (cond) {}
foreach (arr[i]) {}
repeat (n) @(posedge clk);
forever begin end

// CONTROL
break;      // Exit loop
continue;   // Next iteration
return;     // Exit function

6. Functions and Tasks

// FUNCTION (no delay, returns value)
function int add(int a, int b);
  return a + b;
endfunction

// AUTOMATIC (re-entrant)
function automatic int factorial(int n);
  return (n <= 1) ? 1 : n * factorial(n-1);
endfunction

// TASK (can delay, no return)
task wait_cycles(int n);
  repeat(n) @(posedge clk);
endtask

// REF ARGUMENT (pass by reference)
task modify(ref int data);
  data = data * 2;
endtask

// CONST REF (read-only reference)
function void process(const ref bit[1000:0] large);
  // No copy, can't modify
endfunction

7. Classes and OOP

// BASIC CLASS
class packet;
  rand bit [7:0] addr;
  rand bit [31:0] data;
  
  function new();
  endfunction
  
  function void display();
    $display("addr=%h, data=%h", addr, data);
  endfunction
endclass

packet p = new();
p.addr = 8'h10;

// INHERITANCE
class extended extends packet;
  rand bit write;
  
  function void display();
    super.display();  // Call parent
    $display("write=%b", write);
  endfunction
endclass

// VIRTUAL (polymorphism)
class base;
  virtual function void show();
    $display("Base");
  endfunction
endclass

class derived extends base;
  function void show();
    $display("Derived");
  endfunction
endclass

base b = new derived();
b.show();  // Prints "Derived"

// STATIC
class counter;
  static int count = 0;
  int id;
  
  function new();
    count++;
    id = count;
  endfunction
endclass

8. Constraints

class constrained;
  rand bit [7:0] addr;
  rand bit [31:0] data;
  rand bit write;
  
  // BASIC
  constraint c1 {
    addr inside {[0:127]};
    data != 0;
  }
  
  // DISTRIBUTION
  constraint c2 {
    write dist {0 := 30, 1 := 70};  // 30% read, 70% write
  }
  
  // IMPLICATION
  constraint c3 {
    (addr > 100) -> (data < 1000);
  }
  
  // IF-ELSE
  constraint c4 {
    if (write)
      data != 0;
    else
      data == 0;
  }
  
  // SOLVE-BEFORE
  constraint c5 {
    solve addr before data;
  }
endclass

// RANDOMIZE
assert(obj.randomize());

// INLINE CONSTRAINTS
assert(obj.randomize() with {
  addr < 50;
  write == 1;
});

// DISABLE CONSTRAINT
obj.c1.constraint_mode(0);  // Off
obj.c1.constraint_mode(1);  // On

9. Coverage

covergroup cg;
  
  // COVERPOINT
  addr_cp: coverpoint addr {
    bins low  = {[0:63]};
    bins mid  = {[64:127]};
    bins high = {[128:255]};
  }
  
  // AUTO BINS
  write_cp: coverpoint write {
    bins vals[] = {0, 1};  // One bin per value
  }
  
  // EXPRESSION
  data_cp: coverpoint data {
    bins even[] = {[0:255]} with (item % 2 == 0);
  }
  
  // CROSS
  cross_cp: cross addr_cp, write_cp;
  
  // TRANSITIONS
  state_cp: coverpoint state {
    bins t1 = (IDLE => ACTIVE);
    bins t2 = (ACTIVE => DONE);
    bins seq = (IDLE => ACTIVE => DONE);
  }
  
  // IGNORE/ILLEGAL
  cmd_cp: coverpoint cmd {
    bins valid = {[0:10]};
    ignore_bins skip = {11};
    illegal_bins bad = {[12:15]};
  }
  
endgroup

cg my_cg = new();
my_cg.sample();
real coverage = my_cg.get_coverage();

10. Assertions

// IMMEDIATE (in procedural)
always @(posedge clk) begin
  assert (data < 256) else $error("Overflow!");
end

// CONCURRENT (temporal)
property req_gnt;
  @(posedge clk) disable iff (!reset_n)
    req |=> gnt;
endproperty

assert property (req_gnt)
  else $error("Grant missing!");

// OPERATORS
|->             // Overlapping (same cycle)
|=>             // Non-overlapping (next cycle)
##N             // Delay N cycles
##[m:n]         // Delay m to n cycles
[*n]            // Exactly n consecutive
[*m:n]          // m to n consecutive
[+]             // 1 or more consecutive
[->n]           // Goto nth occurrence

// SYSTEM FUNCTIONS
$rose(sig)      // Rising edge
$fell(sig)      // Falling edge
$stable(sig)    // Unchanged
$past(sig, N)   // N cycles ago
$onehot(sig)    // Exactly one bit

// EXAMPLES
property p1;
  @(posedge clk) disable iff (!reset_n)
    req |-> ##[1:5] gnt;  // Grant in 1-5 cycles
endproperty

property p2;
  @(posedge clk) disable iff (!reset_n)
    busy[*3] ##1 done;    // Busy 3 cycles, done next
endproperty

property p3;
  logic [7:0] addr;
  @(posedge clk) disable iff (!reset_n)
    (start, addr = addr_in) |-> 
    ##[1:10] (done && (addr_out == addr));
endproperty

11. Interfaces

interface bus_if(input logic clk);
  
  logic [7:0] data;
  logic valid;
  logic ready;
  
  // MODPORT
  modport master (
    input  clk, ready,
    output data, valid
  );
  
  modport slave (
    input  clk, data, valid,
    output ready
  );
  
  // TASK IN INTERFACE
  task write(bit[7:0] d);
    @(posedge clk);
    data = d;
    valid = 1;
    @(posedge clk);
    valid = 0;
  endtask
  
endinterface

// MODULE WITH INTERFACE
module master(bus_if.master bus);
  initial bus.write(8'hAA);
endmodule

// VIRTUAL INTERFACE (for classes)
class driver;
  virtual bus_if vif;
  
  function new(virtual bus_if v);
    vif = v;
  endfunction
  
  task drive(bit[7:0] d);
    vif.write(d);
  endtask
endclass

12. Common Patterns

Clock and Reset

// Clock
logic clk = 0;
always #5ns clk = ~clk;  // 10ns period

// Reset
logic reset_n;
initial begin
  reset_n = 0;
  #100ns reset_n = 1;
end

FSM

typedef enum {IDLE, ACTIVE, DONE} state_t;
state_t state, next_state;

// State register
always_ff @(posedge clk or negedge reset_n) begin
  if (!reset_n) state <= IDLE;
  else state <= next_state;
end

// Next state logic
always_comb begin
  next_state = state;
  case (state)
    IDLE:   if (start) next_state = ACTIVE;
    ACTIVE: if (done) next_state = DONE;
    DONE:   next_state = IDLE;
  endcase
end

// Outputs
assign busy = (state != IDLE);

Counter

logic [7:0] count;

always_ff @(posedge clk or negedge reset_n) begin
  if (!reset_n)
    count <= 0;
  else if (enable)
    count <= count + 1;
end

FIFO

logic [7:0] fifo[16];
logic [3:0] wr_ptr, rd_ptr;
logic [4:0] count;

assign full = (count == 16);
assign empty = (count == 0);

// Write
always_ff @(posedge clk) begin
  if (wr_en && !full) begin
    fifo[wr_ptr] <= wr_data;
    wr_ptr <= wr_ptr + 1;
  end
end

// Read
always_ff @(posedge clk) begin
  if (rd_en && !empty) begin
    rd_data <= fifo[rd_ptr];
    rd_ptr <= rd_ptr + 1;
  end
end

// Count
always_ff @(posedge clk or negedge reset_n) begin
  if (!reset_n)
    count <= 0;
  else
    case ({wr_en && !full, rd_en && !empty})
      2'b10: count <= count + 1;
      2'b01: count <= count - 1;
    endcase
end

Memory

module memory #(
  parameter DEPTH = 256,
  parameter WIDTH = 32
)(
  input  logic              clk,
  input  logic              wr_en,
  input  logic [7:0]        addr,
  input  logic [WIDTH-1:0]  wr_data,
  output logic [WIDTH-1:0]  rd_data
);

  logic [WIDTH-1:0] mem [DEPTH];
  
  always_ff @(posedge clk) begin
    if (wr_en)
      mem[addr] <= wr_data;
    rd_data <= mem[addr];
  end

endmodule

13. System Tasks

// DISPLAY
$display("Format", args);      // With newline
$write("Format", args);        // No newline
$monitor("val=%d", val);       // On change

// FORMAT
%b %d %h %o %t %s %0d          // Binary, Decimal, Hex, Octal, Time, String

// CONTROL
$finish;                       // End simulation
$stop;                         // Pause
$time;                         // Current time
#10ns;                         // Delay

// FILE I/O
fd = $fopen("file.txt", "w");
$fclose(fd);
$fdisplay(fd, "data=%h", data);
$readmemh("file.hex", mem);
$writememh("out.hex", mem);

// RANDOM
$urandom();
$urandom_range(0, 100);

// VCD DUMP
$dumpfile("waves.vcd");
$dumpvars(0, top);
$dumpon; $dumpoff;

// ASSERTIONS
$assertoff; $asserton;

14. Quick Reference Tables

Data Type Summary

TypeBitsStateSignedRange
bit1+2No0, 1
logic1+4No0, 1, X, Z
byte82Yes-128..127
shortint162Yes-32K..32K
int322Yes-2G..2G
longint642YesLarge
real642YesFloat

Always Block Usage

BlockUseSensitivityAssignment
always_combCombinationalAuto=
always_ffSequential@(edge)<=
always_latchLatchAuto= or <=

Assertion Operators

OperatorMeaningExample
|->Overlappinga |-> b
|=>Non-overlappinga |=> b
##NDelay N cyclesa ##3 b
##[m:n]Delay m-n cyclesa ##[1:5] b
[*n]Consecutive n timesa[*3]
[->n]Goto ntha[->3]

15. Complete Example

//=============================================================================
// COMPLETE TESTBENCH EXAMPLE
//=============================================================================

// Interface
interface dut_if(input logic clk);
  logic [7:0] addr;
  logic [31:0] data;
  logic wr_en;
endinterface

// Transaction
class transaction;
  rand bit [7:0] addr;
  rand bit [31:0] data;
  
  constraint c {
    addr inside {[0:127]};
  }
  
  covergroup cg;
    coverpoint addr;
    coverpoint data;
  endgroup
  
  function new();
    cg = new();
  endfunction
endclass

// Driver
class driver;
  virtual dut_if vif;
  
  function new(virtual dut_if v);
    vif = v;
  endfunction
  
  task drive(transaction t);
    @(posedge vif.clk);
    vif.addr = t.addr;
    vif.data = t.data;
    vif.wr_en = 1;
    @(posedge vif.clk);
    vif.wr_en = 0;
  endtask
endclass

// DUT
module dut(dut_if bus);
  always_ff @(posedge bus.clk) begin
    if (bus.wr_en)
      $display("Write: addr=%h, data=%h", bus.addr, bus.data);
  end
endmodule

// Testbench
module tb;
  logic clk = 0;
  always #5ns clk = ~clk;
  
  dut_if bus(clk);
  dut dut_inst(bus);
  
  initial begin
    transaction t;
    driver d = new(bus);
    
    repeat(100) begin
      t = new();
      assert(t.randomize());
      d.drive(t);
      t.cg.sample();
    end
    
    $display("Coverage: %0.2f%%", t.cg.get_coverage());
    $finish;
  end
endmodule

Best Practices Checklist

DO

  • Use bit for 2-state when X/Z not needed
  • Use always_comb for combinational logic
  • Use always_ff with <= for sequential logic
  • Use typedef for complex types
  • Use unique/priority case for safety
  • Check file open: if (!fopen(...)) $error()
  • Use assert(randomize()) – check return value
  • Use meaningful signal names

DON’T

  • Mix = and <= in same always block
  • Use always @(*) – use always_comb instead
  • Forget default in case statements
  • Use X in RTL (use in testbench only)
  • Create combinational loops
  • Use delays in synthesizable code
  • Ignore randomize() return value

SystemVerilog vs Verilog

FeatureVerilogSystemVerilog
Logic typewire, reglogic
Alwaysalways @(*)always_comb
Arraysreg[7:0] mem[256]int mem[256], dynamic, assoc, queue
EnumN/Atypedef enum {…}
StructN/Atypedef struct {…}
ClassesN/Aclass … endclass
ConstraintsN/Aconstraint {…}
CoverageN/Acovergroup {…}
AssertionsN/Aproperty, assert
InterfacesN/Ainterface … endinterface
PackagesN/Apackage … endpackage

One-Page Summary

// DATA TYPES: bit, logic, int, byte, shortint, longint, real, string
// ARRAYS: int a[10], int d[], int q[$], int assoc[string]
// INIT: arr = '{default: 0}, arr = '{0:10, 1:20}

// OPERATORS: + - * / % ** & | ^ ~ << >> && || ! ?: {,} inside
// FUNCTIONS: $urandom, $clog2, $countones, $bits

// PROCEDURAL
always_comb y = a & b;                      // Combinational
always_ff @(posedge clk) q <= d;            // Sequential
initial begin end                           // Once
fork-join; fork-join_any; fork-join_none;  // Parallel

// CONTROL: if, case, for, while, foreach, repeat, forever

// CLASS
class c; rand bit[7:0] x; constraint con {x < 100;} endclass
c obj = new(); assert(obj.randomize());

// COVERAGE
covergroup cg; coverpoint x; cross a, b; endgroup
cg my_cg = new(); my_cg.sample();

// ASSERTIONS
property p; @(posedge clk) req |=> gnt; endproperty
assert property (p) else $error("Fail!");

// INTERFACE
interface bus_if(input clk); logic[7:0] data; endinterface

// TASKS/FUNCTIONS
function int add(int a, b); return a+b; endfunction
task wait_n(int n); repeat(n) @(posedge clk); endtask

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top