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
Lars-Peter Clausen 2018-04-18 14:30:35 +02:00 committed by István Csomortáni
parent caa188e5a7
commit a98bc88b84
7 changed files with 128 additions and 23 deletions

View File

@ -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),

View File

@ -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),

View File

@ -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)

View File

@ -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)

View File

@ -25,36 +25,116 @@
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;
genvar i;
genvar j;
/* 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
end
endgenerate
endmodule

View File

@ -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 \

View File

@ -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