关于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
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
//角度还原为真实值 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])
至此,基于FPGA的cordic算法代码实现需要注意的问题就讨论到这里。