CORDIC algorithm in Verilog for sine & cos wave generation

CORDIC Algorithm : Here sine and cos wave generation circuit has been designed and implemented using Verilog HDL using the CORDIC Algorithm

CORDIC Algorithm

The working principle for generation trigonometric signal using cordic algorithm is to decompose required rotation angle (θ) into weighted sum of set of pre-defined elementary rotation angles such that rotation through each of them can be attained by simple shift and add operation instead of complex multiplications.

Here in this post the major objective is to :-

  • Generate trigonometric signals like sine and cosine digitally as they come to use in many applications.
  • Implement it with a hardware-friendly algorithm that is less complex and carries less number of multiplication, which can be done through the CORDIC algorithm.

Cartesian Coordinate Plane Rotations :The standard method of rotating a point (x1, y1) by θ degrees in the xy plane to a point is given by the well known equations:

x2 = x1cosθ − y1sinθ
y2 = x1sinθ + y1cosθ

The above-mentioned equations can be rewritten in matrix form as follows:

Let the angle the point rotated or a phase shift to be 90 degrees. That implies the values of sinθ = 1 and cosθ = 0

The CORDIC Method

To pseudo rotate vector according to the above equations multipliers are needed and that makes the calculations and circuit quite complex.

So here is where the CORDIC comes into picture, where one only needs to select angles at those tan function becomes exponents of 2 so that instead of multiplication simple shift and add would be sufficient.

x2 = x1 − y12−i
y2 = y1 + x12−i

At this stage we alter the transform to become an iterative algorithm. We restrict the angles that we are able to rotate by, such that to rotate by an arbitrary requires a series of successively smaller rotations at each iteration i.

The rotation angles obey the law : tanθi = 2−i.

Obeying this law causes the multiplication by the tangent term to become a shift.

Angle accumulator

Now the angle required would be achieved in an iterative manner by adding and subtracting the predefined angles that obey above mentioned law.

The equations can be rewritten for each iteration as follows:

i+1 = xi − di
(y12−i)

i+1 = yi − di
(x12−i)

At this stage a new equation is introduced called the Angle Accumulator which is used to keep track of the accumulative angle rotated at each iteration

zi+1 = zi − dii) ,

Here di = +/-1. The symbol di is a decision operator and is used to decide which direction to rotate.

Signal Flow

Angle Values

A look up table has to be developed with the predefined set of angles that obeys the rule of tangent function in exponents of 2.

The table below shows the rotation angles that can be used for each iteration (i) of the CORDIC algorithm:

iθi (in degrees )tan θi = 2-icos θi
045.010.707106781
126.5550511770.50.894427191
214.0362434670.250.9701425
37.1250163480.1250.992277877
43.5763343740.06250.998052578
51.7899060820.031250.999512076
60.89517971020.0156250.999877952
70.44761417090.00781250.999969484
80.22381050040.003906250.9999992371
90.11190567710.0019531250.999998093
100.05595289190.0009765630.999999523
110.02797645260.000488210.999999881
120.01398822710.0002441410.999999997
....
....
....
....

Verilog Code

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: alljobs.co.in
// Engineer: Team ( alljobs.co.in ) 
// Design Name: CORDIC algorithm in Verilog for sine & cos wave generation
// Module Name: CORDIC
// Project Name: CORDIC algorithm in Verilog for sine & cos wave generation
// Language Used : Verilog HDL.
// Description: Here Cordic algorithm have been used to design and simulate the sine and cos wave generation circuit.
//////////////////////////////////////////////////////////////////////////////////
module CORDIC(clock,angle,Xin,Yin,Xout,Yout); 
parameter XY_SZ = 16; 
localparam STG = XY_SZ; 
input clock; 
input signed [31:0] angle; 
input signed [XY_SZ-1:0] Xin; 
input signed [XY_SZ-1:0] Yin; 
output signed [XY_SZ:0] Xout; 
output signed [XY_SZ:0] Yout; 

wire signed [31:0] atan_table [0:30]; 

 assign atan_table[00] = 32'b00100000000000000000000000000000;
 
 assign atan_table[01] = 32'b00010010111001000000010100011101; 
 assign atan_table[02] = 32'b00001001111110110011100001011011; 
 assign atan_table[03] = 32'b00000101000100010001000111010100;
 assign atan_table[04] = 32'b00000010100010110000110101000011; 
 assign atan_table[05] = 32'b00000001010001011101011111100001;
  
 assign atan_table[06] = 32'b00000000101000101111011000011110; 
 assign atan_table[07] = 32'b00000000010100010111110001010101; 
 assign atan_table[08] = 32'b00000000001010001011111001010011; 
 assign atan_table[09] = 32'b00000000000101000101111100101110; 
 assign atan_table[10] = 32'b00000000000010100010111110011000; 
 
 assign atan_table[11] = 32'b00000000000001010001011111001100; 
 assign atan_table[12] = 32'b00000000000000101000101111100110; 
 assign atan_table[13] = 32'b00000000000000010100010111110011; 
 assign atan_table[14] = 32'b00000000000000001010001011111001; 
 assign atan_table[15] = 32'b00000000000000000101000101111101; 
 
 assign atan_table[16] = 32'b00000000000000000010100010111110; 
 assign atan_table[17] = 32'b00000000000000000001010001011111; 
 assign atan_table[18] = 32'b00000000000000000000101000101111; 
 assign atan_table[19] = 32'b00000000000000000000010100011000; 
 assign atan_table[20] = 32'b00000000000000000000001010001100;
  
 assign atan_table[21] = 32'b00000000000000000000000101000110; 
 assign atan_table[22] = 32'b00000000000000000000000010100011; 
 assign atan_table[23] = 32'b00000000000000000000000001010001; 
 assign atan_table[24] = 32'b00000000000000000000000000101000; 
 assign atan_table[25] = 32'b00000000000000000000000000010100; 
 
 assign atan_table[26] = 32'b00000000000000000000000000001010; 
 assign atan_table[27] = 32'b00000000000000000000000000000101; 
 assign atan_table[28] = 32'b00000000000000000000000000000010; 
 assign atan_table[29] = 32'b00000000000000000000000000000001; 
 assign atan_table[30] = 32'b00000000000000000000000000000000;
 
 reg signed [XY_SZ:0] X [0:STG-1]; 
 reg signed [XY_SZ:0] Y [0:STG-1];
 reg signed [31:0] Z [0:STG-1];
 
 wire [1:0] quadrant; 
 
 assign quadrant = angle[31:30]; 
 
  always @(posedge clock) 
 begin 
 case (quadrant) 
 2'b00, 
 2'b11: 
 begin  
 X[0] <= Xin; 
 Y[0] <= Yin; 
 Z[0] <= angle; 
 end 
 
 2'b01: 
 begin 
 X[0] <= -Yin; 
 Y[0] <= Xin; 
 Z[0] <= {2'b00,angle[29:0]}; 
 end 
 
 2'b10: 
 begin 
 X[0] <= Yin; 
 Y[0] <= -Xin; 
 Z[0] <= {2'b11,angle[29:0]};
 
 end 
 endcase 
 end 
  
  
  genvar i; 
  
  generate 
  for (i=0;i<(STG-1);i=i+1) 
  begin: XYZ 
  wire Z_sign; 
  wire signed [XY_SZ:0] X_shr,Y_shr; 
  
  assign X_shr = X[i] >>> i; 
  assign Y_shr = Y[i] >>> i; 
  
  assign Z_sign = Z[i][31]; 
  
  always @(posedge clock) 
  begin 
  X[i+1] <= Z_sign ? X[i] + Y_shr : X[i] - Y_shr; 
  Y[i+1] <= Z_sign ? Y[i] - X_shr : Y[i] + X_shr; 
  Z[i+1] <= Z_sign ? Z[i] + atan_table[i] : Z[i] - atan_table[i]; 
  end 
  end 
  endgenerate 
  
  assign Xout = X[STG-1]; 
  assign Yout = Y[STG-1]; 
 
 endmodule
 
 
 //Testbecnch for CORDIC algorithm
module tb;
 reg clock; 
 reg signed [31:0] angle; 
 reg signed [31:0] Xin; 
 reg signed [15:0] Yin; 
 wire signed [16:0] Xout; 
 wire signed [16:0] Yout; 
 
 CORDIC c1(clock,angle,Xin,Yin,Xout,Yout);
 
 initial
  begin
    clock =1'b0;
    forever #10 clock = ~clock;
  end   
 
 initial 
  begin 
   angle = 32'd35;
   Xin   = 16'd32;
   Yin   = 16'd36;  
  end
endmodule   
 

Synthesis Design

Simulation Result Waveform (Output)