迭代七次的CORDIC算法-Verilog实现求解正弦余弦函数
COEDIC.v
module CORDIC #(
parameter DATA_WIDTH = 4'd8 , // we set data width
parameter PIPELINE = 4'd8
)(
input clk ,
input rst_n ,
input [DATA_WIDTH - 1 : 0] phase ,
input ena ,
output reg [DATA_WIDTH - 1 : 0] sin_out ,
output reg [DATA_WIDTH - 1 : 0] cos_out
);
// ------------------------------------------------ \\
// next is define and parameter \\
// -------------------------------------------------\\
reg [DATA_WIDTH - 1 : 0] phase_reg ;
reg [DATA_WIDTH - 1 : 0] X0 ;
reg [DATA_WIDTH - 1 : 0] Y0 ;
reg [DATA_WIDTH - 1 : 0] Z0 ;
wire [DATA_WIDTH - 1 : 0] X1 , Y1 , Z1 ;
wire [DATA_WIDTH - 1 : 0] X2 , Y2 , Z2 ;
wire [DATA_WIDTH - 1 : 0] X3 , Y3 , Z3 ;
wire [DATA_WIDTH - 1 : 0] X4 , Y4 , Z4 ;
wire [DATA_WIDTH - 1 : 0] X5 , Y5 , Z5 ;
wire [DATA_WIDTH - 1 : 0] X6 , Y6 , Z6 ;
wire [DATA_WIDTH - 1 : 0] X7 , Y7 , Z7 ;
reg [1:0] quadrant[PIPELINE : 0] ;
integer i ;
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 0)
for(i = 0 ; i <= PIPELINE ; i=i+1)
quadrant[i] <= 0 ;
else
if(ena == 1)
begin
for(i = 0 ; i <= PIPELINE ; i=i+1)
quadrant[i+1] <= quadrant[i] ;
quadrant[0] <= phase[DATA_WIDTH - 1 : DATA_WIDTH - 2] ;
end
end
// we set a new phase to Unify the phase in the first quadrant
// we set 8'h 0010 0000 => 45度 and 1000 0000 => 180度
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 0)
begin
phase_reg <= 0 ;
end
else if(ena == 1)
begin
case(phase[DATA_WIDTH -1 : DATA_WIDTH -2])
2'b00 :
phase_reg <= phase ;
2'b01 :
phase_reg <= phase - 8'h40 ; // subtract 90
2'b10 :
phase_reg <= phase - 8'h80 ; // subtract 180
2'b11 :
phase_reg <= phase - 8'hC0 ; // subtract 270
default :
;
endcase
end
end
// start to calculate
// we should set x0= 0.607252935 y0= 0 z0
always@(posedge clk or negedge rst_n )
begin
if( rst_n == 0)
begin
X0 <= 0 ;
Y0 <= 0 ;
Z0 <= 0 ;
end
else if(ena == 1 )
begin
X0 <= 8'h4D ;
Y0 <= 0 ;
Z0 <= phase_reg ;
end
end
// next is iteration
INTERATION#(
.DATA_WIDTH ( 4'd8 ),
.shift ( 4'd0 ),
.ANGLE ( 8'h20 )
)u_INTERATION0(
.clk ( clk ),
.rst_n ( rst_n ),
.ena ( ena ),
.X0 ( X0 ),
.Y0 ( Y0 ),
.Z0 ( Z0 ),
.X1 ( X1 ),
.Y1 ( Y1 ),
.Z1 ( Z1 )
);
INTERATION#(
.DATA_WIDTH ( 4'd8 ),
.shift ( 4'd1 ),
.ANGLE ( 8'h12 )
)u_INTERATION1(
.clk ( clk ),
.rst_n ( rst_n ),
.ena ( ena ),
.X0 ( X1 ),
.Y0 ( Y1 ),
.Z0 ( Z1 ),
.X1 ( X2 ),
.Y1 ( Y2 ),
.Z1 ( Z2 )
);
INTERATION#(
.DATA_WIDTH ( 4'd8 ),
.shift ( 4'd2 ),
.ANGLE ( 8'h09 )
)u_INTERATION2(
.clk ( clk ),
.rst_n ( rst_n ),
.ena ( ena ),
.X0 ( X2 ),
.Y0 ( Y2 ),
.Z0 ( Z2 ),
.X1 ( X3 ),
.Y1 ( Y3 ),
.Z1 ( Z3 )
);
INTERATION#(
.DATA_WIDTH ( 4'd8 ),
.shift ( 4'd3 ),
.ANGLE ( 8'h04 )
)u_INTERATION3(
.clk ( clk ),
.rst_n ( rst_n ),
.ena ( ena ),
.X0 ( X3 ),
.Y0 ( Y3 ),
.Z0 ( Z3 ),
.X1 ( X4 ),
.Y1 ( Y4 ),
.Z1 ( Z4 )
);
INTERATION#(
.DATA_WIDTH ( 4'd8 ),
.shift ( 4'd4 ),
.ANGLE ( 8'h02 )
)u_INTERATION4(
.clk ( clk ),
.rst_n ( rst_n ),
.ena ( ena ),
.X0 ( X4 ),
.Y0 ( Y4 ),
.Z0 ( Z4 ),
.X1 ( X5 ),
.Y1 ( Y5 ),
.Z1 ( Z5 )
);
INTERATION#(
.DATA_WIDTH ( 4'd8 ),
.shift ( 4'd5 ),
.ANGLE ( 8'h01 )
)u_INTERATION5(
.clk ( clk ),
.rst_n ( rst_n ),
.ena ( ena ),
.X0 ( X5 ),
.Y0 ( Y5 ),
.Z0 ( Z5 ),
.X1 ( X6 ),
.Y1 ( Y6 ),
.Z1 ( Z6 )
);
INTERATION#(
.DATA_WIDTH ( 4'd8 ),
.shift ( 4'd6 ),
.ANGLE ( 8'h00 )
)u_INTERATION6(
.clk ( clk ),
.rst_n ( rst_n ),
.ena ( ena ),
.X0 ( X6 ),
.Y0 ( Y6 ),
.Z0 ( Z6 ),
.X1 ( X7 ),
.Y1 ( Y7 ),
.Z1 ( Z7 )
);
// The results of different phases are also different
// phase[DATA_WIDTH -1 : DATA_WIDTH -2]
// 00 first quadrant
// 01 second quadrant
// 10 third quadrant
// 11 Fourth Quadrant
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 0)
begin
cos_out <= 0 ;
sin_out <= 0 ;
end
else if( ena == 1)
begin
case(quadrant[7])
2'b00 :
begin
cos_out <= X6 ;
sin_out <= Y6 ;
end
2'b01 :
begin
cos_out <= ~(Y6) + 1 ;
sin_out <= X6 ;
end
2'b10 :
begin
cos_out <= ~(X6) + 1 ;
sin_out <= ~(Y6) + 1 ;
end
2'b11 :
begin
cos_out <= Y6 ;
sin_out <= ~(X6) + 1 ;
end
default:
;
endcase
end
end
endmodule
Interation.v
module INTERATION #(
parameter DATA_WIDTH = 4'd8 ,
parameter shift = 4'd0 ,
parameter ANGLE = 8'h20
)(
input clk ,
input rst_n ,
input ena ,
input [DATA_WIDTH - 1 : 0] X0 ,
input [DATA_WIDTH - 1 : 0] Y0 ,
input [DATA_WIDTH - 1 : 0] Z0 ,
output reg [DATA_WIDTH - 1 : 0] X1 ,
output reg [DATA_WIDTH - 1 : 0] Y1 ,
output reg [DATA_WIDTH - 1 : 0] Z1
);
always@(posedge clk or negedge rst_n)
begin
if( rst_n == 0)
begin
X1 <= 0 ;
Y1 <= 0 ;
Z1 <= 0 ;
end
else if( ena == 1)
begin
if(Z0[DATA_WIDTH - 1] == 0 )
begin
X1 <= X0 - {{shift{ Y0[DATA_WIDTH - 1] }} ,Y0[DATA_WIDTH - 1 : shift] } ;
Y1 <= Y0 + {{shift{ X0[DATA_WIDTH - 1] }} ,X0[DATA_WIDTH - 1 : shift] } ;
Z1 <= Z0 - ANGLE ;
end
else if(Z0[DATA_WIDTH - 1] == 1 )
begin
X1 <= X0 + {{shift{ Y0[DATA_WIDTH - 1 ] }} ,Y0[DATA_WIDTH - 1 : shift] } ;
Y1 <= Y0 - {{shift{ X0[DATA_WIDTH - 1 ] }} ,X0[DATA_WIDTH - 1 : shift] } ;
Z1 <= Z0 + ANGLE ;
end
end
end
endmodule
cordic_tb.v
module cordic_tb #(
parameter DATA_WIDTH = 4'd8
);
reg clk ;
reg rst_n ;
reg [DATA_WIDTH - 1 : 0] phase ;
reg ena ;
wire [DATA_WIDTH - 1 : 0] sin_out ;
wire [DATA_WIDTH - 1 : 0] cos_out ;
CORDIC#(
.DATA_WIDTH ( DATA_WIDTH )
)u_CORDIC(
.clk ( clk ),
.rst_n ( rst_n ),
.phase ( phase ),
.ena ( ena ),
.sin_out ( sin_out ),
.cos_out ( cos_out )
);
always #5 clk = ~clk ;
initial
begin
clk = 0 ;
rst_n = 0 ;
ena = 1 ;
phase = 8'h00 ;
#10
rst_n = 1 ;
end
always #10
phase = phase + 1 ;
endmodule
README.md
# 本文参考自 西电的verilog 课程实验 还有网上的 CORDIC算法详解
对于CORDIC的算法 关键是学会迭代和 掌握自 不同象限角度的换算
我在参阅网上资料的时候 发现有些角度的换算存在了错误这里我再写入一下
| 第一象限 | 第二象限 | 第三象限 | 第四象限 |
| --------| --------| --------| --------|
| (x,y) | (x,y) | (x,y) | (x,y) |
| (x,y) | (-y,x) | (-x ,-y) | (y , -x) |
最关键的是在于理清如何计算的 实际操作起来的 圆周旋转求旋转模式下的正余弦
并不用考虑太多的 角度旋转 选取初始值之后 直接迭代开干
## 波形很奇怪 我也不懂为什么做不到像其他人的这么顺滑 但是应该没错吧
纠正一下 把进制改成 Signed Decimal 就可以得到顺滑的常规正弦函数波形