3721研发网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > 对FPGA实现除法问题的疑问

对FPGA实现除法问题的疑问

时间:12-26 整理:3721RD 点击:
最近在做ADC的校准模块,涉及到除法。但是本人之前没接触过除法,所以先找了一些资料来看。看了一些资料后,发现实现除法的方式有几种,基于乘法的除法、基于减法的除法、基于cordic算法的除法,等等……
由于本人底子较薄,所以我就着重看了基于减法的除法运算,也就时循环移位除法,例子前不久Xilinx社区正好有一篇这样的文章发表(文章链接:http://xilinx.eetop.cn/viewnews-2659#sign_msg)。但是看了这篇文章和其他一些类似的文章后,我发现了如下问题:
1)大家讲的一般都是被除数和除数位宽相同的情况,若被除数和除数位宽不同呢,该如何考虑,也就是商和余数的位宽是多少的问题?(假设被除数为48位,除数为24位,商和余数是多少位呢?)
2)大家讲的一般都是无符号数的除法,那么对于有符号数呢?此时的除法该如何实现?
PS:这个问题我自己在下面也探讨过,我将链接文章中的被除数改为-78(1100_1110),除数为34(0010_0010)保持不变,然后求商和余数。我试过两种办法,一是不考虑是否为有符号数,全部当无符号书处理,求得的结果显然是错误的;二是我将-78求补码(=0011_0010),然后再找文章中讲的那样进行运算发现结果仍然错误。
3)如果一个被除数为1024,除数为1023,十进制数表示结果约为1.000977517106549364613880742913。在FPGA中,这个1024除以1023只能用商和余数的形式表示,如果我想将这个结果值再乘以一个数x,那么FPGA中该如何实现?
help:请论坛中的大神看到此贴后帮帮忙,给小弟我解释或者答惑一些,谢谢啦!

别沉了,顶一下,求助大神们

1.如果是整数除法,48位/24位==(48-24)位。浮点的,根据需要的精度任意定。
2.一般都是无符号数运算。有些算法,除数例外。
3.只要记住小数点在哪就行,把它们作整数运算。
--以上如有错,请网友纠正。
链接中的除法,我粗略看了看,不是实用的算法,实验室练手用的。因为每步先要判断大小,这就相当于做了一次加减法了,然后可能还有一次减法。cordic除法也如此。
除法算法通常有:
恢复余数(Restoring)法、不恢复余数(Non-Restoring)法、SRT算法、预缩放(prescaling)算法。
前2种相对简单,易懂。弄清楚了,你那1,2,3就基本清楚了。
SRT算法较复杂。特别是高基的(High-radix)有点难。
预缩放算法是SRT的变种。
除法器有IP。不必自己设计。

以上算法通常称为数字循环类算法。另外还有收敛类算法,包括Newton-Raphson算法,Goldschmidt算法。

1、位宽不同可以把低位宽的高位补0,做成相同位宽,思路之一吧
2、有符号的,可以符号位单独处理,把数都转成正数,剩下就是无符号除法了
3、乘以一个固定的数?
固定的数视情况可以选择:
a做个表,查找表
b把这个数分解,做成移位和加法的运算

xilinx 和altera 都是有做好的ip可以用的

我现在需要将RTL代码拿到DC上进行综合,如果是生成的除法器IP核,那也可以拿到DC上进行综合吗?

思路1我试过啦,还是可以的;
思路2倒是一个我没想到的做法;
至于乘以一个固定的数,a方案在我这里不可行,因为这个乘数过大,做成查找表就太浪费精力和资源了;b方案说的是移位,移位只适用于2的幂的乘数吧,对于非2的幂的乘数,分解有可能还是分解不完全吧,导致不能移位。

做过除法 直接用的“/”,我是菜鸟 没想到其他办法

学习学习

举个例子,乘以固定的数37:
x*37 = x*32 + x*4 + x
= (x<<5) + (x<<2) + x
假如: reg [31:0]data_in;
那么: data_out[36:0] = {data_in, 5'b00000} +{3'b000, data_in, 2'b00} + {5'b00000, data_in};

方法好多种:
1. 移位减,又可以分为每次移动1bit或者多bit,一般我也就做到一次算3个bit. 1bit的,把除数被除数补到相同位宽。优点面积小,但计算cycle长。 一次算两个bit或者3个bit,面积大些但速度快。
2.查表,考虑牛顿迭代法。 表也不是很大。
求 f(x) = 1/x,计算 f'(x) = -1/x2.
y = f(x0) + f'(x0)(x-x0) = LUT(i) - (LUT(i)- LUT(i+1) ) *R
y(x) = 2f(x0) - f(x0)/f'(x0) = 2f(x0) -y2*x
3. 针对特殊除数,可以考虑泰勒展开。用2的幂次和来近似。
如下 用最近的2的幂去近似的除,将余数和商迭代知道其和小于除数。 Div/(2^X - K)
step 1Div/2^X = M0 ... R0 if K*M0 + R0 >=2^X - K, to step 2, else M= M0, R=R0+K*M0
step 2(K*M0+R0)/2
100/7 = 14 ...2step 1100/8 = 12 .. 4if (12+4) >= 7, to step 2
step 2(12+4)/8 = 2 ...0if (2 +0 )<7.result = 12 +2 ...2.
4. 如果有design ware, 也可以直接调用,一般面积和速度都还不错。

"/"只适用于除数为2的幂次方(2^n,其中n为整数)这样的情况,对于除数未知或者一般的实数类型,"/"就不适用了。而且,在某些综合工具中,并不支持"/"的综合……

恩恩,懂了,非常感谢,那么在Verilog中,对于:reg signed [31:0] data_in;
data_out <= {data_in,5'b00000}+{3'b000, data_in, 2'b00} + {5'b00000, data_in};

data_out <= (data_in <<5) + (data_in<<2) + data_in;
两种写法,功能是一样的我知道,但是其消耗的硬件资源有木有区别呢?

那么: data_out[36:0] = {data_in, 5'b00000} +{3'b000, data_in, 2'b00} + {5'b00000, data_in};
没有区别,但建议你先算好结果的位宽,把其中一个数补到最大位宽,防止系统来帮你截位,
如此处,{1'b0,data_in, 5'b00000} + {data_in, 2'b00} + data_in

如果自己设计的话,就随便做了,只要定义好规则,大家都照着做就行了,非常简单。比如,被除数位数宽,除数位数窄,永远循环除下去,除不尽就补零。

data_out <={1'b0,data_in, 5'b00000}+……,data_out的位宽已经定义为37位,为啥前面还要拓宽一位?是为了防止求和溢出吗?


想得太简单了,你要考虑硬件资源消耗和有效数据输出所耗费的时间问题吧……

求和一般都要补一位防溢出,另外左值的大小和右边应该一致,代码最好用lint工具检查下,可以避免很多低级的错误。

恩恩,了解,了解,非常感谢

你说的对,是要考虑这些。如果不要求处理速度的话,无论是除法还是cordic,还是非常简单的,只要利用paper and pencil算法,没什么搞不定的。

恩恩,

Copyright © 2017-2020 3721研发网 版权所有

网站地图 鄂ICP备17025094号

Top