文章来源:OpenFPGA
缩略词索引:
K7:Kintex 7
V7:Vertex 7
A7:Artix 7
上一篇中介绍了FPGA的启动步骤,如图0 所示,今天这篇文章就要在上一篇文章基础上进行分支细化,首先我们先了解FPGA 启动加载的几种方式。同时对于我们设计中常见的几个问题将在文章最后详细讨论,比如HEX、BIN、MCS区别,在生成MCS时候Bit Swap什么作用,Bitstream 压缩到底在压缩什么等问题进行详细探讨。
图0:7系列FPGA启动步骤-参考:UG470
配置文件框架
在图0中上一篇没有细致讨论的配置文件载入,我们这篇文章详细讨论下,因为后续我们会使用这其中的一两个寄存器,我们就先看下配置文件架构。
7 系列 FPGA 配置文件以帧的形式排列。帧是 7 系列 FPGA 配置内存空间中最小的可寻址段,因此所有操作都必须作用于整个配置帧。每帧由 101 个 32 位组成。根据比特流选项,配置比特流中存在额外开销。确切的比特流长度可在 rawbits 文件 (RBT) 中找到。比特流长度(字)大致等于配置数组大小(字)加上配置开销(字)。比特流长度(位)大致等于比特流长度(字)乘以 32。
配置包
所有 7 系列 FPGA 比特流命令都是通过读取或写入配置寄存器来执行的。
数据包类型
FPGA 比特流由两种数据包类型组成: Type 1 和 Type 2。
Type 1数据包
Type 1 数据包用于寄存器读写。7 系列 FPGA 中仅使用 14 个寄存器中的 5 个。报头部分是 32 位字。
Type 1数据报头之后是Type 1数据部分。
图1:Type 1 数据包头格式-参考:UG470
上图中的OPCODE类型如图2所示。
图2:OPCODE格式-参考:UG470
Type 2数据包
Type 2 数据包必须跟在Type 1 数据包后面,用于写入长块。因为它使用Type 1 数据包地址,所以这里没有显示地址。报头部分同样是 32 位字。
Type 2 数据包头之后是Type 2 数据部分。
图3:Type 2 数据包头格式-参考:UG470
上图中的OPCODE类型如图4所示。
图4:OPCODE格式-参考:UG470
CRC Register(00000)
CRC寄存器,写入此寄存器用于对比特流数据执行 CRC 校验。如果写入的值与当前计算的 CRC 匹配,则清除 CRC_ERROR 标志并允许启动。
Frame Address Register(00001)
帧地址寄存器,7 系列FPGA分为两半,顶部和底部。7 系列FPGA中的所有帧都具有固定的相同长度,即 3,232 位(101 个 32 位字)。
帧地址寄存器 (FAR) 分为五个字段:块类型、顶部/底部位、行地址、列地址和次要地址。地址可以直接写入,也可以在每帧结束时自动递增。典型的比特流从地址 0 开始,并自动递增到最终值。
Command Register(00100)
命令寄存器 (CMD) 用于指示配置控制逻辑选通全局信号并执行其他配置功能。每次将新值加载到 FAR 寄存器时,都会执行 CMD 寄存器中的命令。
MFWR Register (01010)
该寄存器由比特流压缩选项使用。
IDCODE Register(01100)
IDCODE 寄存器,读取该寄存器可返回设备 IDCODE。提供的 IDCODE 必须与设备的 IDCODE 匹配。
Warm Boot Start Address Register (10000)
热启动起始地址寄存器 (WBSTAR) 指定应用 IPROG 命令时要使用的 MultiBoot 地址信息。图5中描述了相关寄存器。
图5:WBSTAR寄存器描述-参考:UG470
Watchdog Timer Register (10001)
看门狗定时器在回退比特流时自动禁用。图6中描述了相关寄存器。
图6:WTR寄存器描述-参考:UG470
Boot History Status Register (10110)
启动历史状态寄存器 (BOOTSTS)是用来指示启动过程中错误的类型,图7中描述了相关寄存器。
图7:BOOTSTS寄存器描述-参考:UG470
上面的相关参数大部分都可以通过JTAG读取到,图8中展示了读取到的BOOTSTS寄存器。
图8:通过JTAG读取BOOTSTS寄存器描述
FPGA 启动加载方式
对于7系列FPGA来说有多种方式启动,包括正常上电自启动,Program_B复位加载等方式,下面详细介绍几种启动方式。
上电自动加载
这个方式就不多说了,FPGA按照上电时序正常上电后,由FPGA主动从外部存储器读取位流,此时CCLK为输出;或者由其它主控制器通过SELETMAP将位流写入到FPGA中,此时CCLK为输入,从而完成上电自动加载。
Program_B复位加载
7 系列FPGA提供了一种通过外部引脚来重新配置FPGA的方式,这个引脚就是Program_B,通过拉低Program_B管脚重新配置FPGA,后续等INIT_B释放拉高后,就和上面步骤一样了。7系列FPGA通过Program_B复位加载时序如图9所示。
图9:Program_B复位加载时序图 - 来源:UG470
Boot加载
Program_B复位加载是通过外部引脚进行重加载过程,AMD-Xilinx还提供一种指令加载方式就是-Boot加载。Boot加载过程实际上是通过JTAG发送JProgram指令,实现FPGA加载功能。JTAG发出JProgram指令后,等到待INIT_B释放拉高后,就和上电自动加载后续过程一样。其功能和拉低Program_b功能相似,Boot加载操作如图10所示。
图10:Boot加载操作
IPROG指令加载
这个加载过程就和MultiBoot息息相关了,IPROG指令的作用跟外部Program_B管脚的作用类似,都是对FPGA芯片进行复位操作,该复位操作对FPGA内部的应用程序进行复位,同时IPROG指令不能复位专用重配置逻辑,如WBSTAR寄存器、TIMER寄存器、BSPI寄存器和BOOTSTS寄存器。IPROG指令能够触发FPGA开启初始化流程,同时拉低INIT和Done信号。完成复位操作后,将默认的加载地址用热启动地址寄存器(Warm Boot Start Address,WB-STAR)中的新地址替换。
IPROG指令可以通过ICAPE2原语和嵌入到位流中实现相关操作。
ICAPE2原语操作
ICAP目前为止有三个版本,包括ICAP,ICAPE2以及ICAPE3。UltraScale系列对应ICAPE3,7系列对应ICAPE2,7系列之前的对应ICAP。
ICAPE2原语通过更改WBSTAR寄存器来实现多重加载。ICAPE2原语发出的指令序列如下图所示,箭头所示就是IPROG指令
图11:ICAPE2原语发出的指令序列
首先写入同步头 32’hAA995566, 然后将需要跳转到的bit文件的起始地址写入WBSTAR寄存器,最后写入IPROG(internal PROGRAM_B)指令。
(1)对于BPI模式来说,可以通过RS[1:0](外部引脚)来控制具体位流的读取,也可以通过STAT_ADDR[28:0]地址来控制具体位流的读取。
(2)对于SPI模式来说,只有STAT_ADDR[23:0]地址来表征FLASH器件的地址,当使用32位地址的SPI(容量大于等于256Mb)时,需要将实际存储的高24地址赋值给STAT_ADDR[23:0]。因此在位流存储的起始地址早于255时,这就要求位流中的dummy数目要大于256个,否则就会出现易失部分有效位流读取,导致加载失败。为了安全起见,在使用大于等于256Mb的FLASH时,可以适当在位流头前加入Dummy。
详细如下图所示:
图12:BPI和SPI加载地址控制信号
位流操作
上面ICAPE2原语操作使用过例化原语指令事项相关操作,我们同样可以通过将IPROG指令嵌入到位流中,这个时候WBSTAR寄存器值也同样嵌入到位流中,也实现相同的操作,上面的过程就是通常使用XDC约束来实现Multiboot功能的应用场景,这种应用场景一般都是主加载SPI模式或主加载BPI模式。
图13:IPROG指令嵌入到位流中操作示意图
具体的操作和详细说明我们后续再详解。接下来我们讲解几个后续要使用的概念。
BIT、RBT、BIN、MCS和HEX区别
7系列的FPGA配置数据文件格式,有五种文件格式,BIT、RBT、BIN、MCS和HEX。对于FPGA开发工作者来说,使用最多的应该是四种格式的文件,BIT、BIN、MCS和HEX。那么这几个格式有啥区别呢?
在UG470中给了这几个格式的区别,如下图所示
图14:BIT、RBT、BIN、MCS和HEX区别 : 上-来源UG470 下-翻译
bit文件比较好理解是用来调试的,通过JTAG进行在线烧录调试。BIN和MCS用于固化,生成存储于flash的固化文件。对于HEX,一般用于远程更新,比如通过网络、PCIe接口方式远程升级时候。当然上面只是推荐的使用方面,也可以按照自己需求使用,我们接下来说一下这几个文件的区别。
mcs文件和bin文件的区别
这两个文件都是我们进行固化时候常见的文件格式,其中MCS文件时包含BIN文件内容的(只是内容),MCS文件的每行有地址信息,最后一个byte时CRC校验信息。所以mcs文件要比bin文件大。
烧录器烧录的时候,MCS文件只会烧写包含bin文件的那部分信息,不会将地址和crc信息烧录到flash中。
我们在做MultiBoot和FallBack时候只能使用MCS,因为MCS包含了地址信息,烧录器在烧写的时候知道golden image放在哪里,multiboot image放在哪里。
bit文件和bin文件的区别
bin文件不包含头部信息,bit为bin+头部信息(工程名称以及时间等信息)。
所以BIN文件时核心,其他文件是在BIN文件基础上增加了不同的信息。
图15:Vivado生成BIN设置
Bit Swapping什么作用
在生成固化文件时候,有个选项如下图所示:
图16:Bit Swapping设置
那么这个选项的作用是什么?
Bit Swapping是指字节内位的交换。除非使用 PROMGen -spi 选项或 SPI 配置模式的 write_cfgmem -interface spi1|spi2|spi4 选项,否则 MCS PROM 文件格式始终是Bit Swapping。HEX 文件格式是可选的,具体取决于用户选项。位流文件 (BIT、RBT、BIN) 则不会进行Bit Swapping。
对于 Xilinx 配置硬件,每个字节的 MSB 对应于 D0,而不是 D7,但是在处理位流文件时候可能会出现相反的操作,所以这一步是在进行纠正后续的操作。
Vivado中生成 MCS、EXO、TEK 文件或 HEX 文件时,D0 引脚对应于每个字节的 LSB。因此,这些文件被称为“字节交换”文件。默认情况下,HEX 文件是位交换的,但可以禁用此功能。 当禁用此选项时,D0 引脚对应于每个字节的 MSB,并且该文件是“非字节交换”文件。 BitGen 生成的 BIT 和 RBT 文件是“非交换字节”文件。 对于所有 FPGA 并行模式(Express、同步/异步外设、主/从并行、SelectMAP)都是如此。Xilinx 软件根据总线排序的一般规则生成字节交换文件。 通常,当使用“字节交换”时,MSB(最左边的位)对应于总线的最大数量(D0) 。 使用处理器或逻辑设备时必须纠正这些差异。 处理器、FPGA 等生成“字节交换”的文件,便可以在配置期间把每个字节的 MSB 对应于 D0。如果使用 BIT、RBT 或“非字节交换”的 HEX 文件进行下载时,则处理器的 MSB 必须与 FPGA 的 D0 相对应。
图16:Bit Swapping示意图 - 来源:UG470
需要注意的是:无论数据的方向如何,每个字节的MSB都将进入D0引脚:
在“字节交换”的版本中,进入D0的位是最右边的位
在“非字节交换”中,进入D0的位是最左边的位。
FPGA比特流内容
7系列FPGA比特流包括三个部分:总线宽度自动检测、同步字和FPGA配置。
总线宽度自动检测模式插入在每个比特流的开始。它用于并行配置模式,以自动检测配置总线宽度。因为它出现在Sync字之前,串行配置模式会忽略它。总线宽度自动检测对大多数用户来说是透明的,因为Xilinx工具生成的所有配置位流(BIT或RBT文件)都包括总线宽度自动探测模式。如果模式引脚设置为主串行、从串行、JTAG或SPI模式,配置逻辑将忽略这些模式。
图17:K7 FPGA Bit 示例 - 来源:UG470
下图为一个bit文件,图中阴影部分就与上述中的总线宽度模式以及同步字等一一对应,同步字之后才是FPGA设计功能的配置内容。
图18:实际 Bit 示例 - 来源:知乎@小灰灰的FPGA
Bitstream 压缩到底在压缩什么
最后就是BIT压缩,我们在设计中都会加入下面脚本:
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
这句话大家都知道是吧我们生成的位流文件进行压缩(压缩比还是很可观的),那么我们进行Bitstream 压缩到底在压缩什么?会不会影响我的功能?
压缩前后会对程序里的功能有影响吗?
答: 肯定没得影响. 影响功能的话就没法用了。
压缩的原理是什么,压缩了哪些部分?
答: 使用length encoding算法来减少配置数据的大小。
烧写的时候还需要解压缩吗?
答: 下载时FPGA会识别并处理解压缩的流程
有没有相关文档可以参考?
答: 可以参考UG908
程序固化后不能启动的排查思路
这个在新板子加工回来后第一次调试常出现的问题,这个问题一般分为两个方向:1、硬件问题;2、FPGA设计问题。
图19:程序固化后不能启动的排查思路
总结
今天文章内容比较杂,是一些常见的问题和疑惑,内容还是以官方文档UG470为主,受篇幅限制,后面有几个问题并没有挖到底层,这个后面会出几个专题进行详细解析。
下一篇会进入正题,进行MultiBoot解析。