4.4 KiB
Flash 布局与 QuickBoot 兜底
板上 flash:Winbond w25q128bv,128 Mbit = 16 MB,SPIx1,24-bit 地址,64 KB sector / 4 KB subsector。
三个地址,一个都不能记错
来自 my_exciter.srcs/sources_1/quickboot/SpiFlashProgrammer.vhd(RU_golden 和 my_exciter 引用的是同一份文件,
见 RU_golden.xpr 里的 $PPRDIR/../my_exciter/.../SpiFlashProgrammer.vhd,所以两个工程的常数天然一致):
cAddrUpdateStart = X"00400000" -- update 镜像起点
cAddrUpdateEnd = X"00C00000" -- update 镜像终点+1 → 槽宽 8 MB
cAddrSwitchWordN25Q = X"00000FFC" -- 切换字
cAddrWidth = 24 -- 和 w25q128bv 匹配
flash 实际布局(从 golden_design_initial.mcs 解码得到,不是推测):
0x000000..0x000FFB FF FF ... 空
0x000FFC 00 99 55 66 切换字(AA 被写成 00 = 无效)
0x001000 20000000 NOOP
30020001 00400000 写 WBSTAR = 0x400000
30008001 0000000F 写 CMD = IPROG → 跳到 update 镜像
0x001050 AA995566 golden bitstream 自己的同步字
..0x3FFFFF golden bitstream(RU_golden_top.bit,3.4 MB)
0x400000..0xBFFFFF update 镜像(8 MB,日常远程升级写这里)
0xC00000..0xFFFFFF 未用
兜底机制:上电时 FPGA 从地址 0 扫描同步字。
- 切换字 =
AA995566→ 在 0xFFC 同步 → 执行 0x1000 处的 IPROG → 加载 update 镜像。 - 切换字 ≠
AA995566(擦除后是FFFFFFFF)→ 0xFFC 不同步 → 继续扫 → 在 0x1050 撞上 golden 的同步字 → 加载 golden。
远程升级一开始就把切换字所在的 subsector 擦掉(sProgrammerEraseSwitchWord,SSE 命令,
擦 0x000000..0x000FFF),写完校验通过后再把切换字写回去。所以升级中途断电只会退回 golden,不会变砖。
subsector 是 4 KB,擦 0xFFC 只波及
0x000000..0x000FFF。IPROG 头在0x001000,属于下一个 subsector,不会被擦到。golden 是安全的 —— 如果怀疑"升级把 golden 弄坏了",可以排除这条。
为什么 -imagesize 64
perl 脚本的模型是"golden 和 update 一样大、update 紧跟 golden":
imageSizeBytes = imagesize(Mbit) × 131072,updateStartAddr = imageSizeBytes。
- golden(
MakeSpiFlashProgrammerOnlyInitMcs.pl -imagesize 32)→ 4 MB → IPROG 里的 WBSTAR =0x400000,和cAddrUpdateStart对上。日志见RU_golden/bitstream/gen_initial.log。 - update(
MakeSpiFlashProgrammerMcsFiles_backup.pl -imagesize 64)→ 8 MB → 负载pad(bitstream, 0x7FFFFC) + crc32正好 8 MB,和槽宽0xC00000-0x400000对上。
两个 imagesize 不一样是故意的(VHDL 注释里的 "Plan B: golden enlarged to 4MB"),别去"统一"它们。
_update.mcs 里的 Intel-HEX 地址写的是 0x800000,看起来和 cAddrUpdateStart=0x400000 矛盾 ——
它不矛盾,因为地址被忽略。imx6 的 recv_upgrade_data_parse() 只从 :10xxxx00<32 hex> 记录里抠出
16 个数据字节,扩展线性地址记录 :02000004 直接当"中间控制字段"丢掉。FPGA 从 cAddrUpdateStart
顺序写。所以对远程升级而言,_update.mcs 只有负载长度和CRC是有意义的。
校验 _update.mcs 的起始地址是 0x800000,本质上是在校验"这个文件是用 -imagesize 64 生成的"。
两条烧写路径,别搞混
| JTAG 直烧 | 网络远程升级 | |
|---|---|---|
| 文件 | RU_golden/bitstream/golden_design_initial.mcs |
bitstream/<tag>_update.mcs |
| 工具 | /fpga_flash skill(flash 型号 w25q128bv) |
scripts/fpga_ru.py |
| 写到 | 0x000000..0x3FFFFF |
0x400000..0xBFFFFF |
| 何时用 | 首次装机、板子变砖、换打底镜像 | 日常迭代 |
_update.mcs 不能拿去 JTAG 烧写:它只是 8 MB 裸数据 + CRC,没有 bitstream 头。
反过来 _initial.mcs 也不能拿去远程升级。
严守上电时序:断电 → 断 USB-Blast → 上电 → 连 USB-Blast → 烧写 → 断电 → 断 USB-Blast → 上电 → 连 USB-Blast。
调试期的第三条路
program_device 直接把 .bit 下到 FPGA,掉电即失,不碰 flash,配 .ltx 还能抓 ILA。
迭代验证用它最快,功能确认后再走远程升级固化。固化用的 bit 要去掉 ILA 重新实现。