如何在一个时钟周期内获得32位input的平方根?

我想在Verilog中devise一个可综合的模块,在计算32位给定input的平方根时只需要一个周期。

[编辑1]修复的代码

最近发现的结果,即使testing确定一切都OK,所以我深入挖掘,发现我有一个愚蠢的错误,在我的方程中,由于名称与我的PGM环境冲突testing得到误报,所以我忽略了之前。 现在它在所有情况下都能正常工作。

我能想到的最好的东西(除了近似或大LUT )是无乘法的二进制search ,这里是C ++代码:

 //--------------------------------------------------------------------------- WORD u32_sqrt(DWORD xx) // 16 T { DWORD x,m,a0,a1,i; const DWORD lut[16]= { // m*m 0x40000000, 0x10000000, 0x04000000, 0x01000000, 0x00400000, 0x00100000, 0x00040000, 0x00010000, 0x00004000, 0x00001000, 0x00000400, 0x00000100, 0x00000040, 0x00000010, 0x00000004, 0x00000001, }; for (x=0,a0=0,m=0x8000,i=0;m;m>>=1,i++) { a1=a0+lut[i]+(x<<(16-i)); if (a1<=xx) { a0=a1; x|=m; } } return x; } //--------------------------------------------------------------------------- 

标准二进制searchsqrt(xx)x位从MSB设置为LSB ,从而得到x*x <= xx 。 幸运的是,我们可以通过简单地将事物重写为增量乘数来避免乘法…在每次迭代中,可以像这样使用较旧的x*x结果:

 x1 = x0+m x1*x1 = (x0+m)*(x0+m) = (x0*x0) + (2*m*x0) + (m*m) 

其中x0是上一次迭代的x值, x1是实际值。 m是实际加工的钻头的重量。 (2*m)(m*m)是恒定的,可以用作LUT和位移,所以不需要相乘。 只需要添加。 令人遗憾的是,迭代必然会受到顺序计算的限制,所以结果最好是16T

在代码中, a0代表最后一个x*xa1代表实际迭代的x*x

正如你所看到的, sqrt是在16 x (BitShiftLeft,BitShiftRight,OR,Plus,Compare)中完成的,位移和LUT可以被硬连线。

如果你有超快的门,那么你可以把input时钟乘以16并用它作为SQRT模块的内部时钟。 类似于以前的时代,在旧的Intel CPU / MCU中MC时钟作为源CPU时钟的划分。这种方式可以得到1T时序(或倍数取决于乘法器的比例)。

我在这里得到了代码

  module sqrt( input[31:0]a, output[15:0]out ); reg [31:0]temp; reg[14:0]x; always@(a) begin if(a<257)x=4; if(a>256 && a<65537)x=80; if(a>65536 && a<16777217)x=1000; if(a>16777216 && a<=4294967295)x=20000; temp=(x+(a/x))/2; temp=(temp+(a/temp))/2; temp=(temp+(a/temp))/2; temp=(temp+(a/temp))/2; temp=(temp+(a/temp))/2; temp=(temp+(a/temp))/2; temp=(temp+(a/temp))/2; end assign out=temp; endmodule