使用verilog 实现cordic 算法 ---- 向量模式
分享个人写的 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)
begin
if (i_rst) begin
r_x <= 65536;
r_y <= 65536;
end else if (w_ready && r_valid) begin
r_x <= r_x + 65536;
r_y <= r_y + 65536;
end else begin
r_x <= r_x;
r_y <= r_y;
end
end */
//测试 tan1 ~ 10 ~
/* always @ (posedge i_clk or posedge i_rst)
begin
if (i_rst) begin
r_x <= 65536;
r_y <= 65536;
end else if (w_ready && r_valid) begin
r_x <= 65536;
r_y <= r_y + 65536;
end else begin
r_x <= r_x;
r_y <= r_y;
end
end */
/* always @ (posedge i_clk or posedge i_rst)
begin
if (i_rst) begin
r_x <= 65536;
r_y <= 65536;
end else if (w_ready && r_valid) begin
r_x <= r_x + 65536;
r_y <= 65536;
end else begin
r_x <= r_x;
r_y <= r_y;
end
end */
// 测试 随机产生的 x、 y值
always @ (posedge i_clk or posedge i_rst)
begin
if (i_rst) begin
r_x <= 65536;
r_y <= 65536;
end else if (w_ready && r_valid) begin
r_x <= {$random} % 3284721; // 取 0~50 以内的数值
r_y <= {$random} % 3284721;
end else begin
r_x <= r_x;
r_y <= r_y;
end
end
always @ (posedge i_clk or posedge i_rst)
begin
if (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;
end
endmodule
//运算公式:
//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)
begin
if (i_valid) begin
r_setx <= i_setx;
r_sety <= i_sety;
end
else if (r_run_cal && r_di ) begin
r_setx <= r_setx + (r_sety >>> r_count);
r_sety <= r_sety - (r_setx >>> r_count);
end else if (r_run_cal && !r_di) begin
r_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)
begin
if (i_rst) begin
r_count <= 0;
end else if (r_count == i_iteration_count -1) begin
r_count <= 0;
end
else if (r_run_cal) begin
r_count <= r_count + 1;
end
end
always @ (posedge i_clk or negedge i_rst)
begin
if (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)
begin
if (i_rst) begin
r_run_cal <= 0;
end
else if (r_count == i_iteration_count -1) begin
r_run_cal <= 0;
end
else if(i_valid) begin
r_run_cal <= 1;
end
else begin
r_run_cal <= r_run_cal;
end
end
always @ (posedge i_clk or posedge i_rst)
begin
if (i_rst) begin
ro_ready <= 1;
end
else if (i_valid || r_run_cal) begin
ro_ready <= 0;
end else begin
ro_ready <= 1;
end
end
//最终输出的 sin cos valid 信号
always @ (posedge i_clk or posedge i_rst)
begin
if (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)
begin
if (i_rst) begin
ro_xmod <= 0;
ro_angle <= 0;
end
else if (r_count == i_iteration_count -1) begin
ro_xmod <= r_setx * K_p;
ro_angle <= r_angle;
end
end
endmodule
module tb_cordic();
reg i_clk;
reg i_rst;
initial begin
i_clk = 0;
i_rst = 1;
#100
@(posedge i_clk)
i_rst =0;
end
always #10 i_clk = ~i_clk;
test_my_cordic_vec inst_test_my_cordic (.i_clk(i_clk), .i_rst(i_rst));
endmodule