分享个人写的 coridic 向量模式的RTL:
cordic 算法向量模式主要作用是求出向量的模值以及 arctan (x/y) 值;
首先从仿真图去了解cordic 算法向量模式的 作用,不同数据测试;
后续拓展:将旋转模式和向量模式在同一个module封装使用起来。
1 . 展示仿真图:
a.下面是改变 x,y坐标得出的 arctan(y/x)值,以及这个坐标构成向量的模值
b.测试 tan1~10…
c.测试 tan1 、 tan0.5 、tan0.33 …
d. 测试 随机产生的 x y 值 ,利用 random函数
2 . RTL
module test_my_cordic_vec(input i_clk,input i_rst);reg signed [31:0] r_angle ;
reg r_valid ;
reg signed [31:0] r_x ;
reg signed [31:0] r_y ;wire w_ready;(*dont_touch = "true"*)
my_cordic_vec inst_my_cordic
(.i_clk (i_clk ),.i_rst (i_rst ),.i_iteration_count (16 ), //设置迭代次数 ,最大16次.i_setx (r_x ),.i_sety (r_y ),.i_set_angle (0 ),.i_valid (r_valid ),.o_xmod ( ),.o_angle ( ),.o_valid ( ),.o_ready (w_ready )
);//测试 45°
/* always @ (posedge i_clk or posedge i_rst)
beginif (i_rst) beginr_x <= 65536;r_y <= 65536;end else if (w_ready && r_valid) beginr_x <= r_x + 65536;r_y <= r_y + 65536; end else beginr_x <= r_x;r_y <= r_y;end
end *///测试 tan1 ~ 10 ~
/* always @ (posedge i_clk or posedge i_rst)
beginif (i_rst) beginr_x <= 65536;r_y <= 65536;end else if (w_ready && r_valid) beginr_x <= 65536;r_y <= r_y + 65536; end else beginr_x <= r_x;r_y <= r_y;end
end *//* always @ (posedge i_clk or posedge i_rst)
beginif (i_rst) beginr_x <= 65536;r_y <= 65536;end else if (w_ready && r_valid) beginr_x <= r_x + 65536;r_y <= 65536; end else beginr_x <= r_x;r_y <= r_y;end
end */// 测试 随机产生的 x、 y值 always @ (posedge i_clk or posedge i_rst)
beginif (i_rst) beginr_x <= 65536;r_y <= 65536;end else if (w_ready && r_valid) beginr_x <= {$random} % 3284721; // 取 0~50 以内的数值r_y <= {$random} % 3284721; end else beginr_x <= r_x;r_y <= r_y;end
end always @ (posedge i_clk or posedge i_rst)
beginif (i_rst) r_valid <= 0;else if (w_ready && r_valid)r_valid <= 0;else if (w_ready)r_valid <= 1; else r_valid <= 0;
endendmodule
//运算公式:
//x(i+1) = x(i) + y(i) * di * 2^(-i)
//y(i+1) = y(i) - x(i) * di * 2^(-i)
//z(i+1) = z(i) + arctan(di * 2^(-i))
//author : 技术小白爱FPGA
//备注:cordic 算法,向量模式,迭代次数固定 16次,可以自己任意设置,最大16次module my_cordic_vec (input i_clk ,input i_rst ,input [4:0] i_iteration_count ,input signed [31:0] i_setx ,input signed [31:0] i_sety ,input signed [31:0] i_set_angle ,input i_valid ,output signed [63:0] o_xmod ,output signed [31:0] o_angle ,output o_valid ,output o_ready );wire signed [31:0] K_p = 39796 ;
wire signed [31:0] r_arctan [0:15];
wire r_di ;reg signed [31:0] r_setx ;
reg signed [31:0] r_sety ;
reg ro_valid ;
reg ro_ready ;
reg signed [63:0] ro_xmod ;
reg signed [31:0] ro_angle ;
reg [4:0] r_count ;
reg r_run_cal ;
reg signed [31:0] r_angle ;//存储 arctan 值,整体表示-----扩大2^16倍数,相当于将小数点定在16bit位置上
assign r_arctan[0] = 2949120 ;
assign r_arctan[1] = 1740967 ;
assign r_arctan[2] = 919879 ;
assign r_arctan[3] = 466945 ;
assign r_arctan[4] = 234378 ;
assign r_arctan[5] = 117303 ;
assign r_arctan[6] = 58666 ;
assign r_arctan[7] = 29334 ;
assign r_arctan[8] = 14667 ;
assign r_arctan[9] = 7333 ;
assign r_arctan[10]= 3666 ;
assign r_arctan[11]= 1833 ;
assign r_arctan[12]= 916 ;
assign r_arctan[13]= 458 ;
assign r_arctan[14]= 229 ;
assign r_arctan[15]= 114 ;//判断旋转的方向
assign r_di = (r_sety > 0 && r_run_cal)?1:0;assign o_xmod = ro_xmod ;
assign o_angle = ro_angle;
assign o_ready = ro_ready;
assign o_valid = ro_valid;//运算迭代 >>> --- > 算数右移,不改变符号位; 如果使用 >> ,移位,高位补0;
always @ (posedge i_clk)
beginif (i_valid) beginr_setx <= i_setx;r_sety <= i_sety;endelse if (r_run_cal && r_di ) beginr_setx <= r_setx + (r_sety >>> r_count);r_sety <= r_sety - (r_setx >>> r_count); end else if (r_run_cal && !r_di) beginr_setx <= r_setx - (r_sety >>> r_count);r_sety <= r_sety + (r_setx >>> r_count); end
end//迭代运算次数
always @ (posedge i_clk or posedge i_rst)
beginif (i_rst) beginr_count <= 0;end else if (r_count == i_iteration_count -1) beginr_count <= 0;endelse if (r_run_cal) beginr_count <= r_count + 1;end
endalways @ (posedge i_clk or negedge i_rst)
beginif (i_rst)r_angle <= 0;else if (i_valid)r_angle <= i_set_angle; else if (r_di && r_run_cal)r_angle <= r_angle + r_arctan[r_count];else if (!r_di && r_run_cal)r_angle <= r_angle - r_arctan[r_count];else r_angle <= r_angle;
end//迭代运算标志
always @ (posedge i_clk or posedge i_rst)
beginif (i_rst) beginr_run_cal <= 0;endelse if (r_count == i_iteration_count -1) beginr_run_cal <= 0; endelse if(i_valid) beginr_run_cal <= 1; endelse beginr_run_cal <= r_run_cal; end
endalways @ (posedge i_clk or posedge i_rst)
beginif (i_rst) beginro_ready <= 1;endelse if (i_valid || r_run_cal) beginro_ready <= 0; end else beginro_ready <= 1;end
end//最终输出的 sin cos valid 信号
always @ (posedge i_clk or posedge i_rst)
beginif (i_rst) ro_valid <= 0;else if (r_count == i_iteration_count -1)ro_valid <= 1; else ro_valid <= 0;
end//最终输出的 xmod angle 值
always @ (posedge i_clk or posedge i_rst)
beginif (i_rst) beginro_xmod <= 0;ro_angle <= 0;endelse if (r_count == i_iteration_count -1) beginro_xmod <= r_setx * K_p;ro_angle <= r_angle; end
endendmodule
module tb_cordic();reg i_clk;
reg i_rst;initial begin i_clk = 0;i_rst = 1;#100@(posedge i_clk)i_rst =0;
endalways #10 i_clk = ~i_clk;test_my_cordic_vec inst_test_my_cordic (.i_clk(i_clk), .i_rst(i_rst));endmodule