ad_dds: Add sine generator using CORDIC algorithm

https://en.wikipedia.org/wiki/CORDIC
Configurable in/out data width (14,16,18,20);
The HDL implementation requires pipelines, resulting in a
data_width + 2 clock cycles delay between the phase input data and the
sine data. For this reason, a ddata (delay data) was propagated through
the pipeline stages to help in future use scenarios
main
AndreiGrozav 2018-02-07 12:30:05 +02:00 committed by AndreiGrozav
parent 9b01b9f37c
commit 0e114a39e3
2 changed files with 339 additions and 0 deletions

View File

@ -0,0 +1,103 @@
// ***************************************************************************
// ***************************************************************************
// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
// 1. The GNU General Public License version 2 as published by the
// Free Software Foundation, which can be found in the top level directory
// of this repository (LICENSE_GPL2), and also online at:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
// 2. An ADI specific BSD license, which can be found in the top level directory
// of this repository (LICENSE_ADIBSD), and also on-line at:
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
// This will allow to generate bit files and not release the source code,
// as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
`timescale 1ns/100ps
module ad_dds_cordic_pipe#(
// parameters
parameter DW = 16,
parameter DELAY_DW = 1,
parameter SHIFT = 0) (
// interface
input clk,
(* keep = "TRUE" *) input dir,
(* keep = "TRUE" *) input signed [ DW-1:0] dataa_x,
(* keep = "TRUE" *) input signed [ DW-1:0] dataa_y,
(* keep = "TRUE" *) input signed [ DW-1:0] dataa_z,
(* keep = "TRUE" *) input signed [ DW-1:0] datab_x,
(* keep = "TRUE" *) input signed [ DW-1:0] datab_y,
(* keep = "TRUE" *) input signed [ DW-1:0] datab_z,
(* keep = "TRUE" *) output reg signed [ DW-1:0] result_x,
(* keep = "TRUE" *) output reg signed [ DW-1:0] result_y,
(* keep = "TRUE" *) output reg signed [ DW-1:0] result_z,
output signed [ DW-1:0] sgn_shift_x,
output signed [ DW-1:0] sgn_shift_y,
input [DELAY_DW:1] data_delay_in,
output [DELAY_DW:1] data_delay_out
);
// internal registers
reg [DELAY_DW:1] data_delay = 'd0;
// stage rotation
always @(posedge clk)
begin
case(dir)
1'b0: begin
result_x <= dataa_x - datab_y;
result_y <= dataa_y + datab_x;
result_z <= dataa_z - datab_z;
end
1'b1: begin
result_x <= dataa_x + datab_y;
result_y <= dataa_y - datab_x;
result_z <= dataa_z + datab_z;
end
endcase
end
// stage shift
assign sgn_shift_x = result_x >>> SHIFT + 1;
assign sgn_shift_y = result_y >>> SHIFT + 1;
generate
if (DELAY_DW > 1) begin
always @(posedge clk)
begin
data_delay <= data_delay_in;
end
end
endgenerate
assign data_delay_out = data_delay;
endmodule

View File

@ -0,0 +1,236 @@
// ***************************************************************************
// ***************************************************************************
// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
// 1. The GNU General Public License version 2 as published by the
// Free Software Foundation, which can be found in the top level directory
// of this repository (LICENSE_GPL2), and also online at:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
// 2. An ADI specific BSD license, which can be found in the top level directory
// of this repository (LICENSE_ADIBSD), and also on-line at:
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
// This will allow to generate bit files and not release the source code,
// as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
`timescale 1ns/100ps
module ad_dds_sine_cordic #(
// parameters
parameter CORDIC_DW = 16,
parameter DELAY_DW = 1) (
// interface
input clk,
input [CORDIC_DW-1:0] angle,
output reg [CORDIC_DW-1:0] sine,
input [ DELAY_DW-1:0] ddata_in,
output reg [ DELAY_DW-1:0] ddata_out);
// 1.647 = gain of the system
localparam [19:0] X_VALUE_20 = 318327; // ((20^2)/2)/1.647
localparam [17:0] X_VALUE_18 = 79582; // ((18^2)/2)/1.647
localparam [15:0] X_VALUE_16 = 19883; // ((16^2)/2)/1.647
localparam [13:0] X_VALUE_14 = 4970; // ((14^2)/2)/1.647
localparam Y_VALUE = 0;
// internal registers
reg signed [CORDIC_DW-1:0] x0 = 'd0;
reg signed [CORDIC_DW-1:0] y0 = 'd0;
reg signed [CORDIC_DW-1:0] z0 = 'd0;
// internal signals
wire [CORDIC_DW-1:0] x_value;
wire signed [CORDIC_DW-1:0] x_s [0:CORDIC_DW-1];
wire signed [CORDIC_DW-1:0] y_s [0:CORDIC_DW-1];
wire signed [CORDIC_DW-1:0] z_s [0:CORDIC_DW-1];
wire signed [CORDIC_DW-1:0] x_shr_s [0:CORDIC_DW-1];
wire signed [CORDIC_DW-1:0] y_shr_s [0:CORDIC_DW-1];
wire [ DELAY_DW-1:0] data_in_d [0:CORDIC_DW-1];
wire [CORDIC_DW-1:0] atan_table[0:CORDIC_DW-2];
wire [ 1:0] quadrant;
// arc tangent LUT
generate
if (CORDIC_DW == 20) begin
assign x_value = X_VALUE_20;
assign atan_table[ 0] = 20'b00100000000000000000; // 45
assign atan_table[ 1] = 20'b00010010111001000000; // 26.56505118
assign atan_table[ 2] = 20'b00001001111110110100; // 14.03624347
assign atan_table[ 3] = 20'b00000101000100010001; // 7.125016349
assign atan_table[ 4] = 20'b00000010100010110001; // 3.576334375
assign atan_table[ 5] = 20'b00000001010001011101; // 1.789910608
assign atan_table[ 6] = 20'b00000000101000101111; // 0.895173710
assign atan_table[ 7] = 20'b00000000010100011000; // 0.447614171
assign atan_table[ 8] = 20'b00000000001010001100; // 0.223810500
assign atan_table[ 9] = 20'b00000000000101000110; // 0.111905677
assign atan_table[10] = 20'b00000000000010100011; // 0.055952892
assign atan_table[11] = 20'b00000000000001010001; // 0.027976453
assign atan_table[12] = 20'b00000000000000101001; // 0.013988227
assign atan_table[13] = 20'b00000000000000010100; // 0.006994114
assign atan_table[14] = 20'b00000000000000001010; // 0.003497057
assign atan_table[15] = 20'b00000000000000000101; // 0.001748528
assign atan_table[16] = 20'b00000000000000000011; // 0.000874264
assign atan_table[17] = 20'b00000000000000000001; // 0.000437132
assign atan_table[18] = 20'b00000000000000000001; // 0.000218566
end else if (CORDIC_DW == 18) begin
assign x_value = X_VALUE_18;
assign atan_table[ 0] = 18'b001000000000000000; // 45
assign atan_table[ 1] = 18'b000100101110010000; // 26.56505118
assign atan_table[ 2] = 18'b000010011111101101; // 14.03624347
assign atan_table[ 3] = 18'b000001010001000100; // 7.125016349
assign atan_table[ 4] = 18'b000000101000101100; // 3.576334375
assign atan_table[ 5] = 18'b000000010100010111; // 1.789910608
assign atan_table[ 6] = 18'b000000001010001100; // 0.895173710
assign atan_table[ 7] = 18'b000000000101000110; // 0.447614171
assign atan_table[ 8] = 18'b000000000010100011; // 0.223810500
assign atan_table[ 9] = 18'b000000000001010001; // 0.111905677
assign atan_table[10] = 18'b000000000000101001; // 0.055952892
assign atan_table[11] = 18'b000000000000010100; // 0.027976453
assign atan_table[12] = 18'b000000000000001010; // 0.013988227
assign atan_table[13] = 18'b000000000000000101; // 0.006994114
assign atan_table[14] = 18'b000000000000000011; // 0.003497057
assign atan_table[15] = 18'b000000000000000001; // 0.001748528
assign atan_table[16] = 18'b000000000000000001; // 0.000874264
end else if (CORDIC_DW == 16) begin
assign x_value = X_VALUE_16;
assign atan_table[ 0] = 15'b0010000000000000; // 45
assign atan_table[ 1] = 15'b0001001011100100; // 26.56505118
assign atan_table[ 2] = 15'b0000100111111011; // 14.03624347
assign atan_table[ 3] = 15'b0000010100010001; // 7.125016349
assign atan_table[ 4] = 15'b0000001010001011; // 3.576334375
assign atan_table[ 5] = 15'b0000000101000110; // 1.789910608
assign atan_table[ 6] = 15'b0000000010100011; // 0.895173710
assign atan_table[ 7] = 15'b0000000001010001; // 0.447614171
assign atan_table[ 8] = 15'b0000000000101001; // 0.223810500
assign atan_table[ 9] = 15'b0000000000010100; // 0.111905677
assign atan_table[10] = 15'b0000000000001010; // 0.055952892
assign atan_table[11] = 15'b0000000000000101; // 0.027976453
assign atan_table[12] = 15'b0000000000000011; // 0.013988227
assign atan_table[13] = 15'b0000000000000001; // 0.006994114
assign atan_table[14] = 15'b0000000000000001; // 0.003497057
end else if (CORDIC_DW == 14) begin
assign x_value = X_VALUE_14;
assign atan_table[ 0] = 13'b00100000000000; // 45
assign atan_table[ 1] = 13'b00010010111001; // 26.56505118
assign atan_table[ 2] = 13'b00001001111111; // 14.03624347
assign atan_table[ 3] = 13'b00000101000100; // 7.125016349
assign atan_table[ 4] = 13'b00000010100011; // 3.576334375
assign atan_table[ 5] = 13'b00000001010001; // 1.789910608
assign atan_table[ 6] = 13'b00000000101001; // 0.895173710
assign atan_table[ 7] = 13'b00000000010100; // 0.447614171
assign atan_table[ 8] = 13'b00000000001010; // 0.223810500
assign atan_table[ 9] = 13'b00000000000101; // 0.111905677
assign atan_table[10] = 13'b00000000000011; // 0.055952892
assign atan_table[11] = 13'b00000000000001; // 0.027976453
assign atan_table[12] = 13'b00000000000001; // 0.013988227
end
endgenerate
// pre-rotating
// first two bits represent the quadrant in the unit circle
assign quadrant = angle[CORDIC_DW-1:CORDIC_DW-2];
always @(posedge clk)
begin
case (quadrant)
2'b00,
2'b11:
begin
x0 <= x_value;
y0 <= Y_VALUE;
z0 <= angle;
end
2'b01:
begin
x0 <= Y_VALUE;
y0 <= x_value;
z0 <= {2'b00, angle[CORDIC_DW-3:0]};
end
2'b10:
begin
x0 <= Y_VALUE;
y0 <= -x_value;
z0 <= {2'b11 ,angle[CORDIC_DW-3:0]};
end
endcase
end
assign x_s[0] = x0;
assign y_s[0] = y0;
assign z_s[0] = z0;
assign x_shr_s[0] = x0;
assign y_shr_s[0] = y0;
assign data_in_d[0] = ddata_in;
// cordic pipeline
genvar i;
generate
for (i=0; i < CORDIC_DW-1; i=i+1) begin: rotation
ad_dds_cordic_pipe #(
.DW (CORDIC_DW),
.DELAY_DW (DELAY_DW),
.SHIFT(i))
pipe (
.clk (clk),
.dataa_x (x_s[i]),
.dataa_y (y_s[i]),
.dataa_z (z_s[i]),
.datab_x (x_shr_s[i]),
.datab_y (y_shr_s[i]),
.datab_z (atan_table[i]),
.dir (z_s[i][CORDIC_DW-1]),
.result_x (x_s[i+1]),
.result_y (y_s[i+1]),
.result_z (z_s[i+1]),
.sgn_shift_x (x_shr_s[i+1]),
.sgn_shift_y (y_shr_s[i+1]),
.data_delay_in (data_in_d[i]),
.data_delay_out (data_in_d[i+1])
);
end
endgenerate
// x and y are cos(angle) and sin(angle)
always @(posedge clk) begin
ddata_out <= data_in_d[CORDIC_DW-1];
sine <= y_s[CORDIC_DW-1];
end
endmodule
// ***************************************************************************
// ***************************************************************************