AN 1014: Implementing Analog-to-Digital Converter Multilink Design with Agilex™ 7 FPGA F-Tile JESD204C RX IP
ID
857717
Date
11/24/2025
Public
1.1. ADC to Agilex™ 7 Dual Link Design Overview
1.2. ADC to Agilex™ 7 Dual Link Design Implementation Guidelines
1.3. Synchronized ADC to Agilex™ 7 Dual Link
1.4. Instantiating TX simplex into RX Multi-Link Design for Loopback Hardware Testing
1.5. Document Revision History for AN 1014: Implementing Analog-to-Digital Converter Dual Link Design with Agilex™ 7 FPGA F-Tile JESD204C RX IP
1.3.1.1. Editing Design Example Platform Designer System for Synchronized ADC to Agilex™ 7 Dual Link
1.3.1.2. Editing Design Example Top-Level HDL for Synchronized ADC to Agilex™ 7 Dual Link
1.3.1.3. Editing Simulation Testbench for Synchronized ADC to Agilex™ 7 Dual Link
1.3.1.4. Adding IP Signals to the Simulation Waveform
1.3.1.5. Updating the Simulation Script
1.3.1.6. Simulating the Dual Link Design
1.3.1.7. Viewing the Simulation Results
1.3.2.1. Editing Design Example Platform Designer System for Synchronized ADC to Agilex™ 7 Dual Link
1.3.2.2. Editing Design Example Top-Level HDL for Synchronized ADC to Agilex™ 7 Dual Link
1.3.2.3. Editing Design Example Top-Level SDC Constraint for Synchronized ADC to Agilex™ 7 Dual Link
1.3.2.4. Compiling the Design in Quartus® Prime Software
1.3.1.3. Editing Simulation Testbench for Synchronized ADC to Agilex™ 7 Dual Link
The simulation testbench, tb_top.sv, is located in the simulation/models folder. Follow these steps to edit the testbench.
- Open the testbench (tb_top.sv) in a text editor.
- Add the LINK parameter at the localparam declaration section. Example:
localparam LINK = 2; // Number of IP core in the dual link design
- In the instantiation of the F-Tile JESD204C example design modules, include the LINK parameter. Example:
jesd204c_f_ed_rx #( .LINK (LINK),
- Add the TX_REG and RX_REG text macros for each additional link. The additional IP instance in this example is intel_jesd204c_f_1 and intel_jesd204c_f_tx_1 and the text macro is TX_REG_1 and RX_REG_1. Example:
`define TX_REG_1 tb_top.jesd204c_f_ed.u_j204c_f_ss.j204c_f_ip.intel_jesd204c_f_tx_1.intel_jesd204c_f_tx.j204c_f_sip_100_inst.j204c_gdr_tx_base_inst.j204c_gdr_tx_csr_inst.j204c_tx_regmap_inst `define RX_REG_1 tb_top.jesd204c_f_ed.u_j204c_f_ss.j204c_f_ip.intel_jesd204c_f_1.intel_jesd204c_f.j204c_f_sip_100_inst.j204c_f_rx_base_inst.j204c_f_rx_csr_inst.j204c_rx_regmap_inst - Add the TX_RST_SEQ and RX_RST_SEQ text macros for each additional link. The text macro is TX_RST_SEQ_1 and RX_RST_SEQ_1. Example:
`define TX_RST_SEQ_1 tb_top.jesd204c_f_ed.u_j204c_f_ss.j204c_f_ip.intel_jesd204c_f_tx_1.intel_jesd204c_f_tx.j204c_f_sip_100_inst.j204c_gdr_sip_rst_seq_tx_inst `define RX_RST_SEQ_1 tb_top.jesd204c_f_ed.u_j204c_f_ss.j204c_f_ip.intel_jesd204c_f_1.intel_jesd204c_f.j204c_f_sip_100_inst.j204c_f_sip_rst_seq_rx_inst - Add the TX_TOP and RX_TOP text macros for each additional link. The text macro is TX_TOP_1 and RX_TOP_1. Example:
`define TX_TOP_1 tb_top.jesd204c_f_ed.u_j204c_f_ss.j204c_f_ip.intel_jesd204c_f_tx_1.intel_jesd204c_f_tx `define RX_TOP_1 tb_top.jesd204c_f_ed.u_j204c_f_ss.j204c_f_ip.intel_jesd204c_f_1.intel_jesd204c_f - Comment out or delete the sysref_out port at the instantiation of the intel_j204c_f_ed subsystem.
// Example in Verilog //.sysref_out (sysref), - Change the dimension and assignment of the following wires and registers:
reg [LINK-1:0] tx_link_error_reg = 1'b0; reg [LINK-1:0] rx_link_error_reg = 1'b0; reg [LINK-1:0] data_error_reg = 1'b0; reg [LINK-1:0] cmd_data_error_reg= 1'b0; wire [LINK*L-1:0] tx_serial_data; wire [LINK*L-1:0] rx_serial_data; wire [LINK*L-1:0] tx_serial_data_n; wire [LINK*L-1:0] rx_serial_data_n; wire [LINK-1:0] data_valid; wire [LINK-1:0] data_error; wire [LINK-1:0] tx_link_error; wire [LINK-1:0] rx_link_error; wire [LINK-1:0] tx_rst_ack_n; wire [LINK-1:0] rx_rsk_ack_n; wire [LINK-1:0] rx_avst_ready; wire [LINK-1:0][(TOTAL_SAMPLE*N)-1:0] rx_avst_data; wire [LINK-1:0] cmd_data_valid; wire [LINK-1:0] cmd_data_error; wire [LINK-1:0][L*18-1:0] cmd_data; wire [LINK-1:0] tx_err_sysref_lemc_err; wire [LINK-1:0] tx_err_dll_data_invalid_err; wire [LINK-1:0] tx_err_frame_data_invalid_err; wire [LINK-1:0] tx_err_cmd_invalid_err; wire [LINK-1:0] tx_err_tx_ready_err; wire [LINK-1:0] tx_err_pcfifo_full_err; wire [LINK-1:0] tx_err_tx_gb_underflow_err; wire [LINK-1:0] tx_err_tx_gb_overflow_err; wire [LINK-1:0] tx_err_efifo_overflow_err; wire [LINK-1:0] tx_err_src_tx_alarm; wire [LINK-1:0] tx_err_txpll_lock_err; wire [LINK-1:0] tx_err_syspll_lock_err; wire [LINK-1:0] rx_err_sysref_lemc_err; wire [LINK-1:0] rx_err_dll_data_ready_err; wire [LINK-1:0] rx_err_frame_data_ready_err; wire [LINK-1:0] rx_err_cmd_ready_err; wire [LINK-1:0] rx_err_cdr_locked_err; wire [LINK-1:0] rx_err_pcfifo_full_err; wire [LINK-1:0] rx_err_pcfifo_empty_err; wire [LINK-1:0] rx_err_lane_deskew_err; wire [LINK-1:0] rx_err_invalid_sync_header; wire [LINK-1:0] rx_err_invalid_eomb; wire [LINK-1:0] rx_err_invalid_eoemb; wire [LINK-1:0] rx_err_cmd_par_err; wire [LINK-1:0] rx_err_crc_err; wire [LINK-1:0] rx_err_rx_gb_underflow_err; wire [LINK-1:0] rx_err_rx_gb_overflow_err; wire [LINK-1:0] rx_err_sh_unlock_err; wire [LINK-1:0] rx_err_emb_unlock_err; wire [LINK-1:0] rx_err_eb_full_err; wire [LINK-1:0] rx_err_ecc_corrected_err; wire [LINK-1:0] rx_err_ecc_fatal_err; wire [LINK-1:0] rx_err_src_rx_alarm; wire [LINK-1:0] rx_err_syspll_lock_err; wire [LINK-1:0] rx_err_fec_uncorr_err; wire [LINK-1:0] rx_err_fec_corr_err; - Modify tx_ready and rx_ready so they include all IP’s transceiver channels.
assign tx_ready = (&`TX_RST_SEQ.lane_out_of_reset[L-1:0]) & (&`TX_RST_SEQ_1.lane_out_of_reset[L-1:0]); assign rx_ready = (&`RX_RST_SEQ.lane_out_of_reset[L-1:0]) & (&`RX_RST_SEQ_1.lane_out_of_reset[L-1:0]); - Scale the dimensions of the rx_avst_ready, tx_rst_ack_n, rx_rst_ack_n, and rx_is_lockedtodata assignments according to the number of links. Example for LINK = 2:
//Scale the dimension to [number of link-1:0] assign rx_avst_ready = tb_top.jesd204c_f_ed.rx_avst_ready[1:0]; assign tx_rst_ack_n = tb_top.jesd204c_f_ed.tx_rst_ack_n[1:0]; assign rx_rst_ack_n = tb_top.jesd204c_f_ed.rx_rst_ack_n[1:0]; assign rx_is_lockedtodata = (&`RX_TOP.phy_rx_is_lockedtodata[L-1:0]) & (&`RX_TOP_1.phy_rx_is_lockedtodata[L-1:0]);
- Scale the dimensions of the cmd_data_valid, cmd_data_error, and cmd_data assignments according to the number of links. Example for LINK = 2:
assign cmd_data_valid [0] = `RX_TOP.j204c_rx_cmd_valid; assign cmd_data_valid [1] = `RX_TOP_1.j204c_rx_cmd_valid; assign cmd_data_error = tb_top.jesd204c_f_ed.o_cmd_ramp_chk_err[1:0]; assign cmd_data [0] = `RX_TOP.j204c_rx_cmd_data; assign cmd_data [1] = `RX_TOP_1.j204c_rx_cmd_data; - Add the LINK parameter to the assignment statements for rx_serial_data and rx_serial_data_n as shown below:
//Internal Loopback assign rx_serial_data = INTERNAL_SERIAL_LB ? {LINK*L{1'b0}} : tx_serial_data; assign rx_serial_data_n = INTERNAL_SERIAL_LB ? {LINK*L{1'b0}} : tx_serial_data_n; - Add an index to each assignment of the TX and RX IP error. Assign the errors for each link according to the TX and RX IP text macro. Example:
//TX Error LINK 0 assign tx_err_sysref_lemc_err [0] = `TX_REG.tx_err_sysref_lemc_err; assign tx_err_dll_data_invalid_err [0] = `TX_REG.tx_err_dll_data_invalid_err; assign tx_err_frame_data_invalid_err[0] = `TX_REG.tx_err_frame_data_invalid_err; assign tx_err_cmd_invalid_err [0] = `TX_REG.tx_err_cmd_invalid_err; assign tx_err_tx_gb_underflow_err[0] = `TX_REG.tx_err_tx_gb_underflow_err; assign tx_err_tx_gb_overflow_err[0] = `TX_REG.tx_err_tx_gb_overflow_err; assign tx_err_efifo_overflow_err[0] = `TX_REG.tx_err_efifo_overflow_err; assign tx_err_src_tx_alarm[0] = `TX_REG.tx_err_src_tx_alarm; assign tx_err_txpll_lock_err[0] = `TX_REG.tx_err_txpll_lock_err; assign tx_err_syspll_lock_err[0] = `TX_REG.tx_err_syspll_lock_err; //TX Error LINK 1 assign tx_err_sysref_lemc_err [1] = `TX_REG_1.tx_err_sysref_lemc_err; assign tx_err_dll_data_invalid_err [1] = `TX_REG_1.tx_err_dll_data_invalid_err; assign tx_err_frame_data_invalid_err[1] = `TX_REG_1.tx_err_frame_data_invalid_err; assign tx_err_cmd_invalid_err [1] = `TX_REG_1.tx_err_cmd_invalid_err; assign tx_err_tx_gb_underflow_err[1] = `TX_REG_1.tx_err_tx_gb_underflow_err; assign tx_err_tx_gb_overflow_err[1] = `TX_REG_1.tx_err_tx_gb_overflow_err; assign tx_err_efifo_overflow_err[1] = `TX_REG_1.tx_err_efifo_overflow_err; assign tx_err_src_tx_alarm[1] = `TX_REG_1.tx_err_src_tx_alarm; assign tx_err_txpll_lock_err[1] = `TX_REG_1.tx_err_txpll_lock_err; assign tx_err_syspll_lock_err[1] = `TX_REG_1.tx_err_syspll_lock_err; //RX Error LINK 0 assign rx_err_sysref_lemc_err[0] = `RX_REG.rx_err_sysref_lemc_err; assign rx_err_dll_data_ready_err[0] = `RX_REG.rx_err_dll_data_ready_err; assign rx_err_frame_data_ready_err[0] = `RX_REG.rx_err_frame_data_ready_err; assign rx_err_cmd_ready_err[0] = `RX_REG.rx_err_cmd_ready_err; assign rx_err_cdr_locked_err[0] = `RX_REG.rx_err_cdr_locked_err; assign rx_err_lane_deskew_err[0] = `RX_REG.rx_err_lane_deskew_err; assign rx_err_invalid_sync_header[0] = `RX_REG.rx_err_invalid_sync_header; assign rx_err_invalid_eomb[0] = `RX_REG.rx_err_invalid_eomb; assign rx_err_invalid_eoemb [0] = `RX_REG.rx_err_invalid_eoemb; assign rx_err_cmd_par_err[0] = `RX_REG.rx_err_cmd_par_err; assign rx_err_crc_err[0] = `RX_REG.rx_err_crc_err; assign rx_err_rx_gb_underflow_err[0] = `RX_REG.rx_err_rx_gb_underflow_err; assign rx_err_rx_gb_overflow_err[0] = `RX_REG.rx_err_rx_gb_overflow_err; assign rx_err_sh_unlock_err[0] = `RX_REG.rx_err_sh_unlock_err; assign rx_err_emb_unlock_err[0] = `RX_REG.rx_err_emb_unlock_err; assign rx_err_eb_full_err[0] = `RX_REG.rx_err_eb_full_err; assign rx_err_ecc_corrected_err[0] = `RX_REG.rx_err_ecc_corrected_err; assign rx_err_ecc_fatal_err [0] = `RX_REG.rx_err_ecc_fatal_err; assign rx_err_src_rx_alarm [0] = `RX_REG.rx_err_src_rx_alarm; assign rx_err_fec_corr_err [0] = `RX_REG.rx_err_fec_corr_err; assign rx_err_fec_uncorr_err [0] = `RX_REG.rx_err_fec_uncorr_err; assign rx_err_syspll_lock_err [0] = `RX_REG.rx_err_syspll_lock_err; //RX Error LINK 1 assign rx_err_sysref_lemc_err[1] = `RX_REG_1.rx_err_sysref_lemc_err; assign rx_err_dll_data_ready_err[1] = `RX_REG_1.rx_err_dll_data_ready_err; assign rx_err_frame_data_ready_err[1] = `RX_REG_1.rx_err_frame_data_ready_err; assign rx_err_cmd_ready_err[1] = `RX_REG_1.rx_err_cmd_ready_err; assign rx_err_cdr_locked_err[1] = `RX_REG_1.rx_err_cdr_locked_err; assign rx_err_lane_deskew_err[1] = `RX_REG_1.rx_err_lane_deskew_err; assign rx_err_invalid_sync_header[1] = `RX_REG_1.rx_err_invalid_sync_header; assign rx_err_invalid_eomb[1] = `RX_REG_1.rx_err_invalid_eomb; assign rx_err_invalid_eoemb [1] = `RX_REG_1.rx_err_invalid_eoemb; assign rx_err_cmd_par_err[1] = `RX_REG_1.rx_err_cmd_par_err; assign rx_err_crc_err[1] = `RX_REG_1.rx_err_crc_err; assign rx_err_rx_gb_underflow_err[1] = `RX_REG_1.rx_err_rx_gb_underflow_err; assign rx_err_rx_gb_overflow_err[1] = `RX_REG_1.rx_err_rx_gb_overflow_err; assign rx_err_sh_unlock_err[1] = `RX_REG_1.rx_err_sh_unlock_err; assign rx_err_emb_unlock_err[1] = `RX_REG_1.rx_err_emb_unlock_err; assign rx_err_eb_full_err[1] = `RX_REG_1.rx_err_eb_full_err; assign rx_err_ecc_corrected_err[1] = `RX_REG_1.rx_err_ecc_corrected_err; assign rx_err_ecc_fatal_err [1] = `RX_REG_1.rx_err_ecc_fatal_err; assign rx_err_src_rx_alarm [1] = `RX_REG_1.rx_err_src_rx_alarm; assign rx_err_fec_corr_err [1] = `RX_REG_1.rx_err_fec_corr_err; assign rx_err_fec_uncorr_err [1] = `RX_REG_1.rx_err_fec_uncorr_err; assign rx_err_syspll_lock_err [1] = `RX_REG_1.rx_err_syspll_lock_err;
- Create the generation loops for the data and link error signals:
genvar i; // Pass/Fail Mechanism // generate for (i=0; i<LINK; i=i+1) begin: LINK_ERROR // Make sure interrupts do not assert always @(posedge mgmt_clk or negedge tx_rst_n) begin if(!tx_rst_n) tx_link_error_reg[i] <= 1'b0; else if (tx_link_error[i] !== 0) tx_link_error_reg[i] <= 1'b1; else tx_link_error_reg[i] <= tx_link_error_reg[i]; end always @(posedge mgmt_clk or negedge rx_rst_n) begin if(!rx_rst_n) rx_link_error_reg[i] <= 1'b0; else if (rx_link_error[i] !== 0) rx_link_error_reg[i] <= 1'b1; else rx_link_error_reg[i] <= rx_link_error_reg[i]; end always @ (posedge data_error or negedge rx_rst_n) begin if (!rx_rst_n) data_error_reg[i] <= 1'b0; else if (data_valid[i] === 1'b1) data_error_reg[i] <= 1'b1; end always @ (posedge cmd_data_error or negedge rx_rst_n) begin if (!rx_rst_n) cmd_data_error_reg[i] <= 1'b0; else if (cmd_data_valid[i] === 1'b1) cmd_data_error_reg[i] <= 1'b1; end end endgenerate - To monitor the combined simulation results of the dual link, modify the test_passed assignment statement so that, if the IP in any of the links has an interrupt or error, the simulation reports failure:
assign test_passed = (|data_error_reg===1'b0) & (|cmd_data_error_reg===1'b0) & (|tx_link_error_reg===1'b0) & (|rx_link_error_reg===1'b0) & (sh_lock_out===1'b1) & (emb_lock_out===1'b1) & (rx_is_lockedtodata===1'b1) & (tx_ready===1'b1) & (rx_ready===1'b1);
- Edit the criteria for displaying the link error message for data_error_reg, cmd_data_error_reg, tx_link_error_reg, and rx_link_error_reg signals so that, if the IP in any of the links has an interrupt, the simulation reports failure. Example:
wait(&data_valid===1'b1); //AND the valid signals wait wait(&cmd_data_valid===1'b1); //AND the valid signals if (&data_valid===1'b1) begin if (|data_error_reg===1'b1) begin $display("Pattern Checker(s): Data error(s) found!"); end else begin $display("Pattern Checker(s): OK!"); end end else begin if (|rx_avst_data===0) begin $display("Pattern Checker(s): No valid data found!"); end else begin if (|data_error_reg===1'b1) begin $display("Pattern Checker(s): Data error(s) found!"); end else begin $display("Pattern Checker(s): OK!"); end end end if (&cmd_data_valid===1'b1) begin if (|cmd_data_error_reg===1'b1) begin $display("Command Channel Pattern Checker(s): Data error(s) found!"); end else begin $display("Command Channel Pattern Checker(s): OK!"); end end else begin if (|cmd_data===0) begin $display("Command Channel Pattern Checker(s): No valid data found!"); end else begin if (|cmd_data_error_reg===1'b1) begin $display("Command Channel Pattern Checker(s): Data error(s) found!"); end else begin $display("Command Channel Pattern Checker(s): OK!"); end end end if (|tx_link_error_reg===1'b1) begin $display("JESD204C Tx Core(s): Tx link error(s) found!"); end else begin $display("JESD204C Tx Core(s): OK!"); end if (|rx_link_error_reg===1'b1) begin $display("JESD204C Rx Core(s): Rx link error(s) found!"); end else begin $display("JESD204C Rx Core(s): OK!"); end