FPGA学习记录(11)<CORDIC算法的FPGA实现>

Written by @hzj
//JinXing Project
#2021.11.26 V1.0
#2021.11.27 V1.1
#2021.11.27 V1.2

CORDIC算法详解

cordic算法的FPGA实现中,对于cordic算法的理解非常重要,下面对整个算法的流程进行详解:

1、cordic的算法表示式

在这里插入图片描述
也有上述的表示式:
x 2 = x 1 c o s θ − y 1 s i n θ x_2 = x_1cos\theta - y_1sin\theta x2=x1cosθy1sinθ
y 2 = y 1 c o s θ + x 1 s i n θ y_2 = y_1cos\theta + x_1sin\theta y2=y1cosθ+x1sinθ

2、提取cordic的算法表示式中的cos分量

将式子右边提出一个cos分量之后,可以得到如下的变换过程:
x 2 = x 1 c o s θ − y 1 s i n θ = c o s θ ( x 1 − y 1 t a n θ ) x_2 = x_1cos\theta - y_1sin\theta =cos\theta (x_1- y_1tan\theta) x2=x1cosθy1sinθ=cosθ(x1y1tanθ)
y 2 = y 1 c o s θ + x 1 s i n θ = c o s θ ( y 1 + x 1 t a n θ ) y_2 = y_1cos\theta + x_1sin\theta = cos\theta(y_1 + x_1tan\theta) y2=y1cosθ+x1sinθ=cosθ(y1+x1tanθ)
以上为旋转分量。

3、去掉cordic的算法表示式中的cos分量

由于被一次的变换都需要乘以一个cos分量,因此,可以利用这个规律进行简化。
由此我们有:
X 2 = x 1 − y 1 t a n θ = x 2 / c o s θ X_2 = x_1 - y_1tan\theta =x_2/cos\theta X2=x1y1tanθ=x2/cosθ
Y 2 = y 1 + x 1 t a n θ = y 2 / c o s θ Y_2 = y_1 +x_1tan\theta = y_2/cos\theta Y2=y1+x1tanθ=y2/cosθ
此刻可以发现:现在的X2,Y2相对于x2,y2,放大了 c o s θ cos\theta cosθ倍。
通往在一般的情况下,我们这个地方有:
x n = x n − 1 c o s θ n − 1 − y n − 1 s i n θ n − 1 = c o s θ n − 1 ( x n − 1 − y n − 1 t a n θ n − 1 ) x_n = x_{n-1}cos\theta_{n-1} - y_{n-1}sin\theta_{n-1} = cos\theta_{n-1} (x_{n-1}- y_{n-1}tan\theta_{n-1} ) xn=xn1cosθn1yn1sinθn1=cosθn1(xn1yn1tanθn1)
y n = y n − 1 c o s θ n − 1 + x n − 1 s i n θ n − 1 = c o s θ n − 1 ( y n − 1 + x n − 1 t a n θ n − 1 ) y_n = y_{n-1}cos\theta_{n-1} + x_{n-1}sin\theta_{n-1} = cos\theta_{n-1} (y_{n-1}+x_{n-1}tan\theta_{n-1} ) yn=yn1cosθn1+xn1sinθn1=cosθn1(yn1+xn1tanθn1)
同理去掉cos函数有:
X n = X n − 1 − Y n − 1 t a n θ n − 1 X_n = X_{n-1} - Y_{n-1}tan\theta_{n-1} Xn=Xn1Yn1tanθn1
Y n = Y n − 1 + X n − 1 t a n θ n − 1 Y_n = Y_{n-1} + X_{n-1}tan\theta_{n-1} Yn=Yn1+Xn1tanθn1
以上称之为伪旋转分量。

4、将去掉cordic的算法表示式中的cos分量进行累成成系数K

由于每一次都要进行一次乘法运算,因此可以有:
K n = c o s θ 1 ∗ c o s θ 2 ∗ c o s θ 3 ∗ . . . ∗ c o s θ n K_n = cos\theta_1* cos\theta_2* cos\theta_3*...* cos\theta_n Kn=cosθ1cosθ2cosθ3...cosθn
因此就可以有,可以配合原始式子有:
x n = K n ∗ X n x_n = K_n*X_n xn=KnXn
y n = K n ∗ Y n y_n = K_n*Y_n yn=KnYn

5、设置一个控制算子

引入一个控制算子,用来控制旋转的方向,若是顺时针旋转,则这个地方d=-1,反而若是逆时针旋转,则应该为d=1。因此,上述的式子应该为:
X n = X n − 1 − d n − 1 ∗ Y n − 1 ∗ t a n θ n − 1 X_n = X_{n-1} - d_{n-1}*Y_{n-1}*tan\theta_{n-1} Xn=Xn1dn1Yn1tanθn1
Y n = Y n − 1 + d n − 1 ∗ X n − 1 ∗ t a n θ n − 1 Y_n = Y_{n-1} + d_{n-1}*X_{n-1}*tan\theta_{n-1} Yn=Yn1+dn1Xn1tanθn1
其中d = 1或-1

6、设置一个误差系数

虽然这个地方只需要求得sin以及cos值的输出,但是还需要一个误差系数,来保存当前的误差值。误差系数设为z,误差输入的初始值为z=angle_in,也就是角度输入值,最终在不断的计算下,这个误差值趋近于0。而z的运算如下所示:
Z n = Z n − 1 − d n − 1 θ Z_n = Z_{n-1} - d_{n-1}\theta Zn=Zn1dn1θ

7、简化运算

t a n θ n = 2 − n tan\theta_n = 2^{-n} tanθn=2n,其中i=0,1,…,n-1。由此可以得到,上述式子有:
X n = X n − 1 − d n − 1 ∗ Y n − 1 ∗ 2 n − 1 X_n = X_{n-1} - d_{n-1}*Y_{n-1} *2^{n-1} Xn=Xn1dn1Yn12n1
Y n = Y n − 1 + d n − 1 ∗ X n − 1 ∗ 2 n − 1 Y_n = Y_{n-1} + d_{n-1}*X_{n-1} *2^{n-1} Yn=Yn1+dn1Xn12n1
Z n = Z n − 1 − d n − 1 ∗ a r c t a n 2 ( n − 1 ) Z_n = Z_{n-1} - d_{n-1}*arctan2^{(n-1)} Zn=Zn1dn1arctan2(n1)

8、FPGA运算实现逻辑

实现方式以30°输入为例子,输出对应的sin以及cos值。同时观察每时每刻的误差值z的大小。首先输入x,y,z的值为x = K 16 K_{16} K16,y=1

计算次数 2 n − 1 2^{n-1} 2n1角度值 θ \theta θ( a r c t a n 2 n − 1 arctan2^{n-1} arctan2n1)xyz
0\\0.60724030
1 2 0 2^{0} 2045°0.607240.60724-15
2 2 1 2^{1} 2126.5654°0.910860.3036211.5651
3 2 2 2^{2} 2214.036°0.834960.5313-2.4711
4 2 3 2^{3} 237.125°0.90140.426964.6539
5 2 4 2^{4} 243.576°0.874690.48331.0776
6 2 5 2^{5} 251.79°0.85960.5106-0.7123
7 2 6 2^{6} 260.8955°0.86760.497190.1829
8 2 7 2^{7} 270.4473°0.863690.50397-0.2647
9 2 8 2^{8} 280.2236°0.86570.5006-0.0409
10 2 9 2^{9} 290.1123°0.86660.49890.071
11 2 10 2^{10} 2100.05566°0.86620.49980.015
12 2 11 2^{11} 2110.02832°0.86590.5002-0.013
13 2 12 2^{12} 2120.0137°0.86610.499970.001
14 2 13 2^{13} 2130.0068°0.86600.5001-0.006
15 2 14 2^{14} 2140.0039°0.866040.50002-0.0025
16 2 15 2^{15} 2150.00195°0.866060.5-0.0007

整个FPGA对于cordic的实现流程采用的是状态机实现法,因此,整个过程的实现代码如下所示:

/* cordic算法的实现 */
/* 输入一个角度值(拓展了2^16次大小),进行16次运算之后,输出一个对应的sin值以及cos值,同时获得每一次运算的时候的误差大小z*/
/* 整个模块的运算宽度范围大小为45 + 26.5654 + 14.036 + 7.125 + 3.576 + 1.79 + 0.8955 + 0.4473 + 0.2236 + 0.1123 + 0.05566 + 0.02832 + 0.0137 + 0.0068 + 0.0039 + 0.00195 = 99.88*/
`timescale  1ns / 1ps


module cordic_top(
    input clk                       ,//设置系统时钟clk
    input rst_n                     ,//设置复位电平,电平的低电平位有效
    input [31:0]angle_in            ,//通过控制testbench中的角度输入,来达到不同角度输入一个值,并且同时输出对应的sin值以及cos值

    output reg signed[31:0] sin_value     ,//输出对应的sin值输出通道
    output reg signed[31:0] cos_value      //输出对应的cos值输出通道
);

parameter U_DLY = 1                 ;//设置延迟的时限

parameter angle_2_0  =  32'd2949120 ; //45°
parameter angle_2_1  =  32'd1740992 ; //26.5654°    
parameter angle_2_2  =  32'd919872  ; //14.036° 
parameter angle_2_3  =  32'd466944  ; //7.125° 
parameter angle_2_4  =  32'd234368  ; //3.576° 
parameter angle_2_5  =  32'd117312  ; //1.79° 
parameter angle_2_6  =  32'd58688   ; //0.8955°  
parameter angle_2_7  =  32'd29312   ; //0.4473°  
parameter angle_2_8  =  32'd14656   ; //0.2236°  
parameter angle_2_9  =  32'd7360    ; //0.1123°   
parameter angle_2_10 =  32'd3648    ; //0.05566°  
parameter angle_2_11 =  32'd1856    ; //0.02832°	 
parameter angle_2_12 =  32'd896     ; //0.0137°   
parameter angle_2_13 =  32'd448     ; //0.0068°   
parameter angle_2_14 =  32'd256     ; //0.0039°   
parameter angle_2_15 =  32'd128     ; //0.00195°   

parameter K16  =  32'd39796         ; //作为初始的cos分值变量之积,总共是16次分值变量之积 

//保留每一次变量的的寄存器值,一共是17组,分别保存计算的sin值、cos值以及对应的误差值z。
reg signed [31:0] x_inital          ; 
reg signed [31:0] y_inital          ;       
reg signed [31:0] z_inital          ;
reg signed [31:0] x1                ;
reg signed [31:0] y1                ;  
reg signed [31:0] z1                ; 
reg signed [31:0] x2                ; 
reg signed [31:0] y2                ; 
reg signed [31:0] z2                ; 
reg signed [31:0] x3                ;
reg signed [31:0] y3                ;
reg signed [31:0] z3                ;
reg signed [31:0] x4                ;
reg signed [31:0] y4                ;
reg signed [31:0] z4                ;
reg signed [31:0] x5                ;
reg signed [31:0] y5                ;
reg signed [31:0] z5                ;
reg signed [31:0] x6                ;
reg signed [31:0] y6                ;
reg signed [31:0] z6                ;
reg signed [31:0] x7                ;
reg signed [31:0] y7                ;
reg signed [31:0] z7                ;
reg signed [31:0] x8                ;
reg signed [31:0] y8                ;
reg signed [31:0] z8                ;
reg signed [31:0] x9                ;
reg signed [31:0] y9                ;
reg signed [31:0] z9                ; 
reg signed [31:0] x10               ;
reg signed [31:0] y10               ;
reg signed [31:0] z10               ;
reg signed [31:0] x11               ;
reg signed [31:0] y11               ;
reg signed [31:0] z11               ;
reg signed [31:0] x12               ;
reg signed [31:0] y12               ;
reg signed [31:0] z12               ; 
reg signed [31:0] x13               ;
reg signed [31:0] y13               ;
reg signed [31:0] z13               ;
reg signed [31:0] x14               ;
reg signed [31:0] y14               ;
reg signed [31:0] z14               ;
reg signed [31:0] x15               ;
reg signed [31:0] y15               ;
reg signed [31:0] z15               ;
reg signed [31:0] x16               ;
reg signed [31:0] y16               ;
reg signed [31:0] z16               ;

/*计数器寄存器,用来保存整体的时序次数*/
reg  [4:0] count                    ;

/*状态机实现方式,用来控制状态机的整体逻辑,循环次数控制到17次,第0次的时候因为没有上升沿,因此*/
/*可能会出问题,所以这个地方采用的是1-18,当值的大小位18的时候,执行复位的操作*/
always@(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        count <= #U_DLY 32'b0              ;
    end
    else if(count == 5'd18)begin
        count <= 1'b0                      ;
    end
    else begin
        count <= count + 1'b1              ;
    end
end

/*进入状态机的主模块*/
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)begin                                  //如果复位信号出现使能,所有寄存器的值置1
        x_inital    <= #U_DLY 32'b0                    ;
        y_inital    <= #U_DLY 32'b0                    ;
        z_inital    <= #U_DLY 32'b0                    ;
        x1          <= #U_DLY 32'b0                    ;
        y1          <= #U_DLY 32'b0                    ;
        z1          <= #U_DLY 32'b0                    ;
        x2          <= #U_DLY 32'b0                    ;
        y2          <= #U_DLY 32'b0                    ;
        z2          <= #U_DLY 32'b0                    ;
        x3          <= #U_DLY 32'b0                    ;
        y3          <= #U_DLY 32'b0                    ;
        z3          <= #U_DLY 32'b0                    ;
        x4          <= #U_DLY 32'b0                    ;
        y4          <= #U_DLY 32'b0                    ;
        z4          <= #U_DLY 32'b0                    ;
        x5          <= #U_DLY 32'b0                    ;
        y5          <= #U_DLY 32'b0                    ;
        z5          <= #U_DLY 32'b0                    ;
        x6          <= #U_DLY 32'b0                    ;
        y6          <= #U_DLY 32'b0                    ;
        z6          <= #U_DLY 32'b0                    ;
        x7          <= #U_DLY 32'b0                    ;
        y7          <= #U_DLY 32'b0                    ;
        z7          <= #U_DLY 32'b0                    ;
        x8          <= #U_DLY 32'b0                    ;
        y8          <= #U_DLY 32'b0                    ;
        z8          <= #U_DLY 32'b0                    ;
        x9          <= #U_DLY 32'b0                    ;
        y9          <= #U_DLY 32'b0                    ;
        z9          <= #U_DLY 32'b0                    ;
        x10         <= #U_DLY 32'b0                    ;
        y10         <= #U_DLY 32'b0                    ;
        z10         <= #U_DLY 32'b0                    ;
        x11         <= #U_DLY 32'b0                    ;
        y11         <= #U_DLY 32'b0                    ;
        z11         <= #U_DLY 32'b0                    ;
        x12         <= #U_DLY 32'b0                    ;
        y12         <= #U_DLY 32'b0                    ;
        z12         <= #U_DLY 32'b0                    ;
        x13         <= #U_DLY 32'b0                    ;
        y13         <= #U_DLY 32'b0                    ;
        z13         <= #U_DLY 32'b0                    ;
        x14         <= #U_DLY 32'b0                    ;
        y14         <= #U_DLY 32'b0                    ;
        z14         <= #U_DLY 32'b0                    ;
        x15         <= #U_DLY 32'b0                    ;
        y15         <= #U_DLY 32'b0                    ;
        z15         <= #U_DLY 32'b0                    ;
        x16         <= #U_DLY 32'b0                    ;
        y16         <= #U_DLY 32'b0                    ;
        z16         <= #U_DLY 32'b0                    ;
        sin_value   <= #U_DLY 32'b0                    ;
        cos_value   <= #U_DLY 32'b0                    ;
    end
    else begin
        case(count)
            5'd1: begin                                 //由于需要将K16的值放入运算,这里直接设置初始值的大小就为K16,方便我们的运算
                x_inital <= #U_DLY K16                 ;
                y_inital <= #U_DLY 32'd0               ;
                z_inital <= #U_DLY angle_in            ;
            end

            5'd2: begin
                if(z_inital[31] == 1'b1)begin
                    x1 <= #U_DLY x_inital + y_inital   ;
                    y1 <= #U_DLY y_inital - x_inital   ;
                    z1 <= #U_DLY z_inital + angle_2_0  ;
                end
                else begin
                    x1 <= #U_DLY x_inital - y_inital   ;
                    y1 <= #U_DLY y_inital + x_inital   ;
                    z1 <= #U_DLY z_inital - angle_2_0  ;
                end
            end

            5'd3:begin
                if(z1[31] == 1'b1)begin
                    x2 <= #U_DLY x1 + (y1>>>1)         ;
                    y2 <= #U_DLY y1 - (x1>>>1)         ;
                    z2 <= #U_DLY z1 + angle_2_1        ;
                end
                else begin
                    x2 <= #U_DLY x1 - (y1>>>1)         ;
                    y2 <= #U_DLY y1 + (x1>>>1)         ;
                    z2 <= #U_DLY z1 - angle_2_1        ;
                end
            end

            5'd4:begin
                if(z2[31] == 1'b1)begin
                    x3 <= #U_DLY x2 + (y2>>>2)         ;
                    y3 <= #U_DLY y2 - (x2>>>2)         ;
                    z3 <= #U_DLY z2 + angle_2_2        ;
                end
                else begin
                    x3 <= #U_DLY x2 - (y2>>>2)         ;
                    y3 <= #U_DLY y2 + (x2>>>2)         ;
                    z3 <= #U_DLY z2 - angle_2_2        ;
                end
            end
            5'd5:begin
                if(z3[31] == 1'b1)begin
                    x4 <= #U_DLY x3 + (y3>>>3)         ;
                    y4 <= #U_DLY y3 - (x3>>>3)         ;
                    z4 <= #U_DLY z3 + angle_2_3        ;
                end
                else begin
                    x4 <= #U_DLY x3 - (y3>>>3)         ;
                    y4 <= #U_DLY y3 + (x3>>>3)         ;
                    z4 <= #U_DLY z3 - angle_2_3        ;
                end
            end

            5'd6:begin
                if(z4[31] == 1'b1)begin
                    x5 <= #U_DLY x4 + (y4>>>4)         ;
                    y5 <= #U_DLY y4 - (x4>>>4)         ;
                    z5 <= #U_DLY z4 + angle_2_4        ;
                end
                else begin
                    x5 <= #U_DLY x4 - (y4>>>4)         ;
                    y5 <= #U_DLY y4 + (x4>>>4)         ;
                    z5 <= #U_DLY z4 - angle_2_4        ;
                end
            end

            5'd7:begin
                if(z5[31] == 1'b1)begin
                    x6 <= #U_DLY x5 + (y5>>>5)         ;
                    y6 <= #U_DLY y5 - (x5>>>5)         ;
                    z6 <= #U_DLY z5 + angle_2_5        ;
                end
                else begin
                    x6 <= #U_DLY x5 - (y5>>>5)         ;
                    y6 <= #U_DLY y5 + (x5>>>5)         ;
                    z6 <= #U_DLY z5 - angle_2_5        ;
                end
            end

            5'd8:begin
                if(z6[31] == 1'b1)begin
                    x7 <= #U_DLY x6 + (y6>>>6)         ;
                    y7 <= #U_DLY y6 - (x6>>>6)         ;
                    z7 <= #U_DLY z6 + angle_2_6        ;
                end
                else begin
                    x7 <= #U_DLY x6 - (y6>>>6)         ;
                    y7 <= #U_DLY y6 + (x6>>>6)         ;
                    z7 <= #U_DLY z6 - angle_2_6        ;
                end
            end

            5'd9:begin
                if(z7[31] == 1'b1)begin
                    x8 <= #U_DLY x7 + (y7>>>7)         ;
                    y8 <= #U_DLY y7 - (x7>>>7)         ;
                    z8 <= #U_DLY z7 + angle_2_7        ;
                end
                else begin
                    x8 <= #U_DLY x7 - (y7>>>7)         ;
                    y8 <= #U_DLY y7 + (x7>>>7)         ;
                    z8 <= #U_DLY z7 - angle_2_7        ;
                end
            end

            5'd10:begin
                if(z8[31] == 1'b1)begin
                    x9 <= #U_DLY x8 + (y8>>>8)         ;
                    y9 <= #U_DLY y8 - (x8>>>8)         ;
                    z9 <= #U_DLY z8 + angle_2_8        ;
                end
                else begin
                    x9 <= #U_DLY x8 - (y8>>>8)         ;
                    y9 <= #U_DLY y8 + (x8>>>8)         ;
                    z9 <= #U_DLY z8 - angle_2_8        ;
                end
            end

            5'd11:begin
                if(z9[31] == 1'b1)begin
                    x10 <= #U_DLY x9 + (y9>>>9)        ;
                    y10 <= #U_DLY y9 - (x9>>>9)        ;
                    z10 <= #U_DLY z9 + angle_2_9       ;
                end
                else begin
                    x10 <= #U_DLY x9 - (y9>>>9)        ;
                    y10 <= #U_DLY y9 + (x9>>>9)        ;
                    z10 <= #U_DLY z9 - angle_2_9       ;
                end
            end

            5'd12:begin
                if(z10[31] == 1'b1)begin
                    x11 <= #U_DLY x10 + (y10>>>10)     ;
                    y11 <= #U_DLY y10 - (x10>>>10)     ;
                    z11 <= #U_DLY z10 + angle_2_10     ;
                end
                else begin
                    x11 <= #U_DLY x10 - (y10>>>10)     ;
                    y11 <= #U_DLY y10 + (x10>>>10)     ;
                    z11 <= #U_DLY z10 - angle_2_10     ;
                end
            end

            5'd13:begin
                if(z11[31] == 1'b1)begin
                    x12 <= #U_DLY x11 + (y11>>>11)     ;
                    y12 <= #U_DLY y11 - (x11>>>11)     ;
                    z12 <= #U_DLY z11 + angle_2_11     ;
                end
                else begin
                    x12 <= #U_DLY x11 - (y11>>>11)     ;
                    y12 <= #U_DLY y11 + (x11>>>11)     ;
                    z12 <= #U_DLY z11 - angle_2_11     ;
                end
            end

            5'd14:begin
                if(z12[31] == 1'b1)begin
                    x13 <= #U_DLY x12 + (y12>>>12)     ;
                    y13 <= #U_DLY y12 - (x12>>>12)     ;
                    z13 <= #U_DLY z12 + angle_2_12     ;
                end
                else begin
                    x13 <= #U_DLY x12 - (y12>>>12)     ;
                    y13 <= #U_DLY y12 + (x12>>>12)     ;
                    z13 <= #U_DLY z12 - angle_2_12     ;
                end
            end

            5'd15:begin
                if(z13[31] == 1'b1)begin
                    x14 <= #U_DLY x13 + (y13>>>13)     ;
                    y14 <= #U_DLY y13 - (x13>>>13)     ;
                    z14 <= #U_DLY z13 + angle_2_13     ;
                end
                else begin
                    x14 <= #U_DLY x13 - (y13>>>13)     ;
                    y14 <= #U_DLY y13 + (x13>>>13)     ;
                    z14 <= #U_DLY z13 - angle_2_13     ;
                end
            end

            5'd16:begin
                if(z14[31] == 1'b1)begin
                    x15 <= #U_DLY x14 + (y14>>>14)     ;
                    y15 <= #U_DLY y14 - (x14>>>14)     ;
                    z15 <= #U_DLY z14 + angle_2_14     ;
                end
                else begin
                    x15 <= #U_DLY x14 - (y14>>>14)     ;
                    y15 <= #U_DLY y14 + (x14>>>14)     ;
                    z15 <= #U_DLY z14 - angle_2_14     ;
                end
            end

            5'd17:begin
                if(z14[31] == 1'b1)begin
                    x16 <= #U_DLY x15 + (y15>>>15)     ;
                    y16 <= #U_DLY y15 - (x15>>>15)     ;
                    z16 <= #U_DLY z15 + angle_2_15     ;
                end
                else begin
                    x16 <= #U_DLY x15 - (y15>>>15)     ;
                    y16 <= #U_DLY y15 + (x15>>>15)     ;
                    z16 <= #U_DLY z15 - angle_2_15     ;
                end
            end

            5'd18:begin                                    //进行完成16次的运算之后,进行sin以及cos值的输出,转而进入下一次的角度运算
                sin_value <= #U_DLY y16                ;
                cos_value <= #U_DLY x16                ;
               end 
            
            default:begin
                x_inital <= 0                       ;
                y_inital <= 0                       ;
                z_inital <= 0                       ;
                x1  <= #U_DLY 32'b0                 ;
                y1  <= #U_DLY 32'b0                 ;
                z1  <= #U_DLY 32'b0                 ;
                x2  <= #U_DLY 32'b0                 ;
                y2  <= #U_DLY 32'b0                 ;
                z2  <= #U_DLY 32'b0                 ;
                x3  <= #U_DLY 32'b0                 ;
                y3  <= #U_DLY 32'b0                 ;
                z3  <= #U_DLY 32'b0                 ;
                x4  <= #U_DLY 32'b0                 ;
                y4  <= #U_DLY 32'b0                 ;
                z4  <= #U_DLY 32'b0                 ;
                x5  <= #U_DLY 32'b0                 ;
                y5  <= #U_DLY 32'b0                 ;
                z5  <= #U_DLY 32'b0                 ;
                x7  <= #U_DLY 32'b0                 ;
                y7  <= #U_DLY 32'b0                 ;
                z7  <= #U_DLY 32'b0                 ;
                x8  <= #U_DLY 32'b0                 ;
                y8  <= #U_DLY 32'b0                 ;
                z8  <= #U_DLY 32'b0                 ;
                x9  <= #U_DLY 32'b0                 ;
                y9  <= #U_DLY 32'b0                 ;
                z9  <= #U_DLY 32'b0                 ;
                x10 <= #U_DLY 32'b0                 ;
                y10 <= #U_DLY 32'b0                 ;
                z10 <= #U_DLY 32'b0                 ;
                x11 <= #U_DLY 32'b0                 ;
                y11 <= #U_DLY 32'b0                 ;
                z11 <= #U_DLY 32'b0                 ;
                x12 <= #U_DLY 32'b0                 ;
                y12 <= #U_DLY 32'b0                 ;
                z12 <= #U_DLY 32'b0                 ;
                x13 <= #U_DLY 32'b0                 ;
                y13 <= #U_DLY 32'b0                 ;
                z13 <= #U_DLY 32'b0                 ;
                x14 <= #U_DLY 32'b0                 ;
                y14 <= #U_DLY 32'b0                 ;
                z14 <= #U_DLY 32'b0                 ;
                x15 <= #U_DLY 32'b0                 ;
                y15 <= #U_DLY 32'b0                 ;
                z15 <= #U_DLY 32'b0                 ;
                x16 <= #U_DLY 32'b0                 ;
                y16 <= #U_DLY 32'b0                 ;
                z16 <= #U_DLY 32'b0                 ;
                sin_value <= #U_DLY 32'b0           ;
                cos_value <= #U_DLY 32'b0           ;            end
        endcase
    end
end
endmodule

对应cordic的的testbench的实现代码如下所示:

`timescale  1ns / 1ps

module tb_cordic_top;

// cordic_top Parameters
parameter PERIOD      = 10         ;
parameter angle_2_0   = 32'd2949120;
parameter angle_2_1   = 32'd1740992;
parameter angle_2_2   = 32'd919872 ;
parameter angle_2_3   = 32'd466944 ;
parameter angle_2_4   = 32'd234368 ;
parameter angle_2_5   = 32'd117312 ;
parameter angle_2_6   = 32'd58688  ;
parameter angle_2_7   = 32'd29312  ;
parameter angle_2_8   = 32'd14656  ;
parameter angle_2_9   = 32'd7360   ;
parameter angle_2_10  = 32'd3648   ;
parameter angle_2_11  = 32'd1856   ;
parameter angle_2_12  = 32'd896    ;
parameter angle_2_13  = 32'd448    ;
parameter angle_2_14  = 32'd256    ;
parameter angle_2_15  = 32'd128    ;
parameter K16         = 32'd39796  ;

// cordic_top Inputs
reg   clk                                  = 0 ;
reg   rst_n                                = 0 ;
reg   [31:0]  angle_in                     = 0 ;

// cordic_top Outputs
wire  signed[31:0] sin                     ;    
wire  signed[31:0] cos                     ;    


initial
begin
    forever #(PERIOD/2)  clk=~clk;
end

initial
begin
    #(PERIOD*4) rst_n  =  1;
end

initial begin
    #(PERIOD*2)  angle_in = 32'd1966080;     //30°
    // #(PERIOD*2)  angle_in = 32'd2949120;  //45°
end
cordic_top #(
    .angle_2_0  ( angle_2_0  ),
    .angle_2_1  ( angle_2_1  ),
    .angle_2_2  ( angle_2_2  ),
    .angle_2_3  ( angle_2_3  ),
    .angle_2_4  ( angle_2_4  ),
    .angle_2_5  ( angle_2_5  ),
    .angle_2_6  ( angle_2_6  ),
    .angle_2_7  ( angle_2_7  ),
    .angle_2_8  ( angle_2_8  ),
    .angle_2_9  ( angle_2_9  ),
    .angle_2_10 ( angle_2_10 ),
    .angle_2_11 ( angle_2_11 ),
    .angle_2_12 ( angle_2_12 ),
    .angle_2_13 ( angle_2_13 ),
    .angle_2_14 ( angle_2_14 ),
    .angle_2_15 ( angle_2_15 ),
    .K16        ( K16        ))
 u_cordic_top (
    .clk                     ( clk                      ),
    .rst_n                   ( rst_n                    ),
    .angle_in                ( angle_in                 ),
    .sin_value               ( sin                      ),
    .cos_value               ( cos                      )
);

endmodule

仿真效果图如下图:
在这里插入图片描述
从最终的结果可以看到,最终输出的结果 s i n o u t p u t = 32768 sin_{output} =32768 sinoutput=32768 c o s o u t p u t = 56758 cos_{output} = 56758 cosoutput=56758 z o u t p u t = 64 z_{output} = 64 zoutput=64,根据放大倍数65536的关系,这个地方可以得出, s i n = 32768 / 65536 = 0.5 sin =32768/65536=0.5 sin=32768/65536=0.5 c o s = 56758 / 65536 = 0.866 cos = 56758/65536=0.866 cos=56758/65536=0.866 z = 64 / 65536 = 0.00098 z = 64/65536 = 0.00098 z=64/65536=0.00098

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值