ad_ip_jesd204_tpl_dac: Add support for modes with N or N' != 16

The ad_ip_jesd204_tpl_dac currently only supports JESD204 modes that have
both N and N' set to 16.

Newer DACs like the AD9172 support modes where N and N' are not equal to
16. Add support for these modes.

The width of the internal channel data path is set to N, only processing as
many bits as necessary. At the framer the data is up-sized to N' bits with
tail bits inserted as necessary. This data is then passed to the link
layer.

The width at the DMA interface is kept at 16 bits per sample regardless of
the configuration of either N or N'. This is done to keep the interface
consistent with the existing infrastructure it will connect to like upack
and DMA. The data is expected to the LSB aligned, the unused MSBs will be
ignored.

Same is true for the test-pattern data registers. These register keep their
existing 16-bit layout, but unused MSBs will be ignored by the core.

The PN generators are modified to create only N bits of data per sample.

Note that while the core can now support modes with N' = 12 there is still
the restriction that requires the number of frames per beat to be an even
number. Which means that not all modes with N' = 12 can be supported yet.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
main
Lars-Peter Clausen 2018-08-08 15:41:00 +02:00 committed by István Csomortáni
parent a98bc88b84
commit 169f38e7d1
9 changed files with 125 additions and 53 deletions

View File

@ -132,6 +132,8 @@ module axi_ad9144 #(
.ID (ID),
.NUM_LANES (NUM_CHANNELS * 2),
.NUM_CHANNELS (NUM_CHANNELS),
.CONVERTER_RESOLUTION (16),
.BITS_PER_SAMPLE (16),
.SAMPLES_PER_FRAME (1),
.DDS_TYPE (DAC_DDS_TYPE),
.DDS_CORDIC_DW (DAC_DDS_CORDIC_DW),

View File

@ -92,6 +92,8 @@ module axi_ad9152 #(
.ID(ID),
.NUM_LANES(4),
.NUM_CHANNELS(2),
.CONVERTER_RESOLUTION (16),
.BITS_PER_SAMPLE (16),
.SAMPLES_PER_FRAME (1),
.DDS_TYPE (DAC_DDS_TYPE),
.DDS_CORDIC_DW (DAC_DDS_CORDIC_DW),

View File

@ -28,6 +28,8 @@ module ad_ip_jesd204_tpl_dac #(
parameter NUM_LANES = 4,
parameter NUM_CHANNELS = 2,
parameter SAMPLES_PER_FRAME = 1,
parameter CONVERTER_RESOLUTION = 16,
parameter BITS_PER_SAMPLE = 16,
parameter DDS_TYPE = 1,
parameter DDS_CORDIC_DW = 16,
parameter DDS_CORDIC_PHASE_DW = 16,
@ -81,8 +83,9 @@ module ad_ip_jesd204_tpl_dac #(
/* Static for now */
localparam OCTETS_PER_BEAT = 4;
localparam DATA_PATH_WIDTH = 2 * OCTETS_PER_BEAT * NUM_LANES / NUM_CHANNELS;
localparam DATA_PATH_WIDTH = OCTETS_PER_BEAT * 8 * NUM_LANES / NUM_CHANNELS / BITS_PER_SAMPLE;
localparam LINK_DATA_WIDTH = NUM_LANES * OCTETS_PER_BEAT * 8;
localparam DMA_DATA_WIDTH = 16 * DATA_PATH_WIDTH * NUM_CHANNELS;
// internal signals
@ -157,6 +160,7 @@ module ad_ip_jesd204_tpl_dac #(
.OCTETS_PER_BEAT (OCTETS_PER_BEAT),
.DATA_PATH_WIDTH (DATA_PATH_WIDTH),
.LINK_DATA_WIDTH (LINK_DATA_WIDTH),
.DMA_DATA_WIDTH (DMA_DATA_WIDTH),
.DDS_TYPE (DDS_TYPE),
.DDS_CORDIC_DW (DDS_CORDIC_DW),
.DDS_CORDIC_PHASE_DW (DDS_CORDIC_PHASE_DW)

View File

@ -26,6 +26,7 @@
module ad_ip_jesd204_tpl_dac_channel #(
parameter DATAPATH_DISABLE = 0,
parameter DATA_PATH_WIDTH = 4,
parameter CONVERTER_RESOLUTION = 16,
parameter DDS_TYPE = 1,
parameter DDS_CORDIC_DW = 16,
parameter DDS_CORDIC_PHASE_DW = 16
@ -35,12 +36,12 @@ module ad_ip_jesd204_tpl_dac_channel #(
input clk,
input [DATA_PATH_WIDTH*16-1:0] dma_data,
output reg [DATA_PATH_WIDTH*16-1:0] dac_data = 'h00,
output reg [DATA_PATH_WIDTH*CONVERTER_RESOLUTION-1:0] dac_data = 'h00,
// PN data
input [DATA_PATH_WIDTH*16-1:0] pn7_data,
input [DATA_PATH_WIDTH*16-1:0] pn15_data,
input [DATA_PATH_WIDTH*CONVERTER_RESOLUTION-1:0] pn7_data,
input [DATA_PATH_WIDTH*CONVERTER_RESOLUTION-1:0] pn15_data,
// Configuration
@ -62,14 +63,18 @@ module ad_ip_jesd204_tpl_dac_channel #(
output reg dac_enable = 1'b0
);
localparam CR = CONVERTER_RESOLUTION;
localparam CHANNEL_DATA_WIDTH = DATA_PATH_WIDTH * CR;
// internal signals
wire [DATA_PATH_WIDTH*16-1:0] dac_dds_data_s;
wire [DATA_PATH_WIDTH*16-1:0] dac_pat_data_s;
wire [CHANNEL_DATA_WIDTH-1:0] dac_dds_data_s;
wire [CHANNEL_DATA_WIDTH-1:0] dac_dma_data_s;
wire [CHANNEL_DATA_WIDTH-1:0] dac_pat_data_s;
generate
if (DATA_PATH_WIDTH > 1) begin
assign dac_pat_data_s = {DATA_PATH_WIDTH/2{dac_pat_data_1,dac_pat_data_0}};
assign dac_pat_data_s = {DATA_PATH_WIDTH/2{dac_pat_data_1[0+:CR],dac_pat_data_0[0+:CR]}};
end else begin
reg dac_pat_data_sel = 1'b0;
@ -82,7 +87,13 @@ module ad_ip_jesd204_tpl_dac_channel #(
end
assign dac_pat_data_s = dac_pat_data_sel == 1'b0 ?
dac_pat_data_0 : dac_pat_data_1;
dac_pat_data_0[0+:CR] : dac_pat_data_1[0+:CR];
end
genvar i;
/* Data is expected to be LSB aligned, drop unused MSBs */
for (i = 0; i < DATA_PATH_WIDTH; i = i + 1) begin: g_dac_dma_data
assign dac_dma_data_s[CR*i+:CR] = dma_data[16*i+:CR];
end
endgenerate
@ -96,7 +107,7 @@ module ad_ip_jesd204_tpl_dac_channel #(
4'h5: dac_data <= ~pn15_data;
4'h4: dac_data <= ~pn7_data;
4'h3: dac_data <= 'h00;
4'h2: dac_data <= dma_data;
4'h2: dac_data <= dac_dma_data_s;
4'h1: dac_data <= dac_pat_data_s;
default: dac_data <= dac_dds_data_s;
endcase
@ -106,7 +117,7 @@ module ad_ip_jesd204_tpl_dac_channel #(
ad_dds #(
.DISABLE (DATAPATH_DISABLE),
.DDS_DW (16),
.DDS_DW (CONVERTER_RESOLUTION),
.PHASE_DW (16),
.DDS_TYPE (DDS_TYPE),
.CORDIC_DW (DDS_CORDIC_DW),

View File

@ -27,10 +27,13 @@ module ad_ip_jesd204_tpl_dac_core #(
parameter DATAPATH_DISABLE = 0,
parameter NUM_LANES = 1,
parameter NUM_CHANNELS = 1,
parameter BITS_PER_SAMPLE = 16,
parameter CONVERTER_RESOLUTION = 16,
parameter SAMPLES_PER_FRAME = 1,
parameter OCTETS_PER_BEAT = 4,
parameter DATA_PATH_WIDTH = 4,
parameter LINK_DATA_WIDTH = NUM_LANES * OCTETS_PER_BEAT * 8,
parameter DMA_DATA_WIDTH = DATA_PATH_WIDTH * 16 * NUM_CHANNELS,
parameter DDS_TYPE = 1,
parameter DDS_CORDIC_DW = 16,
parameter DDS_CORDIC_PHASE_DW = 16
@ -44,7 +47,7 @@ module ad_ip_jesd204_tpl_dac_core #(
// dma interface
output [NUM_CHANNELS-1:0] dac_valid,
input [LINK_DATA_WIDTH-1:0] dac_ddata,
input [DMA_DATA_WIDTH-1:0] dac_ddata,
// Configuration interface
@ -66,21 +69,28 @@ module ad_ip_jesd204_tpl_dac_core #(
output [NUM_CHANNELS-1:0] enable
);
localparam DAC_CDW = CONVERTER_RESOLUTION * DATA_PATH_WIDTH;
localparam DAC_DATA_WIDTH = DAC_CDW * NUM_CHANNELS;
localparam DMA_CDW = DATA_PATH_WIDTH * 16;
assign link_valid = 1'b1;
wire [LINK_DATA_WIDTH-1:0] dac_data_s;
wire [DAC_DATA_WIDTH-1:0] dac_data_s;
wire [DATA_PATH_WIDTH*16-1:0] pn7_data;
wire [DATA_PATH_WIDTH*16-1:0] pn15_data;
wire [DAC_CDW-1:0] pn7_data;
wire [DAC_CDW-1:0] pn15_data;
// device interface
ad_ip_jesd204_tpl_dac_framer #(
.NUM_LANES (NUM_LANES),
.NUM_CHANNELS (NUM_CHANNELS),
.BITS_PER_SAMPLE (BITS_PER_SAMPLE),
.CONVERTER_RESOLUTION (CONVERTER_RESOLUTION),
.SAMPLES_PER_FRAME (SAMPLES_PER_FRAME),
.OCTETS_PER_BEAT (OCTETS_PER_BEAT),
.LINK_DATA_WIDTH (LINK_DATA_WIDTH)
.LINK_DATA_WIDTH (LINK_DATA_WIDTH),
.DAC_DATA_WIDTH (DAC_DATA_WIDTH)
) i_framer (
.link_data (link_data),
.dac_data (dac_data_s)
@ -88,7 +98,8 @@ module ad_ip_jesd204_tpl_dac_core #(
// PN generator
ad_ip_jesd204_tpl_dac_pn #(
.DATA_PATH_WIDTH (DATA_PATH_WIDTH)
.DATA_PATH_WIDTH (DATA_PATH_WIDTH),
.CONVERTER_RESOLUTION (CONVERTER_RESOLUTION)
) i_pn_gen (
.clk (clk),
.reset (dac_sync),
@ -101,13 +112,13 @@ module ad_ip_jesd204_tpl_dac_core #(
assign dac_valid = {NUM_CHANNELS{1'b1}};
localparam CDW = DATA_PATH_WIDTH * 16;
generate
genvar i;
for (i = 0; i < NUM_CHANNELS; i = i + 1) begin: g_channel
ad_ip_jesd204_tpl_dac_channel #(
.DATA_PATH_WIDTH (DATA_PATH_WIDTH),
.CONVERTER_RESOLUTION (CONVERTER_RESOLUTION),
.DATAPATH_DISABLE (DATAPATH_DISABLE),
.DDS_TYPE (DDS_TYPE),
.DDS_CORDIC_DW (DDS_CORDIC_DW),
@ -115,8 +126,8 @@ module ad_ip_jesd204_tpl_dac_core #(
) i_channel (
.clk (clk),
.dac_enable (enable[i]),
.dac_data (dac_data_s[CDW*i+:CDW]),
.dma_data (dac_ddata[CDW*i+:CDW]),
.dac_data (dac_data_s[DAC_CDW*i+:DAC_CDW]),
.dma_data (dac_ddata[DMA_CDW*i+:DMA_CDW]),
.pn7_data (pn7_data),
.pn15_data (pn15_data),

View File

@ -26,9 +26,12 @@
module ad_ip_jesd204_tpl_dac_framer #(
parameter NUM_LANES = 8,
parameter NUM_CHANNELS = 4,
parameter BITS_PER_SAMPLE = 16,
parameter CONVERTER_RESOLUTION = 16,
parameter SAMPLES_PER_FRAME = 2,
parameter OCTETS_PER_BEAT = 4,
parameter LINK_DATA_WIDTH = OCTETS_PER_BEAT * 8 * NUM_LANES
parameter LINK_DATA_WIDTH = OCTETS_PER_BEAT * 8 * NUM_LANES,
parameter DAC_DATA_WIDTH = LINK_DATA_WIDTH * CONVERTER_RESOLUTION / BITS_PER_SAMPLE
) (
// jesd interface
@ -36,7 +39,7 @@ module ad_ip_jesd204_tpl_dac_framer #(
// dac interface
input [LINK_DATA_WIDTH-1:0] dac_data
input [DAC_DATA_WIDTH-1:0] dac_data
);
/*
@ -44,7 +47,7 @@ module ad_ip_jesd204_tpl_dac_framer #(
* JESD204 link expects for the specified framer configuration.
*
* The input sample data in dac_data is expected to be grouped by converter.
* The first sample is in the LSBs.
* The first sample is in the LSBs. Each sample has CONVERTER_RESOLUTION bits.
*
* Or in other words the data in dac_data is expected to have the following
* layout.
@ -86,12 +89,12 @@ module ad_ip_jesd204_tpl_dac_framer #(
* ordered in either case. That means lower bits are in the LSBs.
*/
localparam BITS_PER_SAMPLE = 16;
localparam FRAMES_PER_BEAT = 8 * OCTETS_PER_BEAT / BITS_PER_LANE_PER_FRAME;
localparam SAMPLES_PER_BEAT = LINK_DATA_WIDTH / 16;
localparam FRAMES_PER_BEAT = OCTETS_PER_BEAT * 8 / BITS_PER_LANE_PER_FRAME;
localparam SAMPLES_PER_BEAT = DAC_DATA_WIDTH / CONVERTER_RESOLUTION;
localparam BITS_PER_CHANNEL_PER_FRAME = BITS_PER_SAMPLE * SAMPLES_PER_FRAME;
localparam BITS_PER_LANE_PER_FRAME = BITS_PER_CHANNEL_PER_FRAME *
NUM_CHANNELS / NUM_LANES;
localparam TAIL_BITS = BITS_PER_SAMPLE - CONVERTER_RESOLUTION;
wire [LINK_DATA_WIDTH-1:0] link_data_msb_s;
wire [LINK_DATA_WIDTH-1:0] frame_data_s;
@ -100,13 +103,17 @@ module ad_ip_jesd204_tpl_dac_framer #(
generate
genvar i;
genvar j;
/* Reorder samples MSB first */
/* Reorder samples MSB first and insert tail bits */
for (i = 0; i < SAMPLES_PER_BEAT; i = i + 1) begin: g_dac_data_msb
localparam w = BITS_PER_SAMPLE;
localparam src_lsb = i * w;
localparam dst_msb = LINK_DATA_WIDTH - 1 - src_lsb;
localparam src_w = CONVERTER_RESOLUTION;
localparam dst_w = BITS_PER_SAMPLE;
localparam src_lsb = i * src_w;
localparam dst_msb = LINK_DATA_WIDTH - 1 - i * dst_w;
assign dac_data_msb[dst_msb-:w] = dac_data[src_lsb+:w];
assign dac_data_msb[dst_msb-:src_w] = dac_data[src_lsb+:src_w];
if (TAIL_BITS > 0) begin
assign dac_data_msb[dst_msb-src_w-:TAIL_BITS] = {TAIL_BITS{1'b0}};
end
end
/* Slice channel and pack it into frames */

View File

@ -81,6 +81,20 @@ ad_ip_parameter NUM_CHANNELS INTEGER 1 true [list \
GROUP $group \
]
ad_ip_parameter BITS_PER_SAMPLE INTEGER 16 false [list \
DISPLAY_NAME "Bits per Sample (N')" \
ALLOWED_RANGES {12 16} \
UNITS bits \
GROUP $group \
]
ad_ip_parameter CONVERTER_RESOLUTION INTEGER 16 true [list \
DISPLAY_NAME "Converter Resolution (N)" \
ALLOWED_RANGES {11 12 16} \
UNITS bits \
GROUP $group \
]
ad_ip_parameter SAMPLES_PER_FRAME INTEGER 1 true [list \
DISPLAY_NAME "Samples per Frame (S)" \
DISPLAY_UNITS "samples" \
@ -141,22 +155,25 @@ proc p_ad_ip_jesd204_tpl_dac_elab {} {
# read core parameters
set m_num_of_lanes [get_parameter_value "NUM_LANES"]
set m_num_of_channels [get_parameter_value "NUM_CHANNELS"]
set channel_bus_width [expr 32*$m_num_of_lanes/$m_num_of_channels]
set L [get_parameter_value "NUM_LANES"]
set M [get_parameter_value "NUM_CHANNELS"]
set NP [get_parameter_value "BITS_PER_SAMPLE"]
# The DMA interface is always 16-bits per sample, regardless of NP
set channel_bus_width [expr 16 * (32 * $L / ($M * $NP))]
# link layer interface
add_interface link_data avalon_streaming source
add_interface_port link_data link_data data output [expr 32*$m_num_of_lanes]
add_interface_port link_data link_data data output [expr 32 * $L]
add_interface_port link_data link_valid valid output 1
add_interface_port link_data link_ready ready input 1
set_interface_property link_data associatedClock link_clk
set_interface_property link_data dataBitsPerSymbol [expr 32*$m_num_of_lanes]
set_interface_property link_data dataBitsPerSymbol [expr 32 * $L]
# dma interface
for {set i 0} {$i < $m_num_of_channels} {incr i} {
for {set i 0} {$i < $M} {incr i} {
add_interface dac_ch_$i conduit end
add_interface_port dac_ch_$i dac_enable_$i enable output 1
set_port_property dac_enable_$i fragment_list [format "enable(%d:%d)" $i $i]

View File

@ -86,6 +86,8 @@ foreach p {DDS_CORDIC_DW DDS_CORDIC_PHASE_DW} {
foreach {p v} {
"NUM_LANES" "1 2 3 4 8" \
"NUM_CHANNELS" "1 2 4 6 8" \
"BITS_PER_SAMPLE" "12 16" \
"CONVERTER_RESOLUTION" "11 12 16" \
"SAMPLES_PER_FRAME" "1 2 3 4 6 8 12 16" \
} { \
set_property -dict [list \
@ -113,6 +115,8 @@ set i 0
foreach {k v} { \
"NUM_LANES" "Number of Lanes (L)" \
"NUM_CHANNELS" "Number of Conveters (M)" \
"BITS_PER_SAMPLE" "Bits per Sample (N')" \
"CONVERTER_RESOLUTION" "Converter Resolution (N)" \
"SAMPLES_PER_FRAME" "Samples per Frame (S)" \
} { \
set p [ipgui::get_guiparamspec -name $k -component $cc]

View File

@ -24,26 +24,33 @@
`timescale 1ns/100ps
module ad_ip_jesd204_tpl_dac_pn #(
parameter DATA_PATH_WIDTH = 4
parameter DATA_PATH_WIDTH = 4,
parameter CONVERTER_RESOLUTION = 16
) (
input clk,
input reset,
output [DATA_PATH_WIDTH*16-1:0] pn7_data,
output [DATA_PATH_WIDTH*16-1:0] pn15_data
output [DATA_PATH_WIDTH*CONVERTER_RESOLUTION-1:0] pn7_data,
output [DATA_PATH_WIDTH*CONVERTER_RESOLUTION-1:0] pn15_data
);
localparam DW = DATA_PATH_WIDTH * 16 - 1;
localparam CR = CONVERTER_RESOLUTION;
localparam DW = DATA_PATH_WIDTH * CR - 1;
reg [DW:0] pn7_state = {DW+1{1'b1}};
reg [DW:0] pn15_state = {DW+1{1'b1}};
/* We need at least enough bits to store the PN state */
localparam PN7_W = DW > 6 ? DW : 6;
localparam PN15_W = DW > 14 ? DW : 14;
reg [PN7_W:0] pn7_state = {PN7_W+1{1'b1}};
reg [PN15_W:0] pn15_state = {PN15_W+1{1'b1}};
wire [DW:0] pn7;
wire [DW+7:0] pn7_full_state;
wire [DW:0] pn7_reset;
wire [PN7_W:0] pn7_reset;
wire [DW:0] pn15;
wire [DW+15:0] pn15_full_state;
wire [DW:0] pn15_reset;
wire [PN15_W:0] pn15_reset;
/* PN7 x^7 + x^6 + 1 */
assign pn7 = pn7_full_state[7+:DW+1] ^ pn7_full_state[6+:DW+1];
@ -53,19 +60,26 @@ module ad_ip_jesd204_tpl_dac_pn #(
assign pn15 = pn15_full_state[15+:DW+1] ^ pn15_full_state[14+:DW+1];
assign pn15_full_state = {pn15_state[14:0],pn15};
assign pn7_reset[DW-:7] = {7{1'b1}};
assign pn7_reset[DW-7:0] = pn7_reset[DW:7] ^ pn7_reset[DW-1:6];
assign pn7_reset[PN7_W-:7] = {7{1'b1}};
assign pn15_reset[PN15_W-:15] = {15{1'b1}};
assign pn15_reset[DW-:15] = {15{1'b1}};
assign pn15_reset[DW-15:0] = pn15_reset[DW:15] ^ pn15_reset[DW-1:14];
generate
if (PN7_W >= 7) begin
assign pn7_reset[PN7_W-7:0] = pn7_reset[PN7_W:7] ^ pn7_reset[PN7_W-1:6];
end
if (PN15_W >= 15) begin
assign pn15_reset[PN15_W-15:0] = pn15_reset[PN15_W:15] ^ pn15_reset[PN15_W-1:14];
end
endgenerate
always @(posedge clk) begin
if (reset == 1'b1) begin
pn7_state <= pn7_reset;
pn15_state <= pn15_reset;
end else begin
pn7_state <= pn7;
pn15_state <= pn15;
pn7_state <= pn7_full_state[PN7_W:0];
pn15_state <= pn15_full_state[PN15_W:0];
end
end
@ -76,9 +90,9 @@ module ad_ip_jesd204_tpl_dac_pn #(
* sample of the PN state and put it into the LSB sample of the output data.
*/
genvar i;
for (i = 0; i <= DW; i = i + 16) begin: g_pn_swizzle
assign pn7_data[i+:16] = pn7_state[DW-i-:16];
assign pn15_data[i+:16] = pn15_state[DW-i-:16];
for (i = 0; i <= DW; i = i + CR) begin: g_pn_swizzle
assign pn7_data[i+:CR] = pn7_state[PN7_W-i-:CR];
assign pn15_data[i+:CR] = pn15_state[PN15_W-i-:CR];
end
endgenerate