ad_ip_jesd204_tpl_dac: Make framer more flexible
The current framer implementation is limited in that it only supports N'=16 and either S=1 or F=1. Rework the framer implementation to be more flexible and support more framer setting combinations. The new framer implementation performs the mapping in two steps. First it groups samples into frames, as there might be more than one frame per beat. In the second step the frames are distributed onto the lanes. Note that this still results in a single input bit being mapped onto a single output bit and no combinatorial logic is involved. The two step implementation just makes it (hopefully) easier to follow. The only restriction that remains is that number of frames per beat must be integer. This means that F must be either 1, 2 or 4. Supporting partial frames would result in partial sample sets being consumed at the input, which is not supported by input pipeline. The new framer has provisions for handling values for the number of octets per beat other than 4, but this is not exposed as a configuration option yet since the link layer can only handle 4 octets per beat. Making the octets per beat configurable is something for future iterations of the core. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>main
parent
caa188e5a7
commit
a98bc88b84
|
@ -132,6 +132,7 @@ module axi_ad9144 #(
|
|||
.ID (ID),
|
||||
.NUM_LANES (NUM_CHANNELS * 2),
|
||||
.NUM_CHANNELS (NUM_CHANNELS),
|
||||
.SAMPLES_PER_FRAME (1),
|
||||
.DDS_TYPE (DAC_DDS_TYPE),
|
||||
.DDS_CORDIC_DW (DAC_DDS_CORDIC_DW),
|
||||
.DDS_CORDIC_PHASE_DW (DAC_DDS_CORDIC_PHASE_DW),
|
||||
|
|
|
@ -92,6 +92,7 @@ module axi_ad9152 #(
|
|||
.ID(ID),
|
||||
.NUM_LANES(4),
|
||||
.NUM_CHANNELS(2),
|
||||
.SAMPLES_PER_FRAME (1),
|
||||
.DDS_TYPE (DAC_DDS_TYPE),
|
||||
.DDS_CORDIC_DW (DAC_DDS_CORDIC_DW),
|
||||
.DDS_CORDIC_PHASE_DW (DAC_DDS_CORDIC_PHASE_DW),
|
||||
|
|
|
@ -27,6 +27,7 @@ module ad_ip_jesd204_tpl_dac #(
|
|||
parameter ID = 0,
|
||||
parameter NUM_LANES = 4,
|
||||
parameter NUM_CHANNELS = 2,
|
||||
parameter SAMPLES_PER_FRAME = 1,
|
||||
parameter DDS_TYPE = 1,
|
||||
parameter DDS_CORDIC_DW = 16,
|
||||
parameter DDS_CORDIC_PHASE_DW = 16,
|
||||
|
@ -77,7 +78,11 @@ module ad_ip_jesd204_tpl_dac #(
|
|||
output [1:0] s_axi_rresp
|
||||
);
|
||||
|
||||
localparam DATA_PATH_WIDTH = 2 * NUM_LANES / NUM_CHANNELS;
|
||||
/* Static for now */
|
||||
localparam OCTETS_PER_BEAT = 4;
|
||||
|
||||
localparam DATA_PATH_WIDTH = 2 * OCTETS_PER_BEAT * NUM_LANES / NUM_CHANNELS;
|
||||
localparam LINK_DATA_WIDTH = NUM_LANES * OCTETS_PER_BEAT * 8;
|
||||
|
||||
// internal signals
|
||||
|
||||
|
@ -148,7 +153,10 @@ module ad_ip_jesd204_tpl_dac #(
|
|||
.DATAPATH_DISABLE (DATAPATH_DISABLE),
|
||||
.NUM_LANES (NUM_LANES),
|
||||
.NUM_CHANNELS (NUM_CHANNELS),
|
||||
.SAMPLES_PER_FRAME (SAMPLES_PER_FRAME),
|
||||
.OCTETS_PER_BEAT (OCTETS_PER_BEAT),
|
||||
.DATA_PATH_WIDTH (DATA_PATH_WIDTH),
|
||||
.LINK_DATA_WIDTH (LINK_DATA_WIDTH),
|
||||
.DDS_TYPE (DDS_TYPE),
|
||||
.DDS_CORDIC_DW (DDS_CORDIC_DW),
|
||||
.DDS_CORDIC_PHASE_DW (DDS_CORDIC_PHASE_DW)
|
||||
|
|
|
@ -27,7 +27,10 @@ module ad_ip_jesd204_tpl_dac_core #(
|
|||
parameter DATAPATH_DISABLE = 0,
|
||||
parameter NUM_LANES = 1,
|
||||
parameter NUM_CHANNELS = 1,
|
||||
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 DDS_TYPE = 1,
|
||||
parameter DDS_CORDIC_DW = 16,
|
||||
parameter DDS_CORDIC_PHASE_DW = 16
|
||||
|
@ -37,11 +40,11 @@ module ad_ip_jesd204_tpl_dac_core #(
|
|||
|
||||
output link_valid,
|
||||
input link_ready,
|
||||
output [NUM_LANES*32-1:0] link_data,
|
||||
output [LINK_DATA_WIDTH-1:0] link_data,
|
||||
|
||||
// dma interface
|
||||
output [NUM_CHANNELS-1:0] dac_valid,
|
||||
input [NUM_LANES*32-1:0] dac_ddata,
|
||||
input [LINK_DATA_WIDTH-1:0] dac_ddata,
|
||||
|
||||
// Configuration interface
|
||||
|
||||
|
@ -65,7 +68,7 @@ module ad_ip_jesd204_tpl_dac_core #(
|
|||
|
||||
assign link_valid = 1'b1;
|
||||
|
||||
wire [NUM_LANES*32-1:0] dac_data_s;
|
||||
wire [LINK_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;
|
||||
|
@ -74,7 +77,10 @@ module ad_ip_jesd204_tpl_dac_core #(
|
|||
|
||||
ad_ip_jesd204_tpl_dac_framer #(
|
||||
.NUM_LANES (NUM_LANES),
|
||||
.NUM_CHANNELS (NUM_CHANNELS)
|
||||
.NUM_CHANNELS (NUM_CHANNELS),
|
||||
.SAMPLES_PER_FRAME (SAMPLES_PER_FRAME),
|
||||
.OCTETS_PER_BEAT (OCTETS_PER_BEAT),
|
||||
.LINK_DATA_WIDTH (LINK_DATA_WIDTH)
|
||||
) i_framer (
|
||||
.link_data (link_data),
|
||||
.dac_data (dac_data_s)
|
||||
|
|
|
@ -25,35 +25,115 @@
|
|||
|
||||
module ad_ip_jesd204_tpl_dac_framer #(
|
||||
parameter NUM_LANES = 8,
|
||||
parameter NUM_CHANNELS = 4
|
||||
parameter NUM_CHANNELS = 4,
|
||||
parameter SAMPLES_PER_FRAME = 2,
|
||||
parameter OCTETS_PER_BEAT = 4,
|
||||
parameter LINK_DATA_WIDTH = OCTETS_PER_BEAT * 8 * NUM_LANES
|
||||
) (
|
||||
// jesd interface
|
||||
|
||||
output [NUM_LANES*32-1:0] link_data,
|
||||
output [LINK_DATA_WIDTH-1:0] link_data,
|
||||
|
||||
// dac interface
|
||||
|
||||
input [NUM_LANES*32-1:0] dac_data
|
||||
input [LINK_DATA_WIDTH-1:0] dac_data
|
||||
);
|
||||
|
||||
localparam DATA_PATH_WIDTH = 2 * NUM_LANES / NUM_CHANNELS;
|
||||
localparam H = NUM_LANES / NUM_CHANNELS / 2;
|
||||
localparam HD = NUM_LANES > NUM_CHANNELS ? 1 : 0;
|
||||
localparam OCT_OFFSET = HD ? 32 : 8;
|
||||
/*
|
||||
* The framer module takes sample data and maps it onto the format that the
|
||||
* 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.
|
||||
*
|
||||
* Or in other words the data in dac_data is expected to have the following
|
||||
* layout.
|
||||
*
|
||||
* MSB LSB
|
||||
* [ MmSn, ..., MmS1, MnS0, ..., M1Sn, ... M1S1, M1S0, M0Sn, ... M0S1, M0S0 ]
|
||||
*
|
||||
* Where MjSi refers to the i-th sample of the j-th converter. With m being
|
||||
* the number of converters and n the number of samples per converter per
|
||||
* beat.
|
||||
*
|
||||
* In the default configuration the framer module processes 4 octets per beat.
|
||||
* This means it can support settings with either 1, 2 or 4 octets per frame
|
||||
* (F). Depending on the octets per frame the frames per beat will either be
|
||||
* 4, 2 or 1 respectively. For other settings of OCTETS_PER_BEAT similar
|
||||
* reasoning applies.
|
||||
*
|
||||
* The number of samples per frame (S) and the number of frames processed per
|
||||
* beat gives the number of samples per converter per beat. This is either
|
||||
* S * 4 (for F=1), S * 2 (for F=2) or S (for F=1).
|
||||
*
|
||||
* The framer module does not have a parameter for the octets per frame (F)
|
||||
* since it can be derived from all other parameters given the following
|
||||
* relationship: F = (M * N' * S) / (L * 8)
|
||||
*
|
||||
*
|
||||
* Mapping in performed in two steps. First samples are grouped into frames,
|
||||
* as there might be more than one frame pert beat. In the second step the
|
||||
* frames are distributed onto the lanes.
|
||||
*
|
||||
* In the JESD204 standard samples and octets are ordered MSB first, this
|
||||
* means earlier data is in the MSBs. This core on the other hand expects
|
||||
* samples and octets to be LSB first ordered. This means earlier data is in
|
||||
* the LSBs. To accommodate this two additional steps are required to order
|
||||
* data from LSB to MSB before the framing process and back from MSB to LSB
|
||||
* after it.
|
||||
*
|
||||
* The data itself that is contained within the samples and octets is LSB
|
||||
* 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 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;
|
||||
|
||||
wire [LINK_DATA_WIDTH-1:0] link_data_msb_s;
|
||||
wire [LINK_DATA_WIDTH-1:0] frame_data_s;
|
||||
wire [LINK_DATA_WIDTH-1:0] dac_data_msb;
|
||||
|
||||
generate
|
||||
genvar i;
|
||||
genvar j;
|
||||
for (i = 0; i < NUM_CHANNELS; i = i + 1) begin: g_framer_outer
|
||||
for (j = 0; j < DATA_PATH_WIDTH; j = j + 1) begin: g_framer_inner
|
||||
localparam k = j + i * DATA_PATH_WIDTH;
|
||||
localparam dac_lsb = k * 16;
|
||||
localparam oct0_lsb = HD ? ((i * H + j % H) * 64 + (j / H) * 8) : (k * 16);
|
||||
localparam oct1_lsb = oct0_lsb + OCT_OFFSET;
|
||||
/* Reorder samples MSB first */
|
||||
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;
|
||||
|
||||
assign link_data[oct0_lsb+:8] = dac_data[dac_lsb+8+:8];
|
||||
assign link_data[oct1_lsb+:8] = dac_data[dac_lsb+:8];
|
||||
assign dac_data_msb[dst_msb-:w] = dac_data[src_lsb+:w];
|
||||
end
|
||||
|
||||
/* Slice channel and pack it into frames */
|
||||
for (i = 0; i < NUM_CHANNELS; i = i + 1) begin: g_frame_data_outer
|
||||
for (j = 0; j < FRAMES_PER_BEAT; j = j + 1) begin: g_frame_data_inner
|
||||
localparam w = BITS_PER_CHANNEL_PER_FRAME;
|
||||
localparam dst_lsb = (i + j * NUM_CHANNELS) * w;
|
||||
localparam src_lsb = (j + i * FRAMES_PER_BEAT) * w;
|
||||
|
||||
assign frame_data_s[dst_lsb+:w] = dac_data_msb[src_lsb+:w];
|
||||
end
|
||||
end
|
||||
|
||||
/* Slice frame and pack it into lanes */
|
||||
for (i = 0; i < FRAMES_PER_BEAT; i = i + 1) begin: g_link_data_msb_outer
|
||||
for (j = 0; j < NUM_LANES; j = j + 1) begin: g_link_data_msb_inner
|
||||
localparam w = BITS_PER_LANE_PER_FRAME;
|
||||
localparam dst_lsb = (i + j * FRAMES_PER_BEAT) * w;
|
||||
localparam src_lsb = (j + i * NUM_LANES) * w;
|
||||
|
||||
assign link_data_msb_s[dst_lsb+:w] = frame_data_s[src_lsb+:w];
|
||||
end
|
||||
end
|
||||
|
||||
/* Reorder octets LSB first */
|
||||
for (i = 0; i < LINK_DATA_WIDTH; i = i + 8) begin: g_link_data
|
||||
assign link_data[i+:8] = link_data_msb_s[LINK_DATA_WIDTH-1-i-:8];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
|
|
@ -81,6 +81,13 @@ ad_ip_parameter NUM_CHANNELS INTEGER 1 true [list \
|
|||
GROUP $group \
|
||||
]
|
||||
|
||||
ad_ip_parameter SAMPLES_PER_FRAME INTEGER 1 true [list \
|
||||
DISPLAY_NAME "Samples per Frame (S)" \
|
||||
DISPLAY_UNITS "samples" \
|
||||
ALLOWED_RANGES {1 2 3 4 6 8 12 16} \
|
||||
GROUP $group \
|
||||
]
|
||||
|
||||
set group "Datapath Configuration"
|
||||
|
||||
ad_ip_parameter DATAPATH_DISABLE boolean 0 true [list \
|
||||
|
|
|
@ -86,6 +86,7 @@ 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" \
|
||||
"SAMPLES_PER_FRAME" "1 2 3 4 6 8 12 16" \
|
||||
} { \
|
||||
set_property -dict [list \
|
||||
"value_validation_type" "list" \
|
||||
|
@ -112,6 +113,7 @@ set i 0
|
|||
foreach {k v} { \
|
||||
"NUM_LANES" "Number of Lanes (L)" \
|
||||
"NUM_CHANNELS" "Number of Conveters (M)" \
|
||||
"SAMPLES_PER_FRAME" "Samples per Frame (S)" \
|
||||
} { \
|
||||
set p [ipgui::get_guiparamspec -name $k -component $cc]
|
||||
ipgui::move_param -component $cc -order $i $p -parent $framer_group
|
||||
|
|
Loading…
Reference in New Issue