ad_dds: Add selectable out data width and fair rounding

The CORDIC has a selectable width range for phase and data of 8-24.
Regarding the width of phase and data, the wider they are the smaller
the precision loss when shifting but with the cost of more FPGA
utilization. The user must decide between precision and utilization.

The DDS_WD parameter is independent of CORDIC(CORDIC_DW) or
Polynomial(16bit), letting the user chose the output width.
Here we encounter two scenarios:
 * DDS_DW < DDS data width - in this case, a fair rounding will be
implemented corresponding to the truncated bits
 * DDS_DW > DDS data width - DDS out data left shift to get the
corresponding concatenation bits.
main
AndreiGrozav 2018-04-03 15:38:17 +03:00 committed by AndreiGrozav
parent 2c1f9193cf
commit ad7e95b169
1 changed files with 54 additions and 22 deletions

View File

@ -37,51 +37,83 @@
module ad_dds #(
// data path disable
// Disable DDS
parameter DISABLE = 0,
// Range = 8-24
parameter DDS_DW = 16,
// Set 1 for CORDIC or 2 for Polynomial
parameter DDS_TYPE = 1,
// Range = 8-24
parameter CORDIC_DW = 16,
// Range = 8-24 ( make sure CORDIC_PHASE_DW < CORDIC_DW)
parameter CORDIC_PHASE_DW = 16) (
// interface
input clk,
input dds_format,
input [15:0] dds_phase_0,
input [15:0] dds_scale_0,
input [15:0] dds_phase_1,
input [15:0] dds_scale_1,
output [15:0] dds_data);
input clk,
input dds_format,
input [ 15:0] dds_phase_0,
input [ 15:0] dds_scale_0,
input [ 15:0] dds_phase_1,
input [ 15:0] dds_scale_1,
output [DDS_DW-1:0] dds_data);
// Local parameters
localparam CORDIC = 1;
localparam POLYNOMIAL = 2;
// The width for Polynomial DDS is fixed (16)
localparam DDS_D_DW = (DDS_TYPE == CORDIC) ? CORDIC_DW : 16;
localparam DDS_P_DW = (DDS_TYPE == CORDIC) ? CORDIC_PHASE_DW : 16;
// concatenation or truncation width
localparam C_T_WIDTH = (DDS_D_DW > DDS_DW) ? (DDS_D_DW - DDS_DW) : (DDS_DW - DDS_D_DW);
// internal registers
reg [15:0] dds_data_int = 'd0;
reg [15:0] dds_data_out = 'd0;
reg [15:0] dds_scale_0_d = 'd0;
reg [15:0] dds_scale_1_d = 'd0;
reg [ DDS_DW-1:0] dds_data_width = 0;
reg [DDS_D_DW-1:0] dds_data_rownd = 0;
reg [DDS_D_DW-1:0] dds_data_int = 0;
reg [ 15:0] dds_scale_0_d = 0;
reg [ 15:0] dds_scale_1_d = 0;
reg [ DDS_DW-1:0] dds_data_out = 0;
// internal signals
wire [15:0] dds_data_0_s;
wire [15:0] dds_data_1_s;
// disable
// disable DDS
generate
if (DISABLE == 1) begin
assign dds_data = 16'd0;
// assign 0 for the exact buss width to avoid warnings
assign dds_data = {DDS_DW{1'b0}};
end else begin
// dds channel output
assign dds_data = dds_data_out;
// dds channel output
// output data format
always @(posedge clk) begin
dds_data_out[DDS_DW-1] <= dds_data_width[DDS_DW-1] ^ dds_format;
dds_data_out[DDS_DW-2: 0] <= dds_data_width[DDS_DW-2: 0];
end
always @(posedge clk) begin
dds_data_int <= dds_data_0_s + dds_data_1_s;
dds_data_out[15:15] <= dds_data_int[15] ^ dds_format;
dds_data_out[14: 0] <= dds_data_int[14:0];
end
// set desired data width
always @(posedge clk) begin
if (DDS_DW <= DDS_D_DW) begin // truncation
// fair rownding
dds_data_rownd <= dds_data_int + {(C_T_WIDTH){dds_data_int[DDS_D_DW-1]}};
dds_data_width <= dds_data_rownd[DDS_D_DW-1:DDS_D_DW-DDS_DW];
end else begin // concatenation
dds_data_width <= dds_data_int << C_T_WIDTH;
end
end
// dual tone
always @(posedge clk) begin
dds_data_int <= dds_data_0_s + dds_data_1_s;
end
always @(posedge clk) begin
dds_scale_0_d <= dds_scale_0;