78 lines
4.4 KiB
Markdown
78 lines
4.4 KiB
Markdown
# 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`,所以两个工程的常数天然一致):
|
||
|
||
```vhdl
|
||
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 重新实现**。
|