LoginSignup
2
0

More than 5 years have passed since last update.

趣味で非パイプラインのCORDICの実装

Posted at

個人的にCORDICによる三角関数の実装に興味があったので実装しました。
次の記事 https://qiita.com/cyebu1103/items/2d51212f27788f8b3c8f がとても親切に解説してくれています。

演算子を極力使わないように実装を試みました。非パイプラインです。
数値はQ29表記の32ビット符号付き固定小数点、入力レンジは[-6.28,6.28]です。
Xilinx LogiCoreIPの三角関数IPの入力範囲は確か[-3.28,3.28]。
ALTERA Megafunctionのalt_sincosのように入力制限がないものを作りたい。

上手なバレルシフタの記述方法を検討中。

COREDIC_sincos.vhd

module CORDIC_sincos(input wire clk, input wire st, input wire [31:0] theta, output wire [31:0] sin, output wire [31:0] cos);

//Format: S2Q29, 32 bit fixed point.

reg on;     initial on=1'b0;
reg [4:0] cnt;
always@(clk) on <= (on==1'b0)? ((st==1'b1)? 1'b1:1'b0) : ((cnt==5'd24)? 1'b0:1'b1);

localparam signed [31:0] PI         = 32'h6487ed51; //3.141593e+00 (Tranceted error: 1.215419e-10)
localparam signed [31:0] PI_2       = 32'h3243f6a8; //1.570796e+00 (Tranceted error: 9.920935e-10)
localparam signed [31:0] inv_PI     = 32'h0a2f9836; //3.183099e-01 (Tranceted error: 1.665406e-09)
localparam signed [31:0] inv_2PI    = 32'h0517cc1b; //1.591549e-01 (Tranceted error: 8.327029e-10)
localparam signed [31:0] inv_sqrt2  = 32'h16a09e66; //7.071068e-01 (Tranceted error: 9.257461e-10)
localparam signed [31:0] PI_4       = 32'h1921fb54; //7.853982e-01 (Tranceted error: 4.960468e-10)
localparam signed [31:0] PI3_4      = 32'h4b65f1fc; //2.356194e+00 (Tranceted error: 1.488140e-09)
localparam signed [31:0] inv_k      = 32'h136e9db5; //6.072529e-01 (Tranceted error: 6.127276e-11)

localparam signed [31:0] atan_no0_P  = 32'h1921fb54; //7.853982e-01 (Tranceted error: 4.960468e-10)
localparam signed [31:0] atan_no1_P  = 32'h0ed63382; //4.636476e-01 (Tranceted error: 1.286868e-09)
localparam signed [31:0] atan_no2_P  = 32'h07d6dd7e; //2.449787e-01 (Tranceted error: 5.466124e-10)
localparam signed [31:0] atan_no3_P  = 32'h03fab753; //1.243550e-01 (Tranceted error: 6.222629e-10)
localparam signed [31:0] atan_no4_P  = 32'h01ff55bb; //6.241881e-02 (Tranceted error: 8.353672e-10)
localparam signed [31:0] atan_no5_P  = 32'h00ffeaad; //3.123983e-02 (Tranceted error: 1.610138e-09)
localparam signed [31:0] atan_no6_P  = 32'h007ffd55; //1.562373e-02 (Tranceted error: 8.071138e-10)
localparam signed [31:0] atan_no7_P  = 32'h003fffaa; //7.812341e-03 (Tranceted error: 1.247584e-09)
localparam signed [31:0] atan_no8_P  = 32'h001ffff5; //3.906230e-03 (Tranceted error: 6.210636e-10)
localparam signed [31:0] atan_no9_P  = 32'h000ffffe; //1.953123e-03 (Tranceted error: 1.241769e-09)
localparam signed [31:0] atan_no10_P = 32'h0007ffff; //9.765622e-04 (Tranceted error: 1.552204e-09)
localparam signed [31:0] atan_no11_P = 32'h0003ffff; //4.882812e-04 (Tranceted error: 1.823840e-09)
localparam signed [31:0] atan_no12_P = 32'h0001ffff; //2.441406e-04 (Tranceted error: 1.857795e-09)
localparam signed [31:0] atan_no13_P = 32'h0000ffff; //1.220703e-04 (Tranceted error: 1.862039e-09)
localparam signed [31:0] atan_no14_P = 32'h00007fff; //6.103516e-05 (Tranceted error: 1.862569e-09)
localparam signed [31:0] atan_no15_P = 32'h00003fff; //3.051758e-05 (Tranceted error: 1.862636e-09)
localparam signed [31:0] atan_no16_P = 32'h00001fff; //1.525879e-05 (Tranceted error: 1.862644e-09)
localparam signed [31:0] atan_no17_P = 32'h00000fff; //7.629395e-06 (Tranceted error: 1.862645e-09)
localparam signed [31:0] atan_no18_P = 32'h000007ff; //3.814697e-06 (Tranceted error: 1.862645e-09)

localparam signed [31:0] atan_no0_N  = 32'he6de04ab; //-7.853982e-01 (Tranceted error: 1.366598e-09)
localparam signed [31:0] atan_no1_N  = 32'hf129cc7d; //-4.636476e-01 (Tranceted error: 5.757768e-10)
localparam signed [31:0] atan_no2_N  = 32'hf8292281; //-2.449787e-01 (Tranceted error: 1.316033e-09)
localparam signed [31:0] atan_no3_N  = 32'hfc0548ac; //-1.243550e-01 (Tranceted error: 1.240382e-09)
localparam signed [31:0] atan_no4_N  = 32'hfe00aa44; //-6.241881e-02 (Tranceted error: 1.027278e-09)
localparam signed [31:0] atan_no5_N  = 32'hff001552; //-3.123983e-02 (Tranceted error: 2.525072e-10)
localparam signed [31:0] atan_no6_N  = 32'hff8002aa; //-1.562373e-02 (Tranceted error: 1.055531e-09)
localparam signed [31:0] atan_no7_N  = 32'hffc00055; //-7.812341e-03 (Tranceted error: 6.150612e-10)
localparam signed [31:0] atan_no8_N  = 32'hffe0000a; //-3.906230e-03 (Tranceted error: 1.241582e-09)
localparam signed [31:0] atan_no9_N  = 32'hfff00001; //-1.953123e-03 (Tranceted error: 6.208760e-10)
localparam signed [31:0] atan_no10_N = 32'hfff80000; //-9.765622e-04 (Tranceted error: 3.104407e-10)
localparam signed [31:0] atan_no11_N = 32'hfffc0000; //-4.882812e-04 (Tranceted error: 3.880510e-11)
localparam signed [31:0] atan_no12_N = 32'hfffe0000; //-2.441406e-04 (Tranceted error: 4.850638e-12)
localparam signed [31:0] atan_no13_N = 32'hffff0000; //-1.220703e-04 (Tranceted error: 6.063298e-13)
localparam signed [31:0] atan_no14_N = 32'hffff8000; //-6.103516e-05 (Tranceted error: 7.579123e-14)
localparam signed [31:0] atan_no15_N = 32'hffffc000; //-3.051758e-05 (Tranceted error: 9.473904e-15)
localparam signed [31:0] atan_no16_N = 32'hffffe000; //-1.525879e-05 (Tranceted error: 1.184238e-15)
localparam signed [31:0] atan_no17_N = 32'hfffff000; //-7.629395e-06 (Tranceted error: 1.480300e-16)
localparam signed [31:0] atan_no18_N = 32'hfffff800; //-3.814697e-06 (Tranceted error: 1.850386e-17)

reg sign;
reg zero;
reg reverse;
reg angle_zero;

reg signed [31:0] x;
reg signed [31:0] y;
reg signed [31:0] x_sh;
reg signed [31:0] y_sh;

reg quadrant;

reg [31:0] theta_sh;
reg [31:0] theta_sh_buf;
reg [31:0] angle_tb;

reg [31:0] sin_in;
reg [31:0] cos_in;

reg div;

assign sin=sin_in;
assign cos=cos_in;

always@(posedge clk)
begin

    div=(on==1'b1)? ~div:1'b0;

    if(div==1'b0)
    begin
        cnt <= (on==1'b1)? cnt+1'b1: 1'b0;

        if(cnt==5'd1) angle_zero <= (theta==1'b0)? 1'b1:1'b0;

        if(cnt==5'd1) theta_sh <= (theta[31]==1'b0)? theta-PI:theta+PI; // Range convert [-2pi,2pi]->[-pi,pi]
        else theta_sh <= (theta_sh_buf!=1'b0)? theta_sh_buf+angle_tb:1'b0;

        if(cnt==5'd2) reverse <= (theta_sh[31]==1'b1)? 1'b1:1'b0; else reverse<=reverse;
        sign <= theta_sh[31];

        if(cnt==5'd6)
        begin
            x<=(angle_zero!=1'b1)? inv_k:32'h20000000;
            y<=(angle_zero!=1'b1)? inv_k:1'b0;
        end
        else
        begin
            x <= (zero!=1'b1)? ((sign==1'b0)? x-y_sh: x+y_sh):x;
            y <= (zero!=1'b1)? ((sign==1'b0)? y+x_sh: y-x_sh):y;
        end

        if(cnt==5'd23)
        begin
            case ({reverse,quadrant})
                2'b00: begin cos_in<=~x+1'b1; sin_in<=~y+1'b1; end
                2'b01: begin cos_in<=y; sin_in<=~x+1'b1; end
                2'b10: begin cos_in<=x; sin_in<=y; end
                2'b11: begin cos_in<=~y+1'b1; sin_in<=x; end
                default: begin cos_in<=1'b0; sin_in<=1'b0; end
            endcase
        end
        else
        begin
            cos_in<=cos_in;
            sin_in<=sin_in;
        end

    end
    else
    begin

        case(cnt)
            5'd2:   angle_tb <= (theta_sh[31]==1'b1)? PI:1'b0;  //Range convert [-pi,pi] to [0,pi];
            5'd4:   angle_tb <= (quadrant==1'b1)? -PI_2:1'b0;   //Range convert [0,pi] to [0,pi/2];
            5'd5:   angle_tb <= (theta_sh[31]==1'b0)? atan_no0_N:atan_no0_P;
            5'd6:   angle_tb <= (theta_sh[31]==1'b0)? atan_no1_N:atan_no1_P;
            5'd7:   angle_tb <= (theta_sh[31]==1'b0)? atan_no2_N:atan_no2_P;
            5'd8:   angle_tb <= (theta_sh[31]==1'b0)? atan_no3_N:atan_no3_P;
            5'd9:   angle_tb <= (theta_sh[31]==1'b0)? atan_no4_N:atan_no4_P;
            5'd10:  angle_tb <= (theta_sh[31]==1'b0)? atan_no5_N:atan_no5_P;
            5'd11:  angle_tb <= (theta_sh[31]==1'b0)? atan_no6_N:atan_no6_P;
            5'd12:  angle_tb <= (theta_sh[31]==1'b0)? atan_no7_N:atan_no7_P;
            5'd13:  angle_tb <= (theta_sh[31]==1'b0)? atan_no8_N:atan_no8_P;
            5'd14:  angle_tb <= (theta_sh[31]==1'b0)? atan_no9_N:atan_no9_P;
            5'd15:  angle_tb <= (theta_sh[31]==1'b0)? atan_no10_N:atan_no10_P;
            5'd16:  angle_tb <= (theta_sh[31]==1'b0)? atan_no11_N:atan_no11_P;
            5'd17:  angle_tb <= (theta_sh[31]==1'b0)? atan_no12_N:atan_no12_P;
            5'd18:  angle_tb <= (theta_sh[31]==1'b0)? atan_no13_N:atan_no13_P;
            5'd19:  angle_tb <= (theta_sh[31]==1'b0)? atan_no14_N:atan_no14_P;
            5'd20:  angle_tb <= (theta_sh[31]==1'b0)? atan_no15_N:atan_no15_P;
            5'd21:  angle_tb <= (theta_sh[31]==1'b0)? atan_no16_N:atan_no16_P;
            5'd22:  angle_tb <= (theta_sh[31]==1'b0)? atan_no17_N:atan_no17_P;
            5'd23:  angle_tb <= (theta_sh[31]==1'b0)? atan_no18_N:atan_no18_P;
            default:angle_tb <= 32'b0;
        endcase

        theta_sh_buf<=theta_sh;
        zero <= (theta_sh==1'b0)? 1'b1:1'b0;
        quadrant <= (cnt==5'd3)? ((theta_sh>PI_2)? 1'b1:1'b0):quadrant;

        if(x[31]==1'b1)
        begin
            x_sh<=1'b0;
        end
        else
        begin
            case(cnt)
                5'd7:       x_sh <= {1'b0,x[31:1]};
                5'd8:       x_sh <= {2'b0,x[31:2]};
                5'd9:       x_sh <= {3'b0,x[31:3]};
                5'd10:      x_sh <= {4'b0,x[31:4]};
                5'd11:      x_sh <= {5'b0,x[31:5]};
                5'd12:      x_sh <= {6'b0,x[31:6]};
                5'd13:      x_sh <= {7'b0,x[31:7]};
                5'd14:      x_sh <= {8'b0,x[31:8]};
                5'd15:      x_sh <= {9'b0,x[31:9]};
                5'd16:      x_sh <= {10'b0,x[31:10]};
                5'd17:      x_sh <= {11'b0,x[31:11]};
                5'd18:      x_sh <= {12'b0,x[31:12]};
                5'd19:      x_sh <= {13'b0,x[31:13]};
                5'd20:      x_sh <= {14'b0,x[31:14]};
                5'd21:      x_sh <= {15'b0,x[31:15]};
                5'd22:      x_sh <= {16'b0,x[31:16]};
                default:    x_sh <= 32'b0;
            endcase
        end

        if(y[31]==1'b1)
        begin
            y_sh<=1'b0;
        end
        else
        begin
            case(cnt)
                5'd7:       y_sh <= {1'b0,y[31:1]};
                5'd8:       y_sh <= {2'b0,y[31:2]};
                5'd9:       y_sh <= {3'b0,y[31:3]};
                5'd10:      y_sh <= {4'b0,y[31:4]};
                5'd11:      y_sh <= {5'b0,y[31:5]};
                5'd12:      y_sh <= {6'b0,y[31:6]};
                5'd13:      y_sh <= {7'b0,y[31:7]};
                5'd14:      y_sh <= {8'b0,y[31:8]};
                5'd15:      y_sh <= {9'b0,y[31:9]};
                5'd16:      y_sh <= {10'b0,y[31:10]};
                5'd17:      y_sh <= {11'b0,y[31:11]};
                5'd18:      y_sh <= {12'b0,y[31:12]};
                5'd19:      y_sh <= {13'b0,y[31:13]};
                5'd20:      y_sh <= {14'b0,y[31:14]};
                5'd21:      y_sh <= {15'b0,y[31:15]};
                5'd22:      y_sh <= {16'b0,y[31:16]};
                default:    y_sh <= 32'b0;
            endcase
        end

    end
end

endmodule


2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0