Math 用VHDL在FPGA上实现不动点的平方根播种

Math 用VHDL在FPGA上实现不动点的平方根播种,math,vhdl,fpga,square-root,newtons-method,Math,Vhdl,Fpga,Square Root,Newtons Method,我正在尝试为Xilinx FPGA创建一个定点平方根函数(因此,real类型已过时,David Bishopsieee_提出的也不支持XST合成) 我已经决定使用牛顿-拉斐逊法来计算平方根的倒数(因为它涉及的除法更少) 剩下的难题之一是如何生成初始种子。我查看了,但它似乎只适用于浮点运算 目前我最好的想法是,计算输入值的长度(即找到最重要的非零位的索引),粗略地将其减半,并将其用作种子的幂 我写了一个简短的测试脚本来快速检查准确性(它在Matlab中,但这只是为了我可以绘制一个图表…) 不出所料

我正在尝试为Xilinx FPGA创建一个定点平方根函数(因此,
real
类型已过时,David Bishops
ieee_提出的
也不支持XST合成)

我已经决定使用牛顿-拉斐逊法来计算平方根的倒数(因为它涉及的除法更少)

剩下的难题之一是如何生成初始种子。我查看了,但它似乎只适用于浮点运算

目前我最好的想法是,计算输入值的长度(即找到最重要的非零位的索引),粗略地将其减半,并将其用作种子的幂

我写了一个简短的测试脚本来快速检查准确性(它在Matlab中,但这只是为了我可以绘制一个图表…)

不出所料,每当一个数字的大小增加时,种子就会变得非常不准确,并且随着输入量的增加而增加。从图表上可以看出:

红线是种子的值,如图所示,以2的幂递增

我的问题很简单:有没有其他简单的方法可以用来为VHDL中的定点平方根值生成种子值,理想情况下,这些方法不会导致越来越多的不精确性(因此每次输入的大小增加时都需要更多的迭代)


对于如何在VHDL中找到固定点平方根的任何其他附带建议,我们将不胜感激

我意识到这是一个老问题,但我确实在这里结束了,这很有用,所以我想补充一下

假设你的Xilinx芯片有一个嵌入的乘法器,你可以考虑这种方法来帮助获得一个更好的启动种子。基本前提是将输入整数转换为所有分数位的定点,然后使用嵌入的乘法器将初始种子值的一半缩放0.X(事后看来,这可能就是人们说的“规格化为区域[0.5..1]”的意思),现在我想起来了)。它基本上是现有seed方法的分段线性插值。下面的步骤应该相对容易地转换为RTL,因为它们只是位移位、加法和一次无符号乘法

1) 从您现有的种子值开始(例如,对于x=9e6,您将使用“粗略减半”方法生成s=4096作为第一次猜测的种子)

2) 将现有种子值右移1以获得上一个种子值(s_half=s>>1=2048)

3) 左移输入,直到最高有效位为1。如果您正在sqrting 32位整数,则x_刻度将为2304000000=0x89544000

4) 从x_刻度上切下18位,然后乘以18位版本的s_半(我建议18位,因为我碰巧知道一些Xilinx芯片嵌入了18x18乘法器)。对于这种情况,结果是x_刻度(31到14)=140625=0x22551。 至少,乘数是这么想的——我们将使用定点,所以它实际上是0b0.100010010101010001=0.53644,而不是140625

此乘法的结果将是s_scale=s_half*x_scale(31向下至14)=2048*140625=2880000,但此输出为18.18格式(18个整数位,18个分数位)。取上18位,得到s_scale(35向下至18)=1098

5) 将s_标尺的上18位添加到s_一半以获得改进种子,在本例中,s_改进=1098+2048=3146


现在你可以用这个种子进行牛顿-拉斐逊的几次迭代。对于x=9e6,你粗略的减半方法得到的初始种子数为4096,上面列出的定点比例为3146,实际的sqrt(9e6)是3000。该值介于种子步骤之间,我的Nappin数学表明它节省了大约3次Newton Raphson迭代

您可能需要添加一些约束,例如您打算使用的定点格式、初始猜测的准确度以及是否需要查找表(例如8位)适合。您首先规范化输入(通过优先级编码器)的基本方法很好,但是您希望查看两个连续的输入二进制码,例如[1,4],并确定其平方根的倒数。然后输出将需要一个二进制码,您可以缩放(通过简单的移位,基于优先级编码器值)获得最终结果所需的中间结果。有两种方法:1)存储以高阶位为索引的查找表,2)使用多项式近似。例如,请参阅,但我认为范围[0..1]的最佳近似值已经计算出来。另请参阅提倡规范化为范围[5..1]的方法并使用线性近似进行初始化。如果您能阅读带注释的x86汇编语言,关于倒数平方根的定点实现可能会有所帮助。下面是一个,使用C代码。看看它可能会让您感兴趣。如果您认为快速逆平方根有任何用处,请再次查看它。有很多其中包含浮点数据类型,但其中没有大量实际的浮点数学。将其转换为纯整数数学应该是相当简单的。您需要实现的最复杂的事情是intfloat转换,这并不十分困难。
x = 1:2^24;
gen_result = zeros(1,length(x));
seed_vals = zeros(1,length(x));
for i = 1:length(x)
   result = 2^-ceil(log2(x(i))/2); %effectively creates seed value from top bit index
   seed_vals(i) = 1/result; %Store seed value
   for j = 1:6
       result = result*(1.5-0.5*x(i)*result^2); %reciprocal root
   end
   gen_result(i) = 1/result; %single division at the end
end