Install any skill in seconds. Free to start, no credit card required.
Get Started Free →RTL code quality checking and linting. Runs lint rules, identifies synthesis issues, detects inferred latches, and generates lint reports with waivers.
.claude/skills/a5c-ai-rtl-linting/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 55% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 105% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 345% | 0% |
| case-15 | ✗→✓ | ▲ Improved | -3% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 155% | 0% |
Expert skill for RTL code quality checking and linting using Verible, SpyGlass, and vendor tools. Provides comprehensive code analysis for synthesis issues, coding style, CDC violations, and best practice enforcement.
The RTL Linting skill enables comprehensive RTL code quality checking, supporting:
Run Verible SystemVerilog lint checks:
bash# Run all default lint rules verible-verilog-lint src/*.sv # Run with specific rules verible-verilog-lint --rules=no-trailing-spaces,line-length src/*.sv # Generate machine-readable output verible-verilog-lint --format=json src/*.sv > lint_report.json # Use rules configuration file verible-verilog-lint --rules_config=.verible.rules src/*.sv # Autofix where possible verible-verilog-lint --autofix=yes src/*.sv
Configure Verible lint rules:
# .verible.rules
# Enable rules
+line-length
+no-trailing-spaces
+no-tabs
+posix-eof
# Disable rules
-endif-comment
-explicit-begin
# Configure rule parameters
line-length=length:120
# Waiver syntax
# waive:rule_name:reasonDetect common RTL issues:
systemverilog// ISSUE: Inferred latch (incomplete if-else) always_comb begin if (sel) output = a; // Missing else - LATCH INFERRED end // FIX: Complete all branches always_comb begin if (sel) output = a; else output = b; end // ISSUE: Blocking assignment in sequential block always_ff @(posedge clk) begin temp = data; // WRONG: blocking in always_ff result <= temp; end // FIX: Use non-blocking always_ff @(posedge clk) begin temp <= data; // CORRECT result <= temp; end // ISSUE: Missing sensitivity list item always @(a or b) begin // c missing! result = a & b | c; end // FIX: Use always_comb or @(*) always_comb begin result = a & b | c; end // ISSUE: Case without default always_comb begin case (sel) 2'b00: out = a; 2'b01: out = b; 2'b10: out = c; // Missing default - potential latch endcase end // FIX: Add default case always_comb begin case (sel) 2'b00: out = a; 2'b01: out = b; 2'b10: out = c; default: out = '0; endcase end
Detect CDC violations:
systemverilog// ISSUE: Unsynchronized CDC always_ff @(posedge clk_b) begin data_b <= data_a; // Direct crossing - CDC VIOLATION end // FIX: Add synchronizer logic [1:0] sync_reg; (* ASYNC_REG = "TRUE" *) always_ff @(posedge clk_b) begin sync_reg <= {sync_reg[0], signal_a}; end assign signal_b = sync_reg[1]; // ISSUE: Multi-bit CDC without gray coding always_ff @(posedge clk_b) begin ptr_b <= ptr_a; // Multi-bit direct - DATA COHERENCY ISSUE end // FIX: Gray code for multi-bit CDC logic [3:0] ptr_gray_a; assign ptr_gray_a = ptr_a ^ (ptr_a >> 1); // Binary to Gray (* ASYNC_REG = "TRUE" *) logic [3:0] ptr_gray_sync [2]; always_ff @(posedge clk_b) begin ptr_gray_sync[0] <= ptr_gray_a; ptr_gray_sync[1] <= ptr_gray_sync[0]; end
Verify proper reset usage:
systemverilog// ISSUE: Missing reset always_ff @(posedge clk) begin counter <= counter + 1; // No reset - INITIALIZATION ISSUE end // FIX: Add reset always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) counter <= '0; else counter <= counter + 1; end // ISSUE: Async reset on BRAM (won't synthesize) (* RAM_STYLE = "block" *) logic [7:0] mem [256]; always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) mem <= '{default: '0}; // Can't reset BRAM! else if (wr_en) mem[addr] <= data; end // FIX: Remove async reset from BRAM always_ff @(posedge clk) begin if (wr_en) mem[addr] <= data; end
Enforce coding standards:
systemverilog// Recommended naming conventions // Signals logic data_valid; // snake_case for signals logic [7:0] byte_count; // descriptive names // Parameters parameter int DATA_WIDTH = 8; // UPPER_CASE for parameters localparam int ADDR_BITS = 4; // UPPER_CASE for localparams // Types typedef enum logic [1:0] { STATE_IDLE, // UPPER_CASE for enum values STATE_RUN, STATE_DONE } state_t; // _t suffix for types // Modules module data_processor ( // snake_case for modules // ... ); // Interfaces interface axi_stream_if; // _if suffix for interfaces // Clock and reset naming input logic clk, // clk for clocks input logic clk_200mhz, // clk_ prefix with frequency input logic rst_n, // rst_n for active-low reset input logic areset_n, // areset_n for async reset
Handle Vivado synthesis warnings:
tcl# Run synthesis with warning report synth_design -top top_module -part xc7a200t-2-fbg484 # Check for critical warnings report_drc -file drc_report.txt report_methodology -file methodology_report.txt # Common Vivado warnings to address: # [Synth 8-327] - Inferring latch # [Synth 8-3332] - Sequential element unused # [Synth 8-6014] - Unused sequential element removed # [Synth 8-3919] - Null assignment to signal # [Synth 8-5534] - Missing connection to port
Generate comprehensive lint reports:
python# lint_report.py import json from dataclasses import dataclass from typing import List @dataclass class LintViolation: file: str line: int rule: str severity: str # error, warning, info message: str waived: bool = False waiver_reason: str = "" def generate_lint_report(violations: List[LintViolation]) -> dict: """Generate structured lint report.""" report = { "summary": { "total": len(violations), "errors": sum(1 for v in violations if v.severity == "error"), "warnings": sum(1 for v in violations if v.severity == "warning"), "waived": sum(1 for v in violations if v.waived) }, "by_rule": {}, "by_file": {}, "violations": [] } for v in violations: # Group by rule if v.rule not in report["by_rule"]: report["by_rule"][v.rule] = [] report["by_rule"][v.rule].append(v.__dict__) # Group by file if v.file not in report["by_file"]: report["by_file"][v.file] = [] report["by_file"][v.file].append(v.__dict__) # Full list report["violations"].append(v.__dict__) return report
Create and manage lint waivers:
tcl# waivers.tcl - SpyGlass waiver format # Waive specific instance waive -rule STARC05-2.1.1.3 \ -msg "Unregistered async input" \ -instance "top/async_input_sync" \ -reason "Synchronizer follows this register" # Waive by file pattern waive -rule W116 \ -file "*/tb/*" \ -reason "Testbench code - not synthesized" # Waive with comment waive -rule STARC-2.1.3.1 \ -msg "Latch inferred" \ -instance "debug_module/state_latch" \ -reason "Intentional latch for debug state capture"
yaml# waivers.yaml - Alternative format waivers: - rule: "inferred-latch" file: "src/debug_capture.sv" line: 42 reason: "Intentional latch for edge detection" author: "jdoe" date: "2026-01-24" - rule: "multi-bit-cdc" instance: "fifo_inst/wr_ptr_sync" reason: "Gray-coded pointer, safe CDC pattern" author: "jdoe" date: "2026-01-24"
This skill integrates with the following processes:
| Process | Integration Point | |---------|-------------------| | vhdl-module-development.js | VHDL code quality | | verilog-systemverilog-design.js | Verilog/SV lint | | synthesis-optimization.js | Pre-synthesis checks | | cdc-design.js | CDC lint rules |
bash# Create Verible rules file cat > .verible.rules << 'EOF' +line-length=length:120 +no-trailing-spaces +no-tabs +posix-eof +explicit-parameter-storage-type +proper-parameter-type -endif-comment EOF
bash# Run Verible lint verible-verilog-lint --rules_config=.verible.rules src/*.sv # Run with JSON output verible-verilog-lint --rules_config=.verible.rules --format=json src/*.sv > lint.json
bash# Auto-format code verible-verilog-format --inplace src/*.sv # Review remaining issues cat lint.json | jq '.[] | select(.severity == "error")'
bash# Add waivers for known issues # Document waiver reason in waivers.yaml
json{ "lintResults": { "summary": { "totalFiles": 25, "filesWithIssues": 8, "totalViolations": 42, "errors": 3, "warnings": 35, "info": 4, "waived": 5 }, "byRule": { "inferred-latch": { "count": 3, "severity": "error", "violations": [ { "file": "src/fsm.sv", "line": 45, "message": "..." } ] }, "line-length": { "count": 20, "severity": "warning", "violations": [...] } }, "byFile": { "src/fsm.sv": { "errors": 2, "warnings": 5, "violations": [...] } } }, "waivers": [ { "rule": "multi-bit-cdc", "instance": "fifo/ptr", "reason": "Gray coded" } ], "recommendations": [ "Fix 3 errors before synthesis", "Review 35 warnings for code quality", "Consider enabling additional rules for CDC" ], "artifacts": [ "reports/lint_summary.txt", "reports/lint_details.json", "waivers/approved_waivers.yaml" ] }
| Rule | Description | |------|-------------| | inferred-latch | Incomplete combinational assignment | | blocking-in-ff | Blocking assignment in always_ff | | multi-bit-cdc | Unprotected multi-bit CDC | | missing-reset | Register without reset | | sensitivity-list | Incomplete sensitivity list |
| Rule | Description | |------|-------------| | line-length | Line exceeds maximum length | | trailing-spaces | Trailing whitespace | | no-tabs | Tab characters in source | | unused-signal | Declared but unused signal | | duplicate-condition | Same condition in if/case |
| Rule | Description | |------|-------------| | naming-convention | Signal/module naming | | explicit-width | Explicit bit widths | | port-order | Port declaration order | | comment-style | Comment formatting |
verilog-systemverilog-design.js - Verilog/SV developmentsynthesis-optimization.js - Synthesis preparation| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 24,445 | 16,519 | -32% | 1 | 1 | 0% | 3,939 | 6,087 | +55% | 0 | 0 | — |
case-02 | fail→pass | 19,645 | 20,725 | +5% | 1 | 1 | 0% | 3,444 | 7,065 | +105% | 0 | 0 | — |
case-03 | fail→fail | 27,627 | 29,798 | +8% | 1 | 1 | 0% | 5,794 | 8,642 | +49% | 0 | 0 | — |
case-04 | pass→pass | 12,667 | 16,227 | +28% | 1 | 1 | 0% | 2,231 | 6,137 | +175% | 0 | 0 | — |
case-05 | pass→pass | 14,988 | 11,516 | -23% | 1 | 1 | 0% | 2,887 | 5,757 | +99% | 0 | 0 | — |
case-06 | pass→pass | 15,115 | 20,164 | +33% | 1 | 1 | 0% | 2,389 | 6,786 | +184% | 0 | 0 | — |
case-07 | pass→pass | 10,840 | 11,471 | +6% | 1 | 1 | 0% | 2,103 | 5,649 | +169% | 0 | 0 | — |
case-08 | pass→pass | 11,026 | 13,546 | +23% | 1 | 1 | 0% | 1,966 | 6,273 | +219% | 0 | 0 | — |
case-09 | fail→fail | 16,355 | 22,056 | +35% | 1 | 1 | 0% | 2,479 | 7,414 | +199% | 0 | 0 | — |
case-10 | pass→pass | 12,134 | 8,309 | -32% | 1 | 1 | 0% | 1,942 | 4,945 | +155% | 0 | 0 | — |
case-11 | pass→pass | 9,899 | 6,891 | -30% | 1 | 1 | 0% | 1,448 | 4,838 | +234% | 0 | 0 | — |
case-12 | fail→fail | 25,724 | 29,222 | +14% | 1 | 1 | 0% | 3,957 | 8,438 | +113% | 0 | 0 | — |
case-13 | pass→pass | 16,513 | 6,056 | -63% | 1 | 1 | 0% | 3,027 | 4,785 | +58% | 0 | 0 | — |
case-14 | fail→pass | 6,448 | 3,052 | -53% | 1 | 1 | 0% | 911 | 4,055 | +345% | 0 | 0 | — |
case-15 | fail→pass | 29,173 | 13,764 | -53% | 1 | 1 | 0% | 6,997 | 6,769 | -3% | 0 | 0 | — |
case-16 | pass→pass | 17,777 | 12,113 | -32% | 1 | 1 | 0% | 2,748 | 5,415 | +97% | 0 | 0 | — |
case-17 | fail→pass | 10,608 | 5,822 | -45% | 1 | 1 | 0% | 1,727 | 4,400 | +155% | 0 | 0 | — |
case-18 | pass→pass | 10,823 | 9,029 | -17% | 1 | 1 | 0% | 1,533 | 4,716 | +208% | 0 | 0 | — |
case-19 | pass→pass | 6,343 | 2,922 | -54% | 1 | 1 | 0% | 1,071 | 4,073 | +280% | 0 | 0 | — |
case-20 | fail→fail | 9,703 | 7,569 | -22% | 1 | 1 | 0% | 1,338 | 4,825 | +261% | 0 | 0 | — |
case-21 | pass→pass | 7,066 | 12,649 | +79% | 1 | 1 | 0% | 1,365 | 5,632 | +313% | 0 | 0 | — |
case-22 | pass→pass | 8,684 | 7,173 | -17% | 1 | 1 | 0% | 1,272 | 4,852 | +281% | 0 | 0 | — |
case-23 | pass→pass | 13,462 | 14,282 | +6% | 1 | 1 | 0% | 2,476 | 5,714 | +131% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +22 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.