/** * 波形追踪工具 * 调用 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 { // 获取可执行文件路径 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) { // 成功时返回 stdout,忽略 stderr 中的进度信息 resolve(stdout || stderr); } 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}` }; } }