SystemVerilog/Randomization & Constraints

Constrained Randomization & Data Types

Master constrained randomization, advanced data types, and solver techniques for comprehensive verification.

🎲 Randomization Fundamentals

Constrained Randomization

Fundamental

Generate random stimuli within specified constraints for comprehensive verification coverage.

Key Topics:

  • β€’rand and randc keywords
  • β€’Constraint blocks and expressions
  • β€’Distribution constraints (dist)
  • β€’Conditional constraints (if-else)
  • β€’Implication constraints (->)

Basic Syntax:

// Basic randomization syntax
class packet;
  rand bit [7:0] length;
  rand bit [3:0] priority;
  randc bit [15:0] id; // cyclic random
  
  // Constraint block
  constraint valid_length {
    length inside {[64:1500]};
  }
  
  constraint priority_dist {
    priority dist {
      0 := 50,     // 50% weight
      [1:3] := 30, // 30% total for 1,2,3
      [4:7] := 20  // 20% total for 4,5,6,7
    };
  }
  
  // Conditional constraint
  constraint conditional {
    if (priority > 4)
      length >= 256;
    else
      length < 256;
  }
endclass

Advanced Example:

// Advanced randomization example
class ethernet_frame;
  typedef enum {IPv4, IPv6, ARP} ether_type_e;
  
  rand bit [47:0] dest_mac;
  rand bit [47:0] src_mac; 
  rand ether_type_e ether_type;
  rand byte payload[];
  rand bit [31:0] fcs;
  
  // Size constraints
  constraint payload_size {
    payload.size() inside {[46:1500]};
  }
  
  // Address constraints
  constraint mac_addresses {
    // Unicast destination (LSB of first byte = 0)
    dest_mac[0] == 1'b0;
    
    // Source cannot be broadcast
    src_mac != 48'hFF_FF_FF_FF_FF_FF;
    
    // Different source and destination
    src_mac != dest_mac;
  }
  
  // Protocol-specific constraints
  constraint protocol_payload {
    if (ether_type == IPv4) {
      payload.size() inside {[20:1500]};
      // First nibble should be 4 for IPv4
      payload[0][7:4] == 4'h4;
    } else if (ether_type == IPv6) {
      payload.size() inside {[40:1500]};
      // First nibble should be 6 for IPv6
      payload[0][7:4] == 4'h6;
    } else if (ether_type == ARP) {
      payload.size() == 28; // Fixed ARP size
    }
  }
  
  // Distribution for protocol mix
  constraint protocol_distribution {
    ether_type dist {
      IPv4 := 70,  // 70% IPv4 traffic
      IPv6 := 25,  // 25% IPv6 traffic  
      ARP  := 5    // 5% ARP traffic
    };
  }
  
  // Cross-field implications
  constraint size_type_relation {
    (ether_type == IPv4) -> (payload.size() >= 46);
    (payload.size() > 1000) -> (ether_type != ARP);
  }
  
  // Custom randomization
  function void post_randomize();
    // Calculate FCS after randomization
    fcs = calculate_fcs();
    $display("Generated frame: type=%s, size=%0d", 
             ether_type.name(), payload.size());
  endfunction
  
  function bit [31:0] calculate_fcs();
    // Simplified FCS calculation
    bit [31:0] crc = 32'hFFFFFFFF;
    foreach(payload[i])
      crc = crc ^ payload[i];
    return crc;
  endfunction
endclass

Advanced Constraint Techniques

Advanced

Master complex constraint relationships, solver hints, and constraint inheritance.

Key Topics:

  • β€’Constraint inheritance and overriding
  • β€’Constraint modes (on/off)
  • β€’Soft constraints and priorities
  • β€’Solving order and hints
  • β€’Inline constraints with randomize()

Basic Syntax:

// Advanced constraint features
class base_transaction;
  rand int delay;
  rand bit [7:0] data;
  
  constraint base_delay {
    delay inside {[1:10]};
  }
  
  constraint base_data {
    data != 8'h00; // No null data
  }
endclass

class urgent_transaction extends base_transaction;
  // Override parent constraint
  constraint base_delay {
    delay inside {[1:3]}; // Urgent = low delay
  }
  
  // Add new constraint
  constraint urgent_data {
    data[7] == 1'b1; // High priority bit
  }
endclass

Advanced Example:

// Complete advanced constraints example
class network_packet;
  rand bit [15:0] src_port;
  rand bit [15:0] dest_port;
  rand int packet_size;
  rand bit [7:0] priority;
  rand bit fragmented;
  rand bit [31:0] sequence_num;
  
  // Constraint modes for different scenarios
  constraint well_known_ports {
    soft src_port inside {[1024:65535]};   // Soft constraint
    soft dest_port inside {[1:1023]};      // Well-known ports
  }
  
  constraint fragment_rules {
    // Large packets more likely to fragment
    (packet_size > 1400) -> (fragmented == 1'b1);
    
    // Fragmented packets have sequence numbers
    fragmented -> (sequence_num != 0);
    
    // Priority affects fragmentation probability
    priority dist {
      [0:3] := 60,    // Low priority, likely fragmented
      [4:6] := 30,    // Medium priority
      [7:7] := 10     // High priority, avoid fragmentation
    };
  }
  
  constraint size_priority_relation {
    // High priority packets tend to be smaller
    if (priority >= 6) {
      packet_size inside {[64:512]};
    } else if (priority >= 4) {
      packet_size inside {[64:1024]};
    } else {
      packet_size inside {[64:1500]};
    }
  }
  
  // Solving order hints
  constraint solve_order {
    solve priority before packet_size;
    solve packet_size before fragmented;
  }
  
  function void enable_client_ports();
    well_known_ports.constraint_mode(0); // Disable
    // Enable client-side port constraint
    constraint client_ports {
      src_port inside {[1024:65535]};
      dest_port inside {[1024:65535]};
    }
  endfunction
  
  function void test_specific_scenario();
    // Inline constraints for specific test
    assert(this.randomize() with {
      packet_size == 1500;
      fragmented == 1'b0;
      priority == 7;
    });
  endfunction
  
  // Constraint inheritance example
  virtual class test_config;
    virtual function void apply_constraints(ref network_packet pkt);
      // Base class - no specific constraints
    endfunction
  endclass
  
  class performance_test_config extends test_config;
    virtual function void apply_constraints(ref network_packet pkt);
      assert(pkt.randomize() with {
        packet_size inside {[1200:1500]};
        priority >= 5;
        fragmented == 1'b0;
      });
    endfunction
  endclass
  
  class stress_test_config extends test_config;
    virtual function void apply_constraints(ref network_packet pkt);
      assert(pkt.randomize() with {
        packet_size inside {[64:256]};
        priority inside {[0:3]};
        fragmented == 1'b1;
      });
    endfunction
  endclass
endclass

Data Types & Typedefs

Intermediate

Leverage SystemVerilog's rich type system including enums, structs, and user-defined types.

Key Topics:

  • β€’Enumerated types and methods
  • β€’Packed and unpacked structures
  • β€’Unions and tagged unions
  • β€’User-defined types with typedef
  • β€’Type parameters and classes

Basic Syntax:

// Data types and typedefs
typedef enum {READ, WRITE, IDLE} bus_op_e;
typedef enum bit [1:0] {
  LOW = 2'b00,
  MED = 2'b01, 
  HIGH = 2'b10
} priority_e;

typedef struct packed {
  bit [7:0] addr;
  bit [31:0] data;
  bit valid;
} bus_transaction_s;

typedef union packed {
  bit [31:0] word;
  bit [7:0] bytes[4];
  struct packed {
    bit [15:0] low;
    bit [15:0] high;
  } halves;
} data_union_t;

Advanced Example:

// Complete data types example
// Enhanced enum with methods
typedef enum bit [2:0] {
  RESET   = 3'b000,
  INIT    = 3'b001,
  ACTIVE  = 3'b010,
  WAIT    = 3'b011,
  DONE    = 3'b100,
  ERROR   = 3'b101
} state_e;

// Packed struct for efficient storage
typedef struct packed {
  bit [3:0]  opcode;
  bit [7:0]  dest_addr;
  bit [7:0]  src_addr;
  bit [15:0] payload_len;
  bit        parity;
} instruction_s;

// Unpacked struct for complex data
typedef struct {
  string name;
  int    transaction_id;
  real   timestamp;
  bit [31:0] data[$]; // Dynamic array
} test_transaction_s;

// Tagged union for protocol variants
typedef union tagged {
  bit [31:0]    IPv4_addr;
  bit [127:0]   IPv6_addr;
  string        hostname;
} address_u;

class protocol_packet;
  rand state_e current_state;
  rand instruction_s instruction;
  rand test_transaction_s transaction;
  rand address_u destination;
  
  // Enum constraints with methods
  constraint state_progression {
    current_state inside {INIT, ACTIVE, WAIT};
    // Use enum methods
    current_state != RESET; // state_e.first()
  }
  
  // Struct field constraints
  constraint instruction_validity {
    instruction.opcode inside {[4'h1:4'hE]};
    instruction.dest_addr != instruction.src_addr;
    
    // Conditional based on opcode
    if (instruction.opcode inside {[4'h1:4'h3]}) {
      instruction.payload_len inside {[16'h1:16'h100]};
    } else {
      instruction.payload_len == 16'h0;
    }
    
    // Parity calculation
    instruction.parity == ^{instruction.opcode, 
                            instruction.dest_addr,
                            instruction.src_addr};
  }
  
  // Dynamic array constraints
  constraint transaction_data {
    transaction.data.size() inside {[1:64]};
    
    foreach(transaction.data[i]) {
      transaction.data[i] inside {[32'h1000_0000:32'h9FFF_FFFF]};
      
      // Pattern constraint
      if (i > 0)
        transaction.data[i] != transaction.data[i-1];
    }
  }
  
  // Tagged union constraints
  constraint address_type {
    destination.type() dist {
      "IPv4_addr" := 50,
      "IPv6_addr" := 30,
      "hostname"  := 20
    };
    
    // Type-specific constraints
    if (destination matches tagged IPv4_addr .addr) {
      addr[31:24] inside {[8'h01:8'hDF]}; // Valid IP range
    }
  }
  
  function void post_randomize();
    // Use enum methods
    $display("State: %s (prev: %s, next: %s)", 
             current_state.name(),
             current_state.prev().name(),
             current_state.next().name());
    
    // Access struct fields
    $display("Instruction: op=%h, dest=%h, src=%h", 
             instruction.opcode,
             instruction.dest_addr, 
             instruction.src_addr);
    
    // Handle tagged union
    case (destination) matches
      tagged IPv4_addr .addr: 
        $display("IPv4 destination: %0d.%0d.%0d.%0d",
                 addr[31:24], addr[23:16], addr[15:8], addr[7:0]);
      tagged IPv6_addr .addr:
        $display("IPv6 destination: %h", addr);
      tagged hostname .name:
        $display("Hostname destination: %s", name);
    endcase
  endfunction
  
  // Custom randomization with type constraints
  function bit randomize_with_protocol(string protocol_type);
    case (protocol_type)
      "TCP": return this.randomize() with {
        current_state inside {ACTIVE, WAIT};
        instruction.opcode inside {[4'h1:4'h4]};
      };
      "UDP": return this.randomize() with {
        current_state == ACTIVE;
        instruction.opcode inside {[4'h5:4'h8]};
      };
      "ICMP": return this.randomize() with {
        current_state inside {INIT, ACTIVE};
        instruction.opcode inside {[4'h9:4'hC]};
      };
      default: return this.randomize();
    endcase
  endfunction
endclass

🎯 Advanced Constraint Techniques

Distribution Constraints

Control probability distribution of random values

Implementation:

constraint data_dist {
  data dist {
    [0:63]    := 40,  // 40% weight
    [64:127]  := 35,  // 35% weight  
    [128:255] := 25   // 25% weight
  };
}
Best for: Realistic traffic patterns

Implication Constraints

Create conditional relationships between variables

Implementation:

constraint implications {
  (mode == BURST) -> (length >= 8);
  (priority > 5) -> (delay inside {[1:3]});
  urgent -> (length < 64);
}
Best for: Protocol compliance

Array Constraints

Constrain dynamic arrays and their elements

Implementation:

constraint array_rules {
  data.size() inside {[1:16]};
  foreach(data[i]) {
    data[i] inside {[0:255]};
    if (i > 0) data[i] > data[i-1];
  }
}
Best for: Sequence generation

Soft Constraints

Provide solver hints that can be overridden

Implementation:

constraint defaults {
  soft size inside {[64:128]};
  soft delay == 5;
}
// Can be overridden with randomize() with {...}
Best for: Default behaviors

πŸ“‹ Randomization Best Practices

Constraint Layering

Build constraints in logical layers for maintainability

Base β†’ Protocol β†’ Test-specific constraints

Solving Order

Guide constraint solver with solve-before hints

solve priority before size; solve size before delay;

Constraint Modes

Enable/disable constraints for different scenarios

constraint_mode(0) to disable, constraint_mode(1) to enable

Inline Constraints

Use randomize() with {…} for test-specific overrides

obj.randomize() with { size == 1500; priority >= 7; }

πŸ”§ Constraint Solver Tips

Constraint Complexity

Keep constraints simple to avoid solver issues

Faster randomization

Contradictory Constraints

Ensure constraints don't conflict with each other

Avoid randomization failures

Solution Space

Provide adequate solution space for variables

Better constraint satisfaction

Debugging Failed Randomization

Use constraint_mode() and debugging techniques

Easier troubleshooting

Ready to Master Constrained Randomization?

Practice advanced constraint techniques and build comprehensive random stimulus generators.