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

FPGA

型号识别

notion image
notion image
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。
notion image
其中第一位代表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

总体流程

  1. run synthesis
  1. run implementation
  1. generate bitstream
  1. 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

包括四部分
  1. Design Sources:代码的核心部分,就是之前熟知的verilog / VHDL
  1. Constraints:对综合工具进行一些限制,确保synthesis、implementation之后的结果能适配具体的硬件
  1. Simulation Sources:用来测试的testbench。一般会调用Design Sources作为其子模块
  1. 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_windows
riscv-gdb:D:\2学业\26春\全栈芯片设计\xpack-riscv-none-elf-gcc-13.2.0-2
input/result hex:D:\2学业\26春\全栈芯片设计\testbench_data
dcache_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口设为shared
usbipd 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地址可能连不上,解决方案有如下几种
  1. 狂按fpga板上的reset
  1. 拔掉usb重连
  1. 去掉bind这一行
  1. 把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激活gdb
target remote: 3333 或者 target remote 0.0.0.0:3333 ,成功的输出同前

GDB

monitor halt刚开始的时候大概率cpu在空转。为了防止后续初始化icache/dcache时触发奇怪的状态,先把cpu停下来
restore dcache_initial.bin binary 0x60000000
restore icache_initial.bin binary 0x80000000 把icache/dcache初始化,不能直接用hex,可以用bin或elf
set $pc = 0x80000000 把pc指向icache的起始位置
x/i $pc查看pc对应的指令
info break查看目前有哪些breakpoint
hb *0x80000488添加硬件断点
disable 1(如果需要)取消第一个break
continue 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:
微处理器routing
Loading...