/*
 CORDIC engine with parameterized width up to 29. Z input is one wider than
 X or Y with MSB = pi. Both optimized rotation module (cordic) and full
 rotation/vectoring setup (cordicf) are included

 Copyright (c) 2009-2012 Dimtel, Inc., All Rights Reserved

 $Id: cordic.v,v 1.3 2012/09/25 20:16:56 dim Exp $
 $Date: 2012/09/25 20:16:56 $
 $Author: dim $
 $Revision: 1.3 $
 $Log: cordic.v,v $
 Revision 1.3  2012/09/25 20:16:56  dim
 Added full rotation/vectoring module

 Revision 1.2  2009/06/02 20:09:44  dim
 Fixed a typo in a comment

 Revision 1.1  2009/02/10 05:27:28  dim
 Initial import

 Revision 1.1  2009/02/09 23:16:20  dim
 Parameterized implementation of CORDIC - initial import


*/

`timescale 1ns/100ps
module cordic #(parameter width=12) (
  input			clk,
  input [width-1:0]	xin,
  input [width-1:0]	yin,
  input [width:0]	zin,
  output [width-1:0]	xout,
  output [width-1:0]	yout,
  output [1:0]		zout
);

  wire [width:0] xc[width+2:0], yc[width+2:0], zc[width+2:0];
  reg  [width:0] x[width+2:0], y[width+2:0], z[width+2:0];
  wire [30:0] atan[29:0];
  wire [30:0] atan_rnd[29:0];
  
  assign atan[ 0] = 536870912;
  assign atan[ 1] = 316933406;
  assign atan[ 2] = 167458907;
  assign atan[ 3] = 85004756;
  assign atan[ 4] = 42667331;
  assign atan[ 5] = 21354465;
  assign atan[ 6] = 10679838;
  assign atan[ 7] = 5340245;
  assign atan[ 8] = 2670163;
  assign atan[ 9] = 1335087;
  assign atan[10] = 667544;
  assign atan[11] = 333772;
  assign atan[12] = 166886;
  assign atan[13] = 83443;
  assign atan[14] = 41722;
  assign atan[15] = 20861;
  assign atan[16] = 10430;
  assign atan[17] = 5215;
  assign atan[18] = 2608;
  assign atan[19] = 1304;
  assign atan[20] = 652;
  assign atan[21] = 326;
  assign atan[22] = 163;
  assign atan[23] = 81;
  assign atan[24] = 41;
  assign atan[25] = 20;
  assign atan[26] = 10;
  assign atan[27] = 5;
  assign atan[28] = 3;
  assign atan[29] = 1;

  // Generate rounded atan constants
  generate
  genvar k;
  for (k=0; k <= width; k = k + 1) begin: atan_gen
    assign atan_rnd[k] = atan[k] + {{width{1'b0}}, 1'b1, {(29-width){1'b0}}};
  end
  endgenerate
  
  // Initial rotation
  _alu #(.width(width+1)) xrot({width+1{1'b0}}, {xin, 1'b0}, xc[0],
                               ~zin[width]^zin[width-1]);
  _alu #(.width(width+1)) yrot({width+1{1'b0}}, {yin, 1'b0}, yc[0],
                               ~zin[width]^zin[width-1]);
  assign zc[0] = {zin[width-1:0], 1'b0};

  generate
  genvar i;
  for (i=0; i <= width+1; i = i + 1) begin: stage
    if (i==0)
      _stage #(.width(width+1), .zw(width+1-i), .shift(i)) 
               cst(x[i], y[i], z[i][width:0], 
                 atan_rnd[i][30:30-width], 1'b0,
                 xc[i+1], yc[i+1], zc[i+1][width:0]);
    else
      _stage #(.width(width+1), .zw(width+2-i), .shift(i)) 
               cst(x[i], y[i], z[i][width+1-i:0], 
                 atan_rnd[i][31-i:30-width], 1'b0,
                 xc[i+1], yc[i+1], zc[i+1][width+1-i:0]);
    
    always @(posedge clk) begin
      x[i] <= xc[i];
      y[i] <= yc[i];
      z[i] <= zc[i];
    end
  end
  endgenerate  

  // Final pipeline - not in generate
  always @(posedge clk) begin
    x[width+2] <= xc[width+2];
    y[width+2] <= yc[width+2];
    z[width+2] <= zc[width+2];
  end

  // Assign outputs
  assign xout = x[width+2][width:1];
  assign yout = y[width+2][width:1];
  assign zout = z[width+2][1:0];
endmodule // cordic

`unconnected_drive pull0

module cordicf #(parameter width=12) (
  input			clk,
  input [width-1:0]	xin,
  input [width-1:0]	yin,
  input [width:0]	zin,
  input			vector,
  output [width-1:0]	xout,
  output [width-1:0]	yout,
  output [width+1:0]	zout
);
  wire d_0;
  wire signed [width:0] xc[width+1:0], yc[width+1:0];
  wire signed [width+1:0] zc[width+1:0];
  reg signed [width:0] x[width+1:0], y[width+1:0];
  reg signed [width+1:0] z[width+1:0];
  wire [30:0] atan[29:0];
  wire [31:0] atan_rnd[29:0];
  
  assign atan[ 0] = 536870912;
  assign atan[ 1] = 316933406;
  assign atan[ 2] = 167458907;
  assign atan[ 3] = 85004756;
  assign atan[ 4] = 42667331;
  assign atan[ 5] = 21354465;
  assign atan[ 6] = 10679838;
  assign atan[ 7] = 5340245;
  assign atan[ 8] = 2670163;
  assign atan[ 9] = 1335087;
  assign atan[10] = 667544;
  assign atan[11] = 333772;
  assign atan[12] = 166886;
  assign atan[13] = 83443;
  assign atan[14] = 41722;
  assign atan[15] = 20861;
  assign atan[16] = 10430;
  assign atan[17] = 5215;
  assign atan[18] = 2608;
  assign atan[19] = 1304;
  assign atan[20] = 652;
  assign atan[21] = 326;
  assign atan[22] = 163;
  assign atan[23] = 81;
  assign atan[24] = 41;
  assign atan[25] = 20;
  assign atan[26] = 10;
  assign atan[27] = 5;
  assign atan[28] = 3;
  assign atan[29] = 1;

  // Generate rounded atan constants
  generate
  genvar k;
  for (k=0; k <= width; k = k + 1) begin: atan_gen
    assign atan_rnd[k] = atan[k] + {{width{1'b0}}, 1'b1, {(29-width){1'b0}}};
  end
  endgenerate
  
  // Initial rotation
  assign d_0 = vector ? ~xin[width-1] : ~zin[width]^zin[width-1];
  _alu #(.width(width+1)) xrot({width+1{1'b0}}, {xin, 1'b0}, xc[0], d_0);
  _alu #(.width(width+1)) yrot({width+1{1'b0}}, {yin, 1'b0}, yc[0], d_0);
  assign zc[0] = {zin[width]^~d_0, zin[width-1:0], 1'b0};

  // Debugging
  wire [width:0] xc0 = xc[0], yc0 = yc[0], zc0 = zc[0];

  generate
  genvar i;
  for (i=0; i <= width; i = i + 1) begin: stage
      _stage #(.width(width+1), .zw(width+2), .shift(i)) 
               cst(x[i], y[i], z[i], 
                 atan_rnd[i][31:30-width], vector,
                 xc[i+1], yc[i+1], zc[i+1]);
    
    always @(posedge clk) begin
      x[i] <= xc[i];
      y[i] <= yc[i];
      z[i] <= zc[i];
    end
  end
  endgenerate  

  // Final pipeline - not in generate
  always @(posedge clk) begin
    x[width+1] <= xc[width+1];
    y[width+1] <= yc[width+1];
    z[width+1] <= zc[width+1];
  end

  // Assign outputs
  assign xout = x[width+1][width:1];
  assign yout = y[width+1][width:1];
  assign zout = z[width+1];
endmodule // cordicf

module cordic13(
  input		clk,
  input signed [13:0]	xin,
  input signed [13:0]	yin,
  input signed [13:0]	zin,
  input		vector,	// 0 - rotation, 1 - vectoring
  output [12:0]	xout,
  output [12:0] yout,
  output [13:0]  zout
);
  // MSB of zin is pi (8192 = pi)
  wire d_0 = vector ? ~xin[12] : ~zin[13]^zin[12];
  wire signed [13:0] xc0, xc1, xc2, xc3, xc4, xc5, xc6, xc7, xc8, xc9, xc10, xc11, xc12, xc13, xc14;
  wire signed [13:0] yc0, yc1, yc2, yc3, yc4, yc5, yc6, yc7, yc8, yc9, yc10, yc11, yc12, yc13, yc14;
  reg [13:0] x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14;
  reg [13:0] y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14;
  
  reg [13:0] z0 ; wire [13:0] zc0 ; wire [13:0] atan0  =	2048;
  reg [13:0] z1 ; wire [13:0] zc1 ; wire [13:0] atan1  =	1209;
  reg [13:0] z2 ; wire [13:0] zc2 ; wire [13:0] atan2  =	639;
  reg [13:0] z3 ; wire [13:0] zc3 ; wire [13:0] atan3  =	324;
  reg [13:0] z4 ; wire [13:0] zc4 ; wire [13:0] atan4  =	163;
  reg [13:0] z5 ; wire [13:0] zc5 ; wire [13:0] atan5  =	81;
  reg [13:0] z6 ; wire [13:0] zc6 ; wire [13:0] atan6  =	41;
  reg [13:0] z7 ; wire [13:0] zc7 ; wire [13:0] atan7  =	20;
  reg [13:0] z8 ; wire [13:0] zc8 ; wire [13:0] atan8  =	10;
  reg [13:0] z9 ; wire [13:0] zc9 ; wire [13:0] atan9  =	5;
  reg [13:0] z10; wire [13:0] zc10; wire [13:0] atan10 =	3;
  reg [13:0] z11; wire [13:0] zc11; wire [13:0] atan11 =	1;
  reg [13:0] z12; wire [13:0] zc12; wire [13:0] atan12 =        1;
  reg [13:0] z13; wire [13:0] zc13; wire [13:0] atan13 =        1;
  reg [13:0] z14; wire [13:0] zc14;

  // Initial rotation by +/- pi
  _alu #(.width(14)) xrot(14'b0, xin, xc0, d_0);
  _alu #(.width(14)) yrot(14'b0, yin, yc0, d_0);
  assign zc0 = {zin[13]^~d_0, zin[12:0]};
  
  _stage #(.width(14), .zw(14), .shift(0)) 
         stage1(x0, y0, z0, atan0, vector, xc1, yc1, zc1);
  _stage #(.width(14), .zw(14), .shift(1)) 
         stage2(x1, y1, z1, atan1, vector, xc2, yc2, zc2);
  _stage #(.width(14), .zw(14), .shift(2)) 
         stage3(x2, y2, z2, atan2, vector, xc3, yc3, zc3);
  _stage #(.width(14), .zw(14), .shift(3)) 
         stage4(x3, y3, z3, atan3, vector, xc4, yc4, zc4);
  _stage #(.width(14), .zw(14), .shift(4)) 
         stage5(x4, y4, z4, atan4, vector, xc5, yc5, zc5);
  _stage #(.width(14), .zw(14), .shift(5)) 
         stage6(x5, y5, z5, atan5, vector, xc6, yc6, zc6);
  _stage #(.width(14), .zw(14), .shift(6)) 
         stage7(x6, y6, z6, atan6, vector, xc7, yc7, zc7);
  _stage #(.width(14), .zw(14), .shift(7)) 
         stage8(x7, y7, z7, atan7, vector, xc8, yc8, zc8);
  _stage #(.width(14), .zw(14), .shift(8)) 
         stage9(x8, y8, z8, atan8, vector, xc9, yc9, zc9);
  _stage #(.width(14), .zw(14), .shift(9)) 
         stage10(x9, y9, z9, atan9, vector, xc10, yc10, zc10);
  _stage #(.width(14), .zw(14), .shift(10)) 
         stage11(x10, y10, z10, atan10, vector, xc11, yc11, zc11);
  _stage #(.width(14), .zw(14), .shift(11)) 
         stage12(x11, y11, z11, atan11, vector, xc12, yc12, zc12);
  _stage #(.width(14), .zw(14), .shift(12)) 
         stage13(x12, y12, z12, atan12, vector, xc13, yc13, zc13);
  _stage #(.width(14), .zw(14), .shift(13)) 
         stage14(x13, y13, z13, atan13, vector, xc14, yc14, zc14);
         
  always @(posedge clk) begin
    x0 <=  xc0;  y0  <= yc0;  z0 <=  zc0;
    x1 <=  xc1;  y1  <= yc1;  z1 <=  zc1;
    x2 <=  xc2;  y2  <= yc2;  z2 <=  zc2;
    x3 <=  xc3;  y3  <= yc3;  z3 <=  zc3;
    x4 <=  xc4;  y4  <= yc4;  z4 <=  zc4;
    x5 <=  xc5;  y5  <= yc5;  z5 <=  zc5;
    x6 <=  xc6;  y6  <= yc6;  z6 <=  zc6;
    x7 <=  xc7;  y7  <= yc7;  z7 <=  zc7;
    x8 <=  xc8;  y8  <= yc8;  z8 <=  zc8;
    x9 <=  xc9;  y9  <= yc9;  z9 <=  zc9;
    x10 <= xc10; y10 <= yc10; z10 <= zc10;
    x11 <= xc11; y11 <= yc11; z11 <= zc11;
    x12 <= xc12; y12 <= yc12; z12 <= zc12;
    x13 <= xc13; y13 <= yc13; z13 <= zc13;
    x14 <= xc14; y14 <= yc14; z14 <= zc14;
  end

  // Assign outputs
  assign xout = x14[13:1];
  assign yout = y14[13:1];
  assign zout = z14;
endmodule // cordic13

`nounconnected_drive

module _stage #(parameter width=12, parameter zw=12, parameter shift=0) (
  input signed [width-1:0]	xin,
  input signed [width-1:0]	yin,
  input signed [zw-1:0]		zin,
  input signed [zw-1:0]		atan,
  input				vector,
  output signed [width-1:0]	xout,
  output signed [width-1:0]	yout,
  output signed [zw-1:0]	zout
);

  wire d_i = vector ? ~yin[width-1] : zin[zw-1]; // MSB
  
  // d_i = 0(+1), 1(-1). X:d_i, Y:~d_i, Z:d_i
  
  _alu #(.width(width)) xalu(.a(xin), .b(yin>>>shift), .c(xout), .sign(d_i));
  _alu #(.width(width)) yalu(.a(yin), .b(xin>>>shift), .c(yout), .sign(~d_i));
  _alu #(.width(zw)) zalu(.a(zin), .b(atan), .c(zout), .sign(d_i));
endmodule // _stage

module _alu #(parameter width=12) (
  input signed [width-1:0]	a,
  input signed [width-1:0]	b,
  output signed [width-1:0]	c,
  input signed			sign
);
  assign c = sign ? a + b : a - b;
endmodule // _alu
