FPGA计算中定标与位扩展的实现
我不知道名字取对没有,在FPGA计算中有时往往需要在不溢出的情况下将数扩大,从而获得更好的计算精度。
比如。在一个8位宽的系统中,将x=0000_0010,算术左移m=5位之后得到xt=0100_0000,此时的xt参与运算之后能得到更好计算精度,并且通过m我们可以把相应的结果移位回来。
典型的应用例子就是,使用cordic计算复数x+jy的相角与模值,那么此时我们可以在保证不溢出的情况下按比例的扩大(x,y),再进行cordic计算,此时我们就可以得到,将计算结果的模值右移相应的m位即可,那么我们就可以计算得到精度较高的模值与相角值。
下面就是移位的过程。以一个8位的数据为例 x=0000_0010为例
1.高四位全为符号位,所以,x<<<3=0_0010_000 m=3.
2.高三位全为符号位,所以,x<<<2=0_10_00000 m=m+2=5.
3.高两位不全为符号位,所以 x<<<0=0_10_00000 m=m+0=5.
对应到每一次的硬件结构为

代码为:
module data_expand #( parameter DSIZE = 8, parameter MSIZE = 3 ) ( input clk, input nd, output rdy, input signed [DSIZE-1:0] din, output signed [DSIZE-1:0] dout, output [MSIZE-1:0] mout ); wire [DSIZE-1:0] dtemp [1:0]; wire [MSIZE-1:0] mtemp [1:0]; wire rtemp [1:0]; data_expand_unit #(.DSIZE(DSIZE),.MSIZE(MSIZE),.K(3)) i0 (.clk(clk), .nd(nd), .rdy(rtemp[0]), .din(din), .dout(dtemp[0]), .min('d0), .mout(mtemp[0])); data_expand_unit #(.DSIZE(DSIZE),.MSIZE(MSIZE),.K(2)) i1 (.clk(clk), .nd(rtemp[0]), .rdy(rtemp[1]), .din(dtemp[0]), .dout(dtemp[1]), .min(mtemp[0]), .mout(mtemp[1])); data_expand_unit #(.DSIZE(DSIZE),.MSIZE(MSIZE),.K(1)) i2 (.clk(clk), .nd(rtemp[1]), .rdy(rdy), .din(dtemp[1]), .dout(dout), .min(mtemp[1]), .mout(mout)); endmodule module data_expand_unit #( parameter DSIZE = 8, parameter MSIZE = 3, parameter [MSIZE-1:0] K = 3 ) ( input clk, input nd, output reg rdy, input signed [DSIZE-1:0] din, output reg signed [DSIZE-1:0] dout, input [MSIZE-1:0] min, output reg [MSIZE-1:0] mout ); always@( posedge clk )begin if( din[(DSIZE-1)-:(K+1)] == {(K+1){1'b0}} || din[(DSIZE-1)-:(K+1)] == {(K+1){1'b1}})begin dout <= din <<< K; mout <= min + K; end else begin dout <= din; mout <= min; end rdy <= nd; end endmodule
仿真结果如下:

浙公网安备 33010602011771号