Files
skills-win/fpga_flash/SKILL.md
T
boweiandClaude Opus 5 e07cfaa6d1 sync: WIN-BOWEI 2026-08-10 fpga_flash 增 Zynq BOOT.bin/QSPI 脚本,rtl-ip-replace 与 sim-rtl-flow 更新
- fpga_flash: 新增 build_zynq_boot.py / program_zynq_qspi.py(bootgen + program_flash,
  含备份、SHA-256/容量/marker 守卫);vivado_env.py 增 resolve_sdk_dir(SDK_ROOT/SDK_PATH);
  SKILL.md 补 Zynq 烧写流程,示例去掉写死的 D:\Xilinx\SDK\2018.1,改由 skills_env.md 解析。
- rtl-ip-replace: gen_ip.tcl / namespace_ip.py 更新。
- sim-rtl-flow: SKILL.md 与 run_sim_rtl_flow.py 更新。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 12:50:44 +08:00

308 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: fpga_flash
description: |
按开发板/器件架构选择正确的 Flash 固化方式。支持 EMV7.1 等 Artix-7 板卡的 MCS/cfgmem 流程,以及 HJX9009(XC7Z100/Zynq-7000)将 FSBL、PL bitstream、PS ELF 打包为 BOOT.bin 后写入双并行 QSPI 的流程。
当用户提到"烧写 flash"、"flash 编程"、"固化 bit 文件"、"下载到 flash"、"program flash"、"write flash"、"burn flash"、"Vivado flash"、"SPI flash 烧写"时,必须触发此 skill。
---
# FPGA Flash 固化流程(按开发板路由)
本 skill 由 Claude **全自动执行**完整的 Flash 固化流程。除了向用户确认必要信息外,所有操作(文件检查、备份、哈希/容量/内容守卫、工具调用、硬件编程)均由 Claude 直接完成,不要求用户手动执行任何命令。执行前必须先识别开发板与 FPGA/SoC 类型;不得把 Artix-7 的 `.mcs/cfgmem` 流程用于 Zynq,也不得把 Zynq 的 `BOOT.bin/program_flash` 流程用于普通 Artix-7。
---
## 执行规范
**自动执行原则:**
- 每个需要调用 Vivado 的步骤,Claude 通过 Bash 工具调用 skill `scripts/` 目录下的 Python 脚本
- **禁止**在用户工程目录或系统临时目录(`%TEMP%`、`/tmp`)下创建任何脚本文件
- 所有可执行脚本已预置在 skill 目录的 `scripts/` 子目录中,Claude 只需传入正确的参数调用
**定位 skill 脚本目录:**
Claude 在执行前需先确认脚本的完整路径。使用 Glob 工具查找:
```
C:/Users/<当前用户>/.claude/skills/fpga_flash/scripts/gen_mcs.py
```
或直接使用默认路径:`%USERPROFILE%/.claude/skills/fpga_flash/scripts/`
**scripts/ 目录内容:**
```
scripts/
check_flash_csv.py # 第一步:检查/更新 Vivado Flash 器件表
gen_mcs.py # 第三步:生成 .mcs 文件
program_flash.py # 第四、五步:连接目标板并烧写 Flash
step3_write_mcs.tcl # gen_mcs.py 使用的 Tcl 模板(勿手动修改)
step4_5_program.tcl # program_flash.py 使用的 Tcl 模板(勿手动修改)
build_zynq_boot.py # Zynq:FSBL + bit + PS ELF 生成受保护的 BOOT.bin
program_zynq_qspi.py # Zynq:哈希/容量/marker 守卫后烧写并强制 verify
vivado_env.py # 解析 Vivado/SDK 工具路径
```
**调用方式(Bash 工具):**
```bash
python "$USERPROFILE/.claude/skills/fpga_flash/scripts/<script>.py" [参数...]
```
各脚本通过命令行参数接受变量(Vivado/SDK 安装目录、bit/ELF/MCS/BOOT 路径、容量和 marker 等)。Artix-7 脚本内部调用 Vivado `-mode batch -source <tcl模板> -tclargs <参数>`;Zynq 脚本调用 SDK 的 `bootgen`/`program_flash`。工程路径和板级文件均由参数传入,不在 skill 中硬编码。
---
## 第零步:识别板卡并选择唯一流程
先用工程名、器件型号、原理图/板卡说明和现有部署资料交叉确认,不允许只根据输出文件扩展名猜测。
| 板卡/器件 | 固化容器 | 写入工具与接口 | 选择的流程 |
|---|---|---|---|
| HJX9009、`xc7z100`、Zynq-7000(PS+PL) | `BOOT.bin`,顺序为启动 FSBL + PL `.bit` + PS `.elf` | SDK `bootgen` + `program_flash -flash_type qspi_dual_parallel` | 本文“Zynq/HJX9009”流程 |
| EMV7.1、`xc7a*`、Artix-7(纯 PL) | `.mcs` | Vivado `write_cfgmem` + Hardware Manager cfgmem | 本文“Artix-7/EMV7.1”流程 |
硬阻断规则:
- 发现 `xc7z*`、PS7、FSBL、PS ELF 或工程明确写明 Zynq 时,禁止运行 `gen_mcs.py`、`program_flash.py` 或 `create_hw_cfgmem`。
- 发现 `xc7a*` 且无 PS/FSBL 时,禁止生成 `BOOT.bin`。
- 板型、Flash 拓扑或容量不明确时,先查原理图/现有已验证部署记录;不得试烧。
- HJX9009 已验证为两片 `s25fl128s` 双并行 QSPI,总容量 32 MiB,必须使用 `qspi_dual_parallel`,不能退化为 `qspi_single`。
---
## Zynq/HJX9009:同时固化 PS 与 PL
### Z1. 输入与两个 FSBL 角色
生成冷启动镜像需要三个输入,BIF 中顺序不可改变:
```text
the_ROM_image:
{
[bootloader]<boot_fsbl.elf>
<implemented_pl.bit>
<ps_application.elf>
}
```
必须区分两个角色不同的 FSBL:
- **启动 FSBL**:封装在 `BOOT.bin` 第一分区,板卡冷启动时由 BootROM 加载,随后配置 PL 并启动 PS 应用。
- **JTAG 烧写辅助 FSBL**:由 `program_flash -fsbl` 临时下载到 OCM,用于初始化当前板卡的 QSPI MIO/控制器并完成写入。它不等于、也不能默认替换 `BOOT.bin` 内的启动 FSBL。
对 HJX9009,必须使用已验证能初始化该板 QSPI MIO 的参考 JTAG 辅助 FSBL。若项目提供其期望 SHA-256/MD5,必须作为守卫验证。错误的辅助 FSBL 可能读出 JEDEC `00,00,00`,造成表面执行但没有可靠写入。
HJX9009 当前工程部署记录中的参考辅助 FSBL 指纹为 MD5 `14232757864453B418E67D63457EE24F`。这只是板级身份参考,不应写死进通用脚本;实际执行仍应从当前项目部署清单取得文件并同时记录 SHA-256。
### Z2. 安全预检与备份顺序
执行顺序固定如下:
1. 确认本次 PS ELF、时序通过的 PL bitstream、启动 FSBL 和 JTAG 辅助 FSBL 的绝对路径。
2. 记录四个输入的 SHA-256、字节数和修改时间;若有 `.ltx`,另记录其 SHA-256,确保它与 bitstream 同次构建。
3. 在覆盖部署目录中的任何已有 `BOOT.bin`、BIF、FSBL、bit 或 ELF 前,复制到带时间戳的备份目录并写 manifest。不得删除已知可回退镜像。
4. 对源文件和 staging 副本逐个比较 SHA-256,任一不一致立即停止。
5. 为新固件指定至少一个能区分版本的 ASCII marker,并在 PS ELF 和生成的 `BOOT.bin` 中检查。marker 不匹配立即停止。
6. 生成后要求 `BOOT.bin` 严格小于物理 QSPI 容量;HJX9009 上限为 33,554,432 字节。
7. 记录最终 `BOOT.bin` 的 SHA-256 和精确长度;烧写命令必须重新校验这两个值,防止旧镜像或 TOCTOU 误烧。
### Z3. 生成 BOOT.bin
调用参数化脚本;示例只表示参数结构,实际路径和 marker 必须来自当前项目。
Xilinx SDK 安装根目录由脚本自行解析(`SDK_ROOT` / `SDK_PATH`:先查环境变量,再查
`~\skills_env.md`),只有需要临时覆盖时才显式传 `--sdk-dir`:
```powershell
python "$env:USERPROFILE\.claude\skills\fpga_flash\scripts\build_zynq_boot.py" `
--boot-fsbl "<cold-boot-fsbl.elf>" `
--bit-file "<implemented-top.bit>" `
--app-elf "<ps-application.elf>" `
--boot-bin "<deployment-dir>\BOOT.bin" `
--bif-file "<deployment-dir>\boot.bif" `
--capacity-bytes 33554432 `
--require-marker "<build-identity-marker>"
```
脚本会备份已有 BOOT/BIF、生成候选镜像、执行容量与 marker 守卫、原子替换最终镜像,并输出 JSON manifest。成功标志为:
```text
ZYNQ_BOOTGEN_PASS size=<n> sha256=<64 hex>
```
如果工程采用 staging 目录,复制 FSBL/bit/ELF 后仍要逐项重算并对比 SHA-256。`BOOT.bin` 约 18 MiB 只是 HJX9009 的常见值,不是成功判据。
### Z4. 启动 Vivado hw_server 并确认 JTAG
HJX9009 当前机器上必须由 **Vivado** 的 `hw_server` 给 Platform Cable USB II 加载固件;SDK 自带 hw_server 可能无法完成该动作。先启动并等待枚举出 `xc7z100`:
```powershell
& '<Vivado-root>\bin\hw_server.bat' -s tcp::3121
```
保持服务运行,确认 `tcp:127.0.0.1:3121` 可连接且 JTAG 链中只有预期目标。若 3121 被未知进程占用、目标器件不是 `xc7z100`、板卡掉电或线缆未枚举,停止,不得烧写。
### Z5. 写入 HJX9009 双并行 QSPI 并强制 verify
从 Z3 的输出/manifest 复制**精确** SHA-256 和长度后执行:
```powershell
python "$env:USERPROFILE\.claude\skills\fpga_flash\scripts\program_zynq_qspi.py" `
--image "<deployment-dir>\BOOT.bin" `
--jtag-fsbl "<verified-jtag-helper-fsbl.elf>" `
--expect-sha256 "<exact-BOOT.bin-sha256>" `
--expect-size <exact-byte-length> `
--capacity-bytes 33554432 `
--flash-type qspi_dual_parallel `
--hw-server-url tcp:127.0.0.1:3121 `
--expect-jtag-fsbl-sha256 "<exact-helper-FSBL-sha256>" `
--require-marker "<build-identity-marker>" `
--log-file "<deployment-dir>\program_flash.log"
```
安全约束:
- offset 必须为 `0`;HJX9009 的 Flash 类型必须保持 `qspi_dual_parallel`。
- 参数顺序必须是 `-verify` 在 `-fsbl` 前,`-cable ...` 最后;参数化脚本已固定此顺序。
- 擦除、编程、回读校验可能超过 10 分钟;期间禁止断电、拔 JTAG、关闭 hw_server 或终止进程。
- 不信任包装层退出码。已验证存在“无法连接 hw_server 但返回码仍为 0”的情况。
真正成功必须在同一次日志中同时出现:
```text
Erase Operation successful
Program Operation successful
Verify Operation successful
Flash Operation Successful
ZYNQ_QSPI_FLASH_VERIFY_PASS
```
若出现 `Verify Operation unsuccessful`、`Flash Operation Failed`,或缺少任一成功行,一律判失败。`End of startup status: HIGH` 只证明易失配置完成,不能证明 Flash 已写入。
### Z6. 完全断电冷启动与 COM5 验收
烧写成功后还必须验证自主启动:
1. 保存烧写日志、BOOT manifest、bit/LTX/ELF 哈希和回退镜像位置。
2. 关闭板卡主电源及可能通过 JTAG 反向供电的接口,静置至少 30 秒;JTAG 枚举异常时按板级规程全断 90 秒。
3. 保持 JTAG 断开,重新打开主电源,让板卡只从 QSPI 启动。
4. 打开 COM5(115200、8N1、无流控),保存带时间戳的启动日志。
5. 要求看到本次 PS 固件的唯一 marker/banner,并执行项目定义的只读状态命令。HJX9009 当前固件通常用 `HELP`、`?`,随后按项目规程输入 `R`;验收期望状态和命令必须以本次固件文档为准。
6. 若 marker 不匹配、COM5 无输出、PL/PS 版本不一致或只能在重新接入 JTAG 后工作,判定冷启动失败并使用已备份的已知良好镜像回退。
只有“写入日志完整成功 + verify 成功 + 完全断电后 COM5 确认本次固件自主启动”三者同时成立,才可以向用户报告 HJX9009 PS+PL 已固化。
---
## Artix-7/EMV7.1:MCS/cfgmem 流程(保留)
## 第一步:检查并修复 Vivado Flash 器件表
**Claude 自动执行:**
调用 `check_flash_csv.py`,检查 `xicom_cfgmem_part_table.csv` 中是否已包含 `w25q128bv-spi-x1_x2_x4`:
```bash
python "$USERPROFILE/.claude/skills/fpga_flash/scripts/check_flash_csv.py"
```
**返回值含义:**
- 退出码 `0`:器件已存在,直接进入第二步
- 退出码 `2`:已成功添加器件行,需提示用户**重启 Vivado** 后才能识别
- 退出码 `1`:CSV 未找到,检查 `~/skills_env.md` 的 `VIVADO_ROOT` 是否指向有效的 Vivado 安装
**Vivado 安装路径不写死在本 skill 里**:三个脚本都通过 `scripts/vivado_env.py`
按 `--vivado-dir` > 环境变量 > `~/skills_env.md` 的 `VIVADO_ROOT`(退化到 `VIVADO_PATH`)
的顺序解析。换机器只改 `~/skills_env.md`,不改 skill。仅在需要临时用另一套 Vivado
时才显式传 `--vivado-dir`。
---
## 第二步:选择 Flash 型号
询问用户板卡上焊接的 Flash 芯片型号,仅支持以下两种:
| 选项 | 厂商 | `--flash-part` 值 |
|------|------|-----------------|
| 1 | Micron | `mt25ql128-spi-x1_x2_x4` |
| 2 | Winbond | `w25q128bv-spi-x1_x2_x4` |
记录用户选择,后续步骤中作为 `--flash-part` 参数传入。如果用户不确定,提示查看板卡丝印或原理图中 Flash 芯片的位号。
---
## 第三步:确认文件路径并自动生成 .mcs
**需向用户确认:**
1. **.bit 文件**的完整路径(通常在工程 `runs/impl_1/` 目录下)
2. **输出 .mcs 文件**的保存路径和文件名(建议与 .bit 文件同目录)
用户确认后,**Claude 自动调用**:
```bash
python "$USERPROFILE/.claude/skills/fpga_flash/scripts/gen_mcs.py" \
--bit-file "E:/Xilinx_design/smod/SMOD_DTMB_CG/RU_golden/RU_golden.runs/impl_1/RU_golden_top.bit" \
--mcs-file "E:/Xilinx_design/smod/SMOD_DTMB_CG/RU_golden/RU_golden.runs/impl_1/RU_golden_smod.mcs"
```
将示例路径替换为用户实际的 .bit 文件路径、.mcs 输出路径(Vivado 路径自动解析,见第一步)。
**验证成功的标志:** 输出中包含 `write_cfgmem completed successfully` 且显示 `0 Errors`。
---
## 第四步 + 第五步:连接目标板、配置存储器并烧写
确认板卡已上电并连接 JTAG 后,**Claude 自动调用**:
```bash
python "$USERPROFILE/.claude/skills/fpga_flash/scripts/program_flash.py" \
--flash-part "w25q128bv-spi-x1_x2_x4" \
--bit-file "E:/Xilinx_design/smod/SMOD_DTMB_CG/RU_golden/RU_golden.runs/impl_1/RU_golden_top.bit" \
--mcs-file "E:/Xilinx_design/smod/SMOD_DTMB_CG/RU_golden/RU_golden.runs/impl_1/RU_golden_smod.mcs" \
--ltx-file "E:/Xilinx_design/smod/SMOD_DTMB_CG/RU_golden/RU_golden.runs/impl_1/RU_golden_top.ltx"
```
**参数说明:**
- `--flash-part`:第二步用户选择的型号
- `--bit-file`:第三步确认的 .bit 路径
- `--mcs-file`:第三步生成的 .mcs 路径
- `--ltx-file`:若设计无 ILA,省略此参数(脚本自动跳过 PROBES.FILE 配置)
此脚本在同一个 Vivado batch 会话中完成:硬件连接 → cfgmem 器件创建 → **载入 flash-loader 比特流(关键步骤)** → 擦除/编程/验证 → 回载用户 bit。
**验证成功的标志(真正写入 flash):** 输出必须包含
`Performing Erase Operation... Erase Operation successful`、
`Program/Verify Operation successful`、`Flash programming completed successfully`,
并能读到非零的 `Mfg ID`(如 Winbond=`ef`、Micron=`20`)。
> ⚠️ 仅有 `End of startup status: HIGH` **不代表写了 flash**——那只是把 bit 载入 FPGA
> 易失配置。若看到 `Mfg ID : 0 / Unable to read device properties`,说明 flash-loader
> 没接管 SPI 总线(本 tcl 已用 `create_hw_bitstream`+`program_hw_devices` 载入
> `spi_<part>_pullnone.bit` 修复此问题)。
ILA core 的 `Dropping logic core` WARNING 是正常现象(载入 loader/golden 镜像时不含 ILA core),不影响烧写结果。
---
## 第六步:上电验证
烧写完成后,提示用户:
1. **断开 JTAG**,给板卡重新上电(或按复位键)
2. 观察 FPGA 是否从 Flash 正常加载(DONE 灯亮起)
3. 如果 DONE 灯不亮,检查:
- BOOT_MODE 跳线是否选择 SPI Flash 启动模式
- MCS 生成时起始地址是否为 `0x0`
- 板卡电源是否满足 Flash 的 VCC 要求(3.3V / 1.8V)
---
## 常见错误排查
| 现象 | 可能原因 | 解决方法 |
|------|----------|----------|
| `check_flash_csv.py` 退出码 1 | `VIVADO_ROOT` 未配置或指错 | 修正 `~/skills_env.md` 的 `VIVADO_ROOT`;临时可传 `--vivado-dir` 覆盖 |
| Vivado 中找不到 w25q128bv | CSV 已修改但 Vivado 未重启 | 提示用户重启 Vivado 后重新执行 |
| `bad lexical cast: source type value could not be interpreted as target`,报在 `get_cfgmem_parts` **或** `refresh_hw_device` 上 | CSV 里的 w25q128bv 行畸形(2026-07-30 之前的版本写的是 9 字段、从 `NAME` 开头,缺了首列数字 `CFGMEM_ID`),Vivado 拿名字当整数解析 | 重跑 `check_flash_csv.py`,它会识别并替换掉畸形行(退出码 2),然后**重启 Vivado**。注意报在 `refresh_hw_device` 上极具误导性 —— 那一步内部也读这张表,看起来像硬件/probe 问题,其实与 `.ltx`、debug core 无关 |
| `No hardware target` 错误 | JTAG 未连接或板卡未上电 | 检查连接后重新执行第四步 |
| DONE 灯不亮 | 启动模式跳线错误 | 检查 MODE 引脚电平,确认为 SPI 启动模式 |
| 烧写后板卡跑旧程序 | Flash 未完全擦除 | 确认 `PROGRAM.ERASE 1` 已设置后重新执行 |
| `PermissionError` 写 CSV | 权限不足 | 提示用户以管理员身份运行 Claude Code |
| Zynq `program_flash` 返回 0 但无成功行 | hw_server 未连接或工具包装层假成功 | 按日志判失败;要求 erase/program/verify/Flash 四组成功标志齐全 |
| HJX9009 JEDEC 为 `00,00,00` | JTAG 辅助 FSBL 未正确初始化 QSPI MIO | 使用项目已验证的参考辅助 FSBL并核对哈希,保持 `qspi_dual_parallel` |
| `BOOT.bin` 可写但冷启动无 COM5 | 启动 FSBL/PS ELF/PL 不匹配或未自主启动 | 完全断电、断开 JTAG,从 QSPI 冷启动并核对固件 marker;失败则回退备份 |