T20F256 JTAG-SPI Loader / Bridge 技术报告
1. 报告目的
本文记录 T20F256 单 SPI Flash JTAG bridge 项目的创建、配置、构建、Flash profile 添加和硬件验证过程,便于后续复用、迁移到其他电脑或更换 Flash 器件时排查问题。
当前工程目录:
D:\dev26\EFI_T20F256\000_JTAG_SPI_LOADER\JTAG_SPI_LOADER
报告基准日期:2026-09-05
最终状态:
- FPGA JTAG ID
0x00210A79可正常识别。 jtag_spi_loaderbridge bit 可通过 JTAG 下载到 FPGA。- SPI Flash
0x684015可识别为Boya BY25Q16BS,容量2 MiB。 - 用户程序可擦除、写入、回读校验并正常运行。
2. 目标硬件和工具版本
| 项目 | 配置 |
|---|---|
| FPGA 厂商/系列 | Efinix Trion |
| FPGA 器件 | T20F256 |
| Timing Model | C4 |
| 配置方式 | Active SPI,x1 |
| Efinity | 2026.1.132.4.5 |
| JTAG 工具 | FT232H,日志中 SPI/JTAG URL 相同 |
| JTAG bridge IP | efx_jtag2spi_flash,IP version 3.2 |
| 外部 Flash | Boya Microelectronics BY25Q16BSTIG / BY25Q16BS |
| Flash JEDEC ID | 68 40 15,合并表示为 0x684015 |
| Flash 实际容量 | 16 Mbit = 2 MiB |
Flash 器件的型号和 JEDEC 表可参考:BY25Q16BSTIG 数据手册。
3. 工程文件结构
工程中与 bridge 相关的主要文件如下:
JTAG_SPI_LOADER/
├─ JTAG_SPI_LOADER.xml Efinity 工程数据库入口
├─ JTAG_SPI_LOADER.sv 顶层 Verilog/SystemVerilog
├─ JTAG_SPI_LOADER.isf Interface Designer 可重放配置脚本
├─ JTAG_SPI_LOADER.peri.xml Interface Designer 生成的 periphery 数据库
├─ JTAG_SPI_LOADER.sdc 时序约束
├─ pins.txt 原始引脚要求
├─ ip/
│ └─ jtag_spi_loader/
│ ├─ settings.json IP 生成参数
│ ├─ jtag_spi_loader.sv Efinity 生成的 bridge RTL
│ ├─ jtag_spi_loader_define.svh
│ └─ ipm/ IP Manager 元数据
├─ work_syn/ 综合工作目录
├─ work_pnr/ 布局布线工作目录
└─ outflow/
├─ JTAG_SPI_LOADER.bit FPGA bitstream
├─ JTAG_SPI_LOADER.hex FPGA HEX 配置文件
├─ JTAG_SPI_LOADER.lpf periphery/布局布线输入
├─ JTAG_SPI_LOADER.pinout.rpt 引脚报告
├─ JTAG_SPI_LOADER.timing.rpt 最终时序报告
├─ JTAG_SPI_LOADER.map.rpt 综合报告
└─ JTAG_SPI_LOADER.pgm.out bit/hex 生成日志
4. 创建 spiloader-bridge 项目的方法
4.1 创建 Efinity 工程
在 Efinity 中新建 Unified Flow 工程,选择:
Family = Trion
Device = T20F256
Timing Model = C4
Top Module = JTAG_SPI_LOADER
工程配置使用 Active SPI x1。工程 XML 中的关键内容是:
<efx:family name="Trion" />
<efx:device name="T20F256" />
<efx:timing_model name="C4" />
<efx:top_module name="JTAG_SPI_LOADER" />
<efx:design_file name="JTAG_SPI_LOADER.sv" />
<efx:sdc_file name="JTAG_SPI_LOADER.sdc" />
<efx:isf_file name="JTAG_SPI_LOADER.isf" />
4.2 通过 IP Catalog 创建 JTAG-SPI bridge
在 IP Catalog/IP Manager 中选择:
Vendor = efinixinc.com
Library = memory_controller
Name = efx_jtag2spi_flash
Version = 3.2
Output = ip/jtag_spi_loader
本工程只连接一颗 SPI Flash,因此必须关闭双 Flash:
{
"args": [
"-o", "jtag_spi_loader",
"--base_path", "ip",
"--vlnv", {
"vendor": "efinixinc.com",
"library": "memory_controller",
"name": "efx_jtag2spi_flash",
"version": "3.2"
}
],
"conf": {
"EN_DUAL_FLASH": "1'b0"
}
}
IP 生成后,顶层 bridge 模块的接口包括:
input i_spi_clk;
output o_spi_clk;
output oe_spi_clk;
output o_spi0_cs;
output oe_spi0_cs;
input [3:0] i_spi0_io;
output [3:0] o_spi0_io;
output [3:0] oe_spi0_io;
input jtag_inst1_CAPTURE;
input jtag_inst1_DRCK;
input jtag_inst1_RESET;
input jtag_inst1_RUNTEST;
input jtag_inst1_SEL;
input jtag_inst1_SHIFT;
input jtag_inst1_TCK;
input jtag_inst1_TDI;
input jtag_inst1_TMS;
input jtag_inst1_UPDATE;
output jtag_inst1_TDO;
其中 spi0 是第一颗 Flash,当前工程没有连接 spi1。JTAG 资源采用 JTAG_USER1,由 Interface Designer 生成 jtag_inst1_* 信号。
4.3 顶层 Verilog 实例化
Efinity Unified Flow 对双向管脚使用 core-side 的输入、输出和输出使能三组信号。因此顶层没有直接声明 inout FLASH_DATA[3:0],而是声明:
input wire [3:0] FLASH_DATA_IN;
output wire [3:0] FLASH_DATA_OUT;
output wire [3:0] FLASH_DATA_OE;
input wire FLASH_CLK_IN;
output wire FLASH_CLK_OUT;
output wire FLASH_CLK_OE;
input wire FLASH_CS_IN;
output wire FLASH_CS_OUT;
output wire FLASH_CS_OE;
实际 bridge 实例化位于 JTAG_SPI_LOADER.sv:
jtag_spi_loader u_jtag_spi_loader (
.i_spi_clk (FLASH_CLK_IN),
.o_spi_clk (FLASH_CLK_OUT),
.oe_spi_clk (FLASH_CLK_OE),
.o_spi0_cs (FLASH_CS_OUT),
.oe_spi0_cs (FLASH_CS_OE),
.i_spi0_io (FLASH_DATA_IN),
.o_spi0_io (FLASH_DATA_OUT),
.oe_spi0_io (FLASH_DATA_OE),
.jtag_inst1_CAPTURE (jtag_inst1_CAPTURE),
.jtag_inst1_DRCK (jtag_inst1_DRCK),
.jtag_inst1_RESET (jtag_inst1_RESET),
.jtag_inst1_RUNTEST (jtag_inst1_RUNTEST),
.jtag_inst1_SEL (jtag_inst1_SEL),
.jtag_inst1_SHIFT (jtag_inst1_SHIFT),
.jtag_inst1_TCK (jtag_inst1_TCK),
.jtag_inst1_TDI (jtag_inst1_TDI),
.jtag_inst1_TMS (jtag_inst1_TMS),
.jtag_inst1_UPDATE (jtag_inst1_UPDATE),
.jtag_inst1_TDO (jtag_inst1_TDO)
);
4.4 顶层附加逻辑
为便于确认用户 bitstream 已经运行,顶层加入了一个不参与 Flash 数据路径的心跳计数器:
reg [24:0] heartbeat_counter = 25'd0;
always @(posedge clk_25m) begin
heartbeat_counter <= heartbeat_counter + 1'b1;
end
assign led[0] = heartbeat_counter[24];
assign led[6:1] = 6'b0;
assign led[7] = ~FLASH_CS_IN;
assign uart_tx = 1'b1;
含义如下:
led[0]:约25 MHz / 2^25 = 0.745 Hz的低频心跳翻转,用于确认用户逻辑运行。led[7]:Flash CS 为低有效,bridge 访问 Flash 时点亮或翻转。led[1]至led[6]:当前保持关闭。uart_tx:保持 UART 空闲高电平。pll0_in1_25m和uart_rx:保留为顶层真实端口并接入约束,但当前 bridge 不使用。
5. 根据 pins.txt 完成引脚和 Interface Designer 配置
5.1 原始引脚表
| 功能 | 顶层信号 | 封装引脚 | 方向 | 说明 |
|---|---|---|---|---|
| 25 MHz 时钟 | clk_25m |
H4 |
Input | bridge 用户侧保留时钟/心跳时钟 |
| PLL 输入 | pll0_in1_25m |
E8 |
Input | 保留端口 |
| LED0 | led[0] |
N8 |
Output | 心跳 |
| LED1 | led[1] |
R6 |
Output | 当前关闭 |
| LED2 | led[2] |
N9 |
Output | 当前关闭 |
| LED3 | led[3] |
P9 |
Output | 当前关闭 |
| LED4 | led[4] |
M10 |
Output | 当前关闭 |
| LED5 | led[5] |
N10 |
Output | 当前关闭 |
| LED6 | led[6] |
A15 |
Output | 当前关闭 |
| LED7 | led[7] |
B15 |
Output | Flash CS 状态 |
| UART TX | uart_tx |
P4 |
Output | 空闲高 |
| UART RX | uart_rx |
M7 |
Input | 弱上拉 |
| Flash IO0 | FLASH_DATA[0] |
L3 |
Bidirectional | SPI IO0/MOSI |
| Flash IO1 | FLASH_DATA[1] |
N1 |
Bidirectional | SPI IO1/MISO |
| Flash IO2 | FLASH_DATA[2] |
K4 |
Bidirectional | Quad/dual 扩展线 |
| Flash IO3 | FLASH_DATA[3] |
L2 |
Bidirectional | Quad/dual 扩展线 |
| Flash CLK | FLASH_CLK |
M3 |
Bidirectional | SPI 时钟 |
| Flash CS | FLASH_CS |
P3 |
Bidirectional | Flash 低有效片选 |
5.2 Interface Designer 资源
JTAG_SPI_LOADER.isf 中完成了以下配置:
design.set_property("jtag_inst1","RESOURCE","JTAG_USER1","JTAG")
design.assign_resource("jtag_inst1","JTAG_USER1","JTAG")
Flash 相关物理 GPIO 按 inout 配置。Interface Designer 会把:
FLASH_DATA[0..3] -> FLASH_DATA_IN[0..3]
-> FLASH_DATA_OUT[0..3]
-> FLASH_DATA_OE[0..3]
FLASH_CLK -> FLASH_CLK_IN / FLASH_CLK_OUT / FLASH_CLK_OE
FLASH_CS -> FLASH_CS_IN / FLASH_CS_OUT / FLASH_CS_OE
分别接到物理三态 I/O。所有使用的 I/O Bank 设置为 3.3 V,UART RX 配置为 WEAK_PULLUP。
JTAG_SPI_LOADER.peri.xml 是 Interface Designer 生成的持久化数据库,不建议直接手工修改。需要改变管脚或 JTAG 资源时,应修改 .isf 或在 Interface Designer 中修改后重新生成 periphery 数据库。
6. 时序约束
JTAG_SPI_LOADER.sdc 的主要约束:
create_clock -name clk_25m \
-period 40.0000 [get_ports {clk_25m}]
create_clock -name pll0_in1_25m \
-period 40.0000 [get_ports {pll0_in1_25m}]
create_clock -name jtag_inst1_TCK \
-period 25.0000 [get_ports {jtag_inst1_TCK}]
set_false_path -from [get_ports {jtag_inst1_RESET}]
说明:
clk_25m约束为 25 MHz。jtag_inst1_TCK按 40 MHz 约束,实际用户日志中的 JTAG 访问频率为 6 MHz,低于该约束。jtag_inst1_RESET是 bridge 状态机的异步复位,设置为 false path。
7. 构建和 bitstream 生成流程
7.1 GUI 流程
在 Efinity 中打开 JTAG_SPI_LOADER.xml,按以下顺序执行:
- 确认 IP 文件已经加入工程,
settings.json中EN_DUAL_FLASH=1'b0。 - 运行 Interface Designer,加载
JTAG_SPI_LOADER.isf,确认 JTAG_USER1、Flash I/O 和封装管脚。 - 运行 Synthesis/Map。
- 运行 Periphery/Unified Timing。
- 运行 Place and Route。
- 检查
JTAG_SPI_LOADER.timing.rpt和JTAG_SPI_LOADER.pinout.rpt。 - 运行 Bitstream Generation,得到
outflow/JTAG_SPI_LOADER.bit和outflow/JTAG_SPI_LOADER.hex。
7.2 日志中实际执行的阶段
Efinity 日志显示实际执行了以下阶段:
efx_run_map.py
efx_run_pt_unified.py
efx_run_pnr.py
efx_run_pgm.py
其中最终 bitstream 生成阶段使用的关键选项为:
mode=active
width=1
enable_roms=smart
spi_low_power_mode=on
io_weak_pullup=on
oscillator_clock_divider=DIV8
bitstream_compression=off
enable_external_master_clock=off
active_capture_clk_edge=posedge
jtag_usercode=0xFFFFFFFF
release_tri_then_reset=on
four_byte_addressing=off
four_byte_addressing=off 对本工程是合理的,因为 FPGA 配置 Flash 是 2 MiB,地址空间没有超过 3-byte addressing 的 16 MiB 边界。
7.3 构建结果
根据 outflow 报告:
| 检查项 | 结果 |
|---|---|
| Verilog 分析/综合 | 完成 |
| Placement | 成功,1066 cells are placed |
| Routing | 完成 |
| Bitstream Generation | 完成 |
| FPGA bitstream | outflow/JTAG_SPI_LOADER.bit |
| FPGA HEX | outflow/JTAG_SPI_LOADER.hex |
| Bit 文件大小 | 2,035,950 bytes |
| Hex 文件大小 | 2,035,950 bytes |
资源使用摘要:
| 资源 | 使用量 | 器件总量 | 使用率 |
|---|---|---|---|
| Inputs | 15 | 438 | 3.42% |
| Outputs | 22 | 1001 | 2.20% |
| Clocks | 2 | 16 | 12.50% |
| Logic Elements | 1066 | 19728 | 5.40% |
| LUTs/Adders | 882 | 19728 | 4.47% |
| Registers | 526 | 13920 | 3.78% |
| Memory Blocks | 0 | 204 | 0.00% |
| Multipliers | 0 | 36 | 0.00% |
最终时序摘要:
| 时钟 | 约束频率 | 分析最大频率 | 最差 Setup Slack | 最差 Hold Slack |
|---|---|---|---|---|
clk_25m |
25 MHz | 391.696 MHz | 37.447 ns | 0.361 ns |
jtag_inst1_TCK |
40 MHz | 96.946 MHz | 8.114 ns | 0.307 ns |
结论:当前约束下没有时序负裕量,且 bridge 的实际 JTAG 工作频率为 6 MHz。
8. JTAG-SPI bridge 的工作原理
8.1 两层下载过程
整个刷写动作不是直接把用户 HEX 通过 JTAG 写入 Flash,而是分成两层:
PC / FT232H
│ JTAG
▼
临时运行在 FPGA 中的 JTAG_SPI_LOADER.bit
│ SPI,由 bridge 产生 CLK/CS/DATA/OE
▼
板上的 BY25Q16BS Flash
│ 上电后的 FPGA 配置读取
▼
用户程序逻辑
因此:
outflow/JTAG_SPI_LOADER.bit是通过 JTAG 下载到 FPGA 的 bridge 固件。led_counter.hex等用户程序文件是通过 bridge 转换成 SPI 操作后写入外部 Flash 的数据。- 用户日志中的
Programming ... JTAG_SPI_LOADER.bit via JTAG表示 bridge 下载阶段。 - 后续
Writing ... to flash表示用户程序数据真正写入 SPI Flash。
8.2 JTAG USER1 协议
生成 IP 的 jtag_spi_loader.sv 中定义了 JTAG bridge 的内部协议:
Data register width = 64 bits
Command width = 6 bits
Register width = 32 bits
主要 command:
| 命令 | 值 | 作用 |
|---|---|---|
JTAG2SPI_CMD_NONE |
0 |
空操作 |
JTAG2SPI_CMD_RESET |
1 |
bridge 状态复位 |
JTAG2SPI_CMD_REGREAD |
2 |
读内部寄存器 |
JTAG2SPI_CMD_REGWRITE |
3 |
写内部寄存器 |
JTAG2SPI_CMD_BRIDGE |
4 |
发送 SPI bridge 数据 |
JTAG2SPI_CMD_CRC |
5 |
读数据 CRC |
JTAG2SPI_CMD_EXIT |
32 |
退出当前状态 |
常用内部寄存器包括:
| 寄存器 | 索引 | 作用 |
|---|---|---|
INTREG_VERSION |
0 | bridge 版本 |
INTREG_STATE |
1 | bridge 状态 |
INTREG_FLASH_SELECT |
2 | 选择 Flash |
INTREG_CLK_OE_MAP |
3 | SPI CLK 输出使能 |
INTREG_OE_MAP |
4 | SPI DATA 输出使能 |
INTREG_ADDRESS |
5 | 当前 Flash 地址 |
INTREG_LENGTH |
6 | 当前传输长度 |
INTREG_OUTPUT_REG0..7 |
7..14 | 通用输出寄存器 |
当前工程只选 Flash 0,IP 通过 FLASH_DATA_OUT/OE、FLASH_CLK_OUT/OE 和 FLASH_CS_OUT/OE 控制物理 Flash。
8.3 Flash SPI 操作序列
对 BY25Q16BS,profile 使用标准 Gen25 SPI NOR 操作模型,典型序列如下:
- 发送
9Fh,读取三个 JEDEC 字节68h 40h 15h。 - 发送
05h读取状态寄存器 SR1。 - 发送
06h置位 WEL(Write Enable Latch)。 - 按需要发送
01h写状态寄存器,清除保护位。 - 擦除:
20h + 24-bit address:4 KiB。52h + 24-bit address:32 KiB。D8h + 24-bit address:64 KiB。C7h:整片擦除。
- 每条擦除/写状态命令后,通过
05h轮询 SR1 的 WIP bit0,直到为 0。 - 编程:发送
06h,再发送02h + 24-bit address + data,每页最多 256 bytes。 - 读取校验:发送
03h + 24-bit address,回读并比较数据。
9. Flash JEDEC ID 和 profile
9.1 JEDEC ID 分解
0x684015 应拆分为三个字节,而不是把它当成一个普通容量数:
| 字节 | 数值 | 含义 |
|---|---|---|
| Manufacturer ID | 0x68 |
Boya |
| Memory Type / Device ID | 0x40 |
BY25Q16BS 系列匹配字段 |
| Capacity ID | 0x15 |
16 Mbit 密度码 |
容量换算:
16 Mbit / 8 = 2 MiB
profile 中的:
"densities": {
"0x15": [2, 20]
}
按 Efinity JSON matcher 的计算方式表示为:
2 << 20 = 2,097,152 bytes = 2 MiB
9.2 profile 的安装位置
本次添加的是 Efinity 用户级 Flash 数据库文件:
C:\Users\Administrator\.efinity\pgm\flash_db\68_40_BY25Q16BS.json
用户目录配置文件:
C:\Users\Administrator\AppData\Local\efinity\user_dir.ini
内容为:
[General]
EFINITY_USER_DIR=C:\\Users\\Administrator\\.efinity
Efinity jtag2SpiJsonFlash.py 的查找顺序是:
$EFINITY_USER_DIR/pgm/flash_db;$EFXPGM_HOME/bin/flash_db。
针对本次 JEDEC ID,程序首先匹配文件名模式:
68_40_*.json
因此文件名中的 68_40 不能省略或写错。
9.3 完整 Flash profile
当前实际使用的 profile 如下:
{
"name": "Boya BY25Q16BS",
"mfg_name": "Boya",
"match": {
"model": "gen25",
"mfg_id": "0x68",
"dev_id": {
"0x40": "BY25Q16BS"
},
"densities": {
"0x15": [
2,
20
]
}
},
"max_spi_frequency": 55,
"write": {
"model": "gen25",
"size": 256,
"cmd": "0x02",
"4byte_cmd": "0x12",
"timing": [
0.0015,
0.003
]
},
"read": {
"model": "gen25"
},
"erase": {
"model": "gen25",
"sizes": [
{
"size": 65536,
"cmd": "0xD8",
"4byte_cmd": null,
"timing": [
0.15,
1.0
]
},
{
"size": 32768,
"cmd": "0x52",
"4byte_cmd": null,
"timing": [
0.15,
1.0
]
},
{
"size": 4096,
"cmd": "0x20",
"4byte_cmd": null,
"timing": [
0.05,
0.5
]
},
{
"size": -1,
"cmd": "0xC7",
"4byte_cmd": null,
"timing": [
15.0,
30.0
]
}
]
},
"lock": {
"model": "gen25",
"read_cmd": "0x05",
"write_cmd": "0x01",
"and_mask": "0x43",
"or_mask": "0x00",
"status2_cmd": "0x35",
"timing": [
0.05,
0.1
]
},
"addr_modes": [],
"io_modes": [
{
"model": "dspi"
}
],
"write_status": {
"model": "gen25"
},
"poll": {
"model": "gen25"
}
}
9.4 profile 字段说明
| 字段 | 配置 | 技术意义 |
|---|---|---|
match.model |
gen25 |
使用通用 25 系列 SPI NOR matcher/操作模型 |
mfg_id |
0x68 |
匹配 Boya 厂商 ID |
dev_id |
0x40 |
匹配 BY25Q16BS 器件字段 |
densities |
0x15: [2,20] |
将容量识别为 2 MiB |
max_spi_frequency |
55 MHz |
profile 允许的最大 SPI 频率;本次实际 JTAG bridge 为 6 MHz |
write.size |
256 |
Flash 页编程大小 |
write.cmd |
0x02 |
普通 SPI Page Program |
write.timing |
1.5/3 ms |
页编程典型/最大等待时间 |
| 64 KiB erase | 0xD8 |
大块擦除 |
| 32 KiB erase | 0x52 |
中块擦除 |
| 4 KiB erase | 0x20 |
最小擦除单位 |
| chip erase | 0xC7 |
整片擦除 |
lock.read_cmd |
0x05 |
读取 SR1 |
lock.write_cmd |
0x01 |
写 SR1/SR2 状态寄存器 |
lock.and_mask |
0x43 |
清除保护相关 BP/SRP 位,同时保留 WEL/WIP 等必要位 |
status2_cmd |
0x35 |
读取并保留 SR2,配合 0x01 联合写状态 |
poll |
gen25 |
使用 SR1 bit0 WIP 轮询忙闲 |
addr_modes |
空 | 不进入 4-byte address mode |
io_modes |
dspi |
声明 dual-SPI 能力;没有添加 qspi,不会主动配置 QE 位 |
10. 原始报错的技术原理
10.1 原始错误日志的关键点
原始日志中有三组重要信息:
Valid device ID found: 0x00210A79
...
... finished with JTAG programming
...
Flash device: Unknown Unknown 16 MiB (JEDEC ID: 0x684015)
...
Command timout (1 cycles), aborting flash operation
这说明:
- FPGA JTAG TAP 正常,
0x00210A79已读出。 - bridge bit 已经成功通过 JTAG 下载,JTAG 到 FPGA 的路径正常。
- bridge 已经能通过 SPI 读到 Flash 的
0x684015,所以 CLK、CS、IO0/IO1 的基本连接和方向也正常。 - 失败发生在 Flash 数据库匹配后的擦除/状态轮询阶段,不是 FPGA JTAG ID 错误,也不是 bridge bit 没下载进去。
10.2 为什么显示 Unknown Unknown 16 MiB
0x684015 没有对应的 JSON profile 时,Efinity 能读取原始 JEDEC 字节,但无法得到:
- 厂商名称;
- 器件名称;
- 正确容量;
- 页编程大小;
- 擦除命令和擦除粒度;
- 状态寄存器读写命令;
- WIP/WEL/保护位位置;
- 擦除、写入和状态写入的等待时间。
于是日志只能打印 Unknown Unknown,并继续使用通用/未知器件路径尝试操作。这个路径不能保证与 BY25Q16BS 的状态寄存器和擦除时序完全匹配;其中显示的 16 MiB 也不能作为该 Flash 的实际容量判断依据。
10.3 Command timout (1 cycles) 的本质
擦除不是发送完命令就立即完成。典型过程是:
WREN(06h)
↓
ERASE(20h/52h/D8h + address)
↓
Flash 内部擦除,SR1.WIP = 1
↓
反复发送 RDSR(05h),直到 SR1.WIP = 0
Efinity bridge 通过 JTAG 发出 RDSR,再把 Flash 返回的数据通过 JTAG 读回 PC。日志中的 Command timout 是主机侧等待/轮询超时,含义是工具在预期的操作时间内没有得到“Flash ready”的状态,不是 JTAG 频率本身超时。
本次 profile 修复了三个关键问题:
- 用
68/40/15进行精确器件匹配,容量从未知值改为2 MiB。 - 告诉工具使用 BY25Q16BS 兼容的
gen25擦除、写入和状态寄存器模型。 - 给出正确的 4 KiB/32 KiB/64 KiB 擦除命令、写状态命令和等待时间,使 WIP 轮询能够结束。
11. 硬件刷写验证
添加 profile 后,实际刷写日志为:
Flash device: Boya BY25Q16BS 2 MiB (JEDEC ID: 0x684015) @ JTAG freq 6.0 MHz
Unlock all sectors for write.
Erasing 664 KiB from flash @ 0x00000000 (may take a while...)
Finished erase in 2 seconds
Writing 662 KiB to flash @ 0x00000000 ...
Finished write in 7 seconds
Reading 662 KiB from flash @ 0x00000000 ...
Finished read in 0 seconds
Flash verify successful
Flash programming...done
Programming operation completed.
验证结论:
- Flash 识别结果与器件实际型号一致。
- 664 KiB 擦除完成。
- 662 KiB 用户程序写入完成。
- 回读数据校验成功。
- 用户程序已经正常运行。
12. 构建警告和解释
当前综合报告存在若干 warning,但没有阻止生成 bitstream,也没有影响实际刷写:
intreg_version is never assigned
expression size ... truncated
i_spi1_io[...] does not have a driver
spi1_io[...] does not have a driver
Removing redundant signal ...
Re-wiring to GND non-driven net/port ...
这些 warning 主要来自:
- IP 的通用生成代码保留了双 Flash/多 IO/内部寄存器接口;
- 本工程配置
EN_DUAL_FLASH=1'b0,所以未使用的 Flash1 通道被综合优化或接地; JTAG_USER1中部分 TAP 辅助信号在当前实现中不直接参与数据路径;- 顶层保留了
pll0_in1_25m、uart_rx等板级端口,但当前逻辑没有使用它们。
需要扩展为双 Flash、QSPI 或使用 UART 调试时,应重新检查这些 warning,不能简单套用当前结论。
13. 交付物和校验值
以下 SHA-256 用于确认工程和 bitstream 没有被意外替换:
| 文件 | 大小 | SHA-256 |
|---|---|---|
JTAG_SPI_LOADER.sv |
4,029 B | b8da680750bb8f2f1ab5d9554c6231f6b05cb8819c8e348717018569b2ed2fa7 |
JTAG_SPI_LOADER.xml |
6,871 B | ce665e808fc786c3c06269b1545b5a78ad0b6fd3c13567ca47809511fc9b756d |
JTAG_SPI_LOADER.isf |
3,227 B | 66091628e8d9a4a9d54b0fdef6d983ad51159647c3e7c02dc3b1c790c7e90bcf |
JTAG_SPI_LOADER.sdc |
418 B | b21676337f00483621b465479659cc7db6d90b1cdb4324ab2c5cee98d4714f79 |
pins.txt |
856 B | 4049385ed29a953a50e3132618a50666b0e9cc64c2dfc99e9d199b62f2df5684 |
ip/jtag_spi_loader/settings.json |
726 B | cd2fb50f7e3de2fbbc64592d9da109a11a670fd9ec988fe972a4fa7ed6cac83d |
outflow/JTAG_SPI_LOADER.bit |
2,035,950 B | b16ff0c28162fb6230f23bc7e7a596400da37397457c4c5a535753c3dc7e2170 |
outflow/JTAG_SPI_LOADER.hex |
2,035,950 B | 99e40da654e2f7723c262c9c4c3eeafa40439449e6a792225ca4a58f033ce147 |
C:\Users\Administrator\.efinity\pgm\flash_db\68_40_BY25Q16BS.json |
1,471 B | de4f148bff3815139948ae2793e28576059d91038def6e5dcff1bd89b468c3a4 |
14. 后续迁移/复用清单
在另一台电脑或另一块相同硬件上复用时,需要同时保留:
-
整个
JTAG_SPI_LOADER工程目录,尤其是JTAG_SPI_LOADER.xml、JTAG_SPI_LOADER.isf、JTAG_SPI_LOADER.sdc和ip/jtag_spi_loader。 -
outflow/JTAG_SPI_LOADER.bit,用于临时把 bridge 下载到 FPGA。 -
用户目录下的 Flash profile:
C:\Users\<用户名>\.efinity\pgm\flash_db\68_40_BY25Q16BS.json -
确认目标电脑的
EFINITY_USER_DIR指向包含pgm/flash_db的用户目录。 -
确认 FT232H 驱动、JTAG/SPI 通道和板上 Flash 电平为 3.3 V。
-
刷写时首先观察 JTAG ID,然后确认日志出现:
Flash device: Boya BY25Q16BS 2 MiB (JEDEC ID: 0x684015)
如果再次看到 Unknown Unknown,应优先检查 profile 路径、文件名 68_40_*.json、JSON 格式和 Efinity 用户目录环境变量,而不是先修改 FPGA bridge RTL。
报告对应工程版本:Efinity 2026.1.132.4.5,Trion T20F256/C4,单 Flash bridge,最终硬件回读校验成功。