feat: 集成 waveform_trace 波形调试工具
新增功能: - waveformTracer.ts: 调用 waveform_trace.exe 的工具实现 - toolExecutor.ts: 添加 waveform_trace 工具分发 - types/api.ts: 添加 WaveformTraceArgs 类型定义 工具源码 (tools/waveform_trace/src/): - AST 解析 + BFS 信号追踪 - VCD 波形解析 - 修复通用 testbench 支持 配置文件: - .gitignore: 排除 exe 和打包产物 - .vscodeignore: 发布时排除源码 - build.bat/build.sh: 打包脚本
This commit is contained in:
149
tools/waveform_trace/src/waveform_trace_cli.py
Normal file
149
tools/waveform_trace/src/waveform_trace_cli.py
Normal file
@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
waveform_trace CLI 入口
|
||||
用于 PyInstaller 打包成独立可执行文件
|
||||
|
||||
使用方式:
|
||||
waveform_trace --verilog <path> --vcd <path> --sim-output <text> [--trace-level <int>] [--output-format text|json]
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import builtins
|
||||
|
||||
# Monkey-patch open 函数,强制使用 UTF-8 编码(解决 pyverilog 读取中文注释的问题)
|
||||
_original_open = builtins.open
|
||||
def _utf8_open(file, mode='r', *args, **kwargs):
|
||||
if 'b' not in mode and 'encoding' not in kwargs:
|
||||
kwargs['encoding'] = 'utf-8'
|
||||
kwargs.setdefault('errors', 'replace')
|
||||
return _original_open(file, mode, *args, **kwargs)
|
||||
builtins.open = _utf8_open
|
||||
|
||||
if sys.platform == 'win32':
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
sys.stderr.reconfigure(encoding='utf-8', errors='replace')
|
||||
|
||||
import argparse
|
||||
import json
|
||||
|
||||
# 添加当前目录到路径(打包后需要)
|
||||
if getattr(sys, 'frozen', False):
|
||||
# 如果是打包后的可执行文件
|
||||
application_path = os.path.dirname(sys.executable)
|
||||
else:
|
||||
# 如果是直接运行的脚本
|
||||
application_path = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
sys.path.insert(0, application_path)
|
||||
|
||||
from waveform_trace_tool import WaveformTracer
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Verilog 波形追踪工具 - 通过 AST + BFS 追踪信号依赖,定位代码问题',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog='''
|
||||
示例:
|
||||
waveform_trace --verilog src/counter.v --vcd output/wave.vcd --sim-output "Mismatches: 3"
|
||||
waveform_trace --verilog src/counter.v --vcd output/wave.vcd --sim-output "Mismatches: 3" --trace-level 3
|
||||
waveform_trace --verilog src/counter.v --vcd output/wave.vcd --sim-output "Mismatches: 3" --output-format json
|
||||
'''
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--verilog',
|
||||
required=True,
|
||||
help='Verilog 源文件路径'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--vcd',
|
||||
required=True,
|
||||
help='VCD 波形文件路径'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--sim-output',
|
||||
required=True,
|
||||
help='仿真工具的输出字符串(必须包含 mismatch 信息)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--trace-level',
|
||||
type=int,
|
||||
default=2,
|
||||
help='BFS 回溯层数,默认 2,建议 2-5'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--output-format',
|
||||
choices=['text', 'json'],
|
||||
default='text',
|
||||
help='输出格式:text(默认)或 json'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
# 验证文件存在
|
||||
if not os.path.exists(args.verilog):
|
||||
raise FileNotFoundError(f"Verilog 文件不存在: {args.verilog}")
|
||||
if not os.path.exists(args.vcd):
|
||||
raise FileNotFoundError(f"VCD 文件不存在: {args.vcd}")
|
||||
|
||||
# 验证 trace_level
|
||||
if args.trace_level < 1:
|
||||
raise ValueError("trace-level 必须大于等于 1")
|
||||
|
||||
# 创建追踪器并执行
|
||||
tracer = WaveformTracer(args.verilog, args.vcd)
|
||||
result = tracer.waveform_trace_tool(args.sim_output, args.trace_level)
|
||||
|
||||
# 输出结果
|
||||
if args.output_format == 'json':
|
||||
output = {
|
||||
'success': True,
|
||||
'result': result,
|
||||
'verilog_path': args.verilog,
|
||||
'vcd_path': args.vcd,
|
||||
'trace_level': args.trace_level
|
||||
}
|
||||
print(json.dumps(output, ensure_ascii=False, indent=2))
|
||||
else:
|
||||
print(result)
|
||||
|
||||
except FileNotFoundError as e:
|
||||
if args.output_format == 'json':
|
||||
print(json.dumps({
|
||||
'success': False,
|
||||
'error': str(e),
|
||||
'error_type': 'FileNotFoundError'
|
||||
}, ensure_ascii=False))
|
||||
else:
|
||||
print(f'[Error] {e}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
except ValueError as e:
|
||||
if args.output_format == 'json':
|
||||
print(json.dumps({
|
||||
'success': False,
|
||||
'error': str(e),
|
||||
'error_type': 'ValueError'
|
||||
}, ensure_ascii=False))
|
||||
else:
|
||||
print(f'[Error] {e}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
if args.output_format == 'json':
|
||||
print(json.dumps({
|
||||
'success': False,
|
||||
'error': str(e),
|
||||
'error_type': type(e).__name__
|
||||
}, ensure_ascii=False))
|
||||
else:
|
||||
print(f'[Error] {e}', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user