• 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算法代码实现需要注意的问题就讨论到这里。

     

  • 相关阅读:
    Static Analysis of Java Enterprise Applications: Frameworks and Caches, the Elephants in the Room
    使用gopacket 解析一个简单的sql server 协议
    gopacket 流量抓包golang 包
    pmm 自定义prometheus 配置
    Hasura 即将支持更多的数据库类型
    apache knox apache hdaoop 生态的rest api && 应用网关
    使用minio替换fastdfs 文件系统
    tcpcollect基于libpcap 监听mysql sql
    一种业务延时状态分析的方法
    tcprstat 使用的几个问题
  • 原文地址:https://www.cnblogs.com/tanqiqi/p/9811022.html
Copyright © 2020-2023  润新知