FPGA之CORDIC算法实现_代码实现(下)

    关于FPGA之CORDIC算法的纯逻辑实现,善良的一休军“https://blog.csdn.net/qq_39210023/article/details/77456031”的博文均给出了较为详细完整的代码,整个算法的思想较为简单,就

是利用迭代流水线的思想,让角度不停逼近所求角度,一般迭代16次就已经比较接近所求角度值:

1、算法实现步骤:

1)设置迭代次数为16,则x0 = 0.607253,y0 = 0(关于初值的设定,上一篇博文有写到)并输入待计算的角度θ,θ在[-99.7°,99.7°]范围内。

2)根据三个迭代公式进行迭代,i从0至15:
xi+1 = xi – d iy i2-i
yi+1 = yi + d ix i2-i
zi+1 = zi - diθi
注:z0 = θ,di与zi同符号。

3) 经过16次迭代计算后,得到的x16 和y16分别为cosθ和sinθ。

2、代码解析:

1)16级流水线迭代实现

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[0]   <= 0;
        y[0]   <= 0;
        z[0]   <= (din<<16);
    end
    else if(din_vld_ff[0]) begin   //初始化设置赋值 x0==0.607253*2^16,y0=0;
        x[0]   <= {2'b0,COS_LM};
        y[0]   <= 0;
        z[0]   <= {1'b0,din_ff,16'b0};  //角度初始化设置
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[1]   <= 0;
        y[1]   <= 0;
        z[1]   <= 0;
    end
    else if(din_vld_ff[1])begin
        if(z[0][25]==0)begin
            x[1] <= x[0] - (y[0]>>>0);
            y[1] <= y[0] + (x[0]>>>0);
            z[1] <= z[0] - `ROT0;
        end
        else begin
            x[1] <= x[0] + (y[0]>>>0);
            y[1] <= y[0] - (x[0]>>>0);
            z[1] <= z[0] + `ROT0;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[2]   <= 0;
        y[2]   <= 0;
        z[2]   <= 0;
    end
    else if(din_vld_ff[2])begin
        if(z[1][25]==0)begin
            x[2] <= x[1] - (y[1]>>>1);
            y[2] <= y[1] + (x[1]>>>1);
            z[2] <= z[1] - `ROT1;
        end
        else begin
            x[2] <= x[1] + (y[1]>>>1);
            y[2] <= y[1] - (x[1]>>>1);
            z[2] <= z[1] + `ROT1;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[3]   <= 0;
        y[3]   <= 0;
        z[3]   <= 0;
    end
    else if(din_vld_ff[3])begin
        if(z[2][25]==0)begin
            x[3] <= x[2] - (y[2]>>>2);
            y[3] <= y[2] + (x[2]>>>2);
            z[3] <= z[2] - `ROT2;
        end
        else begin
            x[3] <= x[2] + (y[2]>>>2);
            y[3] <= y[2] - (x[2]>>>2);
            z[3] <= z[2] + `ROT2;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[4]   <= 0;
        y[4]   <= 0;
        z[4]   <= 0;
    end
    else if(din_vld_ff[4])begin
        if(z[3][25]==0)begin
            x[4] <= x[3] - (y[3]>>>3);
            y[4] <= y[3] + (x[3]>>>3);
            z[4] <= z[3] - `ROT3;
        end
        else begin
            x[4] <= x[3] + (y[3]>>>3);
            y[4] <= y[3] - (x[3]>>>3);
            z[4] <= z[3] + `ROT3;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[5]   <= 0;
        y[5]   <= 0;
        z[5]   <= 0;
    end
    else if(din_vld_ff[5])begin
        if(z[4][25]==0)begin
            x[5] <= x[4] - (y[4]>>>4);
            y[5] <= y[4] + (x[4]>>>4);
            z[5] <= z[4] - `ROT4;
        end
        else begin
            x[5] <= x[4] + (y[4]>>>4);
            y[5] <= y[4] - (x[4]>>>4);
            z[5] <= z[4] + `ROT4;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[6]   <= 0;
        y[6]   <= 0;
        z[6]   <= 0;
    end
    else if(din_vld_ff[6])begin
        if(z[5][25]==0)begin
            x[6] <= x[5] - (y[5]>>>5);
            y[6] <= y[5] + (x[5]>>>5);
            z[6] <= z[5] - `ROT5;
        end
        else begin
            x[6] <= x[5] + (y[5]>>>5);
            y[6] <= y[5] - (x[5]>>>5);
            z[6] <= z[5] + `ROT5;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[7]   <= 0;
        y[7]   <= 0;
        z[7]   <= 0;
    end
    else if(din_vld_ff[7])begin
        if(z[6][25]==0)begin
            x[7] <= x[6] - (y[6]>>>6);
            y[7] <= y[6] + (x[6]>>>6);
            z[7] <= z[6] - `ROT6;
        end
        else begin
            x[7] <= x[6] + (y[6]>>>6);
            y[7] <= y[6] - (x[6]>>>6);
            z[7] <= z[6] + `ROT6;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[8]   <= 0;
        y[8]   <= 0;
        z[8]   <= 0;
    end
    else if(din_vld_ff[8])begin
        if(z[7][25]==0)begin
            x[8] <= x[7] - (y[7]>>>7);
            y[8] <= y[7] + (x[7]>>>7);
            z[8] <= z[7] - `ROT7;
        end
        else begin
            x[8] <= x[7] + (y[7]>>>7);
            y[8] <= y[7] - (x[7]>>>7);
            z[8] <= z[7] + `ROT7;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[9]   <= 0;
        y[9]   <= 0;
        z[9]   <= 0;
    end
    else if(din_vld_ff[9])begin
        if(z[8][25]==0)begin
            x[9] <= x[8] - (y[8]>>>8);
            y[9] <= y[8] + (x[8]>>>8);
            z[9] <= z[8] - `ROT8;
        end
        else begin
            x[9] <= x[8] + (y[8]>>>8);
            y[9] <= y[8] - (x[8]>>>8);
            z[9] <= z[8] + `ROT8;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[10]   <= 0;
        y[10]   <= 0;
        z[10]   <= 0;
    end
    else if(din_vld_ff[10])begin
        if(z[9][25]==0)begin
            x[10] <= x[9] - (y[9]>>>9);
            y[10] <= y[9] + (x[9]>>>9);
            z[10] <= z[9] - `ROT9;
        end
        else begin
            x[10] <= x[9] + (y[9]>>>9);
            y[10] <= y[9] - (x[9]>>>9);
            z[10] <= z[9] + `ROT9;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[11]   <= 0;
        y[11]   <= 0;
        z[11]   <= 0;
    end
    else if(din_vld_ff[11])begin
        if(z[10][25]==0)begin
            x[11] <= x[10] - (y[10]>>>10);
            y[11] <= y[10] + (x[10]>>>10);
            z[11] <= z[10] - `ROT10;
        end
        else begin
            x[11] <= x[10] + (y[10]>>>10);
            y[11] <= y[10] - (x[10]>>>10);
            z[11] <= z[10] + `ROT10;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[12]   <= 0;
        y[12]   <= 0;
        z[12]   <= 0;
    end
    else if(din_vld_ff[12])begin
        if(z[11][25]==0)begin
            x[12] <= x[11] - (y[11]>>>11);
            y[12] <= y[11] + (x[11]>>>11);
            z[12] <= z[11] - `ROT11;
        end
        else begin
            x[12] <= x[11] + (y[11]>>>11);
            y[12] <= y[11] - (x[11]>>>11);
            z[12] <= z[11] + `ROT11;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[13]   <= 0;
        y[13]   <= 0;
        z[13]   <= 0;
    end
    else if(din_vld_ff[13])begin
        if(z[12][25]==0)begin
            x[13] <= x[12] - (y[12]>>>12);
            y[13] <= y[12] + (x[12]>>>12);
            z[13] <= z[12] - `ROT12;
        end
        else begin
            x[13] <= x[12] + (y[12]>>>12);
            y[13] <= y[12] - (x[12]>>>12);
            z[13] <= z[12] + `ROT12;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[14]   <= 0;
        y[14]   <= 0;
        z[14]   <= 0;
    end
    else if(din_vld_ff[14])begin
        if(z[13][25]==0)begin
            x[14] <= x[13] - (y[13]>>>13);
            y[14] <= y[13] + (x[13]>>>13);
            z[14] <= z[13] - `ROT13;
        end
        else begin
            x[14] <= x[13] + (y[13]>>>13);
            y[14] <= y[13] - (x[13]>>>13);
            z[14] <= z[13] + `ROT13;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[15]   <= 0;
        y[15]   <= 0;
        z[15]   <= 0;
    end
    else if(din_vld_ff[15])begin
        if(z[14][25]==0)begin
            x[15] <= x[14] - (y[14]>>>14);
            y[15] <= y[14] + (x[14]>>>14);
            z[15] <= z[14] - `ROT14;
        end
        else begin
            x[15] <= x[14] + (y[14]>>>14);
            y[15] <= y[14] - (x[14]>>>14);
            z[15] <= z[14] + `ROT14;
        end
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        x[16]   <= 0;
        y[16]   <= 0;
        z[16]   <= 0;
    end
    else if(din_vld_ff[16])begin
        if(z[15][25]==0)begin
            x[16] <= x[15] - (y[15]>>>15);
            y[16] <= y[15] + (x[15]>>>15);
            z[16] <= z[15] - `ROT15;
        end
        else begin
            x[16] <= x[15] + (y[15]>>>15);
            y[16] <= y[15] - (x[15]>>>15);
            z[16] <= z[15] + `ROT15;
        end
    end
end
View Code

 


 

2)打拍同步

这点是我看了博主“洋葱洋葱”的代码,发现的简洁打拍写法。

a、din_vld是单比特信号,假设信号din_vld打4拍输入,可以对比下简洁写法和传统写法的代码量:

//传统写法:将信号din_vld_ff打4拍
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        din_vld_ff <=0;
        din_vld_ff0 <= 0;
        din_vld_ff1 <= 0;
        din_vld_ff2 <= 0;
    end
    else begin
        din_vld_ff0 <= din_vld_ff;
        din_vld_ff1 <= din_vld_ff0;
        din_vld_ff2 <= din_vld_ff1;
    end
end




//简洁写法:将信号din_vld_ff打4拍
always @(posedge clk or negedge rst_n )begin 
    if(rst_n==0) begin
        din_vld_ff <= (0)  ;
    end
    else begin
        din_vld_ff <= ({din_vld_ff[2:0],din_vld})  ;  //din_vld为1bit
    end 
end

 

 


 

以上是单比特din_vld打4拍的对比写法,假如是要打十几拍,可以明显看出简洁写法的代码量少很多,这种打拍子的写法值得推崇。

b、din_vld是多比特信号,假设din_vld同样打4拍输入,利用简洁写法可以写成:

always @(posedge clk or negedge rst_n )begin 
    if(rst_n==0) begin
        din_vld_ff <= (0)  ;
    end
    else begin
        din_vld_ff <= ({din_vld_ff[5:0],din_vld})  ;  //din_vld为2bit
    end 
end

3)反正切函数,要注意由于θ在[-99.7°,99.7°]范围内,因此在角度输入时要注意换成第一、第四象限,最后结果输出时要注意还原成真实角度。

 

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        din_ff <= 0;
        flag   <= 0;
    end
    else if(din_vld)begin
        if(din<90)begin
            din_ff = din;
            flag   = 0;
        end
        else if(din<180)begin
            din_ff = din-90;
            flag   = 1;
        end
        else if(din<270)begin
            din_ff = din-180;
            flag   = 2;
        end
        else begin
            din_ff = din-270;
            flag   = 3;
        end
    end
end
View Code

 

 

//角度还原为真实值
always @(posedge clk or negedge rst_n )begin 
    if(rst_n==0) begin
        dout_sin <= (0)  ;
    end
    else if(flag_ff[33:32]==0)begin       //第一象限,y(16) = sin(x)
        dout_sin <= (y[16])  ;
    end 
    else if(flag_ff[33:32]==1)begin       //第二象限,Sin(X)=Sin(A+90)=CosA,Cos(X)=Cos(A+90)=-SinA
        dout_sin <= (x[16])  ;
    end 
    else if(flag_ff[33:32]==2)begin       //第三象限,the Sin(X)=Sin(A+180)=-SinA,Cos(X)=Cos(A+180)=-CosA
        dout_sin <= ~(y[16]) + 1'b1  ;
    end 
    else if(flag_ff[33:32]==3)begin       //第四象限,the Sin(X)=Sin(A+270)=-CosA,Cos(X)=Cos(A+270)=SinA
        dout_sin <= ~(x[16]) 
View Code

 

至此,基于FPGA的cordic算法代码实现需要注意的问题就讨论到这里。

 

posted @ 2018-10-18 16:13  谭渣渣  阅读(1469)  评论(1编辑  收藏  举报