diff --git a/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc.v b/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc.v index c46755a31..1821cc220 100644 --- a/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc.v +++ b/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc.v @@ -34,6 +34,7 @@ module ad_ip_jesd204_tpl_adc #( parameter SAMPLES_PER_FRAME = 1, parameter CONVERTER_RESOLUTION = 14, parameter BITS_PER_SAMPLE = 16, + parameter DMA_BITS_PER_SAMPLE = 16, parameter OCTETS_PER_BEAT = 4, parameter TWOS_COMPLEMENT = 1 ) ( @@ -51,7 +52,7 @@ module ad_ip_jesd204_tpl_adc #( output [NUM_CHANNELS-1:0] enable, output [NUM_CHANNELS-1:0] adc_valid, - output [NUM_LANES*8*OCTETS_PER_BEAT-1:0] adc_data, + output [DMA_BITS_PER_SAMPLE * OCTETS_PER_BEAT * 8 * NUM_LANES / BITS_PER_SAMPLE-1:0] adc_data, input adc_dovf, input adc_sync_in, @@ -90,7 +91,7 @@ module ad_ip_jesd204_tpl_adc #( // Number of samples per channel that are processed in parallel. 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 = BITS_PER_SAMPLE * DATA_PATH_WIDTH * NUM_CHANNELS; + localparam DMA_DATA_WIDTH = DMA_BITS_PER_SAMPLE * DATA_PATH_WIDTH * NUM_CHANNELS; localparam BYTES_PER_FRAME = (NUM_CHANNELS * BITS_PER_SAMPLE * SAMPLES_PER_FRAME) / ( 8 * NUM_LANES); @@ -180,7 +181,8 @@ module ad_ip_jesd204_tpl_adc #( .LINK_DATA_WIDTH (LINK_DATA_WIDTH), .DMA_DATA_WIDTH (DMA_DATA_WIDTH), .TWOS_COMPLEMENT (TWOS_COMPLEMENT), - .DATA_PATH_WIDTH (DATA_PATH_WIDTH) + .DATA_PATH_WIDTH (DATA_PATH_WIDTH), + .DMA_BITS_PER_SAMPLE (DMA_BITS_PER_SAMPLE) ) i_core ( .clk (link_clk), diff --git a/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc_core.v b/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc_core.v index dbf501fef..974e9d64b 100644 --- a/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc_core.v +++ b/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc_core.v @@ -29,10 +29,11 @@ module ad_ip_jesd204_tpl_adc_core #( parameter SAMPLES_PER_FRAME = 1, parameter CONVERTER_RESOLUTION = 14, parameter BITS_PER_SAMPLE = 16, + parameter DMA_BITS_PER_SAMPLE = 16, parameter OCTETS_PER_BEAT = 4, parameter DATA_PATH_WIDTH = 1, parameter LINK_DATA_WIDTH = NUM_LANES * OCTETS_PER_BEAT * 8, - parameter DMA_DATA_WIDTH = DATA_PATH_WIDTH * BITS_PER_SAMPLE * NUM_CHANNELS, + parameter DMA_DATA_WIDTH = DATA_PATH_WIDTH * DMA_BITS_PER_SAMPLE * NUM_CHANNELS, parameter TWOS_COMPLEMENT = 1 ) ( input clk, @@ -61,7 +62,7 @@ module ad_ip_jesd204_tpl_adc_core #( // Raw and formatted channel data widths localparam CDW_RAW = CONVERTER_RESOLUTION * DATA_PATH_WIDTH; localparam ADC_DATA_WIDTH = CDW_RAW * NUM_CHANNELS; - localparam CDW_FMT = BITS_PER_SAMPLE * DATA_PATH_WIDTH; + localparam CDW_FMT = DMA_BITS_PER_SAMPLE * DATA_PATH_WIDTH; wire [ADC_DATA_WIDTH-1:0] raw_data_s; @@ -109,7 +110,7 @@ module ad_ip_jesd204_tpl_adc_core #( .DATA_PATH_WIDTH (DATA_PATH_WIDTH), .CONVERTER_RESOLUTION (CONVERTER_RESOLUTION), .TWOS_COMPLEMENT (TWOS_COMPLEMENT), - .BITS_PER_SAMPLE (BITS_PER_SAMPLE) + .BITS_PER_SAMPLE (DMA_BITS_PER_SAMPLE) ) i_channel ( .clk (clk), diff --git a/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc_ip.tcl b/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc_ip.tcl index 77670872d..5ef47e348 100644 --- a/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc_ip.tcl +++ b/library/jesd204/ad_ip_jesd204_tpl_adc/ad_ip_jesd204_tpl_adc_ip.tcl @@ -74,9 +74,10 @@ foreach {p v} { "NUM_LANES" "1 2 3 4 8 16" \ "NUM_CHANNELS" "1 2 4 6 8 16 32 64" \ "BITS_PER_SAMPLE" "8 12 16" \ + "DMA_BITS_PER_SAMPLE" "8 12 16" \ "CONVERTER_RESOLUTION" "8 11 12 16" \ "SAMPLES_PER_FRAME" "1 2 3 4 6 8 12 16" \ - "OCTETS_PER_BEAT" "4 8" \ + "OCTETS_PER_BEAT" "4 6 8 12" \ } { \ set_property -dict [list \ "value_validation_type" "list" \ @@ -104,6 +105,7 @@ foreach {k v} { \ "NUM_LANES" "Number of Lanes (L)" \ "NUM_CHANNELS" "Number of Conveters (M)" \ "BITS_PER_SAMPLE" "Bits per Sample (N')" \ + "DMA_BITS_PER_SAMPLE" "DMA Bits per Sample" \ "CONVERTER_RESOLUTION" "Converter Resolution (N)" \ "SAMPLES_PER_FRAME" "Samples per Frame (S)" \ "OCTETS_PER_BEAT" "Octets per Beat" \ diff --git a/library/jesd204/ad_ip_jesd204_tpl_dac/ad_ip_jesd204_tpl_dac.v b/library/jesd204/ad_ip_jesd204_tpl_dac/ad_ip_jesd204_tpl_dac.v index d6e77221d..ee162b1f1 100644 --- a/library/jesd204/ad_ip_jesd204_tpl_dac/ad_ip_jesd204_tpl_dac.v +++ b/library/jesd204/ad_ip_jesd204_tpl_dac/ad_ip_jesd204_tpl_dac.v @@ -32,8 +32,9 @@ 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 CONVERTER_RESOLUTION = 16, // JESD_N + parameter BITS_PER_SAMPLE = 16, // JESD_NP + parameter DMA_BITS_PER_SAMPLE = 16, parameter OCTETS_PER_BEAT = 4, parameter DDS_TYPE = 1, parameter DDS_CORDIC_DW = 16, @@ -55,7 +56,7 @@ module ad_ip_jesd204_tpl_dac #( output [NUM_CHANNELS-1:0] enable, output [NUM_CHANNELS-1:0] dac_valid, - input [NUM_LANES*8*OCTETS_PER_BEAT-1:0] dac_ddata, + input [DMA_BITS_PER_SAMPLE * OCTETS_PER_BEAT * 8 * NUM_LANES / BITS_PER_SAMPLE-1:0] dac_ddata, input dac_dunf, // external sync, should be on the link_clk clock domain @@ -94,7 +95,7 @@ module ad_ip_jesd204_tpl_dac #( 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 = BITS_PER_SAMPLE * DATA_PATH_WIDTH * NUM_CHANNELS; + localparam DMA_DATA_WIDTH = DMA_BITS_PER_SAMPLE * DATA_PATH_WIDTH * NUM_CHANNELS; localparam BYTES_PER_FRAME = (NUM_CHANNELS * BITS_PER_SAMPLE * SAMPLES_PER_FRAME) / ( 8 * NUM_LANES); @@ -119,6 +120,8 @@ module ad_ip_jesd204_tpl_dac #( wire [NUM_CHANNELS*16-1:0] dac_iqcor_coeff_2; wire [NUM_CHANNELS*8-1:0] dac_src_chan_sel; + reg [LINK_DATA_WIDTH-1:0] dac_ddata_cr; + // regmap ad_ip_jesd204_tpl_dac_regmap #( @@ -205,7 +208,6 @@ 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), @@ -220,7 +222,7 @@ module ad_ip_jesd204_tpl_dac #( .enable (enable), .dac_valid (dac_valid), - .dac_ddata (dac_ddata), + .dac_ddata (dac_ddata_cr), .dac_sync (dac_sync), .dac_sync_in_status (dac_sync_in_status), @@ -246,4 +248,12 @@ module ad_ip_jesd204_tpl_dac #( ); + // Drop DMA padding bits from the MSB + integer i; + always @(*) begin + for (i=0;i 128 ? 8 : localparam BEATS_PER_FRAME_WIDTH = CW-DPW_LOG2; localparam BEATS_PER_MF_WIDTH = 10-DPW_LOG2; -wire [BEATS_PER_MF_WIDTH-1:0] cfg_beats_per_multiframe = cfg_octets_per_multiframe[9:DPW_LOG2]; // For DATA_PATH_WIDTH = 8, special case if F*K%8=4 wire octets_per_mf_4_mod_8 = (DATA_PATH_WIDTH == 8) && ~cfg_octets_per_multiframe[2]; reg [BEATS_PER_MF_WIDTH-1:0] cur_beats_per_multiframe; @@ -114,6 +118,21 @@ initial begin eof_f_6[1] = {4'b0010}; eof_f_6[2] = {4'b1000}; end +end else if(DATA_PATH_WIDTH == 6) begin : gen_dp_6 +initial begin + sof_f_3[0] = {6'b001001}; + sof_f_3[1] = {6'b001001}; + sof_f_3[2] = {6'b001001}; + eof_f_3[0] = {6'b100100}; + eof_f_3[1] = {6'b100100}; + eof_f_3[2] = {6'b100100}; + sof_f_6[0] = {6'b000001}; + sof_f_6[1] = {6'b000001}; + sof_f_6[2] = {6'b000001}; + eof_f_6[0] = {6'b100000}; + eof_f_6[1] = {6'b100000}; + eof_f_6[2] = {6'b100000}; +end end else if(DATA_PATH_WIDTH == 8) begin : gen_dp_8 initial begin sof_f_3[0] = {8'b01001001}; @@ -232,7 +251,7 @@ end assign cur_somf = beat_cnt_mf == 0; assign cur_eomf = beat_cnt_mf == cur_beats_per_multiframe; -if(DATA_PATH_WIDTH == 4) begin : gen_mf_dp_4 +if(DATA_PATH_WIDTH == 4 || DATA_PATH_WIDTH == 6) begin : gen_mf_dp_4_6 always @(*) begin cur_beats_per_multiframe = cfg_beats_per_multiframe; somf = {{DATA_PATH_WIDTH-1{1'b0}}, cur_somf}; diff --git a/library/jesd204/jesd204_common/jesd204_lmfc.v b/library/jesd204/jesd204_common/jesd204_lmfc.v index 1228bf286..af6f06525 100755 --- a/library/jesd204/jesd204_common/jesd204_lmfc.v +++ b/library/jesd204/jesd204_common/jesd204_lmfc.v @@ -54,6 +54,7 @@ module jesd204_lmfc #( input sysref, input [9:0] cfg_octets_per_multiframe, + input [7:0] cfg_beats_per_multiframe, input [7:0] cfg_lmfc_offset, input cfg_sysref_oneshot, input cfg_sysref_disable, @@ -75,7 +76,7 @@ module jesd204_lmfc #( localparam DPW_LOG2 = DATA_PATH_WIDTH == 8 ? 3 : DATA_PATH_WIDTH == 4 ? 2 : 1; localparam BEATS_PER_MF_WIDTH = 10-DPW_LOG2; -wire [BEATS_PER_MF_WIDTH-1:0] cfg_beats_per_multiframe = cfg_octets_per_multiframe[9:DPW_LOG2]; +//wire [BEATS_PER_MF_WIDTH-1:0] cfg_beats_per_multiframe = cfg_octets_per_multiframe[9:DPW_LOG2]; reg [BEATS_PER_MF_WIDTH:0] cfg_whole_beats_per_multiframe; reg sysref_r = 1'b0; diff --git a/library/jesd204/jesd204_rx/Makefile b/library/jesd204/jesd204_rx/Makefile index ec176f9b9..cc74abc87 100644 --- a/library/jesd204/jesd204_rx/Makefile +++ b/library/jesd204/jesd204_rx/Makefile @@ -30,6 +30,7 @@ XILINX_DEPS += ../../jesd204/interfaces/jesd204_rx_ilas_config.xml XILINX_DEPS += ../../jesd204/interfaces/jesd204_rx_ilas_config_rtl.xml XILINX_DEPS += ../../jesd204/interfaces/jesd204_rx_status.xml XILINX_DEPS += ../../jesd204/interfaces/jesd204_rx_status_rtl.xml +XILINX_DEPS += bd/bd.tcl XILINX_LIB_DEPS += jesd204/jesd204_common diff --git a/library/jesd204/jesd204_rx/bd/bd.tcl b/library/jesd204/jesd204_rx/bd/bd.tcl new file mode 100644 index 000000000..7394bb17a --- /dev/null +++ b/library/jesd204/jesd204_rx/bd/bd.tcl @@ -0,0 +1,44 @@ +proc init {cellpath otherInfo} { + set ip [get_bd_cells $cellpath] + + bd::mark_propagate_override $ip \ + "ASYNC_CLK" + +} + +proc detect_async_clk { cellpath ip param_name clk_a clk_b } { + set param_src [get_property "CONFIG.$param_name.VALUE_SRC" $ip] + if {[string equal $param_src "USER"]} { + return; + } + + set clk_domain_a [get_property CONFIG.CLK_DOMAIN $clk_a] + set clk_domain_b [get_property CONFIG.CLK_DOMAIN $clk_b] + set clk_freq_a [get_property CONFIG.FREQ_HZ $clk_a] + set clk_freq_b [get_property CONFIG.FREQ_HZ $clk_b] + set clk_phase_a [get_property CONFIG.PHASE $clk_a] + set clk_phase_b [get_property CONFIG.PHASE $clk_b] + + # Only mark it as sync if we can make sure that it is sync, if the + # relationship of the clocks is unknown mark it as async + if {$clk_domain_a != {} && $clk_domain_b != {} && \ + $clk_domain_a == $clk_domain_b && $clk_freq_a == $clk_freq_b && \ + $clk_phase_a == $clk_phase_b} { + set clk_async 0 + } else { + set clk_async 1 + } + + set_property "CONFIG.$param_name" $clk_async $ip + +} + +proc propagate {cellpath otherinfo} { + set ip [get_bd_cells $cellpath] + + set link_clk [get_bd_pins "$ip/clk"] + set device_clk [get_bd_pins "$ip/device_clk"] + + detect_async_clk $cellpath $ip "ASYNC_CLK" $link_clk $device_clk +} + diff --git a/library/jesd204/jesd204_rx/elastic_buffer.v b/library/jesd204/jesd204_rx/elastic_buffer.v index b060d82b8..208821e0b 100644 --- a/library/jesd204/jesd204_rx/elastic_buffer.v +++ b/library/jesd204/jesd204_rx/elastic_buffer.v @@ -45,15 +45,20 @@ `timescale 1ns/100ps module elastic_buffer #( - parameter WIDTH = 32, - parameter SIZE = 256 + parameter IWIDTH = 32, + parameter OWIDTH = 48, + parameter SIZE = 256, + parameter ASYNC_CLK = 0 ) ( input clk, input reset, - input [WIDTH-1:0] wr_data, + input device_clk, + input device_reset, - output reg [WIDTH-1:0] rd_data, + input [IWIDTH-1:0] wr_data, + + output reg [OWIDTH-1:0] rd_data, input ready_n, input do_release_n @@ -67,20 +72,45 @@ localparam ADDR_WIDTH = SIZE > 128 ? 7 : SIZE > 4 ? 2 : SIZE > 2 ? 1 : 0; +localparam WIDTH = OWIDTH >= IWIDTH ? OWIDTH : IWIDTH; + reg [ADDR_WIDTH:0] wr_addr = 'h00; reg [ADDR_WIDTH:0] rd_addr = 'h00; -reg [WIDTH-1:0] mem[0:SIZE - 1]; +(* ram_style = "distributed" *) reg [WIDTH-1:0] mem[0:SIZE - 1]; + +wire mem_wr; +wire [WIDTH-1:0] mem_wr_data; + +generate if ((OWIDTH > IWIDTH) && ASYNC_CLK) begin + ad_pack #( + .I_W(IWIDTH/8), + .O_W(OWIDTH/8), + .UNIT_W(8) + ) i_ad_pack ( + .clk(clk), + .reset(ready_n), + .idata(wr_data), + .ivalid(1'b1), + + .odata(mem_wr_data), + .ovalid(mem_wr) + ); +end else begin + assign mem_wr = 1'b1; + assign mem_wr_data = wr_data; +end +endgenerate always @(posedge clk) begin if (ready_n == 1'b1) begin wr_addr <= 'h00; - end else begin - mem[wr_addr] <= wr_data; + end else if (mem_wr) begin + mem[wr_addr] <= mem_wr_data; wr_addr <= wr_addr + 1'b1; end end -always @(posedge clk) begin +always @(posedge device_clk) begin if (do_release_n == 1'b1) begin rd_addr <= 'h00; end else begin diff --git a/library/jesd204/jesd204_rx/jesd204_rx.v b/library/jesd204/jesd204_rx/jesd204_rx.v index 6b227bf37..848cf41dc 100755 --- a/library/jesd204/jesd204_rx/jesd204_rx.v +++ b/library/jesd204/jesd204_rx/jesd204_rx.v @@ -53,11 +53,16 @@ module jesd204_rx #( parameter DATA_PATH_WIDTH = LINK_MODE == 2 ? 8 : 4, parameter ENABLE_FRAME_ALIGN_CHECK = 1, parameter ENABLE_FRAME_ALIGN_ERR_RESET = 0, - parameter ENABLE_CHAR_REPLACE = 0 + parameter ENABLE_CHAR_REPLACE = 0, + parameter ASYNC_CLK = 1, + parameter TPL_DATA_PATH_WIDTH = LINK_MODE == 2 ? 8 : 4 ) ( - input clk, + input clk, // Link clock, lane rate / 40 or lane rate / 20 or lane rate / 66 input reset, + input device_clk, // Integer multiple of frame clock + input device_reset, + input [DATA_PATH_WIDTH*8*NUM_LANES-1:0] phy_data, input [2*NUM_LANES-1:0] phy_header, input [DATA_PATH_WIDTH*NUM_LANES-1:0] phy_charisk, @@ -69,8 +74,8 @@ module jesd204_rx #( output lmfc_edge, output lmfc_clk, - output event_sysref_alignment_error, - output event_sysref_edge, + output device_event_sysref_alignment_error, + output device_event_sysref_edge, output event_frame_alignment_error, output event_unexpected_lane_state_error, @@ -78,30 +83,33 @@ module jesd204_rx #( output phy_en_char_align, - output [DATA_PATH_WIDTH*8*NUM_LANES-1:0] rx_data, + output [TPL_DATA_PATH_WIDTH*8*NUM_LANES-1:0] rx_data, output rx_valid, - output [DATA_PATH_WIDTH-1:0] rx_eof, - output [DATA_PATH_WIDTH-1:0] rx_sof, - output [DATA_PATH_WIDTH-1:0] rx_eomf, - output [DATA_PATH_WIDTH-1:0] rx_somf, + output [TPL_DATA_PATH_WIDTH-1:0] rx_eof, + output [TPL_DATA_PATH_WIDTH-1:0] rx_sof, + output [TPL_DATA_PATH_WIDTH-1:0] rx_eomf, + output [TPL_DATA_PATH_WIDTH-1:0] rx_somf, input [NUM_LANES-1:0] cfg_lanes_disable, input [NUM_LINKS-1:0] cfg_links_disable, input [9:0] cfg_octets_per_multiframe, input [7:0] cfg_octets_per_frame, - input [7:0] cfg_lmfc_offset, - input cfg_sysref_disable, - input cfg_sysref_oneshot, - input cfg_buffer_early_release, - input [7:0] cfg_buffer_delay, - input cfg_disable_char_replacement, input cfg_disable_scrambler, + input cfg_disable_char_replacement, + input [7:0] cfg_frame_align_err_threshold, + + input [9:0] device_cfg_octets_per_multiframe, + input [7:0] device_cfg_octets_per_frame, + input [7:0] device_cfg_beats_per_multiframe, + input [7:0] device_cfg_lmfc_offset, + input device_cfg_sysref_oneshot, + input device_cfg_sysref_disable, + input device_cfg_buffer_early_release, + input [7:0] device_cfg_buffer_delay, input ctrl_err_statistics_reset, input [6:0] ctrl_err_statistics_mask, - input [7:0] cfg_frame_align_err_threshold, - output [32*NUM_LANES-1:0] status_err_statistics_cnt, output [NUM_LANES-1:0] ilas_config_valid, @@ -146,10 +154,12 @@ localparam LMFC_COUNTER_WIDTH = MAX_BEATS_PER_MULTIFRAME > 256 ? 9 : /* Helper for common expressions */ localparam DW = 8*DATA_PATH_WIDTH*NUM_LANES; +localparam ODW = 8*TPL_DATA_PATH_WIDTH*NUM_LANES; localparam CW = DATA_PATH_WIDTH*NUM_LANES; localparam HW = 2*NUM_LANES; -wire [7:0] cfg_beats_per_multiframe = cfg_octets_per_multiframe[9:DPW_LOG2]; +wire [7:0] cfg_beats_per_multiframe = cfg_octets_per_multiframe >> DPW_LOG2; +wire [7:0] device_cfg_beats_per_multiframe_s; wire [NUM_LANES-1:0] cgs_reset; wire [NUM_LANES-1:0] cgs_ready; @@ -159,6 +169,7 @@ reg buffer_release_n = 1'b1; reg buffer_release_d1 = 1'b0; wire [NUM_LANES-1:0] buffer_ready_n; wire all_buffer_ready_n; +wire dev_all_buffer_ready_n; reg eof_reset = 1'b1; @@ -169,7 +180,7 @@ wire [CW-1:0] phy_notintable_r; wire [CW-1:0] phy_disperr_r; wire [NUM_LANES-1:0] phy_block_sync_r; -wire [DW-1:0] rx_data_s; +wire [ODW-1:0] rx_data_s; wire rx_valid_s = buffer_release_d1; @@ -182,14 +193,16 @@ wire [NUM_LANES-1:0] ifs_ready; wire event_data_phase; wire err_statistics_reset; +wire lmfc_edge_synced; + reg [NUM_LANES-1:0] frame_align_err_thresh_met = {NUM_LANES{1'b0}}; reg [NUM_LANES-1:0] event_frame_alignment_error_per_lane = {NUM_LANES{1'b0}}; reg buffer_release_opportunity = 1'b0; -always @(posedge clk) begin - if (lmfc_counter == cfg_buffer_delay || - cfg_buffer_early_release == 1'b1) begin +always @(posedge device_clk) begin + if (lmfc_counter == device_cfg_buffer_delay || + device_cfg_buffer_early_release == 1'b1) begin buffer_release_opportunity <= 1'b1; end else begin buffer_release_opportunity <= 1'b0; @@ -198,12 +211,22 @@ end assign all_buffer_ready_n = |(buffer_ready_n & ~cfg_lanes_disable); -always @(posedge clk) begin - if (reset == 1'b1) begin +sync_bits #( + .NUM_OF_BITS (1), + .ASYNC_CLK(ASYNC_CLK) +) i_all_buffer_ready_cdc ( + .in_bits(all_buffer_ready_n), + .out_clk(device_clk), + .out_resetn(1'b1), + .out_bits(dev_all_buffer_ready_n) +); + +always @(posedge device_clk) begin + if (device_reset == 1'b1) begin buffer_release_n <= 1'b1; end else begin if (buffer_release_opportunity == 1'b1) begin - buffer_release_n <= all_buffer_ready_n; + buffer_release_n <= dev_all_buffer_ready_n; end end buffer_release_d1 <= ~buffer_release_n; @@ -234,31 +257,40 @@ pipeline_stage #( ); pipeline_stage #( - .WIDTH(DW+1), + .WIDTH(ODW+2), .REGISTERED(1) ) i_output_pipeline_stage ( - .clk(clk), + .clk(device_clk), .in({ + eof_reset, rx_data_s, rx_valid_s }), .out({ + eof_reset_d, rx_data, rx_valid }) ); +// If input and output widths are symmetric keep the calculation for backwards +// compatibility of the software. +assign device_cfg_beats_per_multiframe_s = (TPL_DATA_PATH_WIDTH == DATA_PATH_WIDTH) ? + device_cfg_octets_per_multiframe >> DPW_LOG2 : + device_cfg_beats_per_multiframe; + jesd204_lmfc #( .LINK_MODE(LINK_MODE), - .DATA_PATH_WIDTH(DATA_PATH_WIDTH) + .DATA_PATH_WIDTH(TPL_DATA_PATH_WIDTH) ) i_lmfc ( - .clk(clk), - .reset(reset), + .clk(device_clk), + .reset(device_reset), - .cfg_octets_per_multiframe(cfg_octets_per_multiframe), - .cfg_lmfc_offset(cfg_lmfc_offset), - .cfg_sysref_oneshot(cfg_sysref_oneshot), - .cfg_sysref_disable(cfg_sysref_disable), + .cfg_octets_per_multiframe(device_cfg_octets_per_multiframe), + .cfg_beats_per_multiframe(device_cfg_beats_per_multiframe_s), + .cfg_lmfc_offset(device_cfg_lmfc_offset), + .cfg_sysref_oneshot(device_cfg_sysref_oneshot), + .cfg_sysref_disable(device_cfg_sysref_disable), .sysref(sysref), .lmfc_edge(lmfc_edge), @@ -268,17 +300,18 @@ jesd204_lmfc #( .lmc_quarter_edge(), .eoemb(), - .sysref_edge(event_sysref_edge), - .sysref_alignment_error(event_sysref_alignment_error) + .sysref_edge(device_event_sysref_edge), + .sysref_alignment_error(device_event_sysref_alignment_error) ); jesd204_frame_mark #( - .DATA_PATH_WIDTH (DATA_PATH_WIDTH) + .DATA_PATH_WIDTH (TPL_DATA_PATH_WIDTH) ) i_frame_mark ( - .clk (clk), - .reset (eof_reset), - .cfg_octets_per_multiframe (cfg_octets_per_multiframe), - .cfg_octets_per_frame (cfg_octets_per_frame), + .clk (device_clk), + .reset (eof_reset_d), + .cfg_beats_per_multiframe (device_cfg_beats_per_multiframe_s), + .cfg_octets_per_multiframe (device_cfg_octets_per_multiframe), + .cfg_octets_per_frame (device_cfg_octets_per_frame), .sof (rx_sof), .eof (rx_eof), .somf (rx_somf), @@ -288,6 +321,16 @@ jesd204_frame_mark #( generate genvar i; +sync_event #( + .NUM_OF_EVENTS (1), + .ASYNC_CLK(ASYNC_CLK) +) i_sync_lmfc ( + .in_clk(device_clk), + .in_event(lmfc_edge), + .out_clk(clk), + .out_event(lmfc_edge_synced) +); + if (LINK_MODE[0] == 1) begin : mode_8b10b wire unexpected_lane_state_error; @@ -307,7 +350,7 @@ jesd204_rx_ctrl #( .phy_ready(1'b1), .phy_en_char_align(phy_en_char_align), - .lmfc_edge(lmfc_edge), + .lmfc_edge(lmfc_edge_synced), .frame_align_err_thresh_met(frame_align_err_thresh_met), .sync(sync), @@ -330,21 +373,28 @@ for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane localparam D_START = i * DATA_PATH_WIDTH*8; localparam D_STOP = D_START + DATA_PATH_WIDTH*8-1; + localparam OD_START = i * TPL_DATA_PATH_WIDTH*8; + localparam OD_STOP = OD_START + TPL_DATA_PATH_WIDTH*8-1; localparam C_START = i * DATA_PATH_WIDTH; localparam C_STOP = C_START + DATA_PATH_WIDTH-1; jesd204_rx_lane #( .DATA_PATH_WIDTH(DATA_PATH_WIDTH), + .TPL_DATA_PATH_WIDTH(TPL_DATA_PATH_WIDTH), .CHAR_INFO_REGISTERED(CHAR_INFO_REGISTERED), .ALIGN_MUX_REGISTERED(ALIGN_MUX_REGISTERED), .SCRAMBLER_REGISTERED(SCRAMBLER_REGISTERED), .ELASTIC_BUFFER_SIZE(ELASTIC_BUFFER_SIZE), .ENABLE_FRAME_ALIGN_CHECK(ENABLE_FRAME_ALIGN_CHECK), - .ENABLE_CHAR_REPLACE(ENABLE_CHAR_REPLACE) + .ENABLE_CHAR_REPLACE(ENABLE_CHAR_REPLACE), + .ASYNC_CLK(ASYNC_CLK) ) i_lane ( .clk(clk), .reset(reset), + .device_clk(device_clk), + .device_reset(device_reset), + .phy_data(phy_data_r[D_STOP:D_START]), .phy_charisk(phy_charisk_r[C_STOP:C_START]), .phy_notintable(phy_notintable_r[C_STOP:C_START]), @@ -355,7 +405,7 @@ for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane .ifs_reset(ifs_reset[i]), - .rx_data(rx_data_s[D_STOP:D_START]), + .rx_data(rx_data_s[OD_STOP:OD_START]), .buffer_release_n(buffer_release_n), .buffer_ready_n(buffer_ready_n[i]), @@ -452,6 +502,17 @@ end if (LINK_MODE[1] == 1) begin : mode_64b66b wire [NUM_LANES-1:0] emb_lock; +wire link_buffer_release_n; + +sync_bits #( + .NUM_OF_BITS (1), + .ASYNC_CLK(ASYNC_CLK) +) i_buffer_release_cdc ( + .in_bits(buffer_release_n), + .out_clk(clk), + .out_resetn(1'b1), + .out_bits(link_buffer_release_n) +); jesd204_rx_ctrl_64b #( .NUM_LANES(NUM_LANES) @@ -465,7 +526,7 @@ jesd204_rx_ctrl_64b #( .emb_lock(emb_lock), .all_emb_lock(all_emb_lock), - .buffer_release_n(buffer_release_n), + .buffer_release_n(link_buffer_release_n), .status_state(status_ctrl_state), .event_unexpected_lane_state_error(event_unexpected_lane_state_error) @@ -475,17 +536,24 @@ for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane localparam D_START = i * DATA_PATH_WIDTH*8; localparam D_STOP = D_START + DATA_PATH_WIDTH*8-1; + localparam TPL_D_START = i * TPL_DATA_PATH_WIDTH*8; + localparam TPL_D_STOP = TPL_D_START + TPL_DATA_PATH_WIDTH*8-1; localparam H_START = i * 2; localparam H_STOP = H_START + 2-1; wire [7:0] status_lane_skew; jesd204_rx_lane_64b #( - .ELASTIC_BUFFER_SIZE(ELASTIC_BUFFER_SIZE) + .ELASTIC_BUFFER_SIZE(ELASTIC_BUFFER_SIZE), + .TPL_DATA_PATH_WIDTH(TPL_DATA_PATH_WIDTH), + .ASYNC_CLK(ASYNC_CLK) ) i_lane ( .clk(clk), .reset(reset), + .device_clk(device_clk), + .device_reset(device_reset), + .phy_data(phy_data_r[D_STOP:D_START]), .phy_header(phy_header_r[H_STOP:H_START]), .phy_block_sync(phy_block_sync_r[i]), @@ -495,13 +563,13 @@ for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane .cfg_rx_thresh_emb_err(5'd8), .cfg_beats_per_multiframe(cfg_beats_per_multiframe), - .rx_data(rx_data_s[D_STOP:D_START]), + .rx_data(rx_data_s[TPL_D_STOP:TPL_D_START]), .buffer_release_n(buffer_release_n), .buffer_ready_n(buffer_ready_n[i]), .all_buffer_ready_n(all_buffer_ready_n), - .lmfc_edge(lmfc_edge), + .lmfc_edge(lmfc_edge_synced), .emb_lock(emb_lock[i]), .ctrl_err_statistics_reset(ctrl_err_statistics_reset), diff --git a/library/jesd204/jesd204_rx/jesd204_rx_constr.ttcl b/library/jesd204/jesd204_rx/jesd204_rx_constr.ttcl index 609edb8cf..3d8795108 100644 --- a/library/jesd204/jesd204_rx/jesd204_rx_constr.ttcl +++ b/library/jesd204/jesd204_rx/jesd204_rx_constr.ttcl @@ -47,6 +47,8 @@ <: setFileExtension ".xdc" :> <: setFileProcessingOrder late :> <: set sysref_iob [get_property PARAM_VALUE.SYSREF_IOB] :> +<: set async_clk [getBooleanValue "ASYNC_CLK"] :> +<: set link_mode [getBooleanValue "LINK_MODE"] :> set_property ASYNC_REG TRUE \ [get_cells {i_lmfc/sysref_d1_reg}] \ @@ -56,3 +58,42 @@ set_property ASYNC_REG TRUE \ # predictable set_property IOB <=: $sysref_iob :> \ [get_cells {i_lmfc/sysref_r_reg}] + +<: if {$async_clk} { :> + +set link_clk [get_clocks -of_objects [get_ports -quiet {clk}]] +set device_clk [get_clocks -of_objects [get_ports -quiet {device_clk}]] + +# sync bits +set_false_path \ + -from $link_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_all_buffer_ready_cdc* && IS_SEQUENTIAL}] + +# sync event i_sync_lmfc +set_false_path -quiet \ + -from $device_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_sync_lmfc/i_sync_out* && IS_SEQUENTIAL}] + +set_false_path -quiet \ + -from $link_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_sync_lmfc/i_sync_in* && IS_SEQUENTIAL}] + +# elastic buffer distributed RAM +set_false_path -quiet \ + -from $link_clk \ + -to [get_cells -quiet -hier *rd_data_reg* \ + -filter {NAME =~ *i_elastic_buffer* && IS_SEQUENTIAL}] + +<: if {$link_mode == 2} { :> +# sync bits i_buffer_release_cdc 64b66b +set_false_path \ + -from $device_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_buffer_release_cdc* && IS_SEQUENTIAL}] +<: } :> + +<: } :> + diff --git a/library/jesd204/jesd204_rx/jesd204_rx_frame_align.v b/library/jesd204/jesd204_rx/jesd204_rx_frame_align.v index 84ccb2501..09c755780 100755 --- a/library/jesd204/jesd204_rx/jesd204_rx_frame_align.v +++ b/library/jesd204/jesd204_rx/jesd204_rx_frame_align.v @@ -94,6 +94,7 @@ reg align_err; reg [DPW_LOG2*2:0] cur_align_err_cnt; wire [8:0] align_err_cnt_next; +wire [7:0] cfg_beats_per_multiframe = cfg_octets_per_multiframe>>DPW_LOG2; jesd204_frame_mark #( .DATA_PATH_WIDTH (DATA_PATH_WIDTH) @@ -101,6 +102,7 @@ jesd204_frame_mark #( .clk (clk), .reset (reset), .cfg_octets_per_multiframe (cfg_octets_per_multiframe), + .cfg_beats_per_multiframe (cfg_beats_per_multiframe), .cfg_octets_per_frame (cfg_octets_per_frame), .sof (), .eof (eof), diff --git a/library/jesd204/jesd204_rx/jesd204_rx_ip.tcl b/library/jesd204/jesd204_rx/jesd204_rx_ip.tcl index c8aa14418..95cedd7d6 100755 --- a/library/jesd204/jesd204_rx/jesd204_rx_ip.tcl +++ b/library/jesd204/jesd204_rx/jesd204_rx_ip.tcl @@ -61,13 +61,17 @@ adi_ip_files jesd204_rx [list \ "jesd204_rx_frame_align.v" \ "jesd204_rx_constr.ttcl" \ "jesd204_rx.v" \ + "../../common/ad_pack.v" \ + "bd/bd.tcl" ] adi_ip_properties_lite jesd204_rx adi_ip_ttcl jesd204_rx "jesd204_rx_constr.ttcl" +adi_ip_bd jesd204_rx "bd/bd.tcl" adi_ip_add_core_dependencies { \ analog.com:user:jesd204_common:1.0 \ + analog.com:user:util_cdc:1.0 \ } set_property display_name "ADI JESD204 Receive" [ipx::current_core] @@ -102,16 +106,19 @@ adi_add_bus "rx_cfg" "slave" \ { "cfg_links_disable" "links_disable" } \ { "cfg_octets_per_multiframe" "octets_per_multiframe" } \ { "cfg_octets_per_frame" "octets_per_frame" } \ - { "cfg_lmfc_offset" "lmfc_offset" } \ - { "cfg_sysref_oneshot" "sysref_oneshot" } \ - { "cfg_sysref_disable" "sysref_disable" } \ - { "cfg_buffer_delay" "buffer_delay" } \ - { "cfg_buffer_early_release" "buffer_early_release" } \ + { "cfg_disable_scrambler" "disable_scrambler" } \ { "cfg_disable_char_replacement" "disable_char_replacement" } \ + { "cfg_frame_align_err_threshold" "frame_align_err_threshold" } \ + { "device_cfg_octets_per_multiframe" "device_octets_per_multiframe" } \ + { "device_cfg_octets_per_frame" "device_octets_per_frame" } \ + { "device_cfg_beats_per_multiframe" "device_beats_per_multiframe" } \ + { "device_cfg_lmfc_offset" "device_lmfc_offset" } \ + { "device_cfg_sysref_oneshot" "device_sysref_oneshot" } \ + { "device_cfg_sysref_disable" "device_sysref_disable" } \ + { "device_cfg_buffer_delay" "device_buffer_delay" } \ + { "device_cfg_buffer_early_release" "device_buffer_early_release" } \ { "ctrl_err_statistics_reset" "err_statistics_reset" } \ { "ctrl_err_statistics_mask" "err_statistics_mask" } \ - { "cfg_disable_scrambler" "disable_scrambler" } \ - { "cfg_frame_align_err_threshold" "frame_align_err_threshold" } \ } adi_add_bus "rx_status" "master" \ @@ -140,13 +147,14 @@ adi_add_bus "rx_event" "master" \ "analog.com:interface:jesd204_rx_event_rtl:1.0" \ "analog.com:interface:jesd204_rx_event:1.0" \ { \ - { "event_sysref_alignment_error" "sysref_alignment_error" } \ - { "event_sysref_edge" "sysref_edge" } \ + { "device_event_sysref_alignment_error" "sysref_alignment_error" } \ + { "device_event_sysref_edge" "sysref_edge" } \ { "event_frame_alignment_error" "frame_alignment_error" } \ { "event_unexpected_lane_state_error" "unexpected_lane_state_error" } \ } -adi_add_bus_clock "clk" "rx_cfg:rx_ilas_config:rx_event:rx_status:rx_data" "reset" +adi_add_bus_clock "clk" "rx_cfg:rx_ilas_config:rx_event:rx_status" "reset" +adi_add_bus_clock "device_clk" "rx_data" "device_reset" adi_set_bus_dependency "rx_ilas_config" "rx_ilas_config" \ "(spirit:decode(id('MODELPARAM_VALUE.LINK_MODE')) = 1)" @@ -198,5 +206,15 @@ set_property -dict [list \ show_label true \ ] $param +set clk_group [ipgui::add_group -name {Clock Domain Configuration} -component $cc \ + -parent $page0 -display_name {Clock Domain Configuration}] + +set p [ipgui::get_guiparamspec -name "ASYNC_CLK" -component $cc] +ipgui::move_param -component $cc -order 0 $p -parent $clk_group +set_property -dict [list \ + "display_name" "Link and Device Clock Asynchronous" \ + "widget" "checkBox" \ +] $p + ipx::create_xgui_files [ipx::current_core] ipx::save_core [ipx::current_core] diff --git a/library/jesd204/jesd204_rx/jesd204_rx_lane.v b/library/jesd204/jesd204_rx/jesd204_rx_lane.v index c3552d4ee..dbaf73b44 100755 --- a/library/jesd204/jesd204_rx/jesd204_rx_lane.v +++ b/library/jesd204/jesd204_rx/jesd204_rx_lane.v @@ -46,16 +46,21 @@ module jesd204_rx_lane #( parameter DATA_PATH_WIDTH = 4, + parameter TPL_DATA_PATH_WIDTH = 4, parameter CHAR_INFO_REGISTERED = 0, parameter ALIGN_MUX_REGISTERED = 0, parameter SCRAMBLER_REGISTERED = 0, parameter ELASTIC_BUFFER_SIZE = 256, parameter ENABLE_FRAME_ALIGN_CHECK = 0, - parameter ENABLE_CHAR_REPLACE = 0 + parameter ENABLE_CHAR_REPLACE = 0, + parameter ASYNC_CLK = 0 ) ( input clk, input reset, + input device_clk, + input device_reset, + input [DATA_PATH_WIDTH*8-1:0] phy_data, input [DATA_PATH_WIDTH-1:0] phy_charisk, input [DATA_PATH_WIDTH-1:0] phy_notintable, @@ -66,7 +71,7 @@ module jesd204_rx_lane #( input ifs_reset, - output [DATA_PATH_WIDTH*8-1:0] rx_data, + output [TPL_DATA_PATH_WIDTH*8-1:0] rx_data, output buffer_ready_n, input buffer_release_n, @@ -304,12 +309,17 @@ pipeline_stage #( ); elastic_buffer #( - .WIDTH(DATA_PATH_WIDTH*8), - .SIZE(ELASTIC_BUFFER_SIZE) + .IWIDTH(DATA_PATH_WIDTH*8), + .OWIDTH(TPL_DATA_PATH_WIDTH*8), + .SIZE(ELASTIC_BUFFER_SIZE), + .ASYNC_CLK(ASYNC_CLK) ) i_elastic_buffer ( .clk(clk), .reset(reset), + .device_clk(device_clk), + .device_reset(device_reset), + .wr_data(data_scrambled), .rd_data(rx_data), diff --git a/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v b/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v index 60aa76421..16c39cd9f 100644 --- a/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v +++ b/library/jesd204/jesd204_rx/jesd204_rx_lane_64b.v @@ -45,16 +45,21 @@ `timescale 1ns/100ps module jesd204_rx_lane_64b #( - parameter ELASTIC_BUFFER_SIZE = 256 + parameter ELASTIC_BUFFER_SIZE = 256, + parameter TPL_DATA_PATH_WIDTH = 8, + parameter ASYNC_CLK = 0 ) ( input clk, input reset, + input device_clk, + input device_reset, + input [63:0] phy_data, input [1:0] phy_header, input phy_block_sync, - output [63:0] rx_data, + output [TPL_DATA_PATH_WIDTH*8-1:0] rx_data, output reg buffer_ready_n = 'b1, input all_buffer_ready_n, @@ -80,6 +85,7 @@ reg [11:0] crc12_calculated_prev; wire [63:0] data_descrambled_s; wire [63:0] data_descrambled; +wire [63:0] data_descrambled_reordered; wire [11:0] crc12_received; wire [11:0] crc12_calculated; @@ -108,7 +114,7 @@ jesd204_rx_header i_rx_header ( .cfg_beats_per_multiframe(cfg_beats_per_multiframe), .emb_lock(emb_lock), - + .valid_eomb(eomb), .valid_eoemb(eoemb), .crc12(crc12_received), @@ -217,14 +223,19 @@ end elastic_buffer #( - .WIDTH(64), - .SIZE(ELASTIC_BUFFER_SIZE) + .IWIDTH(64), + .OWIDTH(TPL_DATA_PATH_WIDTH*8), + .SIZE(ELASTIC_BUFFER_SIZE), + .ASYNC_CLK(ASYNC_CLK) ) i_elastic_buffer ( .clk(clk), .reset(reset), - .wr_data(data_descrambled), - .rd_data(rx_data_msb_s), + .device_clk(device_clk), + .device_reset(device_reset), + + .wr_data(data_descrambled_reordered), + .rd_data(rx_data), .ready_n(buffer_ready_n), .do_release_n(buffer_release_n) @@ -242,7 +253,7 @@ end genvar i; generate for (i = 0; i < 64; i = i + 8) begin: g_link_data - assign rx_data[i+:8] = rx_data_msb_s[64-1-i-:8]; + assign data_descrambled_reordered[i+:8] = data_descrambled[64-1-i-:8]; end endgenerate diff --git a/library/jesd204/jesd204_tx/Makefile b/library/jesd204/jesd204_tx/Makefile index a10af56b1..e0348b09a 100644 --- a/library/jesd204/jesd204_tx/Makefile +++ b/library/jesd204/jesd204_tx/Makefile @@ -24,6 +24,7 @@ XILINX_DEPS += ../../jesd204/interfaces/jesd204_tx_ilas_config.xml XILINX_DEPS += ../../jesd204/interfaces/jesd204_tx_ilas_config_rtl.xml XILINX_DEPS += ../../jesd204/interfaces/jesd204_tx_status.xml XILINX_DEPS += ../../jesd204/interfaces/jesd204_tx_status_rtl.xml +XILINX_DEPS += bd/bd.tcl XILINX_LIB_DEPS += jesd204/jesd204_common XILINX_LIB_DEPS += util_cdc diff --git a/library/jesd204/jesd204_tx/bd/bd.tcl b/library/jesd204/jesd204_tx/bd/bd.tcl new file mode 100644 index 000000000..7394bb17a --- /dev/null +++ b/library/jesd204/jesd204_tx/bd/bd.tcl @@ -0,0 +1,44 @@ +proc init {cellpath otherInfo} { + set ip [get_bd_cells $cellpath] + + bd::mark_propagate_override $ip \ + "ASYNC_CLK" + +} + +proc detect_async_clk { cellpath ip param_name clk_a clk_b } { + set param_src [get_property "CONFIG.$param_name.VALUE_SRC" $ip] + if {[string equal $param_src "USER"]} { + return; + } + + set clk_domain_a [get_property CONFIG.CLK_DOMAIN $clk_a] + set clk_domain_b [get_property CONFIG.CLK_DOMAIN $clk_b] + set clk_freq_a [get_property CONFIG.FREQ_HZ $clk_a] + set clk_freq_b [get_property CONFIG.FREQ_HZ $clk_b] + set clk_phase_a [get_property CONFIG.PHASE $clk_a] + set clk_phase_b [get_property CONFIG.PHASE $clk_b] + + # Only mark it as sync if we can make sure that it is sync, if the + # relationship of the clocks is unknown mark it as async + if {$clk_domain_a != {} && $clk_domain_b != {} && \ + $clk_domain_a == $clk_domain_b && $clk_freq_a == $clk_freq_b && \ + $clk_phase_a == $clk_phase_b} { + set clk_async 0 + } else { + set clk_async 1 + } + + set_property "CONFIG.$param_name" $clk_async $ip + +} + +proc propagate {cellpath otherinfo} { + set ip [get_bd_cells $cellpath] + + set link_clk [get_bd_pins "$ip/clk"] + set device_clk [get_bd_pins "$ip/device_clk"] + + detect_async_clk $cellpath $ip "ASYNC_CLK" $link_clk $device_clk +} + diff --git a/library/jesd204/jesd204_tx/jesd204_tx.v b/library/jesd204/jesd204_tx/jesd204_tx.v index 2225f8d3c..979977b3a 100755 --- a/library/jesd204/jesd204_tx/jesd204_tx.v +++ b/library/jesd204/jesd204_tx/jesd204_tx.v @@ -51,11 +51,16 @@ module jesd204_tx #( parameter LINK_MODE = 1, // 2 - 64B/66B; 1 - 8B/10B /* Only 4 is supported at the moment for 8b/10b and 8 for 64b */ parameter DATA_PATH_WIDTH = LINK_MODE[1] ? 8 : 4, - parameter ENABLE_CHAR_REPLACE = 1'b0 + parameter TPL_DATA_PATH_WIDTH = LINK_MODE[1] ? 8 : 4, + parameter ENABLE_CHAR_REPLACE = 1'b0, + parameter ASYNC_CLK = 1 ) ( input clk, input reset, + input device_clk, + input device_reset, + output [DATA_PATH_WIDTH*8*NUM_LANES-1:0] phy_data, output [DATA_PATH_WIDTH*NUM_LANES-1:0] phy_charisk, output [2*NUM_LANES-1:0] phy_header, @@ -66,21 +71,18 @@ module jesd204_tx #( input [NUM_LINKS-1:0] sync, - input [DATA_PATH_WIDTH*8*NUM_LANES-1:0] tx_data, + input [TPL_DATA_PATH_WIDTH*8*NUM_LANES-1:0] tx_data, output tx_ready, - output [DATA_PATH_WIDTH-1:0] tx_eof, - output [DATA_PATH_WIDTH-1:0] tx_sof, - output [DATA_PATH_WIDTH-1:0] tx_somf, - output [DATA_PATH_WIDTH-1:0] tx_eomf, + output [TPL_DATA_PATH_WIDTH-1:0] tx_eof, + output [TPL_DATA_PATH_WIDTH-1:0] tx_sof, + output [TPL_DATA_PATH_WIDTH-1:0] tx_somf, + output [TPL_DATA_PATH_WIDTH-1:0] tx_eomf, input tx_valid, input [NUM_LANES-1:0] cfg_lanes_disable, input [NUM_LINKS-1:0] cfg_links_disable, input [9:0] cfg_octets_per_multiframe, input [7:0] cfg_octets_per_frame, - input [7:0] cfg_lmfc_offset, - input cfg_sysref_oneshot, - input cfg_sysref_disable, input cfg_continuous_cgs, input cfg_continuous_ilas, input cfg_skip_ilas, @@ -88,14 +90,21 @@ module jesd204_tx #( input cfg_disable_char_replacement, input cfg_disable_scrambler, + input [9:0] device_cfg_octets_per_multiframe, + input [7:0] device_cfg_octets_per_frame, + input [7:0] device_cfg_beats_per_multiframe, + input [7:0] device_cfg_lmfc_offset, + input device_cfg_sysref_oneshot, + input device_cfg_sysref_disable, + output ilas_config_rd, output [1:0] ilas_config_addr, input [NUM_LANES*DATA_PATH_WIDTH*8-1:0] ilas_config_data, input ctrl_manual_sync_request, - output event_sysref_edge, - output event_sysref_alignment_error, + output device_event_sysref_edge, + output device_event_sysref_alignment_error, output [NUM_LINKS-1:0] status_sync, output [1:0] status_state @@ -107,6 +116,8 @@ localparam MAX_OCTETS_PER_MULTIFRAME = (MAX_OCTETS_PER_FRAME * 32) > 1024 ? 1024 : (MAX_OCTETS_PER_FRAME * 32); localparam MAX_BEATS_PER_MULTIFRAME = MAX_OCTETS_PER_MULTIFRAME / DATA_PATH_WIDTH; +localparam DPW_LOG2 = DATA_PATH_WIDTH == 8 ? 3 : DATA_PATH_WIDTH == 4 ? 2 : 1; + localparam LMFC_COUNTER_WIDTH = MAX_BEATS_PER_MULTIFRAME > 256 ? 9 : MAX_BEATS_PER_MULTIFRAME > 128 ? 8 : MAX_BEATS_PER_MULTIFRAME > 64 ? 7 : @@ -140,35 +151,191 @@ reg [DATA_PATH_WIDTH-1:0] tx_sof_fm_d2; reg [DATA_PATH_WIDTH-1:0] tx_eof_fm_d2; reg [DATA_PATH_WIDTH-1:0] tx_somf_fm_d2; reg [DATA_PATH_WIDTH-1:0] tx_eomf_fm_d2; +wire lmfc_edge_synced; wire lmc_edge; wire lmc_quarter_edge; wire eoemb; +wire [DATA_PATH_WIDTH*8*NUM_LANES-1:0] gearbox_data; +wire tx_ready_nx; +wire link_lmfc_edge; +wire link_lmfc_clk; +wire device_lmfc_edge; +wire device_lmfc_clk; +wire device_lmc_edge; +wire device_lmc_quarter_edge; +wire device_eoemb; +wire tx_next_mf_ready; +wire link_tx_ready; + +wire [7:0] cfg_beats_per_multiframe = cfg_octets_per_multiframe >> DPW_LOG2; +wire [7:0] device_cfg_beats_per_multiframe_s; + +// If input and output widths are symmetric keep the calculation for backwards +// compatibility of the software. +assign device_cfg_beats_per_multiframe_s = (TPL_DATA_PATH_WIDTH == DATA_PATH_WIDTH) ? + device_cfg_octets_per_multiframe >> DPW_LOG2 : + device_cfg_beats_per_multiframe; jesd204_lmfc #( .LINK_MODE(LINK_MODE), - .DATA_PATH_WIDTH(DATA_PATH_WIDTH) + .DATA_PATH_WIDTH(TPL_DATA_PATH_WIDTH) ) i_lmfc ( - .clk(clk), - .reset(reset), + .clk(device_clk), + .reset(device_reset), - .cfg_octets_per_multiframe(cfg_octets_per_multiframe), - .cfg_lmfc_offset(cfg_lmfc_offset), - .cfg_sysref_oneshot(cfg_sysref_oneshot), - .cfg_sysref_disable(cfg_sysref_disable), + .cfg_octets_per_multiframe(device_cfg_octets_per_multiframe), + .cfg_lmfc_offset(device_cfg_lmfc_offset), + .cfg_beats_per_multiframe(device_cfg_beats_per_multiframe_s), + .cfg_sysref_oneshot(device_cfg_sysref_oneshot), + .cfg_sysref_disable(device_cfg_sysref_disable), .sysref(sysref), - .sysref_edge(event_sysref_edge), - .sysref_alignment_error(event_sysref_alignment_error), + .sysref_edge(device_event_sysref_edge), + .sysref_alignment_error(device_event_sysref_alignment_error), - .lmfc_edge(lmfc_edge), - .lmfc_clk(lmfc_clk), + .lmfc_edge(device_lmfc_edge), + .lmfc_clk(device_lmfc_clk), .lmfc_counter(), - .lmc_edge(lmc_edge), - .lmc_quarter_edge(lmc_quarter_edge), - .eoemb(eoemb) + .lmc_edge(device_lmc_edge), + .lmc_quarter_edge(device_lmc_quarter_edge), + .eoemb(device_eoemb) ); +generate +if (ASYNC_CLK) begin : dual_lmfc_mode + + reg link_lmfc_reset = 1'b1; + reg device_lmfc_edge_d1 = 1'b0; + reg device_tx_ready = 1'b0; + + jesd204_lmfc #( + .LINK_MODE(LINK_MODE), + .DATA_PATH_WIDTH(DATA_PATH_WIDTH) + ) i_link_lmfc ( + .clk(clk), + .reset(link_lmfc_reset), + + .cfg_octets_per_multiframe(cfg_octets_per_multiframe), + .cfg_lmfc_offset('h0), + .cfg_beats_per_multiframe(cfg_beats_per_multiframe), + .cfg_sysref_oneshot(1'b0), + .cfg_sysref_disable(1'b1), + + .sysref(sysref), + + .sysref_edge(), + .sysref_alignment_error(), + + .lmfc_edge(link_lmfc_edge), + .lmfc_clk(link_lmfc_clk), + .lmfc_counter(), + .lmc_edge(lmc_edge), + .lmc_quarter_edge(lmc_quarter_edge), + .eoemb(eoemb) + ); + + sync_bits #( + .NUM_OF_BITS (1), + .ASYNC_CLK(ASYNC_CLK) + ) i_link_reset_done_cdc ( + .in_bits(~reset), + .out_clk(device_clk), + .out_resetn(~device_reset), + .out_bits(link_reset_n) + ); + + sync_event #( + .NUM_OF_EVENTS (1) + ) i_sync_lmfc ( + .in_clk(device_clk), + .in_event(device_lmfc_edge & link_reset_n), + .out_clk(clk), + .out_event(lmfc_edge_synced) + ); + + always @(posedge clk) begin + if (reset) begin + link_lmfc_reset <= 1'b1; + end else if (lmfc_edge_synced) begin + link_lmfc_reset <= 1'b0; + end + end + + jesd204_tx_gearbox #( + .IN_DATA_PATH_WIDTH(TPL_DATA_PATH_WIDTH), + .OUT_DATA_PATH_WIDTH(DATA_PATH_WIDTH), + .NUM_LANES(NUM_LANES), + .DEPTH(8) + ) i_tx_gearbox( + .link_clk(clk), + .reset(reset), + .device_clk(device_clk), + .device_reset(device_reset), + .device_data(tx_data), + .device_lmfc_edge(device_lmfc_edge_d1), + .link_data(gearbox_data), + .output_ready(tx_ready_nx) + ); + + always @(posedge device_clk) begin + device_lmfc_edge_d1 <= device_lmfc_edge; + end + + sync_bits #( + .NUM_OF_BITS (1), + .ASYNC_CLK(ASYNC_CLK) + ) i_next_mf_ready_cdc ( + .in_bits(tx_next_mf_ready), + .out_clk(device_clk), + .out_resetn(1'b1), + .out_bits(device_tx_next_mf_ready) + ); + + always @(posedge device_clk) begin + if (device_reset) begin + device_tx_ready <= 1'b0; + end else if (device_lmfc_edge & device_tx_next_mf_ready) begin + device_tx_ready <= 1'b1; + end + end + + jesd204_frame_mark #( + .DATA_PATH_WIDTH(TPL_DATA_PATH_WIDTH) + ) i_device_frame_mark ( + .clk(device_clk), + .reset(~device_tx_ready), + .cfg_octets_per_multiframe(device_cfg_octets_per_multiframe), + .cfg_beats_per_multiframe(device_cfg_beats_per_multiframe_s), + .cfg_octets_per_frame(device_cfg_octets_per_frame), + .sof(tx_sof), + .eof(tx_eof), + .somf(tx_somf), + .eomf(tx_eomf) + ); + + assign tx_ready = device_tx_ready; + +end else begin + assign link_lmfc_edge = device_lmfc_edge; + assign link_lmfc_clk = device_lmfc_clk; + assign lmc_edge = device_lmc_edge; + assign lmc_quarter_edge = device_lmc_quarter_edge; + assign eoemb = device_eoemb; + assign gearbox_data = tx_data; + + assign tx_sof = (LINK_MODE == 1) ? tx_sof_fm_d2 : tx_sof_fm; + assign tx_eof = (LINK_MODE == 1) ? tx_eof_fm_d2 : tx_eof_fm; + assign tx_somf = (LINK_MODE == 1) ? tx_somf_fm_d2 : tx_somf_fm; + assign tx_eomf = (LINK_MODE == 1) ? tx_eomf_fm_d2 : tx_eomf_fm; + assign tx_ready = link_tx_ready; + +end +endgenerate + +assign lmfc_edge = device_lmfc_edge; +assign lmfc_clk = device_lmfc_clk; + assign frame_mark_reset = (LINK_MODE == 1) ? eof_gen_reset : ~tx_ready_64b_next; jesd204_frame_mark #( @@ -177,6 +344,7 @@ jesd204_frame_mark #( .clk (clk), .reset (frame_mark_reset), .cfg_octets_per_multiframe (cfg_octets_per_multiframe), + .cfg_beats_per_multiframe (cfg_beats_per_multiframe), .cfg_octets_per_frame (cfg_octets_per_frame), .sof (tx_sof_fm), .eof (tx_eof_fm), @@ -195,11 +363,6 @@ always @(posedge clk) begin tx_eomf_fm_d2 <= tx_eomf_fm_d1; end -assign tx_sof = (LINK_MODE == 1) ? tx_sof_fm_d2 : tx_sof_fm; -assign tx_eof = (LINK_MODE == 1) ? tx_eof_fm_d2 : tx_eof_fm; -assign tx_somf = (LINK_MODE == 1) ? tx_somf_fm_d2 : tx_somf_fm; -assign tx_eomf = (LINK_MODE == 1) ? tx_eomf_fm_d2 : tx_eomf_fm; - generate genvar i; @@ -227,7 +390,7 @@ jesd204_tx_ctrl #( .reset(reset), .sync(sync), - .lmfc_edge(lmfc_edge), + .lmfc_edge(link_lmfc_edge), .somf(tx_somf_fm_d2), .somf_early2(tx_somf_fm), .eomf(tx_eomf_fm_d2), @@ -235,7 +398,9 @@ jesd204_tx_ctrl #( .lane_cgs_enable(lane_cgs_enable), .eof_reset(eof_gen_reset), - .tx_ready(tx_ready), + .tx_ready(link_tx_ready), + .tx_ready_nx(tx_ready_nx), + .tx_next_mf_ready(tx_next_mf_ready), .ilas_data(ilas_data), .ilas_charisk(ilas_charisk), @@ -278,8 +443,8 @@ for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane .ilas_data(ilas_data[D_STOP:D_START]), .ilas_charisk(ilas_charisk[C_STOP:C_START]), - .tx_data(tx_data[D_STOP:D_START]), - .tx_ready(tx_ready), + .tx_data(gearbox_data[D_STOP:D_START]), + .tx_ready(link_tx_ready), .phy_data(phy_data_r[D_STOP:D_START]), .phy_charisk(phy_charisk_r[C_STOP:C_START]), @@ -305,7 +470,7 @@ if (LINK_MODE[1] == 1) begin : mode_64b66b .clk(clk), .reset(reset), - .tx_data(tx_data[D_STOP:D_START]), + .tx_data(gearbox_data[D_STOP:D_START]), .tx_ready(tx_ready_64b), .phy_data(phy_data_r[D_STOP:D_START]), @@ -321,7 +486,7 @@ if (LINK_MODE[1] == 1) begin : mode_64b66b ); end - assign tx_ready_64b_next = reset ? 1'b0 : (lmfc_edge || tx_ready_64b); + assign tx_ready_64b_next = reset ? 1'b0 : (link_lmfc_edge || tx_ready_64b); always @(posedge clk) begin if (reset) begin @@ -331,7 +496,10 @@ if (LINK_MODE[1] == 1) begin : mode_64b66b end end - assign tx_ready = tx_ready_64b; + assign tx_ready_nx = tx_ready_64b_next; + assign tx_next_mf_ready = 1'b1; + + assign link_tx_ready = tx_ready_64b; // Link considered in DATA phase when SYSREF received and LEMC clock started // running assign status_state = {2{tx_ready_64b}}; diff --git a/library/jesd204/jesd204_tx/jesd204_tx_constr.ttcl b/library/jesd204/jesd204_tx/jesd204_tx_constr.ttcl index 609edb8cf..328abb531 100644 --- a/library/jesd204/jesd204_tx/jesd204_tx_constr.ttcl +++ b/library/jesd204/jesd204_tx/jesd204_tx_constr.ttcl @@ -47,6 +47,7 @@ <: setFileExtension ".xdc" :> <: setFileProcessingOrder late :> <: set sysref_iob [get_property PARAM_VALUE.SYSREF_IOB] :> +<: set async_clk [getBooleanValue "ASYNC_CLK"] :> set_property ASYNC_REG TRUE \ [get_cells {i_lmfc/sysref_d1_reg}] \ @@ -56,3 +57,45 @@ set_property ASYNC_REG TRUE \ # predictable set_property IOB <=: $sysref_iob :> \ [get_cells {i_lmfc/sysref_r_reg}] + +<: if {$async_clk} { :> + +set link_clk [get_clocks -of_objects [get_ports -quiet {clk}]] +set device_clk [get_clocks -of_objects [get_ports -quiet {device_clk}]] + +# sync event i_sync_lmfc +set_false_path -quiet \ + -from $device_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_sync_lmfc/i_sync_out* && IS_SEQUENTIAL}] + +set_false_path -quiet \ + -from $link_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_sync_lmfc/i_sync_in* && IS_SEQUENTIAL}] + +# sync bits i_next_mf_ready_cdc +set_false_path \ + -from $link_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_next_mf_ready_cdc* && IS_SEQUENTIAL}] + +# sync bits i_link_reset_done_cdc +set_false_path \ + -from $link_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_link_reset_done_cdc* && IS_SEQUENTIAL}] + +# sync bits gearbox/i_sync_ready +set_false_path \ + -from $link_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_sync_ready* && IS_SEQUENTIAL}] + +# gearbox distributed RAM +set_false_path -quiet \ + -from $device_clk \ + -to [get_cells -quiet -hier *mem_rd_data_reg* \ + -filter {NAME =~ *i_tx_gearbox* && IS_SEQUENTIAL}] + +<: } :> diff --git a/library/jesd204/jesd204_tx/jesd204_tx_ctrl.v b/library/jesd204/jesd204_tx/jesd204_tx_ctrl.v index 427aa31ba..c566403ad 100755 --- a/library/jesd204/jesd204_tx/jesd204_tx_ctrl.v +++ b/library/jesd204/jesd204_tx/jesd204_tx_ctrl.v @@ -62,6 +62,8 @@ module jesd204_tx_ctrl #( output reg eof_reset, output reg tx_ready, + output tx_ready_nx, + output tx_next_mf_ready, output reg [DATA_PATH_WIDTH*8*NUM_LANES-1:0] ilas_data, output reg [DATA_PATH_WIDTH*NUM_LANES-1:0] ilas_charisk, @@ -102,11 +104,11 @@ reg ilas_reset = 1'b1; reg ilas_data_reset = 1'b1; reg sync_request = 1'b0; reg sync_request_received = 1'b0; +reg last_ilas_mframe = 1'b0; reg [7:0] mframe_counter = 'h00; reg [ILAS_COUNTER_WIDTH-1:0] ilas_counter = 'h00; wire ilas_config_rd_start; reg ilas_config_rd_d1 = 1'b1; -reg last_ilas_mframe = 1'b0; reg cgs_enable = 1'b1; wire [DATA_PATH_WIDTH*8-1:0] ilas_default_data; @@ -123,6 +125,7 @@ i_cdc_sync ( .out_resetn(1'b1), .out_bits(status_sync) ); + assign status_sync_masked = status_sync | cfg_links_disable; always @(posedge clk) begin @@ -235,6 +238,9 @@ always @(posedge clk) begin end end +assign tx_next_mf_ready = sync_request_received & last_ilas_mframe & ~cfg_continuous_ilas; +assign tx_ready_nx = tx_ready | (tx_next_mf_ready & lmfc_edge_d2); + always @(posedge clk) begin if (ilas_reset == 1'b1) begin mframe_counter <= 'h00; diff --git a/library/jesd204/jesd204_tx/jesd204_tx_gearbox.v b/library/jesd204/jesd204_tx/jesd204_tx_gearbox.v new file mode 100644 index 000000000..cfe02f58b --- /dev/null +++ b/library/jesd204/jesd204_tx/jesd204_tx_gearbox.v @@ -0,0 +1,144 @@ +// +// The ADI JESD204 Core is released under the following license, which is +// different than all other HDL cores in this repository. +// +// Please read this, and understand the freedoms and responsibilities you have +// by using this source code/core. +// +// The JESD204 HDL, is copyright © 2016-2017 Analog Devices Inc. +// +// This core is free software, you can use run, copy, study, change, ask +// questions about and improve this core. Distribution of source, or resulting +// binaries (including those inside an FPGA or ASIC) require you to release the +// source of the entire project (excluding the system libraries provide by the +// tools/compiler/FPGA vendor). These are the terms of the GNU General Public +// License version 2 as published by the Free Software Foundation. +// +// 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. See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License version 2 +// along with this source code, and binary. If not, see +// . +// +// Commercial licenses (with commercial support) of this JESD204 core are also +// available under terms different than the General Public License. (e.g. they +// do not require you to accompany any image (FPGA or ASIC) using the JESD204 +// core with any corresponding source code.) For these alternate terms you must +// purchase a license from Analog Devices Technology Licensing Office. Users +// interested in such a license should contact jesd204-licensing@analog.com for +// more information. This commercial license is sub-licensable (if you purchase +// chips from Analog Devices, incorporate them into your PCB level product, and +// purchase a JESD204 license, end users of your product will also have a +// license to use this core in a commercial setting without releasing their +// source code). +// +// In addition, we kindly ask you to acknowledge ADI in any program, application +// or publication in which you use this JESD204 HDL core. (You are not required +// to do so; it is up to your common sense to decide whether you want to comply +// with this request or not.) For general publications, we suggest referencing : +// “The design and implementation of the JESD204 HDL Core used in this project +// is copyright © 2016-2017, Analog Devices, Inc.” +// + +`timescale 1ns/100ps + +// Constraints: +// - IN_DATA_PATH_WIDTH >= OUT_DATA_PATH_WIDTH +// + +module jesd204_tx_gearbox #( + parameter IN_DATA_PATH_WIDTH = 6, + parameter OUT_DATA_PATH_WIDTH = 4, + parameter NUM_LANES = 1, + parameter DEPTH = 16 +) ( + input link_clk, + input reset, + input device_clk, + input device_reset, + input [NUM_LANES*IN_DATA_PATH_WIDTH*8-1:0] device_data, + input device_lmfc_edge, + output [NUM_LANES*OUT_DATA_PATH_WIDTH*8-1:0] link_data, + input output_ready +); + +localparam MEM_W = IN_DATA_PATH_WIDTH*8*NUM_LANES; +localparam D_LOG2 = $clog2(DEPTH); + +reg [MEM_W-1:0] mem [0:DEPTH-1]; +reg [D_LOG2-1:0] in_addr ='h00; +reg [D_LOG2-1:0] out_addr = 'b0; +reg mem_rd_valid = 'b0; +reg [MEM_W-1:0] mem_rd_data; + +wire mem_wr_en = 1'b1; +wire mem_rd_en; +wire [D_LOG2-1:0] in_out_addr; +wire [D_LOG2-1:0] out_in_addr; +wire [NUM_LANES-1:0] unpacker_ready; +wire output_ready_sync; + +sync_bits i_sync_ready ( + .in_bits(output_ready), + .out_resetn(~device_reset), + .out_clk(device_clk), + .out_bits(output_ready_sync) +); + +always @(posedge device_clk) begin + if (device_lmfc_edge & ~output_ready_sync) begin + in_addr <= 'h01; + end else if (mem_wr_en) begin + in_addr <= in_addr + 1; + end +end + +always @(posedge device_clk) begin + if (mem_wr_en) begin + mem[in_addr] <= device_data; + end +end + +assign mem_rd_en = output_ready&unpacker_ready[0]; + +always @(posedge link_clk) begin + if (mem_rd_en) begin + mem_rd_data <= mem[out_addr]; + end + mem_rd_valid <= mem_rd_en; +end + +always @(posedge link_clk) begin + if (reset) begin + out_addr <= 'b0; + end else if (mem_rd_en) begin + out_addr <= out_addr + 1; + end +end + +genvar i; +generate for (i = 0; i < NUM_LANES; i=i+1) begin: unpacker + +ad_upack #( + .I_W(IN_DATA_PATH_WIDTH), + .O_W(OUT_DATA_PATH_WIDTH), + .UNIT_W(8), + .O_REG(0) +) i_ad_upack ( + .clk(link_clk), + .reset(reset), + .idata(mem_rd_data[i*IN_DATA_PATH_WIDTH*8+:IN_DATA_PATH_WIDTH*8]), + .ivalid(mem_rd_valid), + .iready(unpacker_ready[i]), + + .odata(link_data[i*OUT_DATA_PATH_WIDTH*8+:OUT_DATA_PATH_WIDTH*8]), + .ovalid() +); + +end +endgenerate + +endmodule + diff --git a/library/jesd204/jesd204_tx/jesd204_tx_ip.tcl b/library/jesd204/jesd204_tx/jesd204_tx_ip.tcl index 4b82cab18..e66c678b1 100644 --- a/library/jesd204/jesd204_tx/jesd204_tx_ip.tcl +++ b/library/jesd204/jesd204_tx/jesd204_tx_ip.tcl @@ -50,13 +50,17 @@ adi_ip_files jesd204_tx [list \ "jesd204_tx_lane.v" \ "jesd204_tx_lane_64b.v" \ "jesd204_tx_header.v" \ + "jesd204_tx_gearbox.v" \ "jesd204_tx_ctrl.v" \ "jesd204_tx_constr.ttcl" \ - "jesd204_tx.v" + "../../common/ad_upack.v" \ + "jesd204_tx.v" \ + "bd/bd.tcl" ] adi_ip_properties_lite jesd204_tx adi_ip_ttcl jesd204_tx "jesd204_tx_constr.ttcl" +adi_ip_bd jesd204_tx "bd/bd.tcl" adi_ip_add_core_dependencies { \ analog.com:user:jesd204_common:1.0 \ @@ -93,15 +97,18 @@ adi_add_bus "tx_cfg" "slave" \ { "cfg_links_disable" "links_disable" } \ { "cfg_octets_per_multiframe" "octets_per_multiframe" } \ { "cfg_octets_per_frame" "octets_per_frame" } \ - { "cfg_lmfc_offset" "lmfc_offset" } \ - { "cfg_sysref_oneshot" "sysref_oneshot" } \ - { "cfg_sysref_disable" "sysref_disable" } \ { "cfg_continuous_cgs" "continuous_cgs" } \ { "cfg_continuous_ilas" "continuous_ilas" } \ { "cfg_skip_ilas" "skip_ilas" } \ { "cfg_mframes_per_ilas" "mframes_per_ilas" } \ { "cfg_disable_char_replacement" "disable_char_replacement" } \ { "cfg_disable_scrambler" "disable_scrambler" } \ + { "device_cfg_octets_per_multiframe" "device_octets_per_multiframe" } \ + { "device_cfg_octets_per_frame" "device_octets_per_frame" } \ + { "device_cfg_beats_per_multiframe" "device_beats_per_multiframe" } \ + { "device_cfg_lmfc_offset" "device_lmfc_offset" } \ + { "device_cfg_sysref_oneshot" "device_sysref_oneshot" } \ + { "device_cfg_sysref_disable" "device_sysref_disable" } \ } adi_add_bus "tx_ilas_config" "master" \ @@ -117,8 +124,8 @@ adi_add_bus "tx_event" "master" \ "analog.com:interface:jesd204_tx_event_rtl:1.0" \ "analog.com:interface:jesd204_tx_event:1.0" \ { \ - { "event_sysref_alignment_error" "sysref_alignment_error" } \ - { "event_sysref_edge" "sysref_edge" } \ + { "device_event_sysref_alignment_error" "sysref_alignment_error" } \ + { "device_event_sysref_edge" "sysref_edge" } \ } adi_add_bus "tx_status" "master" \ @@ -136,8 +143,9 @@ adi_add_bus "tx_ctrl" "slave" \ { "ctrl_manual_sync_request" "manual_sync_request" } \ } -adi_add_bus_clock "clk" "tx_data:tx_cfg:tx_ilas_config:tx_event:tx_status:tx_ctrl" \ - "reset" +adi_add_bus_clock "clk" "tx_cfg:tx_ilas_config:tx_event:tx_status:tx_ctrl" "reset" + +adi_add_bus_clock "device_clk" "tx_data" "device_reset" adi_set_bus_dependency "tx_ilas_config" "tx_ilas_config" \ "(spirit:decode(id('MODELPARAM_VALUE.LINK_MODE')) = 1)" @@ -186,5 +194,16 @@ set_property -dict [list \ show_label true \ ] $param + +set clk_group [ipgui::add_group -name {Clock Domain Configuration} -component $cc \ + -parent $page0 -display_name {Clock Domain Configuration}] + +set p [ipgui::get_guiparamspec -name "ASYNC_CLK" -component $cc] +ipgui::move_param -component $cc -order 0 $p -parent $clk_group +set_property -dict [list \ + "display_name" "Link and Device Clock Asynchronous" \ + "widget" "checkBox" \ +] $p + ipx::create_xgui_files [ipx::current_core] ipx::save_core [ipx::current_core] diff --git a/library/jesd204/scripts/jesd204.tcl b/library/jesd204/scripts/jesd204.tcl index dbd7b50f6..9f99d0beb 100644 --- a/library/jesd204/scripts/jesd204.tcl +++ b/library/jesd204/scripts/jesd204.tcl @@ -69,6 +69,7 @@ proc adi_axi_jesd204_tx_create {ip_name num_lanes {num_links 1} {link_mode 1}} { ad_ip_parameter "${ip_name}/tx" CONFIG.LINK_MODE $link_mode ad_connect "${ip_name}/tx_axi/core_reset" "${ip_name}/tx/reset" + ad_connect "${ip_name}/tx_axi/device_reset" "${ip_name}/tx/device_reset" if {$link_mode == 1} {ad_connect "${ip_name}/tx_axi/tx_ctrl" "${ip_name}/tx/tx_ctrl"} ad_connect "${ip_name}/tx_axi/tx_cfg" "${ip_name}/tx/tx_cfg" ad_connect "${ip_name}/tx/tx_event" "${ip_name}/tx_axi/tx_event" @@ -87,14 +88,17 @@ proc adi_axi_jesd204_tx_create {ip_name num_lanes {num_links 1} {link_mode 1}} { ad_connect "${ip_name}/tx_axi/irq" "${ip_name}/irq" # JESD204 processing + create_bd_pin -dir I -type clk "${ip_name}/link_clk" create_bd_pin -dir I -type clk "${ip_name}/device_clk" if {$link_mode == 1} {create_bd_pin -dir I -from [expr $num_links - 1] -to 0 "${ip_name}/sync"} create_bd_pin -dir I "${ip_name}/sysref" create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:axis_rtl:1.0 "${ip_name}/tx_data" - ad_connect "${ip_name}/device_clk" "${ip_name}/tx_axi/core_clk" - ad_connect "${ip_name}/device_clk" "${ip_name}/tx/clk" + ad_connect "${ip_name}/link_clk" "${ip_name}/tx_axi/core_clk" + ad_connect "${ip_name}/link_clk" "${ip_name}/tx/clk" + ad_connect "${ip_name}/device_clk" "${ip_name}/tx_axi/device_clk" + ad_connect "${ip_name}/device_clk" "${ip_name}/tx/device_clk" if {$link_mode == 1} {ad_connect "${ip_name}/sync" "${ip_name}/tx/sync"} ad_connect "${ip_name}/sysref" "${ip_name}/tx/sysref" ad_connect "${ip_name}/tx_data" "${ip_name}/tx/tx_data" @@ -143,6 +147,7 @@ proc adi_axi_jesd204_rx_create {ip_name num_lanes {num_links 1} {link_mode 1}} { ad_ip_parameter "${ip_name}/rx" CONFIG.LINK_MODE $link_mode ad_connect "${ip_name}/rx_axi/core_reset" "${ip_name}/rx/reset" + ad_connect "${ip_name}/rx_axi/device_reset" "${ip_name}/rx/device_reset" ad_connect "${ip_name}/rx_axi/rx_cfg" "${ip_name}/rx/rx_cfg" ad_connect "${ip_name}/rx/rx_event" "${ip_name}/rx_axi/rx_event" ad_connect "${ip_name}/rx/rx_status" "${ip_name}/rx_axi/rx_status" @@ -160,6 +165,7 @@ proc adi_axi_jesd204_rx_create {ip_name num_lanes {num_links 1} {link_mode 1}} { ad_connect "${ip_name}/rx_axi/irq" "${ip_name}/irq" # JESD204 processing + create_bd_pin -dir I -type clk "${ip_name}/link_clk" create_bd_pin -dir I -type clk "${ip_name}/device_clk" if {$link_mode == 1} {create_bd_pin -dir O -from [expr $num_links - 1] -to 0 "${ip_name}/sync"} create_bd_pin -dir I "${ip_name}/sysref" @@ -172,8 +178,10 @@ proc adi_axi_jesd204_rx_create {ip_name num_lanes {num_links 1} {link_mode 1}} { create_bd_pin -dir O "${ip_name}/rx_data_tvalid" create_bd_pin -dir O -from [expr $num_lanes * 32 - 1] -to 0 "${ip_name}/rx_data_tdata" - ad_connect "${ip_name}/device_clk" "${ip_name}/rx_axi/core_clk" - ad_connect "${ip_name}/device_clk" "${ip_name}/rx/clk" + ad_connect "${ip_name}/link_clk" "${ip_name}/rx_axi/core_clk" + ad_connect "${ip_name}/link_clk" "${ip_name}/rx/clk" + ad_connect "${ip_name}/device_clk" "${ip_name}/rx_axi/device_clk" + ad_connect "${ip_name}/device_clk" "${ip_name}/rx/device_clk" if {$link_mode == 1} {ad_connect "${ip_name}/rx/sync" "${ip_name}/sync"} ad_connect "${ip_name}/sysref" "${ip_name}/rx/sysref" # ad_connect "${ip_name}/phy_ready" "${ip_name}/rx/phy_ready" @@ -204,7 +212,7 @@ proc adi_axi_jesd204_rx_create {ip_name num_lanes {num_links 1} {link_mode 1}} { # L M S N & NP -proc adi_tpl_jesd204_tx_create {ip_name num_of_lanes num_of_converters samples_per_frame sample_width {link_layer_bytes_per_beat 4}} { +proc adi_tpl_jesd204_tx_create {ip_name num_of_lanes num_of_converters samples_per_frame sample_width {link_layer_bytes_per_beat 4} {dma_sample_width 16}} { if {$num_of_lanes < 1 || $num_of_lanes > 16} { @@ -250,6 +258,7 @@ proc adi_tpl_jesd204_tx_create {ip_name num_of_lanes num_of_converters samples_p CONVERTER_RESOLUTION $sample_width \ BITS_PER_SAMPLE $sample_width \ OCTETS_PER_BEAT $tpl_bytes_per_beat \ + DMA_BITS_PER_SAMPLE $dma_sample_width ] if {$num_of_converters > 1} { @@ -332,7 +341,7 @@ proc adi_tpl_jesd204_tx_create {ip_name num_of_lanes num_of_converters samples_p # L M S N & NP -proc adi_tpl_jesd204_rx_create {ip_name num_of_lanes num_of_converters samples_per_frame sample_width {link_layer_bytes_per_beat 4}} { +proc adi_tpl_jesd204_rx_create {ip_name num_of_lanes num_of_converters samples_per_frame sample_width {link_layer_bytes_per_beat 4} {dma_sample_width 16}} { if {$num_of_lanes < 1 || $num_of_lanes > 16} { @@ -381,15 +390,16 @@ proc adi_tpl_jesd204_rx_create {ip_name num_of_lanes num_of_converters samples_p CONVERTER_RESOLUTION $sample_width \ BITS_PER_SAMPLE $sample_width \ OCTETS_PER_BEAT $tpl_bytes_per_beat \ + DMA_BITS_PER_SAMPLE $dma_sample_width ] if {$num_of_converters > 1} { # Slicer cores for {set i 0} {$i < $num_of_converters} {incr i} { ad_ip_instance xlslice ${ip_name}/data_slice_$i [list \ - DIN_WIDTH [expr $sample_width*$samples_per_channel*$num_of_converters] \ - DIN_FROM [expr $sample_width*$samples_per_channel*($i+1)-1] \ - DIN_TO [expr $sample_width*$samples_per_channel*$i] \ + DIN_WIDTH [expr $dma_sample_width*$samples_per_channel*$num_of_converters] \ + DIN_FROM [expr $dma_sample_width*$samples_per_channel*($i+1)-1] \ + DIN_TO [expr $dma_sample_width*$samples_per_channel*$i] \ ] ad_ip_instance xlslice "${ip_name}/enable_slice_${i}" [list \ diff --git a/projects/scripts/adi_board.tcl b/projects/scripts/adi_board.tcl index fe3ea1647..619fe3ebe 100644 --- a/projects/scripts/adi_board.tcl +++ b/projects/scripts/adi_board.tcl @@ -180,12 +180,16 @@ proc ad_disconnect {p_name_1 p_name_2} { # \param[a_jesd] - name of the JESD204 link IP # \param[lane_map] - lane_map maps the logical lane $n onto the physical lane # $lane_map[$n], otherwise logical lane $n is mapped onto physical lane $n. -# \param[device_clk] - define a custom device clock, should be a net name +# \param[link_clk] - define a custom link clock, should be a net name # connected to the clock source. If not used, the rx|tx_clk_out_0 is used as +# link clock. This should be lane rate / (encoder_ratio*datapath width in bits) +# where encoder_ratio is 10/8 for 8b10b encoding or 66/64 for 64b66b link layer. +# \param[device_clk] - define a custom device clock, should be a net name +# connected to the clock source. If not used, the link_clk is used as # device clock # -proc ad_xcvrcon {u_xcvr a_xcvr a_jesd {lane_map {}} {device_clk {}}} { +proc ad_xcvrcon {u_xcvr a_xcvr a_jesd {lane_map {}} {link_clk {}} {device_clk {}}} { global xcvr_index global xcvr_tx_index @@ -244,10 +248,18 @@ proc ad_xcvrcon {u_xcvr a_xcvr a_jesd {lane_map {}} {device_clk {}}} { create_bd_port -dir I $m_sysref create_bd_port -from [expr $num_of_links - 1] -to 0 -dir ${ctrl_dir} $m_sync - if {$device_clk == {}} { - set device_clk ${u_xcvr}/${txrx}_out_clk_${index} + if {$link_clk == {}} { + set link_clk ${u_xcvr}/${txrx}_out_clk_${index} set rst_gen [regsub -all "/" ${a_jesd}_rstgen "_"] set create_rst_gen 1 + } else { + set rst_gen ${link_clk}_rstgen + # Only create one reset gen per clock + set create_rst_gen [expr {[get_bd_cells -quiet ${rst_gen}] == {}}] + } + + if {$device_clk == {}} { + set device_clk $link_clk } else { set rst_gen ${device_clk}_rstgen # Only create one reset gen per clock @@ -284,7 +296,7 @@ proc ad_xcvrcon {u_xcvr a_xcvr a_jesd {lane_map {}} {device_clk {}}} { ad_connect ${a_xcvr}/up_cm_${n} ${u_xcvr}/up_cm_${n} } ad_connect ${a_xcvr}/up_ch_${n} ${u_xcvr}/up_${txrx}_${phys_lane} - ad_connect ${device_clk} ${u_xcvr}/${txrx}_clk_${phys_lane} + ad_connect ${link_clk} ${u_xcvr}/${txrx}_clk_${phys_lane} if {$phys_lane != {}} { if {$jesd204_type == 0} { ad_connect ${u_xcvr}/${txrx}_${phys_lane} ${a_jesd}/${txrx}_phy${n} @@ -303,6 +315,7 @@ proc ad_xcvrcon {u_xcvr a_xcvr a_jesd {lane_map {}} {device_clk {}}} { ad_connect ${a_jesd}/sysref $m_sysref ad_connect ${a_jesd}/sync $m_sync ad_connect ${device_clk} ${a_jesd}/device_clk + ad_connect ${link_clk} ${a_jesd}/link_clk } else { ad_connect ${a_jesd}/${txrx}_sysref $m_sysref ad_connect ${a_jesd}/${txrx}_sync $m_sync