FPGA的最大优势就是能对数据进行并行流水线处理。而实现这一点的关键就是要用FPGA内部的Block Ram对数据进行边缓存边处理。注意,进行流水线处理是用不到DDR的,DDR没有Ram那么高的实时性,只能用来缓存大量数据。要知道FPGA接的DDR速度和容量是远没有CPU上接的DDR快的。所以要发挥FPGA并行流水线处理的优势,其所用的算法也必须并行流水线化。把CPU上的算法照搬到FPGA中,然后接个DDR当内存,这样的做法并不能发挥FPGA的优势。FPGA的优势是并行流水线。那什么样的算法可以并行流水线化呢?简单的说只需要顺序读取数据进行处理的算法都可以。比如像图像处理中用NxN的算子进行滤波,取边缘,膨胀腐蚀等。这些都是很适合用FPGA进行处理的。有些算法看似不是顺序读取数据的,但改造一下之后也可以。比如连通域识别。
那么用FPGA进行NxN的算子法图像处理具体是怎样实现的呢?以3x3的算子为例,3x3的算子要同时取3行的数据,所以先要用FPGA里面的Block Ram缓存上两行的数据。当这一行数据来的时候同时去读取Ram里缓存的上两行数据,并把这3行数据一起移入3x3的移位寄存器中,然后对这3x3个寄存器中的值进行你所需要的算子运算。之后再把这新一行的数据存回Ram中,原先最上面的那一行数据就被覆盖丢弃了。简单的说流程就是这样的,N行的算子只需要缓存N-1行数据。Block Ram是FPGA里最重要的资源,所以能省则省。
具体如何写大家可以去参考我开源的代码,其实也没有多复杂,代码并不长。LineBuffer.v这个模块是负责控制Block Ram读写的,它并没有把Block Ram模块包含进去,是因为Block Ram是需要你自己用ISE或Vivado根据你的算法需要来生成的。OperatorNxN.v这个模块包含了LineBuffer.v和Block Ram模块,负责把数据移入移位寄存器并进行算子的计算。
这个Ram就相当于数组,在软件编程中我们获取数组中的数据只要写个A[n]数据就来了,不需要关心任何细节问题。但在Verilog硬件编程中,数据是怎么写入Ram中的,然后又是怎么读出来的都需要你去描述,这里面关键要处理的就是Ram的读写时序问题。所以在Verilog代码中,进行算子计算的这块代码看起来是和C语言中的差不多的。Verilog中多的就是对Ram的读写操作和移位寄存这块。要想用FPGA进行图像处理,要学会的也就是这些操作。