基于状态机的图像信息提取的FPGA设计及仿真分析

作者:钱 鹏1,2,苏海冰1 2015年微型机与应用第8期

摘 要: 现场可编程逻辑门阵列(FPGA)应用于图像处理时,需要对数据中的图像信息进行准确的提取。设计中,FPGA中解压缩功能需要对压缩数据中的图像信息进行提取。根据压缩格式,设计了一种基于状态机的图像信息提取模块,并且在XST(Xilinx官方综合工具)以及Synplify pro两个综合环境下进行了仿真验证。通过对比仿真结果的差异,尝试分析设计的寄存器传输级视图(RTL视图),并找出了影响状态机工作的关键要素。强调了代码风格对FPGA设计的重要性。

0 引言
  状态机是数字系统设计中的重要组成部分,是FPGA实现高效率高可靠性逻辑控制的重要途径。在实际工程应用中,状态机工作是否正常决定着系统能否稳定工作。本文设计了一个基于状态机的图像信息提取模块,通过对该设计的仿真,分析了状态机设计中的状态竞争、锁存器的引入以及综合工具误判等常见情况。强调了代码规范对于FPGA设计的重要性。

1 设计背景及思路
  基于相机的实时图像目标仿真系统可以产生实时的虚拟目标图像流,因而被用于光电经纬仪等图像跟踪系统的开发调试。目标仿真系统中虚拟目标是经过DSP以一定的压缩格式压缩后储存于DDR中的,FPGA通过SRIO与DSP通信,读取压缩后的目标图形数据,经过FPGA内部解压缩与现实背景叠加输出。该系统中使用灰度图像作为图像源。其简化结构图如图1所示。

简化结构图

目标图像示意图如图2所示,虚拟目标图形以水平方向的线段形式压缩,整个压缩后的目标图形由n条线段组成,每条线段包含该线段的起始行列号、像素点数以及各像素点的像素值。其中每一帧的第一条线段还包含这帧图像压缩后的大小,压缩大小为32 bit。行列号、像素数以及各像素点的像素值均以16 bit表示。

目标图像示意图

FPGA对虚拟目标图像进行复原时,最主要的是对压缩数据中的目标图形的各类信息进行提取,行列号代表着目标图形的位置信息,压缩大小以及像素数表示目标图形的大小信息,像素值则代表各点的灰度信息。本文以有限状态机为基础设计了基于状态机的压缩图像信息提取模块。

  首先需要确定状态机的状态数。压缩图像信息提取模块的目的在于将压缩图像的信息进行分别提取,因此根据压缩的数据格式须将数据分为5块进行提取,分别为一帧压缩图像大小(frame_size,32 bit)、每条线段的起始行号(row_no,16 bit)、起始列号(column_no,16 bit)、每条线段的像素数(row_size,16 bit)以及分别的像素值(pic_element,16 bit)。考虑到16 bit的位宽,须将一帧压缩图像大小(frame_size)进行两次提取,由于空闲状态的存在,共设置7个状态,分别为:wait_state(S0)、frame_s_state1(S1)、frame_s_state2(S2)、row_no_state(S3)、column_no_state(S4)、row_s_state(S5)、pic_element_state(S6)。

  需要注意的是压缩数据中frame_size只存在于第一条线段,因此frame_size的提取在一帧数据中只进行一次。根据数据大小以及每行像素数,可以设置相应的状态转移条件,相应的信号如表1所示。

相应的信号

压缩数据在帧声明信号到来之后开始传输,当帧声明信号到来时,状态机进入等待状态(S0),随后便开始依次提取第一条线段中的信息,包括帧大小的前16 bit,帧大小的后16位,行号、列号、像素数(即依次进入S1、S2、S3、S4、S5状态),接着将r_done信号拉高,并且开始提取像素值数据(即进入S6状态)直至下一线段到来,第二条线段到来时r_done信号拉低,提取第二条线段的行号(即从S6跳转到S3状态),其余步骤与第一条线段相同,直至一帧信号传输完成(即f_done拉高),状态机跳转置等待状态(S0)。根据上述分析,状态转移图如图3所示。

状态转移图

2 综合仿真
  总结前面的分析,可以使用VHDL硬件描述语言对状态机进行描述。在VHDL设计中分3个进程来设计状态机:(1)主控时钟进程,负责下一状态与当前状态的切换,以及相应状态条件的逻辑部分;(2)状态转移组合逻辑进程,根据当前状态及状态条件进行状态转移判断并输出下一状态;(3)同步时序状态输出,用同步时序逻辑寄存状态输出,避免组合逻辑的毛刺与不稳定[1]。

  首先在Modelsim中对设计的代码进行了功能逻辑仿真。仿真结果与预期结果一致。仿真结果如图4所示。

仿真结果

随后对设计在XST和Synplify pro两个综合环境下进行了编译下载,并使用ChipScope进行了板级仿真。使用的FPGA是Xilinx生产的Virtex5系列FPGA,型号为XC5VLX110T。图5是XST综合后的结果,图6是Synplify pro综合的结果。

图5是XST综合后的结果,图6是Synplify pro综合的结果

同一个设计在不同综合环境下出现了差异,XST综合后的时序波形与预期不符,出现了错误,而Synplify pro综合后的波形则满足了设计要求。这说明所设计代码存在着问题。下面将尝试着分析这些问题。

3 错误分析
  通过对代码的分析,发现代码存在很明显的状态竞争,以下面的代码为例:
  when S0=>
  if r_done=′0′ and f_done=′0′ then
  Next_S<=S1;
  end if;

  上面的代码中if条件语句不完备,导致在!(r_done=‘0’and f_done=‘0’)时无法判断下一状态,可能导致综合工具产生误判,并且可能引入锁存器(Latch)来锁存下一状态[2]。而事实上,XST和Synplify pro的确都在设计中引入了锁存器来保证状态的正常切换和保持。这一点从综合报告中可以看得出来。

  在两者都生成锁存器的情况下,认为两个综合工具结果的差异,很有可能是因为综合工具的误判。为了证实这一结论,本文尝试着分析了XST和Synplify pro的综合RTL视图(寄存器传输级)[3-4],找出了两者出现明显差异的RTL视图部分,如图7、图8所示。

XST和Synplify pro的综合RTL视图(寄存器传输级)[3-4],找出了两者出现明显差异的RTL视图部分

图7、图8分别是XST和Synplify pro对下面这段代码的综合。
  when S6=>
  if r_done=′0′ and f_done=′0′ then
  Next_S <=S3;
  elsif r_done=′0′ and f_done=′1′ then
  Next_S<=S0;
  end if;

  可以发现前者的判断逻辑为:!r_done&!f_done 为真时,状态S6跳转到S3;为假时,状态S6跳转到S0。也就是说,在r_done=‘1’时状态没有保持S6,而是跳转到S0,导致结果错误。而后者的判断逻辑为:!r_done&!f_done为真时,状态S6跳转到S3,否则保持S6;f_done=‘1’时,状态S6跳转到S0,否则保持S6。这个组合逻辑保证了在正常情况下,状态机运转正常,因而得到了所希望的状态输出。

  根据上面的分析,找出了两个潜在的问题,锁存器的引入以及综合工具的误判。显然真正导致结果差异的是综合工具对组合逻辑的误判。但是在同步设计中锁存器也常是一个潜在的问题。锁存器不同于寄存器,锁存器没有时钟驱动,对毛刺敏感,上电后处于不确定状态。它会导致同步设计的时序分析复杂化,甚至出现时序以及稳定性上的问题,通常这些问题都是不可复现的。另外FPGA的基本单元是由查找表和触发器组成的,生成锁存器反而需要更多的资源[5]。因此在同步设计中最好不要使用锁存器[6]。

4 完善设计
  根据先前的仿真与分析,对代码中的状态转移条件判断进行了改进和完备。解决的方式很简单,就是完备if条件判断语句,不至于让综合工具去猜测缺省的部分,从而避免综合工具的误判,同时也避免了锁存器的引入。例如:
  when S0=>
  if r_done=′0′ and f_done=′0′ then
  Next_S<=S1;
  else
  Next_S<=S0;
  end if;

  将修改后的代码再次综合,分别查看RTL视图,发现XST和Synplify pro的RTL视图中分别生成了XST和Synplify pro中表示有限状态机的标准模块[3-4],说明本文设计的状态机是符合两者要求的。对完善后的设计进行了板级仿真,仿真结果与预期一致。

  对比了修改前后Synplify pro综合结果的时钟性能和资源使用的情况,如表2所示。

对比了修改前后Synplify pro综合结果的时钟性能和资源使用的情况

5 结论
  本文提出了一种基于状态机的图像信息提取模块的设计,并进行了仿真分析。从上面的仿真分析可以看出代码的设计风格对于综合结果的影响,综合器作为设计工具,它的综合优化结果是依赖于代码的。同一个逻辑,不同的代码在综合工具中可能产生不同的综合结果,有的如同上面分析的Synplify pro,结果一致,但是性能差距很大;或者有些在结果上都不一致,如同上面分析XST一样。因此对于一个FPGA设计,初始设计思路是实现设计的关键,同样实现设计的代码语言风格也对设计的结果有着重要的影响[7]。

文章来源:电子技术应用