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:
145
src/utils/waveformTracer.ts
Normal file
145
src/utils/waveformTracer.ts
Normal file
@ -0,0 +1,145 @@
|
||||
/**
|
||||
* 波形追踪工具
|
||||
* 调用 PyInstaller 打包的 waveform_trace 可执行文件
|
||||
*/
|
||||
import { spawn } from 'child_process';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
/**
|
||||
* 波形追踪参数
|
||||
*/
|
||||
export interface WaveformTraceArgs {
|
||||
/** Verilog 源文件路径(相对于项目根目录) */
|
||||
verilogPath: string;
|
||||
/** VCD 波形文件路径(相对于项目根目录) */
|
||||
vcdPath: string;
|
||||
/** 仿真工具的输出字符串(包含 mismatch 信息) */
|
||||
simOutput: string;
|
||||
/** BFS 回溯层数,默认 2 */
|
||||
traceLevel?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行波形追踪
|
||||
* @param args 追踪参数
|
||||
* @param context 执行上下文
|
||||
* @returns 追踪结果字符串
|
||||
*/
|
||||
export async function executeWaveformTrace(
|
||||
args: WaveformTraceArgs,
|
||||
context: { extensionPath: string }
|
||||
): Promise<string> {
|
||||
// 获取可执行文件路径
|
||||
const tracerPath = getWaveformTracerPath(context.extensionPath);
|
||||
|
||||
// 检查可执行文件是否存在
|
||||
if (!fs.existsSync(tracerPath)) {
|
||||
throw new Error(
|
||||
`waveform_trace 工具未安装: ${tracerPath}\n` +
|
||||
'请确保插件包含 tools/waveform_trace/bin/ 目录'
|
||||
);
|
||||
}
|
||||
|
||||
// 获取工作区路径
|
||||
const workspaceFolders = vscode.workspace.workspaceFolders;
|
||||
if (!workspaceFolders || workspaceFolders.length === 0) {
|
||||
throw new Error('请先打开一个工作区');
|
||||
}
|
||||
const workspacePath = workspaceFolders[0].uri.fsPath;
|
||||
|
||||
// 解析路径(支持相对路径)
|
||||
const verilogAbsPath = path.isAbsolute(args.verilogPath)
|
||||
? args.verilogPath
|
||||
: path.join(workspacePath, args.verilogPath);
|
||||
const vcdAbsPath = path.isAbsolute(args.vcdPath)
|
||||
? args.vcdPath
|
||||
: path.join(workspacePath, args.vcdPath);
|
||||
|
||||
// 验证文件存在
|
||||
if (!fs.existsSync(verilogAbsPath)) {
|
||||
throw new Error(`Verilog 文件不存在: ${args.verilogPath}`);
|
||||
}
|
||||
if (!fs.existsSync(vcdAbsPath)) {
|
||||
throw new Error(`VCD 文件不存在: ${args.vcdPath}`);
|
||||
}
|
||||
|
||||
// 调用可执行文件
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn(tracerPath, [
|
||||
'--verilog', verilogAbsPath,
|
||||
'--vcd', vcdAbsPath,
|
||||
'--sim-output', args.simOutput,
|
||||
'--trace-level', String(args.traceLevel || 2),
|
||||
'--output-format', 'text'
|
||||
], {
|
||||
windowsHide: true,
|
||||
cwd: workspacePath,
|
||||
shell: false
|
||||
});
|
||||
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
|
||||
child.stdout.on('data', (data: Buffer) => {
|
||||
stdout += data.toString();
|
||||
});
|
||||
|
||||
child.stderr.on('data', (data: Buffer) => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
|
||||
child.on('close', (code: number | null) => {
|
||||
if (code === 0) {
|
||||
resolve(stdout);
|
||||
} else {
|
||||
reject(new Error(
|
||||
`waveform_trace 执行失败 (code=${code}):\n${stderr || stdout}`
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
child.on('error', (error: Error) => {
|
||||
reject(new Error(`waveform_trace 启动失败: ${error.message}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 waveform_trace 可执行文件路径
|
||||
*/
|
||||
function getWaveformTracerPath(extensionPath: string): string {
|
||||
const platform = process.platform;
|
||||
let binName = 'waveform_trace';
|
||||
|
||||
if (platform === 'win32') {
|
||||
binName = 'waveform_trace.exe';
|
||||
}
|
||||
|
||||
return path.join(extensionPath, 'tools', 'waveform_trace', 'bin', binName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 waveform_trace 工具是否可用
|
||||
*/
|
||||
export function checkWaveformTraceAvailable(extensionPath: string): {
|
||||
available: boolean;
|
||||
message: string;
|
||||
path?: string;
|
||||
} {
|
||||
const tracerPath = getWaveformTracerPath(extensionPath);
|
||||
|
||||
if (fs.existsSync(tracerPath)) {
|
||||
return {
|
||||
available: true,
|
||||
message: 'waveform_trace 工具可用',
|
||||
path: tracerPath
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
available: false,
|
||||
message: `waveform_trace 工具未找到: ${tracerPath}`
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user