【转载】FPGA算法设计随笔

时间:2022-05-12 07:51:48

  FPGA设计算法依次需要完成MATLAB浮点仿真 MATLAB定点仿真 verilogHDL定点运算以及数据对比的流程。其中浮点到定点的转换尤为重要,需要在数据表示范围和精度之间做出权衡。另外掌握定点运算规则是硬件实现算法的前提。这篇博文介绍了在用FPGA设计实现算法中的一些基础知识,比较全面。

介绍

FPGA是纯粹的硬件设计,当进行算法设计时,Verilog综合后的就是硬件逻辑电路。因此,进行算法设计时,算法设计中需要表示的数字用到的小数、符号、无穷大、整数、浮点数等等对应硬件来说都是一串0和1组合的数字。因此,当FPGA工程师设计算法时,需要对这些数字转换。一般转换为定点数值表示方式,在FPGA中实现定点数运算。具体用多长的位数表示定点,以及定点小数点放在那里,都需要根据具体设计中数值大小、需要表示的精度来确定。 
这里主要介绍一下算法设计的主要过程和知识点,主要阐述下设计过程和用到的知识。不做具体深入细化,主要目的是记录下自己的学习过程,为想本人一样的初学者指个道,有不妥之处见谅,本人也是菜鸟。

一.算法设计基本知识

数字的表示 
知道数值的表示方式是最基本的要求。主要的数值表示方式有原码、反码、补码;定点数、浮点数(单精度和双精度)。注意这些表示方式需要的位数和不同位中的具体实际含义。

二.算法设计前进行浮点仿真

为啥要浮点仿真呢。因为浮点是表示精度很高。而且matlab中默认的运算是双精度浮点型(double),这样浮点仿真得到的结果是最精确的。在以后的定点仿真和Verilog代码设计中的每一步结果都是以浮点对应步骤结果为参照进行的。 
浮点仿真一般在MATLAB和C语言中进行。

##2.1浮点数表示方法 
【转载】FPGA算法设计随笔 
上面方框中表示的浮点数大小是:X=(-1)^sign * 1.fraction * 2^(exponent - bias)。 
初学者这样看其实比较蒙圈,其实就是算术式X中sign和fraction直接由上图的fraction填充,1是固定的。Exponent转换为10进制放到X式子中。Bias在单精度表示法中是127,双精度中是1023。 
对于32位单精度浮点数(float),sign是1位,exponent是8位(指数偏移量是127),fraction是23位。对于64位双精度浮点数(double),sign是1为,exponent是11位(指数偏移量是1023),fraction是52位。以32位单精度浮点数为例(float),其具体的转换规则是:首先把二进制小数(补码)用二进制科学计数法表示,比如上面给出的例子 1111101.001=1.111101001×26。符号位sign表示数的正负(0为正,1为负),故此处填0。exponent表示科学计数法的指数部分,请务必注意的是,这里所填的指数并不是前面算出来的实际指数,而是等于实际指数加上一个数(指数偏移),偏移量为2^(e-1)-1,其中e是exponent的宽度(位数)。对于32位单精度浮点数,exponent宽度为8,因此偏移量为127,所以exponent的值为133,即10000101。之后的fraction表示尾数,即科学计数法中的小数部分11110100100000000000000(共23位)。因此32位浮点数125.125D在计算机中就被表示为01000010111110100100000000000000。

2.2浮点仿真

最简便的浮点仿真是在MATLAB中进行,MATLAB默认数据是双精度,可以把需要计算的数据公式直接换成MATLAB程序,然后输入测试数据,观察输出的双精度结果用来指导下面的设计。

三.算法设计前进行定点仿真

在这一步骤需要将前面的MATLAB浮点仿真程序变换为MATLAB定点仿真程序。并逐步对照各个阶段的定点仿真结果,看偏差是多大。

3.1 定点表示

定点数:一种是规定小数点位置固定不变,称为定点数。 
定点数的表示有Q、S两种方法。

Q格式

小数点位置不同,同一个二进制数可以表示不同的值。为了编程方便,我们通常在同一算法中使用固定的小数点位置。Q格式和S格式是用来表达一个二进制数中整数、小数分别有多少bit的一种表示格式。例如,我们用3bit表述整数部分,4bit表示小数部分,则这个数的格式为S3.4/Q4。 
对于一个字长固定的处理器,另一种可行的表示格式是只表示小数部分。例如,当我们使用一个字长为16bit的处理器的时候,我们可以简单是说我们是使用Q15格式来表示小数。这里的Q15表示小数点右边有15bit,左边有1bit。同时Q15也等效于S1.15。

3.2定点数转换

假设存在浮点数x和定点数xq,则二者转化公式如下: 
x转换为xq:xq = (int)x*2^Q;<下取整> 
xq转换为x:x = (float)xq*2^(-Q) 
Q表示从Q0-Q15之间的定标 
举例: x = 0.5,Q = Q1,则xq = 0.5*2^1 = 1; 
x = 0.5,Q = Q15,则xq = 16384。 
假设xq = 100,Q=Q1,则x = 100*2^(-1) = 50.0; 
xq = 512,Q = Q15,则x = 0.015625

3.3定点数运算的对标概念

定标的大小,影响着整数部分和小数部分的位数,定标的过程其实是在操作数动态范围和精度之间做权衡的过程。 
设一个变量可能出现的最大绝对值为|max|,n为正整数,满足2^(n-1) < |max| < 2^n,则定标Q按如下规则选取最合适: 
Q = 有效数据位 – n 
对于32位的有符号数,数据有效位=31。如|max| = 2.75,选Q = 31 – 2 =29是最合适的。 
两个定点数进行运算,它们的定标可能相同也可能不同,定标就是需要确定定点数加减乘除之前和之后的小数点位置。 
我们知道,用十进制做两个数的加减和乘除过程如下: 
加减法:先对位,后加减; 
乘除法:先乘除,后取小数点。 
而定点数之间的加减乘除,撇开符号位不谈,其过程是一样一样的: 
加减法:先对标,后加减; 
乘除法:先乘除,后定标。

3.2 MATLAB定点仿真

在这里,博文主要介绍一下MATLAB定点仿真用到的知识。MATLAB中有fixed-point-designer工具箱为设计者带来很大方便。大家可以阅读对应知识点。 
https://ww2.mathworks.cn/products/fixed-point-designer.html

3.2.1 MATLAB浮点转定点函数—fi、quantizer函数

1、浮点数转换为定点数: 
有两种方法: 
(1)先量化再转化为二进制:a = 2.1345; b = quantizer([8 5]); c = num2bin(b, a); 
(2)先确定定点数的格式再转换:a = 2.1345; b = numerictype(1,8,5); c = fi(a,b);用c.bin就可以查看c的二进制形式了。 
2、 定点数(二进制)转化为浮点数(十进制): 
先确定定点数的表示方式在用bin2num转换为十进制:d = quantizer([8 5]); e = bin2num(d,c),其中c为浮点转定点输出的数据。

3.2.2 整个程序的定点转换

通过上面的形式,将整个浮点下的算法转换为定点数对应的算法程序。并进行仿真验证。

四.讲定点仿真代码转换为Verilog语言

用Verilog实现定点运算是,需要做到小数点为在程序员心中。用Verilog语言实现加减乘除、对数、指数、开方、三角函数、双曲线函数运算等。 
在这一节设计中,广大FPGA开发者可以参考下面网站很多很好的设计。 
https://opencores.org/projects?lang=2&stage=0&license=0&wishbone_version=0 
同时,MATLAB中有System Generator 2016.2工具和HLS(高层次综合可以直接将C语言转换为HDL语言),遗憾,这两个方法笔者也是初学。

五.对Verilog进行仿真

最后一步,就是对Verilog代码进行仿真。将前面定点MATLAB程序的定点数据输入到Verilog程序中,对应进行仿真,进行数据比对。