VCS 模式配置与使用指南
目录
简介
VCS(版本控制系统)模式文件是一种定义如何识别和处理代码中特定模式的配置文件。这些模式可用于代码审查、文档生成、质量检查和IC设计验证等自动化任务。本指南详细介绍VCS配置模式的语法和使用方法。
模式文件语法
基本结构
VCS模式文件使用类似Perl的语法结构,主要由一个%PATTERNS_DEF哈希/字典结构组成:
1 | %PATTERNS_DEF = ( |
配置选项详解
每个模式可以包含以下配置选项:
- Ignore: 是否忽略此模式(0为不忽略,1为忽略)。
- Required: 是否必须匹配此模式(0为非必须,1为必须)。
- StartString: 开始匹配的正则表达式。
- EndString: 结束匹配的正则表达式。
- RequiredText: 必须包含的文本模式数组。
- OptionalText: 可选包含的文本模式数组。
- ExcludedText: 不应包含的文本模式数组。
- Actions: 匹配后要执行的操作。
常用模式示例
通用代码模式
CommentBlock - 注释块匹配
1 | CommentBlock => { |
其他通用模式
1 | CodeBlock => { |
IC设计验证专用模式
时钟域识别 (ClockDomain)
1 | ClockDomain => { |
属性断言 (AssertProperty)
1 | AssertProperty => { |
工具与脚本
如何调用PAT模式文件
PAT模式文件可以通过多种方式被调用和使用,下面介绍几种常见的调用方法:
1. 命令行直接调用
使用VCS命令行工具直接引用PAT文件:
1 | vcs -full64 -sverilog +pat+c:/prj/example.pat -f filelist.f -l compile.log |
关键参数说明:
+pat+<filepath>- 指定PAT模式文件的路径-f filelist.f- 包含要处理的源文件列表-l compile.log- 指定日志输出文件
2. 通过配置文件引用
在VCS配置文件中引用PAT文件:
1 | // vcs.config |
然后在命令行中引用此配置文件:
1 | vcs -full64 -sverilog -config vcs.config -f filelist.f |
3. 通过脚本间接调用
使用自定义Perl脚本调用处理:
1 | #!/usr/bin/perl |
4. 与VCS GUI工具集成
在VCS的GUI环境中:
- 打开VCS图形界面:
vcs -gui - 选择菜单:
Tools>Code Quality>Pattern Checker - 在弹出窗口中,浏览并选择PAT文件
- 选择要检查的源文件目录
- 选择要应用的模式(可多选)
- 点击”Run”开始验证
5. 与项目Makefile集成
在项目Makefile中定义PAT验证规则:
1 | # Pattern verification target |
然后使用make pattern_check执行验证。
注释检查脚本
以下是check_comments.pl脚本的完整代码,用于检查代码库中的注释:
1 | #!/usr/bin/perl |
最佳实践
- 针对特定语言调整正则表达式:根据语言特性优化StartString和EndString。
- 从宽松规则开始:逐步收紧规则以减少误报。
- 结合工具使用:将模式文件与脚本结合使用,自动化代码审查和验证。
完整示例
以下是一个完整的模式文件示例:
1 | %PATTERNS_DEF = ( |
通过结合模式文件和脚本,您可以实现自动化的代码审查、文档生成和IC设计验证。
This is a sample Python script.
Press Shift+F10 to execute it or replace it with your code.
Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
-- coding: UTF-8 --
import os
import sys
import re
配置
target_dir =”xxx” # 替换为你要扫描的目录
output_file = “verilog_comparison_results.txt”
定义比较操作符
#comparison_ops = [‘>’, ‘>=’, ‘==’, ‘<=’, ‘<’]
#pattern = r’if\s(\s*([a-zA-Z_][a-zA-Z0-9_])\s(>=|<=|>|<|==)\s*(\d+)\s*)‘
pattern = r’([a-zA-Z_][a-zA-Z0-9_]*)\s*(>=|<=|>|<)\s(\d+)’
正则表达式:匹配只包含 “var <= 10” 的行(如 assign var <= 10;)
#single_compare_pattern = r’^\s*([a-zA-Z_][a-zA-Z0-9_])\s(>=|<=|>|<|==)\s*(\d+|1'b0|2'b0|3'b0|4'b0|5'b0|6'b0|7'b0|8'b0|9'b0|10'b0|11'b0|12'b0|13'b0|14'b0|5'b0|6'b0|7'b0|8'b0|9'b0|10'b0|16'b0|32'b0|9'd20|64'h0|1'b1|2'b1|3'b1|16'b1|8'b1|9'd20|64'h1|1'd0|2'd0|3'd0|4'd0|8'd0|16'd0|32'd0|1'h0|2'h0|3'h0|4'h0|8'h0|16'h0|32'h0|9'd20)\s*;$’
single_compare_pattern =r’^\s*([a-zA-Z_][a-zA-Z0-9_])\s*(>=|<=|>|<|==)\s(\d+|(\d+)'[a-zA-Z]+[0-9'])\s;$’
打开输出文件
with open(output_file, ‘w’, encoding=’utf-8’) as f_out:
# 遍历目录中的所有文件
for root, dirs, files in os.walk(target_dir):
for file in files:
# 如果文件名包含 “ecc”,跳过
if “ecc” in file:
continue
if “host” in file:
continue
if “ssu” in file:
continue
if file.endswith(“.v”) or file.endswith(“.sv”): # 只处理 Verilog 和 SystemVerilog 文件
file_path = os.path.join(root, file)
try:
with open(file_path, ‘r’, encoding=’utf-8’) as f_in: # 尝试用 utf-8 读取
lines = f_in.readlines()
except UnicodeDecodeError:
# 如果 utf-8 失败,尝试用 gbk 或其他编码
with open(file_path, ‘r’, encoding=’gbk’) as f_in:
lines = f_in.readlines()
for line_num, line in enumerate(lines, start=1):
# 使用正则表达式匹配条件判断语句中的变量与常值比较
if line.strip().startswith(“for”):
continue
if line.strip().startswith(“//“):
continue
if line.strip().startswith(“assign”):
continue
if line.strip().startswith(“wire”):
continue
if line.strip().startswith(“4’b”):
continue
if line.strip().startswith(“3’b”):
continue
if line.strip().startswith(“default”):
continue
if line.strip().startswith(“input”):
continue
if line.strip().startswith(“generate”):
continue
if line.strip().startswith(“lan”):
continue
if line.strip().startswith(“4’h”):
continue
if line.strip().startswith(“oxu_ibe_inq_chn”):
continue
matches = re.finditer(pattern, line)
for match in matches:
var_name = match.group(1)
op = match.group(2)
value = match.group(3)
# 构造匹配的完整语句
matched_line = line.strip()
# 检查该行是否只包含 “var <= 10”
if re.fullmatch(single_compare_pattern, line.strip()):
# 如果只包含变量与常值比较,不输出
continue
# 否则,输出
f_out.write(f”文件: {file_path}\n”)
f_out.write(f”行号: {line_num}\n”)
f_out.write(f”代码: {matched_line}\n”)
f_out.write(f”变量: {var_name} {op} {value}\n”)
f_out.write(“-“ * 40 + “\n”)
print(f”结果已保存到 {output_file}”)