1-设计流程
● 了解cordic 算法原理,公式,模式,伸缩因子,旋转方向等,推荐以下链接视频了解 cordic 算法。哔哩哔哩-cordic算法原理讲解
● 用matlab 或者 c 实现一遍算法
● 在FPGA中用 verilog 实现,注意使用有符号变量以及小数点定点化处理
备注:
在verilog 需要用 ram 存储的值:列举了13次迭代的tan值和对应角度;
2-RTL
分享自己写的一个cordic rtl :
2-1 测试代码 ,测试 一二三四象限内角度的sin cos 值。
module test_my_cordic(
input i_clk,
input i_rst
);
reg signed [31:0] r_angle;
reg r_valid ;
wire w_ready;
wire signed [31:0] r_x = 39796;
wire signed [31:0] r_y = 0;
(*dont_touch = "true"*)
my_cordic 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 (r_angle),
.i_valid (r_valid),
.o_sin (),
.o_cos (),
.o_valid (),
.o_ready (w_ready)
);
/* 测试 第四象限 0 ~ -90°
always @ (posedge i_clk or posedge i_rst)
begin
if (i_rst) begin
r_angle <= 0;
end else if (r_angle == -5898240 && w_ready) begin
r_angle <= 0;
end else if (w_ready && r_valid) begin
r_angle <= r_angle - 655360;
end else begin
r_angle <= r_angle;
end
end
*/
// 测试 第一象限 0 ~ 90°
always @ (posedge i_clk or posedge i_rst)
begin
if (i_rst) begin
r_angle <= 0;
end else if (r_angle == 5898240 && w_ready) begin
r_angle <= 0;
end else if (w_ready && r_valid) begin
r_angle <= r_angle + 655360;
end else begin
r_angle <= r_angle;
end
end
/* //测试 第三象限 -180 ~ -90°
always @ (posedge i_clk or posedge i_rst)
begin
if (i_rst) begin
r_angle <= -11796480;
end else if (r_angle == -5898240 && w_ready) begin
r_angle <= -11796480;
end else if (w_ready && r_valid) begin
r_angle <= r_angle + 655360;
end else begin
r_angle <= r_angle;
end
end
*/
/*// 测试 第二象限 90° ~ 180 °
always @ (posedge i_clk or posedge i_rst)
begin
if (i_rst) begin
r_angle <= 5898240;
end else if (r_angle == 11796480 && w_ready) begin
r_angle <= 0;
end else if (w_ready && r_valid) begin
r_angle <= r_angle + 655360;
end else begin
r_angle <= r_angle;
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
2-2 核心代码:
//运算公式:
//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 (
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 [31:0] o_sin ,
output signed [31:0] o_cos ,
output o_valid ,
output o_ready
);
wire signed [31:0] r_arctan [0:15];
wire r_di ;
reg signed [31:0] r_sin;
reg signed [31:0] r_cos;
reg signed [31:0] r_setx ;
reg signed [31:0] r_sety ;
reg signed [31:0] r_angle ;
reg [4:0] r_count;
reg r_run_cal;
reg ro_valid ;
reg ro_ready ;
reg [1:0] r_site;
assign o_sin = r_sin;
assign o_cos = r_cos;
assign o_ready = ro_ready;
assign o_valid = ro_valid;
//存储 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_angle > 0 && r_run_cal)?1:0;
//运算迭代 >>> --- > 算数右移,不改变符号位; 如果使用 >> ,移位,高位补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 )
begin
// 处理 一四象限 -90° ~ 90°
if (i_valid && (i_set_angle >= -5898240 && i_set_angle <= 5898240 ) ) begin
r_angle <= i_set_angle;
r_site <= 2'b00;
// 处理 二象限 90° ~ 180°
end else if (i_valid && (i_set_angle > 5898240 && i_set_angle <= 11796480 )) begin
r_angle <= 11796480 - i_set_angle;
r_site <= 2'b10;
// 处理 三象限 -180° ~ -90°
end else if (i_valid && (i_set_angle >= -11796480 && i_set_angle < -5898240 )) begin
r_angle <= -11796480 - i_set_angle ;
r_site <= 2'b11;
end else if (r_di && r_run_cal) begin
r_angle <= r_angle - r_arctan[r_count];
end
else if (!r_di && r_run_cal) begin
r_angle <= r_angle + r_arctan[r_count];
end else begin
r_angle <= r_angle;
r_site <= r_site ;
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 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
//最终输出的 sin cos 值
always @ (posedge i_clk or posedge i_rst)
begin
if (i_rst) begin
r_sin <= 0;
r_cos <= 0;
end
else if (r_site == 2'b00 && r_count == i_iteration_count -1) begin
r_sin <= r_sety;
r_cos <= r_setx;
end else if (r_site == 2'b10 && r_count == i_iteration_count -1) begin
r_sin <= r_sety;
r_cos <= -r_setx;
end else if (r_site == 2'b11 && r_count == i_iteration_count -1) begin
r_sin <= r_sety;
r_cos <= -r_setx;
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
endmodule
2-3 tb仿真代码
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 inst_test_my_cordic (.i_clk(i_clk), .i_rst(i_rst));
endmodule
3-仿真
a. 首先 有符号的信号需要设置 小数点位数,如下图所示:
b. 以第一象限为例子:0 ~ 90°
c. 运算处理 持续周期 就是 迭代次数:
d. 可借助 计算机科学模式验证结果:
4-可优化空间
● r_ange逻辑级数;
● 360°以内,高于180°和小于-180°处理
● 迭代运算拆成流水线形式;
● 加上向量模式
● 整体其它逻辑的优化