414 lines
8.7 KiB
Markdown
414 lines
8.7 KiB
Markdown
# Vivado 联动前后端对接文档
|
||
|
||
## 1. 概述
|
||
|
||
本文档描述后端 AI 服务如何调用前端的 Vivado 工具,以及前端如何响应和返回结果。
|
||
|
||
### 1.1 调用流程
|
||
|
||
```
|
||
后端 AI 服务
|
||
↓ (1) 发送工具调用请求
|
||
前端 Extension (MessageHandler)
|
||
↓ (2) 解析请求,调用 VivadoRunner
|
||
VivadoRunner
|
||
↓ (3) 执行 Vivado,实时推送进度
|
||
前端 Webview
|
||
↓ (4) 显示进度和结果
|
||
前端 Extension
|
||
↓ (5) 返回执行结果给后端
|
||
后端 AI 服务
|
||
```
|
||
|
||
## 2. 工具定义(后端)
|
||
|
||
### 2.1 工具注册
|
||
|
||
后端需要在工具列表中注册 `runVivado` 工具:
|
||
|
||
```json
|
||
{
|
||
"name": "runVivado",
|
||
"description": "调用本地 Vivado 工具执行 FPGA 综合、实现或生成比特流。用于将 Verilog 代码部署到 FPGA 硬件。",
|
||
"inputSchema": {
|
||
"type": "object",
|
||
"properties": {
|
||
"command": {
|
||
"type": "string",
|
||
"enum": ["synthesis", "implementation", "bitstream"],
|
||
"description": "要执行的命令类型:synthesis(综合)、implementation(实现)、bitstream(生成比特流)"
|
||
},
|
||
"topModule": {
|
||
"type": "string",
|
||
"description": "顶层模块名称"
|
||
},
|
||
"files": {
|
||
"type": "array",
|
||
"items": { "type": "string" },
|
||
"description": "输入的 Verilog 文件路径列表"
|
||
},
|
||
"constraints": {
|
||
"type": "string",
|
||
"description": "约束文件路径(.xdc 文件),可选"
|
||
},
|
||
"part": {
|
||
"type": "string",
|
||
"description": "FPGA 型号,可选,默认使用配置中的型号"
|
||
}
|
||
},
|
||
"required": ["command", "topModule", "files"]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2.2 调用示例
|
||
|
||
#### 示例 1:综合单个文件
|
||
|
||
```json
|
||
{
|
||
"tool": "runVivado",
|
||
"parameters": {
|
||
"command": "synthesis",
|
||
"topModule": "counter",
|
||
"files": ["counter.v"]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 示例 2:综合带约束文件
|
||
|
||
```json
|
||
{
|
||
"tool": "runVivado",
|
||
"parameters": {
|
||
"command": "synthesis",
|
||
"topModule": "uart_top",
|
||
"files": ["uart_tx.v", "uart_rx.v", "uart_top.v"],
|
||
"constraints": "constraints.xdc"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 示例 3:实现(需要先综合)
|
||
|
||
```json
|
||
{
|
||
"tool": "runVivado",
|
||
"parameters": {
|
||
"command": "implementation",
|
||
"topModule": "counter"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 示例 4:生成比特流(需要先实现)
|
||
|
||
```json
|
||
{
|
||
"tool": "runVivado",
|
||
"parameters": {
|
||
"command": "bitstream",
|
||
"topModule": "counter"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 3. 前端接收和处理
|
||
|
||
### 3.1 MessageHandler 处理逻辑
|
||
|
||
前端在 `messageHandler.ts` 中添加工具处理:
|
||
|
||
```typescript
|
||
// src/utils/messageHandler.ts
|
||
|
||
export async function handleToolExecution(
|
||
panel: vscode.WebviewPanel,
|
||
toolName: string,
|
||
parameters: any
|
||
): Promise<any> {
|
||
|
||
if (toolName === 'runVivado') {
|
||
return await handleVivadoTool(panel, parameters);
|
||
}
|
||
|
||
// 其他工具处理...
|
||
}
|
||
|
||
async function handleVivadoTool(
|
||
panel: vscode.WebviewPanel,
|
||
parameters: any
|
||
): Promise<VivadoToolResponse> {
|
||
|
||
const { command, topModule, files, constraints, part } = parameters;
|
||
|
||
// 构建请求
|
||
const request: VivadoToolRequest = {
|
||
command,
|
||
parameters: {
|
||
topModule,
|
||
files,
|
||
constraints,
|
||
part
|
||
},
|
||
importOutput: {
|
||
enabled: true,
|
||
targetDir: path.join(
|
||
vscode.workspace.workspaceFolders![0].uri.fsPath,
|
||
'vivado_output'
|
||
)
|
||
}
|
||
};
|
||
|
||
// 向前端发送开始消息
|
||
panel.webview.postMessage({
|
||
type: 'vivado-start',
|
||
command
|
||
});
|
||
|
||
// 执行 Vivado
|
||
const response = await runVivado(request, (progress) => {
|
||
// 实时推送进度到前端
|
||
panel.webview.postMessage({
|
||
type: 'vivado-progress',
|
||
progress
|
||
});
|
||
});
|
||
|
||
// 向前端发送完成消息
|
||
panel.webview.postMessage({
|
||
type: 'vivado-complete',
|
||
response
|
||
});
|
||
|
||
// 返回结果给后端
|
||
return response;
|
||
}
|
||
```
|
||
|
||
## 4. 响应格式
|
||
|
||
### 4.1 成功响应
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"command": "synthesis",
|
||
"executionTime": 45230,
|
||
"output": "Vivado 执行日志...",
|
||
"importedFiles": [
|
||
"/path/to/vivado_output/counter_synth.dcp",
|
||
"/path/to/vivado_output/counter_utilization_synth.rpt"
|
||
],
|
||
"reports": {
|
||
"resources": "LUT: 32/20800 (0.15%)\nFF: 8/41600 (0.02%)",
|
||
"timing": "WNS: 5.234ns, TNS: 0.000ns"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.2 失败响应
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"command": "synthesis",
|
||
"executionTime": 1250,
|
||
"output": "部分执行日志...",
|
||
"error": "ERROR: [Synth 8-439] module 'counter' not found"
|
||
}
|
||
```
|
||
|
||
## 5. 后端使用指南
|
||
|
||
### 5.1 AI 对话流程
|
||
|
||
```
|
||
用户:帮我用 Vivado 综合一下 counter.v
|
||
|
||
AI 分析:
|
||
1. 用户想要综合 Verilog 文件
|
||
2. 需要调用 runVivado 工具
|
||
3. 命令类型是 synthesis
|
||
4. 顶层模块名从文件名推断为 counter
|
||
5. 输入文件是 counter.v
|
||
|
||
AI 调用工具:
|
||
{
|
||
"tool": "runVivado",
|
||
"parameters": {
|
||
"command": "synthesis",
|
||
"topModule": "counter",
|
||
"files": ["counter.v"]
|
||
}
|
||
}
|
||
|
||
前端执行并返回结果
|
||
|
||
AI 回复用户:
|
||
"Vivado 综合完成!
|
||
- 执行时间:45.2 秒
|
||
- 资源使用:LUT: 32/20800 (0.15%), FF: 8/41600 (0.02%)
|
||
- 产出文件已导入到 vivado_output 目录"
|
||
```
|
||
|
||
### 5.2 完整流程示例
|
||
|
||
```
|
||
用户:用 Vivado 跑完整个流程
|
||
|
||
AI:好的,我将依次执行综合、实现和生成比特流。
|
||
|
||
步骤 1:综合
|
||
[调用] runVivado { command: "synthesis", ... }
|
||
[结果] 综合成功,耗时 45s
|
||
|
||
步骤 2:实现
|
||
[调用] runVivado { command: "implementation", ... }
|
||
[结果] 实现成功,耗时 120s,时序满足要求
|
||
|
||
步骤 3:生成比特流
|
||
[调用] runVivado { command: "bitstream", ... }
|
||
[结果] 比特流生成成功,文件:counter.bit
|
||
|
||
完成!所有文件已导入到 vivado_output 目录。
|
||
```
|
||
|
||
## 6. 错误处理
|
||
|
||
### 6.1 常见错误
|
||
|
||
#### 错误 1:Vivado 未配置
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"error": "Vivado 未配置,请在设置中配置 Vivado 路径"
|
||
}
|
||
```
|
||
|
||
**AI 应该回复**:
|
||
"Vivado 尚未配置,请先在插件设置中配置 Vivado 的安装路径。"
|
||
|
||
#### 错误 2:文件不存在
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"error": "输入文件不存在: counter.v"
|
||
}
|
||
```
|
||
|
||
**AI 应该回复**:
|
||
"找不到文件 counter.v,请确认文件路径是否正确。"
|
||
|
||
#### 错误 3:综合失败
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"error": "ERROR: [Synth 8-439] module 'counter' not found",
|
||
"output": "详细日志..."
|
||
}
|
||
```
|
||
|
||
**AI 应该回复**:
|
||
"综合失败,错误信息:找不到模块 'counter'。请检查:
|
||
1. 模块名是否正确
|
||
2. 文件中是否定义了该模块
|
||
3. 是否有语法错误"
|
||
|
||
### 6.2 错误处理建议
|
||
|
||
后端收到 `success: false` 时:
|
||
1. 提取 `error` 字段中的错误信息
|
||
2. 分析错误类型(配置问题、文件问题、语法问题等)
|
||
3. 给用户提供具体的解决建议
|
||
4. 必要时可以查看 `output` 字段获取详细日志
|
||
|
||
## 7. 进度推送(可选)
|
||
|
||
前端会实时推送进度信息到 Webview,后端无需处理,但可以了解进度格式:
|
||
|
||
```json
|
||
{
|
||
"type": "vivado-progress",
|
||
"progress": {
|
||
"stage": "synthesis",
|
||
"percentage": 45,
|
||
"message": "正在综合模块 counter..."
|
||
}
|
||
}
|
||
```
|
||
|
||
## 8. 测试建议
|
||
|
||
### 8.1 后端测试用例
|
||
|
||
```javascript
|
||
// 测试用例 1:基本综合
|
||
test('综合单个文件', async () => {
|
||
const result = await callTool('runVivado', {
|
||
command: 'synthesis',
|
||
topModule: 'counter',
|
||
files: ['counter.v']
|
||
});
|
||
|
||
expect(result.success).toBe(true);
|
||
expect(result.importedFiles.length).toBeGreaterThan(0);
|
||
});
|
||
|
||
// 测试用例 2:错误处理
|
||
test('文件不存在', async () => {
|
||
const result = await callTool('runVivado', {
|
||
command: 'synthesis',
|
||
topModule: 'test',
|
||
files: ['not_exist.v']
|
||
});
|
||
|
||
expect(result.success).toBe(false);
|
||
expect(result.error).toContain('不存在');
|
||
});
|
||
```
|
||
|
||
## 9. 注意事项
|
||
|
||
### 9.1 执行时间
|
||
- 综合:小型设计 30s-2min,大型设计 5-30min
|
||
- 实现:通常是综合时间的 2-3 倍
|
||
- 生成比特流:通常 10-30s
|
||
|
||
后端应该设置合理的超时时间(建议 10 分钟)。
|
||
|
||
### 9.2 依赖关系
|
||
- `implementation` 需要先执行 `synthesis`
|
||
- `bitstream` 需要先执行 `implementation`
|
||
|
||
后端 AI 应该理解这个依赖关系,按顺序调用。
|
||
|
||
### 9.3 文件路径
|
||
- 所有文件路径都是相对于工作区根目录
|
||
- 前端会自动解析为绝对路径
|
||
- 支持相对路径和绝对路径
|
||
|
||
## 10. 快速集成清单
|
||
|
||
后端开发者需要做的事情:
|
||
|
||
- [ ] 在工具列表中注册 `runVivado` 工具
|
||
- [ ] 实现工具调用逻辑(发送请求到前端)
|
||
- [ ] 处理返回结果(success/error)
|
||
- [ ] 实现错误处理和用户提示
|
||
- [ ] 理解三个命令的依赖关系
|
||
- [ ] 设置合理的超时时间
|
||
- [ ] 编写测试用例
|
||
|
||
前端开发者需要做的事情:
|
||
|
||
- [ ] 实现 `handleVivadoTool` 函数
|
||
- [ ] 集成 VivadoRunner
|
||
- [ ] 实现进度推送
|
||
- [ ] 实现结果展示
|
||
- [ ] 处理各种错误情况
|