refactor: 优化代码格式和用户提示
- 统一代码格式化(Prettier) - 将 iverilog 相关错误提示改为 'IC Coder编译器' - 优化后端服务错误提示为 '当前访问人数过多,请稍后重试' - 修复代码风格一致性问题
This commit is contained in:
@ -7,7 +7,7 @@ import { promisify } from "util";
|
||||
function execCommand(
|
||||
command: string,
|
||||
args: string[],
|
||||
options: { cwd: string; env?: any }
|
||||
options: { cwd: string; env?: any },
|
||||
): Promise<{ stdout: string; stderr: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 在 Windows 上,如果路径包含空格,不使用 shell,直接用 spawn
|
||||
@ -23,25 +23,25 @@ function execCommand(
|
||||
let stderr = "";
|
||||
|
||||
// 在 Windows 上使用 GBK 编码解码输出
|
||||
const encoding = process.platform === 'win32' ? 'gbk' : 'utf8';
|
||||
const encoding = process.platform === "win32" ? "gbk" : "utf8";
|
||||
|
||||
child.stdout.on("data", (data) => {
|
||||
try {
|
||||
// 尝试使用 iconv-lite 解码(如果可用)
|
||||
const iconv = require('iconv-lite');
|
||||
const iconv = require("iconv-lite");
|
||||
stdout += iconv.decode(data, encoding);
|
||||
} catch {
|
||||
// 如果 iconv-lite 不可用,使用默认解码
|
||||
stdout += data.toString('utf8');
|
||||
stdout += data.toString("utf8");
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr.on("data", (data) => {
|
||||
try {
|
||||
const iconv = require('iconv-lite');
|
||||
const iconv = require("iconv-lite");
|
||||
stderr += iconv.decode(data, encoding);
|
||||
} catch {
|
||||
stderr += data.toString('utf8');
|
||||
stderr += data.toString("utf8");
|
||||
}
|
||||
});
|
||||
|
||||
@ -93,7 +93,7 @@ export interface VCDGenerationResult {
|
||||
* 检查项目中的 Verilog 文件完整性
|
||||
*/
|
||||
export async function checkVerilogProject(
|
||||
projectPath: string
|
||||
projectPath: string,
|
||||
): Promise<VerilogProjectCheck> {
|
||||
const result: VerilogProjectCheck = {
|
||||
isComplete: false,
|
||||
@ -164,7 +164,7 @@ export async function checkVerilogProject(
|
||||
return result;
|
||||
} catch (error) {
|
||||
result.errors.push(
|
||||
`检查项目时出错: ${error instanceof Error ? error.message : "未知错误"}`
|
||||
`检查项目时出错: ${error instanceof Error ? error.message : "未知错误"}`,
|
||||
);
|
||||
return result;
|
||||
}
|
||||
@ -209,12 +209,30 @@ async function getIverilogPath(extensionPath: string): Promise<string> {
|
||||
let iverilogBin = "";
|
||||
|
||||
if (platform === "win32") {
|
||||
iverilogBin = path.join(extensionPath, "tools", "iverilog", "bin", "iverilog.exe");
|
||||
iverilogBin = path.join(
|
||||
extensionPath,
|
||||
"tools",
|
||||
"iverilog",
|
||||
"bin",
|
||||
"iverilog.exe",
|
||||
);
|
||||
} else if (platform === "darwin") {
|
||||
iverilogBin = path.join(extensionPath, "tools", "iverilog", "bin", "iverilog");
|
||||
iverilogBin = path.join(
|
||||
extensionPath,
|
||||
"tools",
|
||||
"iverilog",
|
||||
"bin",
|
||||
"iverilog",
|
||||
);
|
||||
} else {
|
||||
// Linux
|
||||
iverilogBin = path.join(extensionPath, "tools", "iverilog", "bin", "iverilog");
|
||||
iverilogBin = path.join(
|
||||
extensionPath,
|
||||
"tools",
|
||||
"iverilog",
|
||||
"bin",
|
||||
"iverilog",
|
||||
);
|
||||
}
|
||||
|
||||
// 如果插件包中没有,尝试使用系统安装的 iverilog
|
||||
@ -258,7 +276,7 @@ async function getVvpPath(extensionPath: string): Promise<string> {
|
||||
*/
|
||||
export async function generateVCD(
|
||||
projectPath: string,
|
||||
extensionPath: string
|
||||
extensionPath: string,
|
||||
): Promise<VCDGenerationResult> {
|
||||
try {
|
||||
// 1. 检查项目完整性
|
||||
@ -302,7 +320,7 @@ export async function generateVCD(
|
||||
} catch (error: any) {
|
||||
return {
|
||||
success: false,
|
||||
message: `iverilog 编译失败:\n${error.message}`,
|
||||
message: `IC Coder编译器编译失败:\n${error.message}`,
|
||||
stderr: error.stderr,
|
||||
stdout: error.stdout,
|
||||
};
|
||||
@ -310,17 +328,17 @@ export async function generateVCD(
|
||||
|
||||
// 6.5. 删除 shebang 行(修复 Windows 上的 vvp 解析错误)
|
||||
try {
|
||||
const fs = require('fs');
|
||||
const vvpContent = fs.readFileSync(outputFile, 'utf8');
|
||||
const lines = vvpContent.split('\n');
|
||||
const fs = require("fs");
|
||||
const vvpContent = fs.readFileSync(outputFile, "utf8");
|
||||
const lines = vvpContent.split("\n");
|
||||
|
||||
if (lines.length > 0 && lines[0].startsWith('#!')) {
|
||||
const cleanedContent = lines.slice(1).join('\n');
|
||||
fs.writeFileSync(outputFile, cleanedContent, 'utf8');
|
||||
console.log('已删除 .vvp 文件的 shebang 行');
|
||||
if (lines.length > 0 && lines[0].startsWith("#!")) {
|
||||
const cleanedContent = lines.slice(1).join("\n");
|
||||
fs.writeFileSync(outputFile, cleanedContent, "utf8");
|
||||
console.log("已删除 .vvp 文件的 shebang 行");
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('删除 shebang 失败,继续执行:', error);
|
||||
console.warn("删除 shebang 失败,继续执行:", error);
|
||||
}
|
||||
|
||||
// 7. 执行仿真生成 VCD
|
||||
@ -346,13 +364,17 @@ export async function generateVCD(
|
||||
const projectUri = vscode.Uri.file(projectPath);
|
||||
const entries = await vscode.workspace.fs.readDirectory(projectUri);
|
||||
const vcdFiles = entries
|
||||
.filter(([fileName, fileType]) => fileType === vscode.FileType.File && fileName.endsWith('.vcd'))
|
||||
.filter(
|
||||
([fileName, fileType]) =>
|
||||
fileType === vscode.FileType.File && fileName.endsWith(".vcd"),
|
||||
)
|
||||
.map(([fileName]) => fileName);
|
||||
|
||||
if (vcdFiles.length === 0) {
|
||||
return {
|
||||
success: false,
|
||||
message: "VCD 文件未生成。请确保 testbench 中包含 $dumpfile 和 $dumpvars 语句。",
|
||||
message:
|
||||
"VCD 文件未生成。请确保 testbench 中包含 $dumpfile 和 $dumpvars 语句。",
|
||||
stdout: simResult.stdout,
|
||||
};
|
||||
}
|
||||
@ -388,7 +410,7 @@ export async function generateVCD(
|
||||
* 检查 iverilog 是否可用
|
||||
*/
|
||||
export async function checkIverilogAvailable(
|
||||
extensionPath: string
|
||||
extensionPath: string,
|
||||
): Promise<{ available: boolean; version?: string; message: string }> {
|
||||
try {
|
||||
const iverilogPath = await getIverilogPath(extensionPath);
|
||||
@ -400,7 +422,7 @@ export async function checkIverilogAvailable(
|
||||
} catch (error) {
|
||||
return {
|
||||
available: false,
|
||||
message: `iverilog 不可用。未找到文件: ${iverilogPath}`,
|
||||
message: `IC Coder编译器不可用。未找到文件: ${iverilogPath}`,
|
||||
};
|
||||
}
|
||||
|
||||
@ -419,12 +441,12 @@ export async function checkIverilogAvailable(
|
||||
return {
|
||||
available: true,
|
||||
version: version,
|
||||
message: `iverilog 可用: ${version}`,
|
||||
message: `IC Coder编译器可用: ${version}`,
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
available: false,
|
||||
message: `iverilog 执行失败: ${error.message}\n${error.stderr || ""}`,
|
||||
message: `IC Coder编译器执行失败: ${error.message}\n${error.stderr || ""}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -433,8 +455,8 @@ export async function checkIverilogAvailable(
|
||||
* 要 dump 的模块定义
|
||||
*/
|
||||
export interface DumpModule {
|
||||
name: string; // 模块名(用于 VCD 文件名和宏名)
|
||||
path: string; // 实例路径(如 dut.u_tx)
|
||||
name: string; // 模块名(用于 VCD 文件名和宏名)
|
||||
path: string; // 实例路径(如 dut.u_tx)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -459,10 +481,11 @@ export interface MultiVCDResult {
|
||||
function injectConditionalDump(
|
||||
tbContent: string,
|
||||
dumpModules: DumpModule[],
|
||||
vcdDir: string
|
||||
vcdDir: string,
|
||||
): string {
|
||||
// 匹配 $dumpfile 和 $dumpvars 语句(可能跨多行)
|
||||
const dumpPattern = /(\$dumpfile\s*\([^)]+\)\s*;[\s\S]*?\$dumpvars\s*\([^)]+\)\s*;)/g;
|
||||
const dumpPattern =
|
||||
/(\$dumpfile\s*\([^)]+\)\s*;[\s\S]*?\$dumpvars\s*\([^)]+\)\s*;)/g;
|
||||
|
||||
// 生成条件编译代码
|
||||
const conditionalCode = generateConditionalDumpCode(dumpModules, vcdDir);
|
||||
@ -484,7 +507,7 @@ function injectConditionalDump(
|
||||
*/
|
||||
function generateConditionalDumpCode(
|
||||
dumpModules: DumpModule[],
|
||||
vcdDir: string
|
||||
vcdDir: string,
|
||||
): string {
|
||||
if (dumpModules.length === 0) {
|
||||
return '$dumpfile("output.vcd");\n $dumpvars(0, dut);';
|
||||
@ -495,7 +518,7 @@ function generateConditionalDumpCode(
|
||||
dumpModules.forEach((module, index) => {
|
||||
const macroName = `DUMP_${module.name.toUpperCase()}`;
|
||||
const vcdPath = `${vcdDir}/${module.name}.vcd`;
|
||||
const directive = index === 0 ? '`ifdef' : '`elsif';
|
||||
const directive = index === 0 ? "`ifdef" : "`elsif";
|
||||
|
||||
lines.push(`${directive} ${macroName}`);
|
||||
lines.push(` $dumpfile("${vcdPath}");`);
|
||||
@ -503,12 +526,12 @@ function generateConditionalDumpCode(
|
||||
});
|
||||
|
||||
// 添加默认分支(使用第一个模块)
|
||||
lines.push('`else');
|
||||
lines.push("`else");
|
||||
lines.push(` $dumpfile("${vcdDir}/${dumpModules[0].name}.vcd");`);
|
||||
lines.push(` $dumpvars(1, ${dumpModules[0].path});`);
|
||||
lines.push('`endif');
|
||||
lines.push("`endif");
|
||||
|
||||
return lines.join('\n');
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -519,10 +542,10 @@ export async function generateMultiVCD(
|
||||
extensionPath: string,
|
||||
tbPath: string,
|
||||
dumpModules: DumpModule[],
|
||||
vcdDir: string = 'vcd'
|
||||
vcdDir: string = "vcd",
|
||||
): Promise<MultiVCDResult> {
|
||||
const results: MultiVCDResult['vcdFiles'] = [];
|
||||
let allStdout = '';
|
||||
const results: MultiVCDResult["vcdFiles"] = [];
|
||||
let allStdout = "";
|
||||
|
||||
try {
|
||||
// 1. 创建 vcd 目录
|
||||
@ -535,16 +558,21 @@ export async function generateMultiVCD(
|
||||
}
|
||||
|
||||
// 2. 读取原始 testbench
|
||||
const tbFullPath = path.isAbsolute(tbPath) ? tbPath : path.join(projectPath, tbPath);
|
||||
const tbFullPath = path.isAbsolute(tbPath)
|
||||
? tbPath
|
||||
: path.join(projectPath, tbPath);
|
||||
const tbUri = vscode.Uri.file(tbFullPath);
|
||||
const tbBytes = await vscode.workspace.fs.readFile(tbUri);
|
||||
const originalTb = Buffer.from(tbBytes).toString('utf-8');
|
||||
const originalTb = Buffer.from(tbBytes).toString("utf-8");
|
||||
|
||||
// 3. 注入条件编译代码
|
||||
const modifiedTb = injectConditionalDump(originalTb, dumpModules, vcdDir);
|
||||
await vscode.workspace.fs.writeFile(tbUri, Buffer.from(modifiedTb, 'utf-8'));
|
||||
await vscode.workspace.fs.writeFile(
|
||||
tbUri,
|
||||
Buffer.from(modifiedTb, "utf-8"),
|
||||
);
|
||||
|
||||
console.log('[generateMultiVCD] Testbench 已修改,开始多次仿真...');
|
||||
console.log("[generateMultiVCD] Testbench 已修改,开始多次仿真...");
|
||||
|
||||
// 4. 获取工具路径
|
||||
const iverilogPath = await getIverilogPath(extensionPath);
|
||||
@ -569,27 +597,34 @@ export async function generateMultiVCD(
|
||||
// 编译(带宏定义)
|
||||
const compileArgs = [
|
||||
`-D${macroName}`,
|
||||
"-o", outputFile,
|
||||
...projectCheck.allVerilogFiles
|
||||
"-o",
|
||||
outputFile,
|
||||
...projectCheck.allVerilogFiles,
|
||||
];
|
||||
await execCommand(iverilogPath, compileArgs, { cwd: projectPath, env });
|
||||
|
||||
// 仿真
|
||||
const simResult = await execCommand(vvpPath, [outputFile], { cwd: projectPath, env });
|
||||
const simResult = await execCommand(vvpPath, [outputFile], {
|
||||
cwd: projectPath,
|
||||
env,
|
||||
});
|
||||
allStdout += `\n[${module.name}] ${simResult.stdout}`;
|
||||
|
||||
results.push({
|
||||
moduleName: module.name,
|
||||
vcdPath: vcdPath,
|
||||
success: true
|
||||
success: true,
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error(`[generateMultiVCD] 模块 ${module.name} 仿真失败:`, error.message);
|
||||
console.error(
|
||||
`[generateMultiVCD] 模块 ${module.name} 仿真失败:`,
|
||||
error.message,
|
||||
);
|
||||
results.push({
|
||||
moduleName: module.name,
|
||||
vcdPath: vcdPath,
|
||||
success: false,
|
||||
error: error.message
|
||||
error: error.message,
|
||||
});
|
||||
// 继续执行其他模块
|
||||
}
|
||||
@ -602,19 +637,18 @@ export async function generateMultiVCD(
|
||||
// 忽略
|
||||
}
|
||||
|
||||
const successCount = results.filter(r => r.success).length;
|
||||
const successCount = results.filter((r) => r.success).length;
|
||||
return {
|
||||
success: successCount > 0,
|
||||
vcdFiles: results,
|
||||
message: `生成完成:${successCount}/${dumpModules.length} 个 VCD 文件成功`,
|
||||
stdout: allStdout
|
||||
stdout: allStdout,
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
vcdFiles: results,
|
||||
message: `生成多 VCD 文件失败: ${error instanceof Error ? error.message : '未知错误'}`
|
||||
message: `生成多 VCD 文件失败: ${error instanceof Error ? error.message : "未知错误"}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user