CORDIC算法原理详解及其Verilog实现

CORDIC算法原理详解及其Verilog实现

  • CORDIC简介
  • 算法实现
    • 1. 已 知 坐 标 ( x , y ) , 求 其 向 量 对 应 的 相 角 θ ( 反 正 切 ) 和 模 值 \color{#F00}{1.已知坐标(x,y),求其向量对应的相角θ(反正切)和模值} 1.(x,y)θ
      • `1.1 MATLAB代码`
      • `1.2 Verilog代码`
      • `1.3 testbench A`
    • 2. 已 知 角 度 θ , 求 正 弦 s i n θ 和 余 弦 c o s θ \color{#F00}{2.已知角度θ,求正弦sinθ和余弦cosθ} 2.θsinθcosθ
      • `2.1 MATLAB代码`
      • `2.2 Verilog代码`
      • `2.3 Testbench B`

本文的verilog代码
链接:https://pan.baidu.com/s/1GGbRjxO5CxoIODQAg1l6Lw
提取码:jo0h

CORDIC简介

CORDIC(Coordinate Rotation Digital Computer)坐标旋转数字计算机,是数学与计算机技术交叉产生的一种机器算法,用于解决计算机的数学计算问题。发展到现在,CORDIC算法及其扩展算法大致有三种计算模式:圆周旋转模式、线性旋转模式和双曲线旋转模式,分别用来实现不同的数学运算。本文介绍圆周旋转模式下的CORDIC算法原理及实现过程,另两种模式将分期介绍。

简单来讲,CORDIC利用近似逼近的思想,将计算机中三角函数、开根号、求对数等复杂运算,转化为简单的加减和移位操作。

1)算法描述
CORDIC算法原理详解及其Verilog实现_第1张图片
如图,XY平面中一点 ( x 1 , y 1 ) (x_{1},y_{1}) (x1,y1)经圆周旋转θ角度,得到点 ( x 2 , y 2 ) (x_{2},y_{2}) (x2,y2)。经简单的三角函数关系,可得到:

x 2 = x 1 c o s θ − y 1 s i n θ x_{2} = x_{1}cos\theta - y_{1}sin\theta x2=x1cosθy1sinθ
y 2 = x 1 s i n θ + y 1 c o s θ y_{2} = x_{1}sin\theta + y_{1}cos\theta y2=x1sinθ+y1cosθ

通过提出因数cosθ,可得:
x 2 = x 1 c o s θ − y 1 s i n θ = c o s θ ( x 1 − y 1 t a n θ ) x_{2} = x_{1}cos\theta - y_{1}sin\theta = cos\theta(x_{1}-y_{1}tan\theta) x2=x1cosθy1sinθ=cosθ(x1y1tanθ)
y 2 = x 1 s i n θ + y 1 c o s θ = c o s θ ( y 1 + x 1 t a n θ ) y_{2} = x_{1}sin\theta + y_{1}cos\theta = cos\theta(y_{1} + x_{1}tan\theta) y2=x1sinθ+y1cosθ=cosθ(y1+x1tanθ)

如果不考虑cosθ,得到“伪旋转”方程:
x 2 ^ = c o s θ ( x 1 − y 1 t a n θ ) = x 1 − y 1 t a n θ \hat{x_{2}} = \cancel{cos\theta}(x_{1}-y_{1}tan\theta)=x_{1}-y_{1}tan\theta x2^=cosθ (x1y1tanθ)=x1y1tanθ
y 2 ^ = c o s θ ( y 1 + x 1 t a n θ ) = y 1 + x 1 t a n θ \hat{y_{2}} = \cancel{cos\theta}(y_{1} + x_{1}tan\theta)=y_{1} + x_{1}tan\theta y2^=cosθ (y1+x1tanθ)=y1+x1tanθ

伪旋转仅实现了正确的角度旋转,但向量模值变为原来的1/cosθ。

2)CORDIC方法

若使得 t a n θ = 2 − i tanθ = 2^{-i} tanθ=2i i i i为自然数,则上式变为:
x 2 ^ = x 1 − y 1 t a n θ = x 1 − y 1 2 − i \hat{x_{2}} = x_{1} - y_{1}tan\theta = x_{1}-y_{1}2^{-i} x2^=x1y1tanθ=x1y12i
y 2 ^ = y 1 + x 1 t a n θ = y 1 + x 1 2 − i \hat{y_{2}} = y_{1} + x_{1}tan\theta = y_{1} + x_{1}2^{-i} y2^=y1+x1tanθ=y1+x12i

注意!上式已经仅剩加减和移位运算。

如果我们把所有 t a n θ = 2 − i tanθ = 2^{-i} tanθ=2i对应的相关角度和正切值制成一张表,如下所示:
CORDIC算法原理详解及其Verilog实现_第2张图片

可以确定的是,任意旋转角度θ,都可以由上表中的大小不同 θ i θ_{i} θi进行多次旋转得到。CORDIC正是利用这一点,将θ角度的旋转分解为从大到小、逐次逼近真实旋转角度的一组旋转,而这些旋转的实现又都可以由加减和移位运算来完成。θi可以预先制成表格,供计算机查找使用。

算法实现

1. 已 知 坐 标 ( x , y ) , 求 其 向 量 对 应 的 相 角 θ ( 反 正 切 ) 和 模 值 \color{#F00}{1.已知坐标(x,y),求其向量对应的相角θ(反正切)和模值} 1.(x,y)θ

思想:把原向量逐次向X正轴进行伪旋转逼近,整个过程的累计旋转角度即为θ,而旋转后的x坐标补偿模值增益K后即为原向量模值。

每次迭代的方程为:
x ( i + 1 ) = x ( i ) − d i ( 2 − i y ( i ) ) x^{(i+1)} = x^{(i)}-d_{i}(2^{-i}y^{(i)}) x(i+1)=x(i)di(2iy(i))
y ( i + 1 ) = y ( i ) − d i ( 2 − i x ( i ) ) y^{(i+1)} = y^{(i)}-d_{i}(2^{-i}x^{(i)}) y(i+1)=y(i)di(2ix(i))

模值总增益K为:

z ( i + 1 ) = z ( i ) − d i θ i z^{(i+1)} = z^{(i)}-d_{i}\theta^{i} z(i+1)=z(i)diθi

其中d决定旋转方向为逆时针还是顺时针,z为角度累加值。

注意!查找表中所有θi的总和约为99度,因此能实现计算的角度在-99~99度之间。实际算法实现时,我们可预先判断坐标象限,人为将其转化为第一象限内的计算,并在事后补偿为真实值。

1.1 MATLAB代码

%% ***********************************************************************************
%     已知坐标,用cordic算法计算相角和幅值。基本公式如下:
%     x(k+1) = x(k) - d(k)*y(k)*2^(-k)
%     y(k+1) = y(k) + d(k)*x(k)*2^(-k)
%     z(k) = z(k) - d(k)*actan(2^(-k))
%% ***********************************************************************************

clear;close all;clc;
% 初始化----------------------------------------
N = 16;  %迭代次数
tan_table = 2.^-(0 : N-1);
angle_LUT = atan(tan_table);

K = 1;
for k = 0 : N-1
    K = K*(1/sqrt(1 + 2^(-2*k)));
end

x = 3;
y = sqrt(3);
angle_accumulate = 0;

% cordic算法计算-------------------------------
if (x==0 && y==0) 
    radian_out = 0;
    amplitude_out = 0;
else  % 先做象限判断,得到相位补偿值
    if (x > 0)
        phase_shift = 0;
    elseif (y < 0)
        phase_shift = -pi;
    else
        phase_shift = pi;
    end
  
    for k = 0 : N-1   % 迭代开始
        x_temp = x;
        if (y < 0)  % d(k)=1,逆时针旋转
            x = x_temp - y*2^(-k);
            y = y + x_temp*2^(-k);
            angle_accumulate = angle_accumulate - angle_LUT(k+1);
        else          % d(k)=-1,顺时针旋转
            x = x_temp + y*2^(-k);
            y = y - x_temp*2^(-k);
            angle_accumulate = angle_accumulate + angle_LUT(k+1);
        end     
        radian_out = angle_accumulate + phase_shift; %弧度输出
    end
    
    amplitude_out = x*K;  %幅值输出
end
    
angle_out = radian_out*180/pi;  %相角输出</span>

1.2 Verilog代码

采用16级流水的Verilog (未考虑象限问题)

//*********************************************************
//功能1:已知角度θ,求正弦sinθ和余弦cosθ

//思想:若向量模值为1,则其x坐标就是余弦值,y坐标就是正弦值。
//利用这一点,从(K,0)处迭代旋转至θ处的单位矢量即可。
//*********************************************************


module cordic_A(
input 			clk,
input 			rst_n,
input	[8:0]	angle,
input			start,

output 	reg signed[31:0]	Sin,
output 	reg signed[31:0]	Cos,
output 			finished

);

parameter angle_0 = 32'd2949120;		//45度*2^16
parameter angle_1 = 32'd1740992;     //26.5651度*2^16
parameter angle_2 = 32'd919872;      //14.0362度*2^16
parameter angle_3 = 32'd466944;      //7.1250度*2^16
parameter angle_4 = 32'd234368;      //3.5763度*2^16
parameter angle_5 = 32'd117312;     //1.7899度*2^16
parameter angle_6 = 32'd58688;      //0.8952度*2^16
parameter angle_7 = 32'd29312;      //0.4476度*2^16
parameter angle_8 = 32'd14656;      //0.2238度*2^16
parameter angle_9 = 32'd7360;      //0.1119度*2^16
parameter angle_10 = 32'd3648;      //0.0560度*2^16
parameter angle_11 = 32'd1856;	    //0.0280度*2^16
parameter angle_12 = 32'd896;      //0.0140度*2^16
parameter angle_13 = 32'd448;      //0.0070度*2^16
parameter angle_14 = 32'd256;      //0.0035度*2^16
parameter angle_15 = 32'd128;      //0.0018度*2^16

parameter pipeline = 16;
parameter K = 32'h09b74;			//0.607253*2^16,

// reg signed [31:0] Sin;
// reg signed [31:0] Cos;

reg signed 	[31:0] 		x0 =0,y0 =0,z0 =0;
reg signed 	[31:0] 		x1 =0,y1 =0,z1 =0;
reg signed 	[31:0] 		x2 =0,y2 =0,z2 =0;
reg signed 	[31:0] 		x3 =0,y3 =0,z3 =0;
reg signed 	[31:0] 		x4 =0,y4 =0,z4 =0;
reg signed 	[31:0] 		x5 =0,y5 =0,z5 =0;
reg signed 	[31:0] 		x6 =0,y6 =0,z6 =0;
reg signed 	[31:0] 		x7 =0,y7 =0,z7 =0;
reg signed 	[31:0] 		x8 =0,y8 =0,z8 =0;
reg signed 	[31:0] 		x9 =0,y9 =0,z9 =0;
reg signed 	[31:0] 		x10=0,y10=0,z10=0;
reg signed 	[31:0] 		x11=0,y11=0,z11=0;
reg signed 	[31:0] 		x12=0,y12=0,z12=0;
reg signed 	[31:0] 		x13=0,y13=0,z13=0;
reg signed 	[31:0] 		x14=0,y14=0,z14=0;
reg signed 	[31:0] 		x15=0,y15=0,z15=0;
reg signed 	[31:0] 		x16=0,y16=0,z16=0;

reg  [4:0]           count;

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		count <= 'b0;
	else if(start)begin
		if(count != 5'd18)
			count <= count + 1'b1;
		else 
			count <= count;
	end
end

assign finished = (count == 5'd18)?1'b1:1'b0;

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		x0 <= 'b0;
		y0 <= 'b0;
		z0 <= 'b0;

	end
	
	else begin
		x0 <= K;
		y0 <= 32'd0;
		z0 <= angle << 16;
	end
end 

always@(posedge clk or negedge rst_n)begin//第一次迭代
	if(!rst_n)begin
		x1 <= 'b0;
		y1 <= 'b0;
		z1 <= 'b0;
	end
	else if(z0[31]) begin
		x1 <= x0 + y0;
		y1 <= y0 - x0;
		z1 <= z0 + angle_0;
	end
	else begin
		x1 <= x0 - y0;
		y1 <= y0 + x0;
		z1 <= z0 - angle_0;		
	end
end 

always@(posedge clk or negedge rst_n)begin//第二次迭代
	if(!rst_n)begin
		x2 <= 'b0;
		y2 <= 'b0;
		z2 <= 'b0;
	end
	else if(z1[31]) begin
		x2 <= x1 + (y1>>>1);
		y2 <= y1 - (x1>>>1);
		z2 <= z1 + angle_1;
	end
	else begin
		x2 <= x1 - (y1>>>1);
		y2 <= y1 + (x1>>>1);
		z2 <= z1 - angle_1;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第3次迭代
	if(!rst_n)begin
		x3 <= 'b0;
		y3 <= 'b0;
		z3 <= 'b0;
	end
	else if(z2[31]) begin
		x3 <= x2 + (y2>>>2);
		y3 <= y2 - (x2>>>2);
		z3 <= z2 + angle_2;
	end
	else begin
		x3 <= x2 - (y2>>>2);
		y3 <= y2 + (x2>>>2);
		z3 <= z2 - angle_2;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第4次迭代
	if(!rst_n)begin
		x4 <= 'b0;
		y4 <= 'b0;
		z4 <= 'b0;
	end
	else if(z3[31]) begin
		x4 <= x3 + (y3>>>3);
		y4 <= y3 - (x3>>>3);
		z4 <= z3 + angle_3;
	end
	else begin
		x4 <= x3 - (y3>>>3);
		y4 <= y3 + (x3>>>3);
		z4 <= z3 - angle_3;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第5次迭代
	if(!rst_n)begin
		x5 <= 'b0;
		y5 <= 'b0;
		z5 <= 'b0;
	end
	else if(z4[31]) begin
		x5 <= x4 + (y4>>>4);
		y5 <= y4 - (x4>>>4);
		z5 <= z4 + angle_4;
	end
	else begin
		x5 <= x4 - (y4>>>4);
		y5 <= y4 + (x4>>>4);
		z5 <= z4 - angle_4;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第6次迭代
	if(!rst_n)begin
		x6 <= 'b0;
		y6 <= 'b0;
		z6 <= 'b0;
	end
	else if(z5[31]) begin
		x6 <= x5 + (y5>>>5);
		y6 <= y5 - (x5>>>5);
		z6 <= z5 + angle_5;
	end
	else begin
		x6 <= x5 - (y5>>>5);
		y6 <= y5 + (x5>>>5);
		z6 <= z5 - angle_5;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第7次迭代
	if(!rst_n)begin
		x7 <= 'b0;
		y7 <= 'b0;
		z7 <= 'b0;
	end
	else if(z6[31]) begin
		x7 <= x6 + (y6>>>6);
		y7 <= y6 - (x6>>>6);
		z7 <= z6 + angle_6;
	end
	else begin
		x7 <= x6 - (y6>>>6);
		y7 <= y6 + (x6>>>6);
		z7 <= z6 - angle_6;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第8次迭代
	if(!rst_n)begin
		x8 <= 'b0;
		y8 <= 'b0;
		z8 <= 'b0;
	end
	else if(z7[31]) begin
		x8 <= x7 + (y7>>>7);
		y8 <= y7 - (x7>>>7);
		z8 <= z7 + angle_7;
	end
	else begin
		x8 <= x7 - (y7>>>7);
		y8 <= y7 + (x7>>>7);
		z8 <= z7 - angle_7;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第9次迭代
	if(!rst_n)begin
		x9 <= 'b0;
		y9 <= 'b0;
		z9 <= 'b0;
	end
	else if(z8[31]) begin
		x9 <= x8 + (y8>>>8);
		y9 <= y8 - (x8>>>8);
		z9 <= z8 + angle_8;
	end
	else begin
		x9 <= x8 - (y8>>>8);
		y9 <= y8 + (x8>>>8);
		z9 <= z8 - angle_8;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第10次迭代
	if(!rst_n)begin
		x10 <= 'b0;
		y10 <= 'b0;
		z10 <= 'b0;
	end
	else if(z9[31]) begin
		x10 <= x9 + (y9>>>9);
		y10 <= y9 - (x9>>>9);
		z10 <= z9 + angle_9;
	end
	else begin
		x10 <= x9 - (y9>>>9);
		y10 <= y9 + (x9>>>9);
		z10 <= z9 - angle_9;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第11次迭代
	if(!rst_n)begin
		x11 <= 'b0;
		y11 <= 'b0;
		z11 <= 'b0;
	end
	else if(z10[31]) begin
		x11 <= x10 + (y10>>>10);
		y11 <= y10 - (x10>>>10);
		z11 <= z10 + angle_10;
	end
	else begin
		x11 <= x10 - (y10>>>10);
		y11 <= y10 + (x10>>>10);
		z11 <= z10 - angle_10;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第12次迭代
	if(!rst_n)begin
		x12 <= 'b0;
		y12 <= 'b0;
		z12 <= 'b0;
	end
	else if(z11[31]) begin
		x12 <= x11 + (y11>>>11);
		y12 <= y11 - (x11>>>11);
		z12 <= z11 + angle_11;
	end
	else begin
		x12 <= x11 - (y11>>>11);
		y12 <= y11 + (x11>>>11);
		z12 <= z11 - angle_11;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第13次迭代
	if(!rst_n)begin
		x13 <= 'b0;
		y13 <= 'b0;
		z13 <= 'b0;
	end
	else if(z12[31]) begin
		x13 <= x12 + (y12>>>12);
		y13 <= y12 - (x12>>>12);
		z13 <= z12 + angle_12;
	end
	else begin
		x13 <= x12 - (y12>>>12);
		y13 <= y12 + (x12>>>12);
		z13 <= z12 - angle_12;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第14次迭代
	if(!rst_n)begin
		x14 <= 'b0;
		y14 <= 'b0;
		z14 <= 'b0;
	end
	else if(z13[31]) begin
		x14 <= x13 + (y13>>>13);
		y14 <= y13 - (x13>>>13);
		z14 <= z13 + angle_13;
	end
	else begin
		x14 <= x13 - (y13>>>13);
		y14 <= y13 + (x13>>>13);
		z14 <= z13 - angle_13;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第15次迭代
	if(!rst_n)begin
		x15 <= 'b0;
		y15 <= 'b0;
		z15 <= 'b0;
	end
	else if(z14[31]) begin
		x15 <= x14 + (y14>>>14);
		y15 <= y14 - (x14>>>14);
		z15 <= z14 + angle_14;
	end
	else begin
		x15 <= x14 - (y14>>>14);
		y15 <= y14 + (x14>>>14);
		z15 <= z14 - angle_14;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第16次迭代
	if(!rst_n)begin
		x16 <= 'b0;
		y16 <= 'b0;
		z16 <= 'b0;
	end
	else if(z15[31]) begin
		x16 <= x15 + (y15>>>15);
		y16 <= y15 - (x15>>>15);
		z16 <= z15 + angle_15;
	end
	else begin
		x16 <= x15 - (y15>>>15);
		y16 <= y15 + (x15>>>15);
		z16 <= z15 - angle_15;	
	end
end 

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		Cos <= 'b0;
		Sin <= 'b0;
	end
	else begin
        Sin = y16;
        Cos = x16;
	end
end 

endmodule

1.3 testbench A

输入连续5个时钟上升沿输入60°,30°,45°,90°,30°,看是否能够连续输出相应结果。

`timescale 1ns/1ps

module cordic_Atb();

parameter PERIOD = 10;
reg clk;
reg rst_n;
reg [8:0]angle;
reg start;

wire 	 [31:0] 		Sin;
wire 	 [31:0] 		Cos;
wire 					finished;

initial begin
	clk = 0;
	rst_n = 0;
	start = 0;
	angle = 'b0;

	#100 rst_n =1;
			
	#10 @(posedge clk) start = 1'b1;angle = 9'd60;
	#10 @(posedge clk) 				angle = 9'd30;

	
	#10 @(posedge clk) 				angle = 9'd45;
	#10 @(posedge clk) 				angle = 9'd90;
	#10 @(posedge clk) 				angle = 9'd30;
	
	#100000 $stop;	
end

always #(PERIOD/2) clk = ~clk;

cordic_A inst1(
		.clk(clk),
		.rst_n(rst_n),
		.angle(angle),
		.start(start),
		
		.Sin(Sin),
		.Cos(Cos),
		.finished(finished)
		
);

endmodule

相应仿真波形如图所示:
CORDIC算法原理详解及其Verilog实现_第3张图片
由于硬件实现将数据整体左移16位,从而换区更高精度,因此得到的结果需要向右移16位,进行还原。还原后我们发现跟预期的值相等。

2. 已 知 角 度 θ , 求 正 弦 s i n θ 和 余 弦 c o s θ \color{#F00}{2.已知角度θ,求正弦sinθ和余弦cosθ} 2.θsinθcosθ

思想:若向量模值为1,则其x坐标就是余弦值,y坐标就是正弦值。利用这一点,从(K,0)处迭代旋转至θ处的单位矢量即可。

迭代方程及K的计算同第一小节。同时也要注意预先对象限的判断和补偿。

2.1 MATLAB代码

%% ***********************************************************************************
%     已知相角theta,计算其正弦和余弦值。基本公式如下:
%     x(k+1) = x(k) - d(k)*y(k)*2^(-k)
%     y(k+1) = y(k) + d(k)*x(k)*2^(-k)
%     z(k) = z(k) - d(k)*actan(2^(-k))
%% ***********************************************************************************
clear;close all;clc;

% 初始化----------------------------------------
N = 16;  %迭代次数
tan_table = 2.^-(0 : N-1);
angle_LUT = atan(tan_table);

K = 1;
for k = 0 : N-1
    K = K*(1/sqrt(1 + 2^(-2*k)));
end

theta = -90;
x = 1;
y = 0;
phase_accumulate = theta/180*pi;  %转化为弧度

% cordic算法计算-------------------------------
if (phase_accumulate > pi/2)  % 先做象限判断,得到相位补偿值
    phase_accumulate = phase_accumulate - pi;
    sign_x = -1;
    sign_y = -1;
elseif (phase_accumulate < -pi/2)
    phase_accumulate = phase_accumulate + pi;
    sign_x = -1;
    sign_y = -1;
else
    sign_x = 1;
    sign_y = 1;
end
     
 for k = 0 : N-1   % 迭代开始
        x_temp = x;
        if (phase_accumulate > 0)  % d(k)=1,逆时针旋转
            x = x_temp - y*2^(-k);
            y = y + x_temp*2^(-k);
            phase_accumulate = phase_accumulate - angle_LUT(k+1);
        else                                     % d(k)=-1,顺时针旋转
            x = x_temp + y*2^(-k);
            y = y - x_temp*2^(-k);
            phase_accumulate = phase_accumulate + angle_LUT(k+1);
        end
end
    
cos_out = sign_x*x*K;  %余弦输出
sin_out = sign_y*y*K;   %正弦输出</span>

2.2 Verilog代码

16级流水的Verilog代码如下:

//*********************************************************
//已知坐标(x,y),求其向量对应的相角θ(反正切)和模值

//思想:把原向量逐次向X正轴进行伪旋转逼近.
//整个过程的累计旋转角度即为θ,
//而旋转后的x坐标补偿模值增益K后即为原向量模值。
//*********************************************************

module cordic_B(
input 						clk,
input 						rst_n,
input	signed [31:0]		x,
input	signed [31:0]		y,
input						start,
output 	reg signed[31:0]	angle,
output 	reg signed[31:0]	mozhi,
output						finished
);

parameter angle_0 = 32'd2949120;		//45度*2^16
parameter angle_1 = 32'd1740992;     //26.5651度*2^16
parameter angle_2 = 32'd919872;      //14.0362度*2^16
parameter angle_3 = 32'd466944;      //7.1250度*2^16
parameter angle_4 = 32'd234368;      //3.5763度*2^16
parameter angle_5 = 32'd117312;     //1.7899度*2^16
parameter angle_6 = 32'd58688;      //0.8952度*2^16
parameter angle_7 = 32'd29312;      //0.4476度*2^16
parameter angle_8 = 32'd14656;      //0.2238度*2^16
parameter angle_9 = 32'd7360;      //0.1119度*2^16
parameter angle_10 = 32'd3648;      //0.0560度*2^16
parameter angle_11 = 32'd1856;	    //0.0280度*2^16
parameter angle_12 = 32'd896;      //0.0140度*2^16
parameter angle_13 = 32'd448;      //0.0070度*2^16
parameter angle_14 = 32'd256;      //0.0035度*2^16
parameter angle_15 = 32'd128;      //0.0018度*2^16

parameter pipeline = 16;
parameter K = 32'h09b74;			//0.607253*2^16,

// reg signed [31:0] Sin;
// reg signed [31:0] Cos;

reg signed 	[31:0] 		x0 =0,y0 =0,z0 =0;
reg signed 	[31:0] 		x1 =0,y1 =0,z1 =0;
reg signed 	[31:0] 		x2 =0,y2 =0,z2 =0;
reg signed 	[31:0] 		x3 =0,y3 =0,z3 =0;
reg signed 	[31:0] 		x4 =0,y4 =0,z4 =0;
reg signed 	[31:0] 		x5 =0,y5 =0,z5 =0;
reg signed 	[31:0] 		x6 =0,y6 =0,z6 =0;
reg signed 	[31:0] 		x7 =0,y7 =0,z7 =0;
reg signed 	[31:0] 		x8 =0,y8 =0,z8 =0;
reg signed 	[31:0] 		x9 =0,y9 =0,z9 =0;
reg signed 	[31:0] 		x10=0,y10=0,z10=0;
reg signed 	[31:0] 		x11=0,y11=0,z11=0;
reg signed 	[31:0] 		x12=0,y12=0,z12=0;
reg signed 	[31:0] 		x13=0,y13=0,z13=0;
reg signed 	[31:0] 		x14=0,y14=0,z14=0;
reg signed 	[31:0] 		x15=0,y15=0,z15=0;
reg signed 	[31:0] 		x16=0,y16=0,z16=0;

reg  [4:0]           count;

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		count <= 'b0;
	else if(start)begin
		if(count != 5'd18)
			count <= count + 1'b1;
		else 
			count <= count;
	end
end

assign finished = (count == 5'd18)?1'b1:1'b0;

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		x0 <= 'b0;
		y0 <= 'b0;
		z0 <= 'b0;

	end
	
	else begin
		x0 <= x<<<16;
		y0 <= y<<<16;
		z0 <= 'b0;
	end
end 

always@(posedge clk or negedge rst_n)begin//第一次迭代
	if(!rst_n)begin
		x1 <= 'b0;
		y1 <= 'b0;
		z1 <= 'b0;
	end
	else if(!y0[31]) begin					//和A不同的是,每次判断y坐标的正负,从而决定是顺时针还是逆时针旋转。
		x1 <= x0 + y0;
		y1 <= y0 - x0;
		z1 <= z0 + angle_0;
	end
	else begin
		x1 <= x0 - y0;
		y1 <= y0 + x0;
		z1 <= z0 - angle_0;		
	end
end 

always@(posedge clk or negedge rst_n)begin//第二次迭代
	if(!rst_n)begin
		x2 <= 'b0;
		y2 <= 'b0;
		z2 <= 'b0;
	end
	else if(!y1[31]) begin
		x2 <= x1 + (y1>>>1);
		y2 <= y1 - (x1>>>1);
		z2 <= z1 + angle_1;
	end
	else begin
		x2 <= x1 - (y1>>>1);
		y2 <= y1 + (x1>>>1);
		z2 <= z1 - angle_1;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第3次迭代
	if(!rst_n)begin
		x3 <= 'b0;
		y3 <= 'b0;
		z3 <= 'b0;
	end
	else if(!y2[31]) begin
		x3 <= x2 + (y2>>>2);
		y3 <= y2 - (x2>>>2);
		z3 <= z2 + angle_2;
	end
	else begin
		x3 <= x2 - (y2>>>2);
		y3 <= y2 + (x2>>>2);
		z3 <= z2 - angle_2;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第4次迭代
	if(!rst_n)begin
		x4 <= 'b0;
		y4 <= 'b0;
		z4 <= 'b0;
	end
	else if(!y3[31]) begin
		x4 <= x3 + (y3>>>3);
		y4 <= y3 - (x3>>>3);
		z4 <= z3 + angle_3;
	end
	else begin
		x4 <= x3 - (y3>>>3);
		y4 <= y3 + (x3>>>3);
		z4 <= z3 - angle_3;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第5次迭代
	if(!rst_n)begin
		x5 <= 'b0;
		y5 <= 'b0;
		z5 <= 'b0;
	end
	else if(!y4[31]) begin
		x5 <= x4 + (y4>>>4);
		y5 <= y4 - (x4>>>4);
		z5 <= z4 + angle_4;
	end
	else begin
		x5 <= x4 - (y4>>>4);
		y5 <= y4 + (x4>>>4);
		z5 <= z4 - angle_4;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第6次迭代
	if(!rst_n)begin
		x6 <= 'b0;
		y6 <= 'b0;
		z6 <= 'b0;
	end
	else if(!y5[31]) begin
		x6 <= x5 + (y5>>>5);
		y6 <= y5 - (x5>>>5);
		z6 <= z5 + angle_5;
	end
	else begin
		x6 <= x5 - (y5>>>5);
		y6 <= y5 + (x5>>>5);
		z6 <= z5 - angle_5;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第7次迭代
	if(!rst_n)begin
		x7 <= 'b0;
		y7 <= 'b0;
		z7 <= 'b0;
	end
	else if(!y6[31]) begin
		x7 <= x6 + (y6>>>6);
		y7 <= y6 - (x6>>>6);
		z7 <= z6 + angle_6;
	end
	else begin
		x7 <= x6 - (y6>>>6);
		y7 <= y6 + (x6>>>6);
		z7 <= z6 - angle_6;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第8次迭代
	if(!rst_n)begin
		x8 <= 'b0;
		y8 <= 'b0;
		z8 <= 'b0;
	end
	else if(!y7[31]) begin
		x8 <= x7 + (y7>>>7);
		y8 <= y7 - (x7>>>7);
		z8 <= z7 + angle_7;
	end
	else begin
		x8 <= x7 - (y7>>>7);
		y8 <= y7 + (x7>>>7);
		z8 <= z7 - angle_7;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第9次迭代
	if(!rst_n)begin
		x9 <= 'b0;
		y9 <= 'b0;
		z9 <= 'b0;
	end
	else if(!y8[31]) begin
		x9 <= x8 + (y8>>>8);
		y9 <= y8 - (x8>>>8);
		z9 <= z8 + angle_8;
	end
	else begin
		x9 <= x8 - (y8>>>8);
		y9 <= y8 + (x8>>>8);
		z9 <= z8 - angle_8;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第10次迭代
	if(!rst_n)begin
		x10 <= 'b0;
		y10 <= 'b0;
		z10 <= 'b0;
	end
	else if(!y9[31]) begin
		x10 <= x9 + (y9>>>9);
		y10 <= y9 - (x9>>>9);
		z10 <= z9 + angle_9;
	end
	else begin
		x10 <= x9 - (y9>>>9);
		y10 <= y9 + (x9>>>9);
		z10 <= z9 - angle_9;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第11次迭代
	if(!rst_n)begin
		x11 <= 'b0;
		y11 <= 'b0;
		z11 <= 'b0;
	end
	else if(!y10[31]) begin
		x11 <= x10 + (y10>>>10);
		y11 <= y10 - (x10>>>10);
		z11 <= z10 + angle_10;
	end
	else begin
		x11 <= x10 - (y10>>>10);
		y11 <= y10 + (x10>>>10);
		z11 <= z10 - angle_10;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第12次迭代
	if(!rst_n)begin
		x12 <= 'b0;
		y12 <= 'b0;
		z12 <= 'b0;
	end
	else if(!y11[31]) begin
		x12 <= x11 + (y11>>>11);
		y12 <= y11 - (x11>>>11);
		z12 <= z11 + angle_11;
	end
	else begin
		x12 <= x11 - (y11>>>11);
		y12 <= y11 + (x11>>>11);
		z12 <= z11 - angle_11;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第13次迭代
	if(!rst_n)begin
		x13 <= 'b0;
		y13 <= 'b0;
		z13 <= 'b0;
	end
	else if(!y12[31]) begin
		x13 <= x12 + (y12>>>12);
		y13 <= y12 - (x12>>>12);
		z13 <= z12 + angle_12;
	end
	else begin
		x13 <= x12 - (y12>>>12);
		y13 <= y12 + (x12>>>12);
		z13 <= z12 - angle_12;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第14次迭代
	if(!rst_n)begin
		x14 <= 'b0;
		y14 <= 'b0;
		z14 <= 'b0;
	end
	else if(!y13[31]) begin
		x14 <= x13 + (y13>>>13);
		y14 <= y13 - (x13>>>13);
		z14 <= z13 + angle_13;
	end
	else begin
		x14 <= x13 - (y13>>>13);
		y14 <= y13 + (x13>>>13);
		z14 <= z13 - angle_13;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第15次迭代
	if(!rst_n)begin
		x15 <= 'b0;
		y15 <= 'b0;
		z15 <= 'b0;
	end
	else if(!y14[31]) begin
		x15 <= x14 + (y14>>>14);
		y15 <= y14 - (x14>>>14);
		z15 <= z14 + angle_14;
	end
	else begin
		x15 <= x14 - (y14>>>14);
		y15 <= y14 + (x14>>>14);
		z15 <= z14 - angle_14;	
	end
end 

always@(posedge clk or negedge rst_n)begin//第16次迭代
	if(!rst_n)begin
		x16 <= 'b0;
		y16 <= 'b0;
		z16 <= 'b0;
	end
	else if(!y15[31]) begin
		x16 <= x15 + (y15>>>15);
		y16 <= y15 - (x15>>>15);
		z16 <= z15 + angle_15;
	end
	else begin
		x16 <= x15 - (y15>>>15);
		y16 <= y15 + (x15>>>15);
		z16 <= z15 - angle_15;	
	end
end 

wire[31:0]  mozhi_tmp;
wire[31:0]  mozhi_tmp1;
wire[31:0]  mozhi_tmp2;

assign mozhi_tmp = x16>>>6;
assign mozhi_tmp1 = mozhi_tmp+mozhi_tmp+mozhi_tmp+mozhi_tmp+mozhi_tmp+mozhi_tmp+mozhi_tmp;
assign mozhi_tmp2 = x16>>>1;


always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		mozhi <= 'b0;
		angle <= 'b0;
	end
	else begin
        mozhi 	= (mozhi_tmp1 + mozhi_tmp2)>>>16;
		angle 	= z16>>>16;
	end
end 

endmodule

2.3 Testbench B

Testbench代码如下:

`timescale 1ns/1ps

module cordic_Btb();

parameter PERIOD = 10;
reg clk;
reg rst_n;
reg signed [31:0] x;
reg signed [31:0] y;
reg start;
wire signed [31:0] 	angle;
wire signed [31:0] 	mozhi;
wire finished;
initial begin
	clk = 0;
	rst_n = 0;
	x = 'b0;
	y = 'b0;
	start = 0;
	#100 rst_n = 1;

	#10 @(posedge clk) start = 1;	x = 9'd100 ; 	y = 9'd100 ;
	#10 @(posedge clk) 				x = 9'd10; 		y = 9'd10;
	#10 @(posedge clk) 				x = 9'd3 ; 		y = 9'd4 ;
	#10 @(posedge clk) 				x = 9'd6 ; 		y = 9'd8 ;
	
	#100000 $stop;	
end

always #(PERIOD/2) clk = ~clk;

cordic_B inst1(
		.clk(clk),
		.rst_n(rst_n),
		.x(x),
		.y(y),
		.start(start),
		
		.angle(angle),
		.mozhi(mozhi),
		.finished(finished)
		
);
endmodule

相应仿真波形如下图所示:
CORDIC算法原理详解及其Verilog实现_第4张图片
可以看到,输入的(x,y)为(100,100)时,其夹角 θ \theta θ=45°,模值近似为141。其他情况同理。

END

*本文的Verilog代码均没有考虑象限问题,MATLAB代码有考虑。
*本文参考博客
[1]https://blog.csdn.net/qq_39210023/article/details/77456031
[2]https://blog.csdn.net/longxuekun1992/article/details/52435024

你可能感兴趣的:(数字IC,CORDIC,Verilog)