cordic算法的verilog实现及modelsim仿真

1. 算法介绍

CORDIC(Coordinate Rotation Digital Computer)算法即坐标旋转数字计算方法,是J.D.Volder1于1959年首次提出,主要用于三角函数、双曲线、指数、对数的计算。该算法通过基本的加和移位运算代替乘法运算,使得矢量的旋转和定向的计算不再需要三角函数、乘法、开方、反三角、指数等函数,计算向量长度并能把直角坐标系转换为极坐标系。因为Cordic 算法只用了移位和加法,很容易用纯硬件来实现,非常适合FPGA实现。

CORDIC算法完成坐标或向量的平面旋转(下图以逆时针旋转为例)。

image

旋转后,可得如下向量:

image

旋转的角度θ经过多次旋转得到的(步步逼近,接近二分查找法),每次旋转一小角度。单步旋转定义如下公式:

image

公式(2)提取cosθ,可修改为:

image

修改后的公式把乘法次数从4次改为3次,剩下的乘法运算可以通过选择每次旋转的角度去除,将每一步的正切值选为2的指数(二分查找法),除以2的指数可以通过右移操作完成(verilog)。

每次旋转的角度可以表示为:

image

所有迭代角度累加值等于最终需要的旋转角度θ:

image

这里Sn为1或者-1,根据旋转方向确定(后面有确定方法,公式(15)),顺时针为-1,逆时针为1。

image

可以得到如下公式:

image

结合公式(3)和(7),得到公式(8):

image

到这里,除了余弦值这个系数,算法只要通过简单的移位和加法操作完成。而这个系数可以通过预先计算最终值消掉。首先重新重写这个系数如下:

image

第二步计算所有的余弦值并相乘,这个值K称为增益系数。

image

由于K值是常量,我们可以先忽略它。

image

image

到这里我们发现,算法只剩下移位和加减法,这就非常适合硬件实现了,为硬件快速计算三角函数提供了一种新的算法。在进行迭代运算时,需要引入一个新的变量Z,表示需要旋转的角度θ中还没有旋转的角度。

image 

这里,我们可以把前面提到确定旋转方向的方法介绍了,就是通过这个变量Z的符号确定。

image

image

通过公式(5)和(15),将未旋转的角度变为0。

一个类编程风格的结构如下,反正切值是预先计算好的。

image

1.1 旋转模式

旋转模式下,CORDIC算法驱动Z变为0,结合公式(13)和(16),算法的核心计算如下:

image

一种特殊情况是,另初始值如下:

image

因此,旋转模式下CORDIC算法可以计算一个输入角度的正弦值和余弦值。

1.2 向量模式

向量模式下,有两种特例:

image

因此,向量模式下CORDIC算法可以用来计算输入向量的模和反正切,也能开方计算,并可以将直角坐标转换为极坐标。

算法介绍:http://en.wikipedia.org/wiki/Cordichttp://blog.csdn.net/liyuanbhu/article/details/8458769

2. matlab实现

根据算法原理,利用维基百科中给的程序,在matlab中跑了一遍,对算法有了一定程度的了解。

程序如下:

 1 function v = cordic(beta,n)
 2 % This function computes v = [cos(beta), sin(beta)] (beta in radians)
 3 % using n iterations. Increasing n will increase the precision.
 4  
 5 if beta < -pi/2 || beta > pi/2
 6     if beta < 0
 7         v = cordic(beta + pi, n);
 8     else
 9         v = cordic(beta - pi, n);
10     end
11     v = -v; % flip the sign for second or third quadrant
12 %     return
13 end
14  
15 % Initialization of tables of constants used by CORDIC
16 % need a table of arctangents of negative powers of two, in radians:
17 % angles = atan(2.^-(0:27));
18 angles =  [  ...
19     0.78539816339745   0.46364760900081   0.24497866312686   0.12435499454676 ...
20     0.06241880999596   0.03123983343027   0.01562372862048   0.00781234106010 ...
21     0.00390623013197   0.00195312251648   0.00097656218956   0.00048828121119 ...
22     0.00024414062015   0.00012207031189   0.00006103515617   0.00003051757812 ...
23     0.00001525878906   0.00000762939453   0.00000381469727   0.00000190734863 ...
24     0.00000095367432   0.00000047683716   0.00000023841858   0.00000011920929 ...
25     0.00000005960464   0.00000002980232   0.00000001490116   0.00000000745058 ];
26 % and a table of products of reciprocal lengths of vectors [1, 2^-2j]:
27 Kvalues = [ ...
28     0.70710678118655   0.63245553203368   0.61357199107790   0.60883391251775 ...
29     0.60764825625617   0.60735177014130   0.60727764409353   0.60725911229889 ...
30     0.60725447933256   0.60725332108988   0.60725303152913   0.60725295913894 ...
31     0.60725294104140   0.60725293651701   0.60725293538591   0.60725293510314 ...
32     0.60725293503245   0.60725293501477   0.60725293501035   0.60725293500925 ...
33     0.60725293500897   0.60725293500890   0.60725293500889   0.60725293500888 ];
34 Kn = Kvalues(min(n, length(Kvalues)));
35  
36 % Initialize loop variables:
37 v = [1;0]; % start with 2-vector cosine and sine of zero
38 poweroftwo = 1;
39 angle = angles(1);
40  
41 % Iterations
42 for j = 0:n-1;
43     if beta < 0
44         sigma = -1;
45     else
46         sigma = 1;
47     end
48     factor = sigma * poweroftwo;
49     R = [1, -factor; factor, 1];
50     v = R * v; % 2-by-2 matrix multiply
51     beta = beta - sigma * angle; % update the remaining angle
52     poweroftwo = poweroftwo / 2;
53     % update the angle from table, or eventually by just dividing by
54     % two,(a=arctan(a),a is small enough)
55     if j+2 > length(angles)
56         angle = angle / 2;
57     else
58         angle = angles(j+2);
59     end
60 end
61  
62 % Adjust length of output vector to be [cos(beta), sin(beta)]:
63 v = v * Kn;
64 return
65 end
cordic_matlab

3. 硬件实现

实现主要参考了相关作者的代码,然后对其进行了修改,最终实现了16级的流水线,设计完成旋转模式下正弦值和余弦值的计算。

http://www.cnblogs.com/qiweiwang/archive/2010/07/28/1787021.htmlhttp://www.amobbs.com/forum.php?mod=viewthread&tid=5513050&highlight=cordic

下面分段介绍下各部分代码:

首先是角度的表示,进行了宏定义,360读用16位二进制表示2^16,每一度为2^16/360。

 1 //360°--2^16,phase_in = 16bits (input [15:0] phase_in)
 2 //1°--2^16/360
 3 `define rot0  16'h2000    //45
 4 `define rot1  16'h12e4    //26.5651
 5 `define rot2  16'h09fb    //14.0362
 6 `define rot3  16'h0511    //7.1250
 7 `define rot4  16'h028b    //3.5763
 8 `define rot5  16'h0145    //1.7899
 9 `define rot6  16'h00a3    //0.8952
10 `define rot7  16'h0051    //0.4476
11 `define rot8  16'h0028    //0.2238
12 `define rot9  16'h0014    //0.1119
13 `define rot10 16'h000a    //0.0560
14 `define rot11 16'h0005    //0.0280
15 `define rot12 16'h0003    //0.0140
16 `define rot13 16'h0001    //0.0070
17 `define rot14 16'h0001    //0.0035
18 `define rot15 16'h0000    //0.0018
View Code

然后是流水线级数定义、增益放大倍数以及中间结果位宽定义。流水线级数16,为了满足精度要求,有文献指出流水线级数必须大于等于角度位宽16(针对正弦余弦计算的CORDIC算法优化及其FPGA实现)。增益放大2^16,为了避免溢出状况中间结果(x,y,z)定义为17为,最高位作为符号位判断,1为负数,0为正数。

 1 parameter PIPELINE = 16;
 2 //parameter K = 16'h4dba;//k=0.607253*2^15
 3 parameter K = 16'h9b74;//gian k=0.607253*2^16,9b74,n means the number pipeline
 4 //pipeline 16-level    //maybe overflow,matlab result not overflow
 5 //MSB is signed bit,transform the sin and cos according to phase_in[15:14]
 6 reg [16:0] x0=0,y0=0,z0=0;
 7 reg [16:0] x1=0,y1=0,z1=0;
 8 reg [16:0] x2=0,y2=0,z2=0;
 9 reg [16:0] x3=0,y3=0,z3=0;
10 reg [16:0] x4=0,y4=0,z4=0;
11 reg [16:0] x5=0,y5=0,z5=0;
12 reg [16:0] x6=0,y6=0,z6=0;
13 reg [16:0] x7=0,y7=0,z7=0;
14 reg [16:0] x8=0,y8=0,z8=0;
15 reg [16:0] x9=0,y9=0,z9=0;
16 reg [16:0] x10=0,y10=0,z10=0;
17 reg [16:0] x11=0,y11=0,z11=0;
18 reg [16:0] x12=0,y12=0,z12=0;
19 reg [16:0] x13=0,y13=0,z13=0;
20 reg [16:0] x14=0,y14=0,z14=0;
21 reg [16:0] x15=0,y15=0,z15=0;
22 reg [16:0] x16=0,y16=0,z16=0;
View Code

还需要定义memory型寄存器数组并初始化为0,用于寄存输入角度高2位的值。

1 reg [1:0] quadrant [PIPELINE:0];
2 integer i;
3 initial
4 begin
5     for(i=0;i<=PIPELINE;i=i+1)
6     quadrant[i] = 2'b0;
7 end
View Code

接着,是对输入角度象限处理,将角度都转换到第一象限,方便处理。输入角度值最高两位赋值0,即转移到第一象限[0°,90°]。此外,完成x0,y0和z0的初始化,并增加一位符号位。

1 //phase_in[15:14] determines which quadrant the angle is.
2 //00 means first;01 means second;00 means third;00 means fourth
3 //initialization: x0 = K,y0 = 0,z0 = phase_in,then the last result(x16,y16) = (cos(phase_in),sin(phase_in))  
4 always @ (posedge clk)//stage 0,not pipeline
5 begin
6     x0 <= {1'b0,K}; //add one signed bit,0 means positive
7     y0 <= 17'b0;
8     z0 <= {3'b0,phase_in[13:0]};//control the phase_in to the range[0-Pi/2]
9 end
View Code

接下来根据剩余待旋转角度z的符号位进行16次迭代处理,即完成16级流水线处理。迭代公式:x(n+1) <= x(n) + {{n{y(n)[16]}},y(n)[16:n]},n为移位个数。右移之后高位补位,这里补位有一些不理解。移位可能存在负数,且没有四舍五入。按理说第一象限不存在负数,但后续仿真汇总确实有负数出现,但仿真结果良好。

  1 always @ (posedge clk)//stage 1
  2 begin
  3   if(z0[16])//the diff is negative so clockwise
  4   begin
  5       x1 <= x0 + y0;
  6       y1 <= x0 - y0;
  7       z1 <= z0 + `rot0;
  8   end
  9   else
 10   begin
 11       x1 <= x0 - y0;//x1 <= x0;
 12       y1 <= x0 + y0;//y1 <= x0;
 13       z1 <= z0 - `rot0;//reversal 45
 14   end
 15 end
 16 
 17 always @ (posedge clk)//stage 2
 18 begin
 19     if(z1[16])//the diff is negative so clockwise
 20     begin
 21         x2 <= x1 + {y1[16],y1[16:1]};
 22         y2 <= y1 - {x1[16],x1[16:1]};
 23         z2 <= z1 + `rot1;//clockwise 26
 24     end
 25     else
 26     begin
 27         x2 <= x1 - {y1[16],y1[16:1]};
 28         y2 <= y1 + {x1[16],x1[16:1]};
 29         z2 <= z1 - `rot1;//anti-clockwise 26
 30     end
 31 end
 32 
 33 always @ (posedge clk)//stage 3
 34 begin
 35     if(z2[16])//the diff is negative so clockwise
 36     begin
 37         x3 <= x2 + {{2{y2[16]}},y2[16:2]}; //right shift n bits,divide 2^n
 38         y3 <= y2 - {{2{x2[16]}},x2[16:2]}; //left adds n bits of MSB,in first quadrant x or y are positive,MSB =0 ??
 39         z3 <= z2 + `rot2;//clockwise 14    //difference of positive and negtive number and no round(4,5)
 40     end
 41     else
 42     begin
 43         x3 <= x2 - {{2{y2[16]}},y2[16:2]};
 44         y3 <= y2 + {{2{x2[16]}},x2[16:2]};
 45         z3 <= z2 - `rot2;//anti-clockwise 14
 46     end
 47 end
 48 
 49 always @ (posedge clk)//stage 4
 50 begin
 51     if(z3[16])
 52     begin
 53         x4 <= x3 + {{3{y3[16]}},y3[16:3]};
 54         y4 <= y3 - {{3{x3[16]}},x3[16:3]};
 55         z4 <= z3 + `rot3;//clockwise 7
 56     end
 57     else
 58     begin
 59         x4 <= x3 - {{3{y3[16]}},y3[16:3]};
 60         y4 <= y3 + {{3{x3[16]}},x3[16:3]};
 61         z4 <= z3 - `rot3;//anti-clockwise 7
 62     end
 63 end
 64 
 65 always @ (posedge clk)//stage 5
 66 begin
 67     if(z4[16])
 68     begin
 69         x5 <= x4 + {{4{y4[16]}},y4[16:4]};
 70         y5 <= y4 - {{4{x4[16]}},x4[16:4]};
 71         z5 <= z4 + `rot4;//clockwise 3
 72     end
 73     else
 74     begin
 75         x5 <= x4 - {{4{y4[16]}},y4[16:4]};
 76         y5 <= y4 + {{4{x4[16]}},x4[16:4]};
 77         z5 <= z4 - `rot4;//anti-clockwise 3
 78     end
 79 end
 80 
 81 always @ (posedge clk)//STAGE 6
 82 begin
 83     if(z5[16])
 84     begin
 85         x6 <= x5 + {{5{y5[16]}},y5[16:5]};
 86         y6 <= y5 - {{5{x5[16]}},x5[16:5]};
 87         z6 <= z5 + `rot5;//clockwise 1
 88     end
 89     else
 90     begin
 91         x6 <= x5 - {{5{y5[16]}},y5[16:5]};
 92         y6 <= y5 + {{5{x5[16]}},x5[16:5]};
 93         z6 <= z5 - `rot5;//anti-clockwise 1 
 94     end
 95 end
 96 
 97 always @ (posedge clk)//stage 7
 98 begin
 99     if(z6[16])
100     begin
101         x7 <= x6 + {{6{y6[16]}},y6[16:6]};
102         y7 <= y6 - {{6{x6[16]}},x6[16:6]};
103         z7 <= z6 + `rot6;
104     end
105     else
106     begin
107         x7 <= x6 - {{6{y6[16]}},y6[16:6]};
108         y7 <= y6 + {{6{x6[16]}},x6[16:6]};
109         z7 <= z6 - `rot6;
110     end
111 end
View Code

由于进行了象限的转换,最终流水结果需要根据象限进行转换为正确的值。这里寄存17次高2位角度输入值,配合流水线结果用于象限判断,并完成转换。

 1 //according to the pipeline,register phase_in[15:14]
 2 always @ (posedge clk)
 3 begin
 4   quadrant[0] <= phase_in[15:14];
 5   quadrant[1] <= quadrant[0];
 6   quadrant[2] <= quadrant[1];
 7   quadrant[3] <= quadrant[2];
 8   quadrant[4] <= quadrant[3];
 9   quadrant[5] <= quadrant[4];
10   quadrant[6] <= quadrant[5];
11   quadrant[7] <= quadrant[6];
12   quadrant[8] <= quadrant[7];
13   quadrant[9] <= quadrant[8];
14   quadrant[10] <= quadrant[9];
15   quadrant[11] <= quadrant[10];
16   quadrant[12] <= quadrant[11];
17   quadrant[13] <= quadrant[12];
18   quadrant[14] <= quadrant[13];
19   quadrant[15] <= quadrant[14];
20   quadrant[16] <= quadrant[15];
21 end
View Code

最后,根据寄存的高2位角度输入值,利用三角函数关系,得出最后的结果,其中负数进行了补码操作。

 1 //alter register, according to quadrant[16] to transform the result to the right result
 2 always @ (posedge clk) begin
 3 eps <= z15;
 4 case(quadrant[16]) //or 15
 5 2'b00:begin //if the phase is in first quadrant,the sin(X)=sin(A),cos(X)=cos(A)
 6         cos <= x16;
 7         sin <= y16;
 8         end
 9 2'b01:begin //if the phase is in second quadrant,the sin(X)=sin(A+90)=cosA,cos(X)=cos(A+90)=-sinA
10         cos <= ~(y16) + 1'b1;//-sin
11         sin <= x16;//cos
12         end
13 2'b10:begin //if the phase is in third quadrant,the sin(X)=sin(A+180)=-sinA,cos(X)=cos(A+180)=-cosA
14         cos <= ~(x16) + 1'b1;//-cos
15         sin <= ~(y16) + 1'b1;//-sin
16         end
17 2'b11:begin //if the phase is in forth quadrant,the sin(X)=sin(A+270)=-cosA,cos(X)=cos(A+270)=sinA
18         cos <= y16;//sin
19         sin <= ~(x16) + 1'b1;//-cos
20         end
21 endcase
22 end
View Code

4. Modelsim仿真结果

仿真结果应该还是挺理想的。后续需要完成的工作:1.上述红色出现的问题的解决;2.应用cordic算法,完成如FFT的算法。

后记:

在3中,迭代公式:x(n+1) <= x(n) + {{n{y(n)[16]}},y(n)[16:n]},上述右移操作都是手动完成:首先最高位增加1位符号位(1为负,0为正),然后手动添加n位符号位(最高位)补齐,即实际上需要完成的算术右移(>>>)。本设计定义的reg为无符号型,在定义时手动添加最高位为符号位。verilog-1995中只有integer为有符号型,reg和wire都是无符号型,只能手动添加扩展位实现有符号运算。而在verilog-2001中reg和wire可以通过保留字signed定义为有符号型。另外,涉及有符号和无符号型的移位操作等可参考下面的文章。

verilog有符号数详解:http://www.cnblogs.com/LJWJL/p/3481995.html

Verilog-2001新特性及代码实现:http://www.asic-world.com/verilog/verilog2k.html

逻辑移位与算术移位区别:http://www.cnblogs.com/yuphone/archive/2010/09/21/1832217.htmlhttp://blog.sina.com.cn/s/blog_65311d330100ij9n.html

原来的算法实现针对Verilog-1995中reg和wire没有有符号型,也没有verilog-2001中的算术移位而实现的。根据verilog-2001新特性,引入有符号型reg和算术右移,同样实现了前文的结果。代码如下:

  1 `timescale 1 ns/100 ps
  2 //360?°--2^16,phase_in = 16bits (input [15:0] phase_in)
  3 //1?°--2^16/360
  4 `define rot0  16'h2000    //45
  5 `define rot1  16'h12e4    //26.5651
  6 `define rot2  16'h09fb    //14.0362
  7 `define rot3  16'h0511    //7.1250
  8 `define rot4  16'h028b    //3.5763
  9 `define rot5  16'h0145    //1.7899
 10 `define rot6  16'h00a3    //0.8952
 11 `define rot7  16'h0051    //0.4476
 12 `define rot8  16'h0028    //0.2238
 13 `define rot9  16'h0014    //0.1119
 14 `define rot10 16'h000a    //0.0560
 15 `define rot11 16'h0005    //0.0280
 16 `define rot12 16'h0003    //0.0140
 17 `define rot13 16'h0001    //0.0070
 18 `define rot14 16'h0001    //0.0035
 19 `define rot15 16'h0000    //0.0018
 20 
 21 module cordic(
 22 output reg signed [16:0] sin,cos,eps,
 23 input [15:0] phase_in,
 24 input clk
 25 );
 26 parameter PIPELINE = 16;
 27 //parameter K = 16'h4dba;//k=0.607253*2^15
 28 parameter K = 17'h09b74;//gian k=0.607253*2^16,9b74,
 29 //pipeline 16-level    //maybe overflow,matlab result not overflow
 30 //MSB is signed bit,transform the sin and cos according to phase_in[15:14]
 31 reg signed [16:0] x0=0,y0=0,z0=0;
 32 reg signed [16:0] x1=0,y1=0,z1=0;
 33 reg signed [16:0] x2=0,y2=0,z2=0;
 34 reg signed [16:0] x3=0,y3=0,z3=0;
 35 reg signed [16:0] x4=0,y4=0,z4=0;
 36 reg signed [16:0] x5=0,y5=0,z5=0;
 37 reg signed [16:0] x6=0,y6=0,z6=0;
 38 reg signed [16:0] x7=0,y7=0,z7=0;
 39 reg signed [16:0] x8=0,y8=0,z8=0;
 40 reg signed [16:0] x9=0,y9=0,z9=0;
 41 reg signed [16:0] x10=0,y10=0,z10=0;
 42 reg signed [16:0] x11=0,y11=0,z11=0;
 43 reg signed [16:0] x12=0,y12=0,z12=0;
 44 reg signed [16:0] x13=0,y13=0,z13=0;
 45 reg signed [16:0] x14=0,y14=0,z14=0;
 46 reg signed [16:0] x15=0,y15=0,z15=0;
 47 reg signed [16:0] x16=0,y16=0,z16=0;
 48 
 49 reg [1:0] quadrant [PIPELINE:0];
 50 integer i;
 51 initial
 52 begin
 53     for(i=0;i<=PIPELINE;i=i+1)
 54     quadrant[i] = 2'b0;
 55 end
 56 
 57 //phase_in[15:14] determines which quadrant the angle is.
 58 //00 means first;01 means second;00 means third;00 means fourth
 59 //initialization: x0 = K,y0 = 0,z0 = phase_in,then the last result(x16,y16) = (cos(phase_in),sin(phase_in))  
 60 always @ (posedge clk)//stage 0,not pipeline
 61 begin
 62     x0 <= K; //add one signed bit,0 means positive
 63     y0 <= 17'd0;
 64     z0 <= {3'b0,phase_in[13:0]};//control the phase_in to the range[0-Pi/2]
 65 end
 66 //pipeline
 67 //z0[16] = 0,positive
 68 always @ (posedge clk)//stage 1
 69 begin
 70   if(z0[16])//the diff is negative so clockwise
 71   begin
 72       x1 <= x0 + y0;
 73       y1 <= y0 - x0;
 74       z1 <= z0 + `rot0;
 75   end
 76   else
 77   begin
 78       x1 <= x0 - y0;//x1 <= x0;
 79       y1 <= y0 + x0;//y1 <= x0;
 80       z1 <= z0 - `rot0;//reversal 45
 81   end
 82 end
 83 
 84 always @ (posedge clk)//stage 2
 85 begin
 86     if(z1[16])//the diff is negative so clockwise
 87     begin
 88         x2 <= x1 + (y1 >>> 1);
 89         y2 <= y1 - (x1 >>> 1);
 90         z2 <= z1 + `rot1;//clockwise 26
 91     end
 92     else
 93     begin
 94         x2 <= x1 - (y1 >>> 1);
 95         y2 <= y1 + (x1 >>> 1);
 96         z2 <= z1 - `rot1;//anti-clockwise 26
 97     end
 98 end
 99 
100 always @ (posedge clk)//stage 3
101 begin
102     if(z2[16])//the diff is negative so clockwise
103     begin
104         x3 <= x2 + (y2 >>> 2); //right shift n bits,divide 2^n,signed extension,Arithmetic shift right
105         y3 <= y2 - (x2 >>> 2); //left adds n bits of MSB,in first quadrant x or y are positive,MSB =0 ??
106         z3 <= z2 + `rot2;//clockwise 14    //difference of positive and negtive number and no round(4,5)
107     end
108     else
109     begin
110         x3 <= x2 - (y2 >>> 2); //Arithmetic shift right
111         y3 <= y2 + (x2 >>> 2);
112         z3 <= z2 - `rot2;//anti-clockwise 14
113     end
114 end
115 
116 always @ (posedge clk)//stage 4
117 begin
118     if(z3[16])
119     begin
120         x4 <= x3 + (y3 >>> 3);
121         y4 <= y3 - (x3 >>> 3);
122         z4 <= z3 + `rot3;//clockwise 7
123     end
124     else
125     begin
126         x4 <= x3 - (y3 >>> 3);
127         y4 <= y3 + (x3 >>> 3);
128         z4 <= z3 - `rot3;//anti-clockwise 7
129     end
130 end
131 
132 always @ (posedge clk)//stage 5
133 begin
134     if(z4[16])
135     begin
136         x5 <= x4 + (y4 >>> 4);
137         y5 <= y4 - (x4 >>> 4);
138         z5 <= z4 + `rot4;//clockwise 3
139     end
140     else
141     begin
142         x5 <= x4 - (y4 >>> 4);
143         y5 <= y4 + (x4 >>> 4);
144         z5 <= z4 - `rot4;//anti-clockwise 3
145     end
146 end
147 
148 always @ (posedge clk)//STAGE 6
149 begin
150     if(z5[16])
151     begin
152         x6 <= x5 + (y5 >>> 5);
153         y6 <= y5 - (x5 >>> 5);
154         z6 <= z5 + `rot5;//clockwise 1
155     end
156     else
157     begin
158         x6 <= x5 - (y5 >>> 5);
159         y6 <= y5 + (x5 >>> 5);
160         z6 <= z5 - `rot5;//anti-clockwise 1 
161     end
162 end
163 
164 always @ (posedge clk)//stage 7
165 begin
166     if(z6[16])
167     begin
168         x7 <= x6 + (y6 >>> 6);
169         y7 <= y6 - (x6 >>> 6);
170         z7 <= z6 + `rot6;
171     end
172     else
173     begin
174         x7 <= x6 - (y6 >>> 6);
175         y7 <= y6 + (x6 >>> 6);
176         z7 <= z6 - `rot6;
177     end
178 end
179 
180 always @ (posedge clk)//stage 8
181 begin
182     if(z7[16])
183     begin
184         x8 <= x7 + (y7 >>> 7);
185         y8 <= y7 - (x7 >>> 7);
186         z8 <= z7 + `rot7;
187     end
188     else
189     begin
190         x8 <= x7 - (y7 >>> 7);
191         y8 <= y7 + (x7 >>> 7);
192         z8 <= z7 - `rot7;
193     end
194 end
195 
196 always @ (posedge clk)//stage 9
197 begin
198     if(z8[16])
199     begin
200         x9 <= x8 + (y8 >>> 8);
201         y9 <= y8 - (x8 >>> 8);
202         z9 <= z8 + `rot8;
203     end
204     else
205     begin
206         x9 <= x8 - (y8 >>> 8);
207         y9 <= y8 + (x8 >>> 8);
208         z9 <= z8 - `rot8;
209     end
210 end
211 
212 always @ (posedge clk)//stage 10
213 begin
214     if(z9[16])
215     begin
216         x10 <= x9 + (y9 >>> 9);
217         y10 <= y9 - (x9 >>> 9);
218         z10 <= z9 + `rot9;
219     end
220     else
221     begin
222         x10 <= x9 - (y9 >>> 9);
223         y10 <= y9 + (x9 >>> 9);
224         z10 <= z9 - `rot9;
225     end
226 end
227 
228 always @ (posedge clk)//stage 11
229 begin
230     if(z10[16])
231     begin
232         x11 <= x10 + (y10 >>> 10);
233         y11 <= y10 - (x10 >>> 10);
234         z11 <= z10 + `rot10;//clockwise 3
235     end
236     else
237     begin
238         x11 <= x10 - (y10 >>> 10);
239         y11 <= y10 + (x10 >>> 10);
240         z11 <= z10 - `rot10;//anti-clockwise 3
241     end
242 end
243 
244 always @ (posedge clk)//STAGE 12
245 begin
246     if(z11[16])
247     begin
248         x12 <= x11 + (y11 >>> 11);
249         y12 <= y11 - (x11 >>> 11);
250         z12 <= z11 + `rot11;//clockwise 1
251     end
252     else
253     begin
254         x12 <= x11 - (y11 >>> 11);
255         y12 <= y11 + (x11 >>> 11);
256         z12 <= z11 - `rot11;//anti-clockwise 1 
257     end
258 end
259 
260 always @ (posedge clk)//stage 13
261 begin
262     if(z12[16])
263     begin
264         x13 <= x12 + (y12 >>> 12);
265         y13 <= y12 - (x12 >>> 12);
266         z13 <= z12 + `rot12;
267     end
268     else
269     begin
270         x13 <= x12 - (y12 >>> 12);
271         y13 <= y12 + (x12 >>> 12);
272         z13 <= z12 - `rot12;
273     end
274 end
275 
276 always @ (posedge clk)//stage 14
277 begin
278     if(z13[16])
279     begin
280         x14 <= x13 + (y13 >>> 13);
281         y14 <= y13 - (x13 >>> 13);
282         z14 <= z13 + `rot13;
283     end
284     else
285     begin
286         x14 <= x13 - (y13 >>> 13);
287         y14 <= y13 + (x13 >>> 13);
288         z14 <= z13 - `rot13;
289     end
290 end
291 
292 always @ (posedge clk)//stage 15
293 begin
294     if(z14[16])
295     begin
296         x15 <= x14 + (y14 >>> 14);
297         y15 <= y14 - (x14 >>> 14);
298         z15 <= z14 + `rot14;
299     end
300     else
301     begin
302         x15 <= x14 - (y14 >>> 14);
303         y15 <= y14 + (x14 >>> 14);
304         z15 <= z14 - `rot14;
305     end
306 end
307 
308 always @ (posedge clk)//stage 16
309 begin
310     if(z15[16])
311     begin
312         x16 <= x15 + (y15 >>> 15);
313         y16 <= y15 - (x15 >>> 15);
314         z16 <= z15 + `rot15;
315     end
316     else
317     begin
318         x16 <= x15 - (y15 >>> 15);
319         y16 <= y15 + (x15 >>> 15);
320         z16 <= z15 - `rot15;
321     end
322 end
323 //according to the pipeline,register phase_in[15:14]
324 always @ (posedge clk)
325 begin
326   quadrant[0] <= phase_in[15:14];
327   quadrant[1] <= quadrant[0];
328   quadrant[2] <= quadrant[1];
329   quadrant[3] <= quadrant[2];
330   quadrant[4] <= quadrant[3];
331   quadrant[5] <= quadrant[4];
332   quadrant[6] <= quadrant[5];
333   quadrant[7] <= quadrant[6];
334   quadrant[8] <= quadrant[7];
335   quadrant[9] <= quadrant[8];
336   quadrant[10] <= quadrant[9];
337   quadrant[11] <= quadrant[10];
338   quadrant[12] <= quadrant[11];
339   quadrant[13] <= quadrant[12];
340   quadrant[14] <= quadrant[13];
341   quadrant[15] <= quadrant[14];
342   quadrant[16] <= quadrant[15];
343 end
344 //alter register, according to quadrant[16] to transform the result to the right result
345 always @ (posedge clk) begin
346 eps <= z15;
347 case(quadrant[16]) //or 15
348 2'b00:begin //if the phase is in first quadrant,the sin(X)=sin(A),cos(X)=cos(A)
349         cos <= x16;
350         sin <= y16;
351         end
352 2'b01:begin //if the phase is in second quadrant,the sin(X)=sin(A+90)=cosA,cos(X)=cos(A+90)=-sinA
353         cos <= ~(y16) + 1'b1;//-sin
354         sin <= x16;//cos
355         end
356 2'b10:begin //if the phase is in third quadrant,the sin(X)=sin(A+180)=-sinA,cos(X)=cos(A+180)=-cosA
357         cos <= ~(x16) + 1'b1;//-cos
358         sin <= ~(y16) + 1'b1;//-sin
359         end
360 2'b11:begin //if the phase is in forth quadrant,the sin(X)=sin(A+270)=-cosA,cos(X)=cos(A+270)=sinA
361         cos <= y16;//sin
362         sin <= ~(x16) + 1'b1;//-cos
363         end
364 endcase
365 end
366 
367 endmodule 
View Code

另外,代码中可以适当优化下:1.流水线操作时,定义的中间寄存器在定义是可以选择memory型,且可以单独建立module或者task进行封装迭代过程; 2. 最后对高2位角度寄存时,可以利用for语句选择移位寄存器实现,如下所示。

always @ (posedge clk,negedge rst_n)
begin
    if(!rst_n)
        for(i=0;i<=PIPELINE;i=i+1)
            quadrant[i]<=2'b00;
    else
        if(ena)
            begin
                for(i=0;i<PIPELINE;i=i+1)
                    quadrant[i+1]<=quadrant[i];
                quadrant[0]<=phase_in[7:6];
            end
end
移位寄存器寄存角度高2位

疑问:有一点比较奇怪的是,转移到第一象限后,x和y不该存在负数的情况,但是现在确实有,这一点比较费解,所以将算术右移改为逻辑右移,在函数极值时存在错误。

原文地址:https://www.cnblogs.com/aikimi7/p/3929592.html