Files
CGA-bench/coverage_agent.py
2026-05-22 10:02:42 +08:00

124 lines
4.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import sys
import re
import os
class CoverageAnalyzer:
def __init__(self, annotated_file_path):
self.file_path = annotated_file_path
self.source_code = self._load_file()
self.module_name = self._extract_module_name()
self.coverage_score = 0.0
self.missing_blocks = []
def _load_file(self):
"""加载文件内容,处理异常"""
if not os.path.exists(self.file_path):
raise FileNotFoundError(f"Cannot find file: {self.file_path}")
with open(self.file_path, 'r', encoding='utf-8') as f:
return f.readlines()
def _extract_module_name(self):
"""通用化步骤1自动从代码中提取 module name"""
for line in self.source_code:
match = re.search(r'module\s+(\w+)', line)
if match:
return match.group(1)
return "unknown_module"
def analyze(self):
"""核心分析逻辑:计算分数并提取未覆盖块"""
total_lines = 0
covered_lines = 0
current_block = []
recording = False
for i, line in enumerate(self.source_code):
# === [修复点] 安检门:如果行是空的,直接跳过 ===
if not line.strip():
continue
# 判定行类型
is_missed = line.startswith('%000000') or line.strip().startswith('#')
is_covered = line.startswith('%') and not is_missed
# 统计分数
if is_missed or is_covered:
total_lines += 1
if is_covered:
covered_lines += 1
# === [修复点] 安全切分:防止切割失败 ===
parts = line.split(maxsplit=1)
if len(parts) < 2:
# 如果这一行切不出两部分(比如只有标号没有代码),也跳过
continue
clean_code = parts[-1].strip()
# 过滤掉非实质性代码
is_substantive = len(clean_code) > 3 and not clean_code.startswith("//")
if is_missed and is_substantive:
if not recording:
recording = True
# 添加上下文 (尝试找前一行非空行作为上下文比较复杂,这里简化处理)
if i > 0 and self.source_code[i-1].strip():
prev_parts = self.source_code[i-1].split(maxsplit=1)
if len(prev_parts) >= 2:
prev_code = prev_parts[-1].strip()
current_block.append(f"Line {i}: {prev_code} ...")
current_block.append(f"Line {i+1}: {clean_code} <--- MISSING")
else:
if recording:
recording = False
self.missing_blocks.append(current_block)
current_block = []
# 计算最终分数
if total_lines > 0:
self.coverage_score = (covered_lines / total_lines) * 100.0
return self.coverage_score
def generate_prompt(self):
"""通用化步骤2使用模板生成 Prompt"""
prompt_template = """
You are an expert FPGA verification engineer.
I am verifying a Verilog module named '{module_name}'.
The current testbench achieves only {score:.2f}% coverage.
The following logic blocks are NEVER executed during simulation:
{missing_logic_str}
[Task]
Please write a NEW SystemVerilog task to target these specific missing scenarios.
1. Analyze WHY these lines are not executed (e.g., specific counter value, rare state transition).
2. Generate a task named 'test_coverage_fix' that drives inputs to trigger these conditions.
3. Return ONLY the code block.
"""
blocks_str = ""
for idx, block in enumerate(self.missing_blocks[:4]):
blocks_str += f"--- Missing Scenario {idx+1} ---\n"
blocks_str += "\n".join(block)
blocks_str += "\n\n"
if not blocks_str:
blocks_str = "(No significant missing logic found. Coverage is likely high.)"
return prompt_template.format(
module_name=self.module_name,
score=self.coverage_score,
missing_logic_str=blocks_str
)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python3 coverage_agent.py <annotated_file_path>")
sys.exit(1)
agent = CoverageAnalyzer(sys.argv[1])
score = agent.analyze()
print(f"--- Analysis Report for {agent.module_name} ---")
print(f"Score: {score:.2f}%")
print("-" * 30)
print(agent.generate_prompt())