SystemVerilog/Assertions & Coverage

SystemVerilog Assertions & Functional Coverage

Master SVA, functional coverage, and coverage-driven verification for comprehensive design validation.

πŸ›‘οΈ Verification Fundamentals

SystemVerilog Assertions (SVA)

Advanced

Create powerful temporal assertions to verify protocol compliance and design behavior.

Key Topics:

  • β€’Immediate vs concurrent assertions
  • β€’Sequence definitions and operators
  • β€’Property declarations and binding
  • β€’Temporal operators (##, [*], [->])
  • β€’System tasks ($assert, $cover, $assume)

Basic Syntax:

// Basic SVA syntax
// Immediate assertion
always_comb begin
  assert (reset_n || !valid) 
    else $error("Valid should be low during reset");
end

// Concurrent assertion
property req_ack_handshake;
  @(posedge clk) disable iff (!reset_n)
  req |-> ##[1:3] ack;
endproperty

assert property (req_ack_handshake)
  else $error("Request not acknowledged in time");

// Sequence definition
sequence addr_valid_seq;
  @(posedge clk) addr_valid ##1 !addr_valid;
endsequence

Advanced Implementation:

// Comprehensive SVA example for AXI protocol
interface axi_assertions_if (
  input logic aclk,
  input logic aresetn,
  // AXI signals
  input logic awvalid, awready,
  input logic wvalid, wready,
  input logic bvalid, bready,
  input logic arvalid, arready,
  input logic rvalid, rready
);

  // Sequence definitions
  sequence write_addr_handshake;
    @(posedge aclk) awvalid && awready;
  endsequence
  
  sequence write_data_handshake;
    @(posedge aclk) wvalid && wready;
  endsequence
  
  sequence write_resp_handshake;
    @(posedge aclk) bvalid && bready;
  endsequence
  
  sequence read_addr_handshake;
    @(posedge aclk) arvalid && arready;
  endsequence
  
  sequence read_data_handshake;
    @(posedge aclk) rvalid && rready;
  endsequence

  // Property definitions
  property write_sequence_order;
    @(posedge aclk) disable iff (!aresetn)
    write_addr_handshake ##0 write_data_handshake |-> 
      ##[1:16] write_resp_handshake;
  endproperty
  
  property read_sequence;
    @(posedge aclk) disable iff (!aresetn)
    read_addr_handshake |-> ##[1:16] read_data_handshake;
  endproperty
  
  property valid_stable;
    @(posedge aclk) disable iff (!aresetn)
    (awvalid && !awready) |=> $stable(awvalid);
  endproperty
  
  property no_valid_during_reset;
    @(posedge aclk)
    !aresetn |-> (!awvalid && !wvalid && !arvalid);
  endproperty
  
  property exclusive_write_channels;
    @(posedge aclk) disable iff (!aresetn)
    !(write_addr_handshake && write_data_handshake && write_resp_handshake);
  endproperty

  // Assertion bindings
  assert_write_order: assert property(write_sequence_order)
    else $error("[%0t] Write sequence violation", $time);
    
  assert_read_sequence: assert property(read_sequence)
    else $error("[%0t] Read sequence violation", $time);
    
  assert_valid_stable: assert property(valid_stable)
    else $error("[%0t] Valid signal not stable", $time);
    
  assert_reset_behavior: assert property(no_valid_during_reset)
    else $error("[%0t] Valid signals active during reset", $time);

  // Coverage assertions
  cover_write_sequence: cover property(write_sequence_order);
  cover_read_sequence: cover property(read_sequence);
  cover_back_to_back_writes: cover property(
    @(posedge aclk) write_addr_handshake ##1 write_addr_handshake
  );
  
  // Assumptions for formal verification
  assume_reset_duration: assume property(
    @(posedge aclk) $fell(aresetn) |-> ##[1:10] $rose(aresetn)
  );

endinterface

Functional Coverage

Intermediate

Implement comprehensive functional coverage to measure verification completeness and identify gaps.

Key Topics:

  • β€’Covergroups and coverpoints
  • β€’Cross coverage and bins
  • β€’Coverage options and sampling
  • β€’Temporal coverage with transitions
  • β€’Coverage-driven verification

Basic Syntax:

// Basic functional coverage
covergroup cg_packet @(posedge clk);
  // Simple coverpoint
  cp_length: coverpoint packet.length {
    bins small  = {[1:64]};
    bins medium = {[65:256]};
    bins large  = {[257:1500]};
  }
  
  // Cross coverage
  cp_type: coverpoint packet.pkt_type;
  cross_type_length: cross cp_type, cp_length;
  
  // Transition coverage
  cp_state: coverpoint fsm.state {
    bins transitions = (IDLE => ACTIVE), 
                      (ACTIVE => WAIT),
                      (WAIT => DONE);
  }
endgroup

Advanced Implementation:

// Advanced functional coverage example
class network_coverage;
  // Packet properties
  typedef enum {TCP, UDP, ICMP, ARP} protocol_e;
  typedef enum {LOW, MED, HIGH, URGENT} priority_e;
  
  // Coverage group for protocol analysis
  covergroup cg_protocol_coverage @(posedge clk);
    option.per_instance = 1;
    option.name = "protocol_analysis";
    
    // Protocol distribution
    cp_protocol: coverpoint protocol {
      bins tcp_traffic  = {TCP};
      bins udp_traffic  = {UDP};
      bins icmp_traffic = {ICMP};
      bins arp_traffic  = {ARP};
      
      // Illegal bins
      illegal_bins reserved = {4,5,6,7};
    }
    
    // Packet size coverage with custom bins
    cp_size: coverpoint size {
      bins tiny   = {[1:63]};
      bins small  = {[64:127]};
      bins medium = {[128:511]};
      bins large  = {[512:1023]};
      bins jumbo  = {[1024:1500]};
      bins huge   = {[1501:$]};
      
      // Ignore specific values
      ignore_bins zero_size = {0};
    }
    
    // Priority with weighted bins
    cp_priority: coverpoint priority {
      bins low    = {LOW} with (item inside {[0:25]});
      bins medium = {MED} with (item inside {[26:75]});
      bins high   = {HIGH} with (item inside {[76:90]});
      bins urgent = {URGENT} with (item inside {[91:100]});
    }
    
    // Cross coverage for protocol combinations
    cross_protocol_size: cross cp_protocol, cp_size {
      // Focus on specific combinations
      bins tcp_large = binsof(cp_protocol.tcp_traffic) &&
                      binsof(cp_size.large);
      bins udp_small = binsof(cp_protocol.udp_traffic) &&
                      binsof(cp_size.small);
      
      // Ignore unrealistic combinations
      ignore_bins arp_jumbo = binsof(cp_protocol.arp_traffic) &&
                             binsof(cp_size.jumbo);
    }
    
    // Complex cross with conditions
    cross_prio_proto_size: cross cp_priority, cp_protocol, cp_size {
      option.cross_num_print_missing = 10;
      
      // Define interesting scenarios
      bins urgent_tcp_any = binsof(cp_priority.urgent) &&
                           binsof(cp_protocol.tcp_traffic);
      bins low_udp_small = binsof(cp_priority.low) &&
                          binsof(cp_protocol.udp_traffic) &&
                          binsof(cp_size.small);
    }
  endgroup
  
  // State machine coverage
  covergroup cg_fsm_coverage @(posedge clk);
    option.per_instance = 1;
    
    cp_current_state: coverpoint current_state {
      bins idle_state   = {IDLE};
      bins active_state = {ACTIVE};
      bins wait_state   = {WAIT};
      bins done_state   = {DONE};
      bins error_state  = {ERROR};
    }
    
    cp_next_state: coverpoint next_state;
    
    // State transitions
    cp_state_transitions: coverpoint current_state {
      bins valid_transitions = 
        (IDLE => ACTIVE),
        (ACTIVE => WAIT),
        (ACTIVE => DONE),
        (WAIT => ACTIVE),
        (WAIT => DONE),
        (DONE => IDLE),
        (ERROR => IDLE);
        
      bins error_transitions =
        (IDLE => ERROR),
        (ACTIVE => ERROR),
        (WAIT => ERROR);
        
      // Illegal transitions
      illegal_bins invalid = 
        (DONE => ACTIVE),
        (DONE => WAIT),
        (ERROR => ACTIVE);
    }
    
    // Cross current and next states
    cross_state_machine: cross cp_current_state, cp_next_state;
  endgroup
  
  // Temporal coverage with sequences
  covergroup cg_temporal_coverage @(posedge clk);
    // Back-to-back transactions
    cp_back_to_back: coverpoint {
      sequence back_to_back_seq;
        valid && ready ##1 valid && ready;
      endsequence
      
      cover property(@(posedge clk) back_to_back_seq);
    }
    
    // Burst transactions
    cp_burst_length: coverpoint burst_count iff (burst_active) {
      bins single  = {1};
      bins short   = {[2:4]};
      bins medium  = {[5:8]};
      bins long    = {[9:16]};
    }
  endgroup
  
  // Coverage instantiation and control
  function new();
    cg_protocol_coverage = new();
    cg_fsm_coverage = new();
    cg_temporal_coverage = new();
    
    // Set coverage options
    cg_protocol_coverage.option.goal = 95;
    cg_protocol_coverage.option.comment = "Network protocol coverage";
  endfunction
  
  function void sample_packet(input packet_t pkt);
    this.protocol = pkt.protocol;
    this.size = pkt.size;
    this.priority = pkt.priority;
    
    cg_protocol_coverage.sample();
  endfunction
  
  function void sample_fsm(input state_e curr, state_e next);
    this.current_state = curr;
    this.next_state = next;
    
    cg_fsm_coverage.sample();
  endfunction
  
  function real get_coverage();
    real protocol_cov = cg_protocol_coverage.get_inst_coverage();
    real fsm_cov = cg_fsm_coverage.get_inst_coverage();
    return (protocol_cov + fsm_cov) / 2.0;
  endfunction
  
  function void print_coverage();
    $display("=== Coverage Report ===");
    $display("Protocol Coverage: %.2f%%", 
             cg_protocol_coverage.get_inst_coverage());
    $display("FSM Coverage: %.2f%%", 
             cg_fsm_coverage.get_inst_coverage());
    $display("Overall Coverage: %.2f%%", get_coverage());
    
    // Print missing coverage
    cg_protocol_coverage.option.print_missing = 1;
  endfunction
endclass

Coverage-Driven Verification

Expert

Implement feedback-driven verification flows that automatically adjust stimulus based on coverage holes.

Key Topics:

  • β€’Coverage feedback loops
  • β€’Adaptive test generation
  • β€’Coverage exclusion and waivers
  • β€’Metrics and reporting
  • β€’Integration with formal verification

Basic Syntax:

// Coverage-driven test generation
class adaptive_test_generator;
  coverage_database cov_db;
  constraint_engine engine;
  
  function void generate_stimulus();
    // Analyze coverage holes
    hole_analysis_t holes = cov_db.find_holes();
    
    // Adjust constraints based on holes
    foreach(holes[i]) begin
      engine.boost_probability(holes[i].scenario, 2.0);
    end
    
    // Generate targeted stimulus
    stimulus_t stim = engine.generate();
  endfunction
endclass

Advanced Implementation:

// Complete coverage-driven verification framework
class coverage_driven_testbench;
  // Coverage database and analysis
  typedef struct {
    string scenario_name;
    real current_coverage;
    real target_coverage;
    int hit_count;
    int total_attempts;
  } coverage_scenario_t;
  
  coverage_scenario_t coverage_scenarios[];
  real overall_coverage_target = 95.0;
  int max_iterations = 10000;
  
  // Test generation engine
  class adaptive_generator;
    rand bit [31:0] data;
    rand bit [7:0] cmd;
    rand bit [3:0] priority;
    rand bit [15:0] addr;
    
    // Dynamic constraint weights
    real data_weights[4] = '{25.0, 25.0, 25.0, 25.0}; // Equal initially
    real cmd_weights[16];  // Command weights
    real addr_weights[4];  // Address region weights
    
    constraint adaptive_data {
      data dist {
        [32'h0000_0000:32'h3FFF_FFFF] := data_weights[0],
        [32'h4000_0000:32'h7FFF_FFFF] := data_weights[1],
        [32'h8000_0000:32'hBFFF_FFFF] := data_weights[2],
        [32'hC000_0000:32'hFFFF_FFFF] := data_weights[3]
      };
    }
    
    constraint adaptive_cmd {
      cmd dist {
        [8'h00:8'h03] := cmd_weights[0],
        [8'h04:8'h07] := cmd_weights[1],
        [8'h08:8'h0B] := cmd_weights[2],
        [8'h0C:8'h0F] := cmd_weights[3]
      };
    }
    
    function void update_weights(string scenario, real boost_factor);
      case (scenario)
        "high_data": data_weights[3] *= boost_factor;
        "low_addr": addr_weights[0] *= boost_factor;
        "rare_cmd": cmd_weights[3] *= boost_factor;
        default: $warning("Unknown scenario: %s", scenario);
      endcase
    endfunction
    
    function new();
      // Initialize uniform weights
      foreach(cmd_weights[i]) cmd_weights[i] = 6.25; // 16 commands
      foreach(addr_weights[i]) addr_weights[i] = 25.0;
    endfunction
  endclass
  
  // Coverage analysis and feedback
  class coverage_analyzer;
    network_coverage net_cov;
    
    function coverage_scenario_t[] analyze_holes();
      coverage_scenario_t holes[];
      real protocol_cov = net_cov.cg_protocol_coverage.get_coverage();
      real fsm_cov = net_cov.cg_fsm_coverage.get_coverage();
      
      // Identify specific coverage holes
      if (net_cov.cg_protocol_coverage.cp_protocol.get_coverage() < 90.0) begin
        coverage_scenario_t hole;
        hole.scenario_name = "rare_protocols";
        hole.current_coverage = net_cov.cg_protocol_coverage.cp_protocol.get_coverage();
        hole.target_coverage = 95.0;
        holes = {holes, hole};
      end
      
      if (net_cov.cg_protocol_coverage.cross_protocol_size.get_coverage() < 85.0) begin
        coverage_scenario_t hole;
        hole.scenario_name = "protocol_size_cross";
        hole.current_coverage = net_cov.cg_protocol_coverage.cross_protocol_size.get_coverage();
        hole.target_coverage = 90.0;
        holes = {holes, hole};
      end
      
      return holes;
    endfunction
    
    function real calculate_progress_rate(coverage_scenario_t scenario);
      if (scenario.total_attempts == 0) return 0.0;
      return real'(scenario.hit_count) / real'(scenario.total_attempts) * 100.0;
    endfunction
    
    function bit is_coverage_sufficient();
      real overall = (net_cov.cg_protocol_coverage.get_coverage() +
                     net_cov.cg_fsm_coverage.get_coverage()) / 2.0;
      return overall >= overall_coverage_target;
    endfunction
  endclass
  
  // Main verification loop
  task run_coverage_driven_verification();
    adaptive_generator gen = new();
    coverage_analyzer analyzer = new();
    int iteration = 0;
    
    $display("Starting coverage-driven verification...");
    $display("Target coverage: %.1f%%", overall_coverage_target);
    
    while (iteration < max_iterations && !analyzer.is_coverage_sufficient()) begin
      // Analyze current coverage state
      coverage_scenario_t holes[] = analyzer.analyze_holes();
      
      // Report progress every 100 iterations
      if (iteration % 100 == 0) begin
        real current_cov = (net_cov.cg_protocol_coverage.get_coverage() +
                           net_cov.cg_fsm_coverage.get_coverage()) / 2.0;
        $display("[%0d] Current coverage: %.2f%%, Holes: %0d", 
                 iteration, current_cov, holes.size());
      end
      
      // Adjust generation strategy based on holes
      foreach(holes[i]) begin
        real boost_factor = calculate_boost_factor(holes[i]);
        gen.update_weights(holes[i].scenario_name, boost_factor);
        
        $display("  Boosting scenario '%s' by %.1fx (current: %.1f%%)",
                 holes[i].scenario_name, boost_factor, holes[i].current_coverage);
      end
      
      // Generate and apply stimulus
      if (gen.randomize()) begin
        apply_stimulus(gen.data, gen.cmd, gen.priority, gen.addr);
        net_cov.sample_packet(create_packet(gen));
        
        // Update hole statistics
        foreach(holes[i]) begin
          holes[i].total_attempts++;
          if (hit_target_scenario(holes[i].scenario_name, gen)) begin
            holes[i].hit_count++;
          end
        end
      end else begin
        $error("Failed to randomize stimulus at iteration %0d", iteration);
      end
      
      iteration++;
    end
    
    // Final coverage report
    $display("
=== Final Coverage Report ===");
    $display("Iterations completed: %0d", iteration);
    $display("Protocol coverage: %.2f%%", net_cov.cg_protocol_coverage.get_coverage());
    $display("FSM coverage: %.2f%%", net_cov.cg_fsm_coverage.get_coverage());
    
    real final_coverage = (net_cov.cg_protocol_coverage.get_coverage() +
                          net_cov.cg_fsm_coverage.get_coverage()) / 2.0;
    $display("Overall coverage: %.2f%%", final_coverage);
    
    if (final_coverage >= overall_coverage_target) begin
      $display("βœ“ Coverage target achieved!");
    end else begin
      $display("βœ— Coverage target not reached. Consider:");
      $display("  - Increasing max_iterations");
      $display("  - Adding more targeted constraints");
      $display("  - Reviewing coverage model");
    end
  endtask
  
  function real calculate_boost_factor(coverage_scenario_t hole);
    real gap = hole.target_coverage - hole.current_coverage;
    
    if (gap > 20.0) return 4.0;      // Large gap - high boost
    else if (gap > 10.0) return 2.5; // Medium gap
    else if (gap > 5.0) return 1.5;  // Small gap
    else return 1.1;                 // Minimal boost
  endfunction
  
  function bit hit_target_scenario(string scenario, adaptive_generator gen);
    case (scenario)
      "rare_protocols": return (gen.cmd inside {8'h0C, 8'h0D, 8'h0E, 8'h0F});
      "high_data": return (gen.data >= 32'hC000_0000);
      "protocol_size_cross": return (gen.cmd == 8'h01 && gen.data > 32'h8000_0000);
      default: return 0;
    endcase
  endfunction
  
endclass

🎯 Assertion Categories

Safety Properties

Something bad never happens

Example:

Bus collision never occurs

SVA Syntax:

assert property (@(posedge clk) !(req1 && req2));

Liveness Properties

Something good eventually happens

Example:

Every request gets acknowledged

SVA Syntax:

assert property (@(posedge clk) req |-> ##[1:$] ack);

Fairness Properties

Resources are allocated fairly

Example:

All masters get bus access

SVA Syntax:

assert property (@(posedge clk) req |-> ##[1:10] grant);

Functional Properties

Correct functional behavior

Example:

Data integrity maintained

SVA Syntax:

assert property (@(posedge clk) write |-> ##1 (mem[addr] == data));

πŸ“Š Coverage Best Practices

Layered Coverage Model

Build coverage in logical layers from basic to complex

Benefit: Systematic coverage development

Cross Coverage

Combine multiple dimensions for comprehensive analysis

Benefit: Identify interaction scenarios

Temporal Coverage

Cover sequences and state transitions

Benefit: Protocol compliance verification

Exclude Unreachable Scenarios

Use ignore_bins for impossible combinations

Benefit: Realistic coverage metrics

πŸ“ˆ Key Verification Metrics

Functional Coverage

Percentage of design features exercised

Target: 95-100%

Code Coverage

Percentage of RTL code executed

Target: 90-95%

Assertion Coverage

Percentage of assertions triggered

Target: 100%

Bug Discovery Rate

Rate of finding new bugs over time

Target: Decreasing trend

Ready to Build Comprehensive Verification Environments?

Master SVA and functional coverage to create robust, metrics-driven verification flows.