锁相环技术原理及FPGA实现(第二章2.2)

2.2 FPGA 中数的运算

2.2.1 加/减法运算

        如前节所述, FPGA 中的二进制数可以分为定点数和浮点数两种格式,虽然浮点数的加
减法运算相对于定点数而言在运算步聚和实现难度上都要复杂得多,但基本的运算仍然是
通过分解为定点数运算,以及移位等运算步骤来实现的,因此本节只针对定点数运算进行
分析讲解。
        进行 FPGA 实现的设计输入语言主要有 Verilog HDL 和 VHDL 两种。由于本书使用
Verilog HDL 语言讲解,这里只介绍 Verilog HDL 语言中对定点数的运算及处理方法。
Verilog HDL 设计文件中最常用的数据类型是单比特 wire 及 reg, 以及它们的向量形式。
当需要进行数据运算时, Verilog HDL 如何判断二进制数据的小数位、有符号数表示形式等
信息呢?在 Verilog HDL 程序中,所有二进制数均当作整数处理,也就是说小数点均在最低
位的右边。如果要在程序中表示带小数的二进制运算,该如何处理呢?其实,进行 Verilog
HDL 程序设计时,定点数据的小数点位可由程序设计者隐性标定。比如,对于两个二进制
数 00101 和 00110,当进行加法运算时, Verilog HDL 的编译器按二进制规则逐位相加,结
果为 01011。如果设计者将数据均看成无符号整数,则表示 5+6=11,将数据的小数点位均
看成在最高位与次高位之间, 即 0  0101、 0  0110、 0  1011, 则表示 0.3125+0.375=0.6875。
        需要注意的是,与十进制数运算规则相同,即做加减法运算时,参加运算的两个数的
小数点位置必须对齐,且结果的小数点位置相同。仍然是两个二进制数 00101 和 00110,进
行加法运算时,如果两个数的小数点位置不相同,比如分别为 0  0101、 00 110,代表的
十进制数分别为 0.3125 和 0.75。两个数不经过处理,仍然直接相加, Verilog HDL 的编译器
按二进制规则逐位相加,结果为 01011。小数点位置与第一个数相同,则表示 0.6875,小数
点位置与第二个数相同,则表示 1.375,显然结果不正确。为进行正确的运算,需要在第二
个数末位补 0,为 00 1100, 两个数再直接相加, 得到 011001, 转换成十进制数为 1.0625,
得到正确的结果。
         显然,如果设计者将数据均看成无符号整数,则不需要进行小数位扩展,因为 Verilog
HDL 编译器会自动将参加运算的数据以最低位对齐进行运算。

        Verilog HDL 如何表示负数呢?比如二进制数 1111,在程序中是表示 15 还是-1?方法
十分简单。声明端口或信号时,默认状态均表示无符号数;如需指定某个数为有符号数,则只需在声明时增加 signed 关键字即可。如“wire signed [7:0] number;”则表示将 number声明为 8 比特字长的有符数,在对其进行运算时自动采用有符号数运算。这里所说的无符号整数指所有二进制数均是正整数,对于 B 比特的二进制数:

例 2-1 Verilog HDL 实现符号数运算
        在 Quartus II 中编写一个 Verilog HDL 程序文件,在一个文件中同时使用有符号数及无
符号数运算,并进行仿真。由于该程序文件十分简单,这里直接给出文件源代码。

--这是 SymbExam.v 文件的程序清单
module SymbExam (
d1,d2,
signed_out,unsigned_out);
input [3:0] d1; //输入加数 1
input [3:0] d2; //输入加数 2
output [3:0] unsigned_out; //无符号加法输出
output signed [3:0] signed_out; //有符号加法输出
//无符号加法运算
assign unsigned_out = d1 + d2;
//有符号加法运算
wire signed [3:0] s_d1;
wire signed [3:0] s_d2;
assign s_d1 = d1;
assign s_d2 = d2;
assign signed_out = s_d1 + s_d2;
endmodule

图 2-4 为该程序的 RTL 原理图,从图中可以看出, signed_out、 unsigned_ou 均为 d1、d2 以进行相加后的输出,且加法器并没有标明是否为有符号运算。

图 2-5 为程序的仿真波形图。从图中可以看出, signed_out 及 unsigned_out 的输出结果完全相同,这是什么原因呢?相同的输入数据,进行无符号数运算和有符号数运算的结果竟然没有任何区别!

既然如此,何必在程序中区分有符号数及无符号数呢?原因其实十分简单,对于加法、减法,无论是否为符号数运算,其结果均完全相同,因为二进制的运算规则完全相同。如果将二进制数据转换成十进制数据,我们就以看出两者的差别了。下面以列表的形式来分析具体的运算结果,如表 2-3 所示。

        分析表 2-3 中的数据,结合二进制数据的运算规则可以得出以下几点结论。
         B 比特的二进制数,如当作无符号整数,表示的范围为 0~2B-1;如当作有符号整数,表示的范围为-2B-1~2B-1-1;
         如果二进制数的表示范围没有溢出,将运算数据均当作无符号数或有符号数,则运算结果正确;
         两个 B 比特的二进制数做加/减法运算,如要确保运算结果不溢出,需要 B+1 位数据
存放运算结果;
         两个二进制数据进行加/减法运算,只要输入数据相同,则不论是当作有符号数还是无符号数,其运算结果的二进制数完全相同。
        虽然在二进制的加/减法运算中,两个二进制数据运算结果的二进制形式完全相同,在实际 Verilog HDL 程序设计时,仍然十分有必要根据设计需要,采用 signed 关键字对信号进行有符号声明。比如做比较运算时,对于无符号数据, 1000 大于 0100,对于有符号数据,1000 小于 0100。

2.2.2 乘法运算

        加法及减法运算在数字电路中实现相对较为简单,在用综合工具综合设计时, RTL 电路图中加、减操作会被直接综合成加法器或减法器组件。乘法运算在其他软件编程语言中实现也十分简单,但用门电路、加法器、触发器等基本数字电路元件实现乘法功能却不是一件容易的事。用 Altera 公司器件做 FPGA/CPLD 设计时,如果选用的目标器件内部集成了专用的硬件乘法器核, 则 Verilog HDL 语言的乘法运算符在综合成电路时将直接综合成硬件乘法器,否则综合成由 LUT 等基本元件组成的乘法电路。乘法器运算与加减法运算相比,需要占用成倍的硬件逻辑资源。当然,实际 FPGA 工程设计中,在需要用到乘法运算的情况下,可以尽量使用目标器件提供的硬件乘法器 IP 核,这种方法不仅不需占用普通逻辑资源,并且往往可以达到很高的运算速度。
        FPGA 器件中的硬件乘法器核资源是十分有限的,而乘法运算本身比较复杂,用基本逻辑单元按照乘法运算规则实现乘法运算的资源占用比较高。设计中遇到的乘法运算可分为信号与信号之间的运算,以及常数与信号之间的运算。对于信号与信号之间的运算通常只能使用乘法器核实现,而对于常数与信号之间的运算则可以通过移位及加减法实现。信号 A与常数相乘运算操作的分解例子如下。
                                                        A×16=A 左移 4 位

        需要注意的是,由于乘法运算结果的数据位数比乘数的数据位数多,因此在用移位及加法操作实现乘法运算前,需要将数据位数进行扩展,以免出现数据溢出现象。

2.2.3 除法运算

        在 Quartus II 集成开发环境下的 Verilog HDL 语言编译环境中,除法、指数、求模、求余等操作均无法在 Verilog HDL 程序中直接进行相关运算。实际上,用基本逻辑元件构建这4 种运算本身是十分复杂的工作,如果要用 Verilog HDL 实现这些运算,一种方法是使用开发环境提供的 IP 核或使用商业 IP 核,另一种方法只能是将算法分解成加、减、移位等操作步骤来逐步实现。Altera 的 FPGA 器件一般都提供除法器 IP 核。对于信号与信号之间的除法运算,最好的方法是采用 Quartus II 提供的现成 IP 核,而对于除数是常量的除法运算,则可以采取加、减、移位运算来完成除法功能。下面是一些信号 A 与常数相除运算操作的分解例子。

        需要说明的是,与乘法运算不同,常数乘法通过左移运算可以得到完全准确的结果,而常数除法运算却不可避免地存在运算误差。显然,采用分解方法的除法运算只能得到近似正确的结果,且分解运算的项数越多,精度越高。这正是由 FPGA 等数字信号处理硬件平台不可避免的有限字长效应引起的。

2.2.4 有效数据位的计算

        1.有效数据位的概念
        众所周知,在 FPGA 数字运算中,每个数据位需要相应的寄存器来存储,参与运算处理的数据位越多,所占用的硬件资源也越多。为确保运算结果的正确性,或者为尽量获取较高的运算精度,通常又不得不增加相应的运算字长。因此,为确保硬件资源的有效利用,需要在工程设计时,准确掌握运算中的有效数据位长度,尽量减少无效数据位参与运算,从而避免浪费宝贵的硬件资源。所谓有效数据位,即指表示有用信息的数据位。 例如, 整数型的有符号二进制数据 001,显然只需要用二比特数据即可正确表示 01,因此最高位的符号位其实没有代表任何信息。

2.加法运算中的有效数据位
        先考虑两个二进制数之间的加法(对于补码数据来说,加减法运算规则相同,因此只讨论加法运算情况)运算。假设数据位较大的位数为 N,则加法运算结果需要用 N+1 位才能保证运算结果不溢出,也就是说两个长度为 N(另一个数据位长度也可以小于 N)的二进制数进行加法运算,运算结果的有效数据位长度为 N+1。如果运算结果只能采用 N 位数据表示时,该如何对结果进行截取呢?截取后的结果如何能保证运算的正确性呢?下面我们还是以具体的例子来进行分析。比如两个长度为 4 的二进制数据 d1、 d2 进行相加运算。我们来考查 d1、 d2 取不同值时的运算结果及截位后的结果。为便于分析比较,见表 2-4。

        分析表 2-4 的运算结果可知,对于两个长度为 N 的二进制数据进行加法运算,需要采用 N+1 位数据才能获得完全准确的结果。如果需要采用 N 位数据存放结果,则取低 N 位会产生溢出,得出错误结果,取高 N 位不会出现溢出,但运算结果相当于降低了 1/2。
        前面的分析实际上是将数据均当作整数,也就是说小数点位置均位于最低位的右边。在数字信号处理中,定点数通常把数限制在-1~1 之间,即把小数点规定在最高位和次高位之间。同样是表 2-4 的例子,考虑小数运算时,运算结果的小数点位置又该如何确定呢?对比表 2-4 中的数据,可以很容易地看出,如果采用 N+1 位数据表示运算结果,则小数点位置位于次高位的右边,而不再是最高位的右边;如果有用 N 位数据表示运算结果,则小数点位置位于最高位的右边。也就是说,运算前后小数点右边的数据位数(也是小数位数)是恒定不变的。实际上,在 Verilog HDL 语言环境中,如果对两个长度为 N 的数据进行加法运算,为了得到 N+1 位的准确结果,必须先对参加运算的数进行一位符号位扩展。
3.乘法运算中的有效数据位
        与加法运算一样,我们同样考查乘数均是补码表示形式(有符号数)的情况,这也是FPGA 进行数字信号处理最常用的数据表示方式,在讨论清楚补码的相关情况后,读者很容易得出无符号数的运算规律。从表 2-5 可以得出以下几条运算规律。
         对于字长分别为 M、 N 的数据进行乘法运算,需要采用 M+N 位字长的数据才能得到
准确的结果;
         对于乘法运算,不需要通过扩展位数来对齐乘数的小数点位置;
         当乘数为小数时,乘法结果的小数位位数等于两个乘数的小数位位数之和;
         当需要对乘法运算结果截取时,为保证得到正确的结果,只能取高位,而舍去低位
数据,这样相当于降低了运算结果的精度;
         只有当两个乘数均为所能表示的最小负数(最高位为 1,其余位均为 0)时,才有可
能出现最高位与次高位不同的情况,也就是说,只有在这种情况下,才需要 M+N 位
字长的数据来存放准确的最终结果,其他情况下,实际上均有两位相同的符号位,
只需要 M+N-1 位字长即可存放准确的运算结果。

        在 Quartus 开发环境中,提供的乘法器 IP 核在选择输出数据位数时,如果选择全精度运算,则会自动生成 M+N 位字长的运算结果。在实际工程设计中,如果预先知道某位乘数不可能出现最小负值的情况,或者通过一些控制手段去除出现最小负值的情况,则完全可以只用 M+N-1 位字长存放运算结果,从而节约一位寄存器资源。如果乘法运算只是系统的中间环节,则后续的每个运算步骤均可节约一位寄存器资源。

4.乘加运算中的有效数据位
        前面讨论运算结果的有效数据位时,都是指参加运算的信号均是变量的情况。在数字信号处理中,通常会遇到乘加运算的情况,一个典型的例子是有限脉冲响应(Finite Impulse
Response, FIR)滤波器的设计。当乘法系数是常量时,最终运算结果的有效数据位需要根据常量的大小来重新计算。
        比如需要设计一个 FIR 滤波器:

        假设滤波器系数为[13,-38, 74, 99, 99, 74,-38, 13],如果输入数据为 N 比特的二
进制数,则滤波器输出最少需要采用多少位来准确表示呢?显然,要保证运算结果不溢出,我们需要计算滤波器输出的最大值,并以此推算输出有效数据位数。方法其实很简单,只需要计算所有滤波器系数绝对值之和,再计算表示该绝对值之和所需的最小无符号二进制数据位 n,则滤波器输出的有效数据位数为 N+n。对于这个实例,可知滤波器绝对值之和为448,至少需要 9 比特二进制数表示,因此 n=9。

猜你喜欢

转载自blog.csdn.net/qq_43416206/article/details/135316102