tags
实用工具箱
科研
type
Post
status
Published
date
Feb 24, 2026
slug
fpga
summary
category
摸鱼的笔记
password
icon
FPGA
型号识别


AX7035B / ACKU095 是核心板的商品型号,但我们在vivado中需要选择的是芯片信号,如XC7A35T-2FGG484I / XCKU095-1FFVA1156I。其中“-1””-2”标示的是速度,”I”标示的是工业温度标准,这两个参数的位置可能与说明手册不同,如vivado中实际型号分别为xc7a35t-fgg484-2 / xcku095-ffva1156-1-i。
同时,每个型号有自己专属的IDCODE。可以从该型号的bsd文件中获得。比如xcku095的bsd文件中搜索IDCODE,将这些数据拼起来就得到IDCODE=0x03844093。

其中第一位代表version,其实是不确定的。在用openocd连接时看到:
Info : JTAG tap: riscv.cpu tap/device found: 0x23844093 (mfg: 0x049 (Xilinx), part: 0x3844, ver: 0x2) 第一位是2,对应ver=0x2。xc7a35t的IDCODE=0x0362D093
连线
FPGA自身需要圆孔黑色电源线
从PC向FPGA烧录需要JTAG线,中间有一个红色的转换器
PC与FPGA之间的通信需要uart线
不同型号的连线可能有差异
Vivado
总体流程
- run synthesis
- run implementation
- generate bitstream
- open hardware manager → program device
右上角可以切换模式(比较常用的是I/O planning)
不同模式或不同Design(在左边栏中标黑标示当前Design,如Open Implemented Design、Open Hardware Manager)中菜单栏会有所不同
有两个版本,都在D:/Xilinx,但在/vivado和/SDK的不同文件夹(2019.1/2018.2)
Sources
包括四部分
- Design Sources:代码的核心部分,就是之前熟知的verilog / VHDL
- Constraints:对综合工具进行一些限制,确保synthesis、implementation之后的结果能适配具体的硬件
- Simulation Sources:用来测试的testbench。一般会调用Design Sources作为其子模块
- Utility Sources:暂时没用上
如果system verilog语法报错,主要是因为没有用”.sv”后缀名。可以改后缀,也可以在下方“Source File Properties”里改变文件的Type。
Constraints
右击Sources/Constraints的具体文件可以设置used in sythesis/implementation,最好选择在两个阶段都使用
[Constraints 18-5210] No constraints selected for write. 是因为constraints中没有clk约束只有pin约束,因此在systhesis阶段被忽略了(以下以led_test的constraints为例)
voltage
设定用户IO口的电压,可以看Flash的电压标准(因为Flash的IO也属于用户IO)
CFGBVS是用来选择电压的,只能设定为GND/VCCO。如果电压为1.8V则设为GND,如果电压为3.3V则设为VCCO
如果删去会导致warning,最好手动设置
flash
定义SPI参数以及是否压缩(不压缩可能导致文件超过128Mb写不上去)
目前烧写Flash之后FPGA并不会开始运行,原因不明
选择flash芯片型号mt25qu256-spi-x1_x2_x4
(特别注意不能选x8因为x8代表这两块flash芯片)
其实完全可以不用Flash,则这些都不用写
clock
pins
- clk
这里是差分时钟的定义。在Design Source中用如下代码转化为单端时钟(频率同手册中差分时钟的频率,200MHz)。
create_clock只要写sys_clk_p即可,因为有下面的代码,vivado会自动识别sys_clk_n为前者的Neg Diff Pair。这两个时钟信号不是独立的,所以不用写两次
- other ports
Top Module中所有的输入输出都必须绑定物理的引脚。在clk中我们已经绑定了2个,剩下还有4个led和rst。
如果不想直接写代码,可以在I/O planning模式下直接改。
WNS正的表示时序合规
在使用 Vivado 时,如果仅对代码进行了非实质性的修改(如添加注释或调整格式),设计状态可能会变为“Out-of-date”,提示需要重新运行综合或实现。然而,这种情况下无需浪费时间重新运行,可以使用 Force Up-to-Date 功能将状态强制更新为“Complete”。
RTL analysis/open elaborated design/schematic可以看到以logic cell为单位的原理图
注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏
OpenOCD & GDB
Connection有wsl和windows两种flow
完成连接之后,gdb的命令没区别
Address
OpenOCD:
D:\2学业\26春\全栈芯片设计\openocd_windowsriscv-gdb:
D:\2学业\26春\全栈芯片设计\xpack-riscv-none-elf-gcc-13.2.0-2input/result hex:
D:\2学业\26春\全栈芯片设计\testbench_datadcache_initial对应原来src中的data.hex
icache_initial对应原来src中的sram_initial1.hex
dcache_result是github上的dcache.hex
Connection (wsl)
- 打开管理员powershell
usbipd list查看usb口连接情况后两个与fpga调试有关。
其中4-4是板子uart/jtag接口(黑线,是电源线也是电脑向fpga烧程序的线),不直接用于我们的jtag通信;
而4-3是专用jtag接口,是我们后续使用的接口(这里显示Digilent USB是安装驱动之后的结果,未安装的时候显示的是USB Serial Converter)
usbipd bind --busid=4-3将4-3口设为sharedusbipd attach --wsl --busid=4-3把这个usb口给wsl使用(此时需要有wsl在运行),这个操作之后windows将无法再看见4-3口。正因如此,如果我们这里错误地挑选了4-4口,vivado将会有硬件断开连接的报错- 打开之前已经在运行的wsl(不建议用管理员模式,不要给openocd过多的权限)
lsusb查看wsl能看到的usb口编写openocd的配置文件
sudo openocd -f config_openocd.cfg启动openocd。看到Info : Listening on port 3333 for gdb connections
Ready for Remote Connections 即为成功,说明我们可以用3333口发送gdb调试信号了- 继续让openocd运行,打开一个新的wsl
在xpach-riscv文件夹中先输入./bin/riscv-none-elf-gdb激活gdb
target remote: 3333 看到以下信息即为连接成功!Connection (windows)
- 先打开管理员powershell
用
usbipd list查看usb接口情况如果显示6014对应设备为Digilent USB,说明驱动已经安装,可以跳过UsbDriverTool这步(未安装的时候显示的是USB Serial Converter)
- 打开D:\UsbDriverTool
在USB Serial Converter上Install WinUSB(注意VID=0403, PID=6014)。
安装成功后后面会多出一个
(WinUSB)。打开设备管理器,在“通用串行总线设备”中能找到“Digilent USB Device”。- 打开一个新的powershell(不建议管理员权限)
教程说:编写win_openocd的配置文件,相比wsl的版本只需要在最开头加上
bindto <WSL IP Address> 。写的IP是ipconfig指令获取的ipv4地址实操发现:写上wsl地址可能连不上,解决方案有如下几种
- 狂按fpga板上的reset
- 拔掉usb重连
- 去掉bind这一行
- 把ip写成0.0.0.0或者127.0.0.1
.\openocd_windows\bin\openocd.exe -f .\config_openocd_win.cfg建立连接,正确输出同前- 打开wsl
在xpack-riscv文件夹中先输入
./bin/riscv-none-elf-gdb激活gdbtarget remote: 3333 或者 target remote 0.0.0.0:3333 ,成功的输出同前GDB
monitor halt刚开始的时候大概率cpu在空转。为了防止后续初始化icache/dcache时触发奇怪的状态,先把cpu停下来restore dcache_initial.bin binary 0x60000000restore icache_initial.bin binary 0x80000000 把icache/dcache初始化,不能直接用hex,可以用bin或elfset $pc = 0x80000000 把pc指向icache的起始位置x/i $pc查看pc对应的指令info break查看目前有哪些breakpointhb *0x80000488添加硬件断点disable 1(如果需要)取消第一个breakcontinue or c执行直到断点被触发riscv地址以Byte为最小颗粒度。通常数据以8个“数字”为一组展示,即8个16进制数,等于4Byte,对应地址【+4】
- cv32e40p项目结果
7D0对应dcache_res.hex第500行
11F8对应dcache_res.hex第1150行
125C对应dcache_res.hex第1175行
- 附:空转状态
vivado加的debug core检测到instr_addr(由于实际上检测的是instr_addr[31:2],末两位是没有的,所以vivado波形图上的结果要乘4才是正确结果)在以下6个循环:
0x80000000 unimp
0x80000004 unimp
0x80000008 unimp
0x00010000 lui t0 0x80000000
0x00010004 jr t0
0x00010008 unimp
gdb检测到pc在以下3个循环:
0x80000000 unimp
0x00010000 lui t0 0x80000000
0x000100004 jr t0
其他:
halt_addr=0x800 j 0x80c
0x80c fence
BSCANE2
上述实验成功之后,尝试移植到xcku095上。然而这个板子没有GPIO,所以考虑复用vivado烧写程序用的jtag口来进行通信
xilinx7和ultrascale系列都提供vivado原语BSCANE2,可以把本来在top层上的jtag端口绑到原生jtag口。
正确的log:
gpio.log dmi_jtag代码中换成irlen=6,用GPIO,cfg只改irlen=6也可以成功
- 可能失败原因
用了bscan2jtag就不用use_bscan_tunnel了?
cv32e40p光改变dmi的irLength是不够的,可能它就不支持irlen=6?
cfg文件里ftdi的setup错了?
cfg文件里target & tunnel的irlen和channel要怎么设?
Can’t read DTMControl 或者 Unsupported DTM version一般就是length没匹配好,读错位了,或者IDCODE不对
通信链路
以下概念的详细解释(generated)GDB通过TCP端口3333“看到”OpenOCD。但GDB本身是不知道任何关于jtag或fpga的细节的,它发给OpenOCD的是诸如halt、x/i等抽象的指令
OpenOCD通过USB端口“看到”Digilent Adapter(就是那个红色的适配器,内置一颗FTDI芯片如FT2232H,可以把USB信号转换成JTAG信号)。OpenOCD需要把GDB的抽象指令转化成具体jtag操作,装成USB数据包发给Digilent Adapter来解码。
Digilent Adapter通过jtag线“看到”fpga。它解码OpenOCD发来的jtag操作并在jtag线上产生实际的信号(tck/tms/tdi/tdo)。
- jtag协议
信号 | 方向(相对于目标芯片) | 全称 | 作用 |
TCK | 输入 | Test Clock | 提供同步时钟,所有 JTAG 操作都以此时钟为基准。 |
TMS | 输入 | Test Mode Select | 控制 TAP(Test Access Port)控制器的状态机跳转。 |
TDI | 输入 | Test Data In | 串行数据输入,用于将指令或数据移入芯片。 |
TDO | 输出 | Test Data Out | 串行数据输出,用于将芯片内部的数据(如寄存器值、IDCODE)移出。 |
jtag协议是一个菊花链(chain)的形式。在这个环上可能有很多”门”(TAP),大家“控制并行,数据串行”,即不同TAP共享TCK和TMS,而TDI和TDO首尾相连。Adapter会产生TCK/TMS/TDI,并接受链尾的TDO。
每个TAP内部,TDI的串行数据转为并行触发器Instr Reg或Data Reg的数据,或者把这些数据转为串行从TDO发出。还有一个状态机(在cv32e40p中就是fpga上的dmi)负责处理指令(IR)和数据(DR)的移位,每次的移位长度由
irlen控制。在每个TAP位置上可以创建target。target是调试指令最终的接收者(如cpu),他们通过自己的debug module接收TAP(dmi)的指令,并反馈相应数据。
除了以上层级之外,如果不用GPIO,而要用FPGA上vivado专用jtag口,由于它的指令IR与riscv约定的IR有区别,还需要经过一层转换。
这一层转换具体怎么实现仍未清楚。参考资料:
- 其他参考资料
Issues:
openocd cfg:
bscane2:
cv32e40p:
- 作者:Tianyao Xiao
- 链接:https://xty27.top/article/fpga
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。








