FPGA中的小数计算(定点小数) 与 verilog/VHDL有符号数计算

本文深入解析FPGA中定点小数运算原理,包括二进制小数表示、四则运算规则,以及Verilog与VHDL处理有符号数的技巧。通过实例演示如何将浮点数转换为定点数,以及不同情况下乘法和除法的具体实现。

这篇blog有两个关键点,如题,一是关于FPGA或者说HDL是如何执行定点小数运算的;二是verilog和VHDL有符号数运算的解释和对比。

1. 小数计算(定点小数)
1.1 用二进制表示小数

由于FPGA中存在的都是二进制数,所以首先明确一个知识点:如何用二进制表示小数?
这里写图片描述
如上图,一个带小数点的8位二进制所表示的数的大小就是:1*4+1*2+1*1+1*0.5+1*0.25+1*0.125+1*0.0625+1*0.03125 = 7.96875.实际上还有另外一种表示方式:0xff/2^5 = 7.96875.
由于我上面的8位数用5位表示小数,所以能表示的最小粒度即LSB就是0.03125,就是说只能表示0.03125的整数倍;从这里我们也可以看出,用来表示小数的位数越多,可以表示的小数范围越大,表示的越精准。
x表示实际的数(浮点数,如2.2), q表示它的n位定点小数。

q = (int) (x * 2^n)

x = (float)q/2^n

比如我想把2.2转换为有5为小数的8位二进制。则2.2*2^5 = 70.4,取整数即70=b’1000110. 那么整数70表示的实际小数是多少呢,70/2^5 = 2.1875,所以我其实是用2.1875来近似表示了2.2.

1.2 小数的加减乘除

执行运算的基本原则如下所示,其中x1, x2, x3代表三个浮点数,q1, q2, q3代表其二进制表示。

q3 = q1 + q2   若 x3 = x1 + x2

q3 = q1 - q2   若 x3 = x1 - x2

q3 = q1 * q2 / 2^n 若 x3 = x1 * x2

q3 = q1 * 2^n / q2 若 x3 = x1 / x2

加法和减法运算不做解释,对于乘法运算:
这里写图片描述
如上所示,两个16位数相乘,将得到一个32位数。可以看作是整数部分两个8位相乘得到一个16位整数;小数部分两个16位相乘得到一个16位小数。如果最后我们想要一个16位的结果,就只能选择中间的16位,将得到的32位数右移8位之后,高位截断8位,就可以得到我们要的16位结果。这就是上面 “/2^n”的来源。
除法比较复杂,不在此解释。

2. FPGA有符号数运算

在FPGA中,有符号数的运算规则是不需要自己来写的,比如对于负数还要考虑反码啊啥的,这些都是不用考虑的,无论是Verilog还是VHDL都给我们提供了相应的解决方案。

2.1 Verilog有符号数运算

对于Verilog,这里我直接翻译一位大神的博客。原网址见:http://billauer.co.il/blog/2012/10/signed-arithmetics-verilog/

黄金法则:两个操作数必须都是有符号数,结果才是有符号数!

Verilog倾向于使用无符号数,比如以下几种计算的结果都会是无符号数:

  • 任何有两个操作数的计算。除非这两个都是有符号数
  • 基本的数字的运算(如12’d10),除非显示指定了“s”
  • 位选操作
  • Part-select results
  • 级联操作 Concatenations

所以,要进行有符号数运算,要么使用$signed系统函数,要么在定义wire或者reg类型变量时加上signed
例如要把一个有符号数和一个无符号数相乘,得到一个有符号数,要这样做:

reg         [15:0] a; // Unsigned
reg signed  [15:0] b;
wire signed [16:0] signed_a;
wire signed [31:0] a_mult_b;

assign signed_a = a; // Convert to signed
assign a_mult_b = signed_a * b

注意,signed_a要比a位宽多一位,这一位用来放置符号位0. 也许你会觉得需要显式指定signed_a的最高位,比如{1’b0, a}而不仅仅是直接赋值为a,但其实是不用的。

关于更多更详细的verilog有符号数计算,我上传一份名为“Signed Arithmetic in Verilog 2001 – Opportunities and Hazards” 的文档,请在我的资源中下载。

2.2 VHDL有符号数运算

关于VHDL有符号数的计算,跟VHDL的signed和unsigned两种数据类型息息相关,请移步我的另一篇blogVHDL中数据类型转换与移位(STD_LOGIC_ARITH与NUMERIC_STD) 中查看详解。

参考链接
  1. verilog数值计算-有符号数和无符号数 https://blog.youkuaiyun.com/mdpsdhr/article/details/61922126
  2. FPGA内部计算小数 http://www.cnblogs.com/woshitianma/archive/2013/05/19/3087258.html
  3. FPGA浮点小数与定点小数的换算及应用 https://blog.youkuaiyun.com/github_33678609/article/details/53465626
### 有符号数乘法的概念实现 #### 定义背景 在计算机体系结构中,处理带有正负号的数据是非常重要的。对于有符号数而言,最高位通常用来表示符号:0代表正值,1代表负值[^3]。 #### Booth乘法器的应用 为了高效地执行有符号数之间的乘法运算,Booth乘法器被广泛应用于硬件设计之中。这种特殊的二进制乘法算法不仅能够有效地减少所需的加法次数,还能通过引入减法规则来简化操作流程[^1]。 具体来说,在Booth编码过程中会检查相邻两位(当前位及其右边一位),并依据不同的组合情况决定下一步的操作: - 如果检测到`01`模式,则加上被乘数; - 若遇到`10`模式,则从累加寄存器中减去被乘数; - 对于其他任何情形(`00`, `11`)保持不变; 每次迭代之后都需要右移部分积以及乘数直到完成全部n次循环为止。 ```c++ // C++ implementation of booth's algorithm for signed multiplication #include <iostream> using namespace std; void addBinary(char *a, char *b, int n){ // Function to perform binary addition between two strings a and b. } void subtractBinary(char *a, char *b, int n){ // Function to perform binary subtraction where result = a - b. } int main(){ string multiplicand="0110"; // Example positive number (6 in decimal) string multiplier="-0011"; // Example negative number (-3 in decimal) int length=max(multiplicand.length(), abs((int)multiplier.length())); char A[length+1], S[length+1]; fill(A,A+length,'0'); A[length]='\0'; strcpy(S,""); if(multiplier[0]=='-' || multiplicand[0]=='-'){ cout << "One or both numbers are negative.\n"; // Convert the absolute value into its complement form when necessary... } // Initialize Q[-1]=0 as per Booth’s rule char q_minus_1='0'; while(length--){ switch(q_minus_1*2+(multiplier.back()-'0')){ case 0:// '00' break; case 1:// '01' addBinary(A,multiplicand.c_str(),multiplicand.size()); break; case 2:// '10' subtractBinary(A,S,strlen(S)); break; default:// '11' break; } // Arithmetic shift right on concatenated AQ register pair here... q_minus_1=multiplier.back(); rotate(multiplier.rbegin(),multiplier.rbegin()+1,multiplier.rend()); } printf("Product=%s\n",A); } ``` 此代码片段展示了如何利用C++编程语言模拟Booth乘法过程中的基本逻辑判断和相应的算术运算。需要注意的是实际应用时还需要考虑更多细节如溢出处理等问题。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值