Lint Rules

AF_FCOV_ARRAY_BIN_LIMIT_VLT

Array-based coverpoint bin expansion must not exceed 1024 bins.

Rationale: When bins b[] = {[low:high]} is used, the simulator creates one named bin per value in the range. Very large ranges (> 1024) cause significant memory overhead and slow down coverage collection. Keeping the number of expanded bins within 1024 ensures manageable simulation performance and coverage database size.

Violation:

covergroup cg;
  option.per_instance = 1;
  cp_a : coverpoint a {
    bins b[] = {[0:65535]};  // expands to 65536 bins -- violation
  }
endgroup : cg

Correct usage:

covergroup cg;
  option.per_instance = 1;
  cp_a : coverpoint a {
    bins b[] = {[0:15]};  // expands to 16 bins -- compliant
  }
endgroup : cg

Severity: ERROR


AF_FCOV_CLASS_MEM_REF_VLT

Coverpoints must not directly reference member variables of the enclosing class.

Rationale: Verilator does not support coverpoints that reference member variables of the class that contains the covergroup. The reference is resolved through the implicit this pointer, which Verilator cannot handle in the coverage context. Pass the variable as a covergroup argument instead, or reference a non-member signal from the enclosing scope.

Violation:

class env;
  int data;
  covergroup cg;
    option.per_instance = 1;
    cp : coverpoint data;  // references class member 'data' -- violation
  endgroup : cg
endclass

Correct usage:

int data;           // module-level variable
covergroup cg;
  option.per_instance = 1;
  cp : coverpoint data;  // references module-level 'data' -- compliant
endgroup : cg

Severity: ERROR


AF_FCOV_CONST_OPT_VLT

option.at_least and option.auto_bin_max must be assigned constant integer values.

Rationale: Verilator evaluates covergroup options at elaboration time. Assigning a runtime variable to option.at_least or option.auto_bin_max prevents Verilator from resolving the option value and causes a compilation error or silent misbehaviour. Using literal integer constants guarantees correct elaboration across all simulators.

Violation:

covergroup cg;
  option.per_instance = 1;
  option.at_least     = threshold;         // variable -- violation
  option.auto_bin_max = threshold + 5;     // expression -- violation
  cp_a : coverpoint a;
endgroup : cg

Correct usage:

covergroup cg;
  option.per_instance = 1;
  option.at_least     = 10;   // constant -- compliant
  option.auto_bin_max = 64;   // constant -- compliant
  cp_a : coverpoint a;
endgroup : cg

Severity: ERROR


AF_FCOV_CROSS_USE_CP_VLT

Every item in a cross must be an explicitly declared coverpoint name.

Rationale: Verilator requires each item in a cross statement to refer to an explicitly declared coverpoint, not a raw variable or signal name. A raw variable reference causes Verilator to silently ignore the cross or emit a compilation error, producing incomplete coverage data without any clear warning to the engineer.

Violation:

covergroup cg;
  option.per_instance = 1;
  cp_addr : coverpoint addr;
  cross_addr_data : cross cp_addr, data;  // 'data' is not a coverpoint -- violation
endgroup : cg

Correct usage:

covergroup cg;
  option.per_instance = 1;
  cp_addr : coverpoint addr;
  cp_data : coverpoint data;
  cross_addr_data : cross cp_addr, cp_data;  // both are coverpoints -- compliant
endgroup : cg

Severity: ERROR


AF_FCOV_INTF_IN_MOD_VLT

Interface declarations must not be nested inside module declarations.

Rationale: The SystemVerilog standard permits interfaces to be declared at the global scope or inside packages, but not nested inside module bodies. Verilator rejects nested interface declarations with a parse error. Moving the interface definition to the global scope ensures portability across simulators and tools.

Violation:

module top;
  interface my_intf;  // nested inside module -- violation
    logic req;
    logic ack;
  endinterface
endmodule

Correct usage:

interface my_intf;  // declared at global scope -- compliant
  logic req;
  logic ack;
endinterface

module top;
  my_intf intf_inst();
endmodule

Severity: ERROR


AF_FCOV_CR_ABIN_MAX_IN_CROSS_VLT

option.cross_auto_bin_max must not appear inside a cross coverage specification.

Rationale: Verilator does not recognise option.cross_auto_bin_max inside a cross body. Using it causes a compilation error or silent coverage loss. To limit cross bin growth under Verilator, reduce the number of coverpoints or manually define bins entries. For non-Verilator flows that do support the option, use rule AF_FCOV_PERF_USE_CR_ABIN_MAX to enforce its presence instead.

Violation:

covergroup cg;
  option.per_instance = 1;
  cp_a : coverpoint a;
  cp_b : coverpoint b;
  x_ab : cross cp_a, cp_b {
    option.cross_auto_bin_max = 16;  // unsupported by Verilator -- violation
  }
endgroup : cg

Correct usage:

covergroup cg;
  option.per_instance = 1;
  cp_a : coverpoint a;
  cp_b : coverpoint b;
  x_ab : cross cp_a, cp_b;  // no cross_auto_bin_max -- compliant
endgroup : cg

Severity: ERROR


AF_FCOV_PERF_NO_EDGE_IMPL_SAMP

Clock-edge implicit sampling (posedge/negedge) must not be used in covergroups.

Rationale: Attaching a clock edge to the covergroup header (covergroup cg @(posedge clk)) causes the covergroup to sample on every clock edge regardless of whether a meaningful transaction has occurred. This creates unnecessary simulation overhead and inflates coverage numbers with redundant samples. Use transaction-triggered event sampling or explicit cg.sample() calls so that coverage is recorded only when relevant activity takes place.

Violation:

covergroup cg @(posedge clk);  // edge-based implicit sampling -- violation
  option.per_instance = 1;
  cp_addr : coverpoint addr;
endgroup : cg

Correct usage:

covergroup cg;                 // no implicit sampling trigger -- compliant
  option.per_instance = 1;
  cp_addr : coverpoint addr;
endgroup : cg
// sample explicitly when a transaction completes:
// cg_inst.sample();

Severity: ERROR


AF_FCOV_FUNC_NO_GOAL_OPT

option.goal must not be set in SystemVerilog source code.

Rationale: Coverage goals define the acceptance threshold for a verification sign-off decision. Hard-coding option.goal inside a covergroup couples the goal to the RTL source and makes it impossible to adjust targets without a code change and re-simulation. Coverage goals should be managed externally via a vPlan or HVP coverage reporting tool, keeping the verification intent separate from the coverage model implementation.

Violation:

covergroup cg;
  option.per_instance = 1;
  option.goal = 90;  // goal hardcoded in source -- violation
  cp_a : coverpoint a;
endgroup : cg

Correct usage:

covergroup cg;
  option.per_instance = 1;  // no option.goal -- compliant
  cp_a : coverpoint a;
endgroup : cg
// set coverage goals in vPlan or reporting configuration

Severity: ERROR


AF_FCOV_NO_HIER_CROSS_VLT

Cross coverage must not use hierarchical references.

Rationale: Verilator does not support hierarchical path expressions (e.g., u_child.sig) inside cross coverage items. Such references cause a Verilator compilation error or are silently ignored, leaving the cross unmonitored. All items in a cross must be locally declared coverpoint names.

Violation:

module fcov_f;
  logic [1:0] a; child u_child();
  covergroup cg;
    option.per_instance = 1;
    cp_a : coverpoint a;
    x_ab : cross cp_a, u_child.sig;  // hierarchical ref -- violation
  endgroup : cg
endmodule

Correct usage:

module fcov_p;
  logic [1:0] a; logic [1:0] b;
  covergroup cg;
    option.per_instance = 1;
    cp_a : coverpoint a;
    cp_b : coverpoint b;
    x_ab : cross cp_a, cp_b;  // only local coverpoints -- compliant
  endgroup : cg
endmodule

Severity: ERROR


AF_FCOV_FUNC_NO_ILLEGAL_BINS

Covergroups must not use illegal_bins.

Rationale: An illegal_bins entry causes the simulator to throw a fatal error whenever the sampled value falls in the illegal range. This stops the simulation immediately, which can abort the testbench, disrupt UVM error reporting, and mask the coverage of subsequent stimulus. Use ignore_bins to exclude unwanted values from the coverage metric, and enforce illegal-state detection separately via SVA assertions or a scoreboard check.

Violation:

covergroup cg;
  option.per_instance = 1;
  cp_state : coverpoint state {
    illegal_bins ill = {3'b111};  // fatal on hit -- violation
  }
endgroup : cg

Correct usage:

covergroup cg;
  option.per_instance = 1;
  cp_state : coverpoint state {
    ignore_bins unused = {3'b111};  // silently excluded -- compliant
  }
endgroup : cg
// enforce illegal state separately:
// assert property (@(posedge clk) state != 3'b111);

Severity: ERROR


AF_FCOV_PERF_NO_IMPL_SAMP

Implicit event-triggered sampling must not be used in covergroups.

Rationale: Implicit sampling (any @(...) on the covergroup header) causes the covergroup to sample on every occurrence of that event. When the event is a clock edge this fires on every cycle; even for transaction events it couples the coverage model to a specific event, making it fragile and hard to reuse. Using explicit cg.sample() calls gives precise control over when samples are taken and makes the sampling intent visible at the call site.

Violation:

covergroup cg @(posedge clk);  // any implicit @(...) -- violation
  option.per_instance = 1;
  cp_addr : coverpoint addr;
endgroup : cg

Correct usage:

covergroup cg;                 // no @(...) trigger -- compliant
  option.per_instance = 1;
  cp_addr : coverpoint addr;
endgroup : cg
// call explicitly at transaction boundaries:
// cg_inst.sample();

Severity: ERROR


AF_FCOV_FUNC_NO_MERGE_INST

type_option.merge_instances must not be set in covergroups.

Rationale: Setting type_option.merge_instances = 1 collapses the coverage data from all instances of the covergroup into a single type-level report. This masks per-instance coverage holes — an instance that never samples certain bins is invisible in the merged report. Keeping instances separate (the default) provides full visibility into which instance is under-covered.

Violation:

covergroup cg;
  option.per_instance = 1;
  type_option.merge_instances = 1;  // hides per-instance holes -- violation
  cp_a : coverpoint a;
endgroup : cg

Correct usage:

covergroup cg;
  option.per_instance = 1;  // no merge_instances -- compliant
  cp_a : coverpoint a;
endgroup : cg

Severity: ERROR


AF_FCOV_FUNC_PER_INSTANCE

All covergroups must set option.per_instance = 1.

Rationale: Without option.per_instance = 1, the simulator merges coverage data from all instances of a covergroup into a single type-level bucket. In reusable components (UVM agents, environments) that are instantiated multiple times, this hides the fact that some instances may never exercise certain bins. Setting option.per_instance = 1 ensures each instance is tracked individually, making coverage holes visible at the instance level.

Violation:

covergroup cg;          // no per_instance option -- violation
  cp_a : coverpoint a;
endgroup : cg

Correct usage:

covergroup cg;
  option.per_instance = 1;  // instance-level tracking -- compliant
  cp_a : coverpoint a;
endgroup : cg

Severity: ERROR


AF_FCOV_PERF_USE_CR_ABIN_MAX

All cross coverage specifications must define option.cross_auto_bin_max.

Rationale: A cross of two coverpoints each with N bins produces up to N² automatically generated bins. Without option.cross_auto_bin_max, the simulator generates every combination, which can exhaust memory and slow coverage database writes. Explicitly setting a maximum caps the bin count and prevents combinatorial explosion.

Violation:

covergroup cg;
  option.per_instance = 1;
  cp_a : coverpoint a;
  cp_b : coverpoint b;
  x_ab : cross cp_a, cp_b;  // no cross_auto_bin_max -- violation
endgroup : cg

Correct usage:

covergroup cg;
  option.per_instance = 1;
  cp_a : coverpoint a;
  cp_b : coverpoint b;
  x_ab : cross cp_a, cp_b {
    option.cross_auto_bin_max = 64;  // caps bin count -- compliant
  }
endgroup : cg

Severity: ERROR


AF_FCOV_CONSEC_RPT_VLT

Consecutive repetition [*] in coverage transition bins is unsupported by Verilator.

Rationale: Verilator emits %Warning-COVERIGN and silently ignores any coverage bin that uses a consecutive repetition operator [*N]. The bin is present in the source but never hit, leaving contiguous state transitions permanently unmonitored without any runtime indication. Replace the repetition with explicit single-step transitions.

Violation:

bins b = (sig [*2]);  // consecutive repetition -- violation

Correct usage:

bins b = (sig => sig);  // explicit two-step transition -- compliant

Severity: ERROR


AF_FCOV_GOTO_RPT_VLT

Goto repetition [->] in coverage transition bins is unsupported by Verilator.

Rationale: Verilator emits %Warning-COVERIGN and silently ignores any coverage bin that uses a goto repetition operator [->N]. The bin is never hit during simulation, failing to track target reachability across delays. Restructure the bin using explicit single-step transition sequences.

Violation:

bins b = (sig [->2]);  // goto repetition -- violation

Correct usage:

bins b = (0 => 1 => 0 => 1);  // explicit transition sequence -- compliant

Severity: ERROR


AF_FCOV_NONCONSEC_RPT_VLT

Non-consecutive repetition [=] in coverage transition bins is unsupported by Verilator.

Rationale: Verilator emits %Warning-COVERIGN and silently ignores any coverage bin that uses a non-consecutive repetition operator [=N]. The bin is never hit during simulation, resulting in silent coverage loss for sparse or delayed events. Reframe the coverage using explicit transition sequences.

Violation:

bins b = (sig [=2]);  // non-consecutive repetition -- violation

Correct usage:

bins b = (0 => 1 => 0 => 1);  // explicit transition sequence -- compliant

Severity: ERROR


AF_FCOV_TRANS_RANGE_VLT

Value ranges [low:high] must not appear in transition bin specifications.

Rationale: Verilator does not support value ranges inside transition expressions (e.g., ([0:3] => 4)). The transition bin is silently ignored, leaving the corresponding state-machine arc unmonitored. Replace the range with discrete values or define separate bins for each value of interest.

Violation:

bins trans_b = ([0:3] => 4);  // range in transition -- violation

Correct usage:

bins trans_0 = (0 => 4);      // discrete values -- compliant
bins trans_1 = (1 => 4);
bins trans_2 = (2 => 4);
bins trans_3 = (3 => 4);

Severity: ERROR


AF_FCOV_TRANS_MULTI_VAL_VLT

Multi-value transition bins are not supported by Verilator.

Rationale: Verilator only supports transition bins with a single value on each side of the => operator (e.g., (3 => 4)). A comma-separated list on either side (e.g., (1,2,3 => 4,5)) is not recognised by Verilator and the bin is silently ignored, producing no coverage hits for those transitions. Use one explicit bin per transition pair.

Violation:

cp_state : coverpoint state {
  bins state_trans = (1,2,3 => 4,5);  // multi-value -- violation
}

Correct usage:

cp_state : coverpoint state {
  bins state_trans = (3 => 4);  // single value each side -- compliant
}

Severity: ERROR


AF_FCOV_STYLE_ENDLABEL

Covergroups must include an explicit endlabel after endgroup.

Rationale: Adding a label to endgroup (e.g., endgroup : cg_name) mirrors the style used for modules, interfaces, and other named blocks in SystemVerilog. It makes the scope boundaries immediately visible in code review and grep output, and helps tools that associate the closing token with the named covergroup. Omitting the label is legal but reduces readability.

Violation:

covergroup cg;
  option.per_instance = 1;
  cp_a : coverpoint a;
endgroup                // no endlabel -- violation

Correct usage:

covergroup cg;
  option.per_instance = 1;
  cp_a : coverpoint a;
endgroup : cg           // explicit endlabel -- compliant

Severity: ERROR