module axi_adrv9001_if #(
  parameter CMOS_LVDS_N = 0,
  parameter FPGA_TECHNOLOGY = 0,
  parameter NUM_LANES = 3,
  parameter DRP_WIDTH = 5,
  parameter IO_DELAY_GROUP = "dev_if_delay_group",
  parameter USE_RX_CLK_FOR_TX = 0
) (
  input             ref_clk,
  input             tx_output_enable,

  input             mssi_sync,

  // device interface
  input             rx1_dclk_in_n_NC,
  input             rx1_dclk_in_p_dclk_in,
  input             rx1_idata_in_n_idata0,
  input             rx1_idata_in_p_idata1,
  input             rx1_qdata_in_n_qdata2,
  input             rx1_qdata_in_p_qdata3,
  input             rx1_strobe_in_n_NC,
  input             rx1_strobe_in_p_strobe_in,

  input             rx2_dclk_in_n_NC,
  input             rx2_dclk_in_p_dclk_in,
  input             rx2_idata_in_n_idata0,
  input             rx2_idata_in_p_idata1,
  input             rx2_qdata_in_n_qdata2,
  input             rx2_qdata_in_p_qdata3,
  input             rx2_strobe_in_n_NC,
  input             rx2_strobe_in_p_strobe_in,

  output            tx1_dclk_out_n_NC,
  output            tx1_dclk_out_p_dclk_out,
  input             tx1_dclk_in_n_NC,
  input             tx1_dclk_in_p_dclk_in,
  output            tx1_idata_out_n_idata0,
  output            tx1_idata_out_p_idata1,
  output            tx1_qdata_out_n_qdata2,
  output            tx1_qdata_out_p_qdata3,
  output            tx1_strobe_out_n_NC,
  output            tx1_strobe_out_p_strobe_out,

  output            tx2_dclk_out_n_NC,
  output            tx2_dclk_out_p_dclk_out,
  input             tx2_dclk_in_n_NC,
  input             tx2_dclk_in_p_dclk_in,
  output            tx2_idata_out_n_idata0,
  output            tx2_idata_out_p_idata1,
  output            tx2_qdata_out_n_qdata2,
  output            tx2_qdata_out_p_qdata3,
  output            tx2_strobe_out_n_NC,
  output            tx2_strobe_out_p_strobe_out,

  // delay interface (for IDELAY macros)
  input             delay_clk,
  input             delay_rx1_rst,
  input             delay_rx2_rst,
  output            delay_rx1_locked,
  output            delay_rx2_locked,

  input             up_clk,

  input   [NUM_LANES-1:0]           up_rx1_dld,
  input   [DRP_WIDTH*NUM_LANES-1:0] up_rx1_dwdata,
  output  [DRP_WIDTH*NUM_LANES-1:0] up_rx1_drdata,

  input   [NUM_LANES-1:0]           up_rx2_dld,
  input   [DRP_WIDTH*NUM_LANES-1:0] up_rx2_dwdata,
  output  [DRP_WIDTH*NUM_LANES-1:0] up_rx2_drdata,

  // upper layer data interface

  output            rx1_clk,
  input             rx1_rst,
  output            rx1_data_valid,
  output    [15:0]  rx1_data_i,
  output    [15:0]  rx1_data_q,

  input             rx1_single_lane,
  input             rx1_sdr_ddr_n,

  output            rx2_clk,
  input             rx2_rst,
  output            rx2_data_valid,
  output    [15:0]  rx2_data_i,
  output    [15:0]  rx2_data_q,

  input             rx2_single_lane,
  input             rx2_sdr_ddr_n,

  output            tx1_clk,
  input             tx1_rst,
  input             tx1_data_valid,
  input     [15:0]  tx1_data_i,
  input     [15:0]  tx1_data_q,

  input             tx1_single_lane,
  input             tx1_sdr_ddr_n,

  output            tx2_clk,
  input             tx2_rst,
  input             tx2_data_valid,
  input     [15:0]  tx2_data_i,
  input     [15:0]  tx2_data_q,

  input             tx2_single_lane,
  input             tx2_sdr_ddr_n
);

  // Tx has an extra lane to drive the clock
  localparam TX_NUM_LANES = NUM_LANES + 1;

  wire        adc_1_clk_div;
  wire  [7:0] adc_1_data_0;
  wire  [7:0] adc_1_data_1;
  wire  [7:0] adc_1_data_2;
  wire  [7:0] adc_1_data_3;
  wire  [7:0] adc_1_data_strobe;
  wire        adc_1_clk;
  wire        adc_1_valid;
  wire        adc_1_ssi_rst;

  wire        adc_2_clk_div;
  wire  [7:0] adc_2_data_0;
  wire  [7:0] adc_2_data_1;
  wire  [7:0] adc_2_data_2;
  wire  [7:0] adc_2_data_3;
  wire  [7:0] adc_2_data_strobe;
  wire        adc_2_clk;
  wire        adc_2_valid;
  wire        adc_2_ssi_rst;

  wire        dac_1_clk_div;
  wire  [7:0] dac_1_data_0;
  wire  [7:0] dac_1_data_1;
  wire  [7:0] dac_1_data_2;
  wire  [7:0] dac_1_data_3;
  wire  [7:0] dac_1_data_strobe;
  wire  [7:0] dac_1_data_clk;
  wire        dac_1_data_valid;

  wire        dac_2_clk_div;
  wire  [7:0] dac_2_data_0;
  wire  [7:0] dac_2_data_1;
  wire  [7:0] dac_2_data_2;
  wire  [7:0] dac_2_data_3;
  wire  [7:0] dac_2_data_strobe;
  wire  [7:0] dac_2_data_clk;
  wire        dac_2_data_valid;

  wire        rx_ssi_sync_out;

  adrv9001_rx
    #(.CMOS_LVDS_N (CMOS_LVDS_N),
      .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
      .NUM_LANES (NUM_LANES),
      .DRP_WIDTH (DRP_WIDTH),
      .IODELAY_CTRL (1),
      .IO_DELAY_GROUP ({IO_DELAY_GROUP,"_rx"})
    ) i_rx_1_phy (
    .rx_dclk_in_n_NC (rx1_dclk_in_n_NC),
    .rx_dclk_in_p_dclk_in (rx1_dclk_in_p_dclk_in),
    .rx_idata_in_n_idata0 (rx1_idata_in_n_idata0),
    .rx_idata_in_p_idata1 (rx1_idata_in_p_idata1),
    .rx_qdata_in_n_qdata2 (rx1_qdata_in_n_qdata2),
    .rx_qdata_in_p_qdata3 (rx1_qdata_in_p_qdata3),
    .rx_strobe_in_n_NC (rx1_strobe_in_n_NC),
    .rx_strobe_in_p_strobe_in (rx1_strobe_in_p_strobe_in),

    .adc_rst (rx1_rst),
    .adc_clk (adc_1_clk),
    .adc_clk_div (adc_1_clk_div),
    .adc_data_0 (adc_1_data_0),
    .adc_data_1 (adc_1_data_1),
    .adc_data_2 (adc_1_data_2),
    .adc_data_3 (adc_1_data_3),
    .adc_data_strobe (adc_1_data_strobe),
    .adc_valid (adc_1_valid),

    .up_clk (up_clk),
    .up_adc_dld (up_rx1_dld),
    .up_adc_dwdata (up_rx1_dwdata),
    .up_adc_drdata (up_rx1_drdata),
    .delay_clk (delay_clk),
    .delay_rst (delay_rx1_rst),
    .delay_locked (delay_rx1_locked),

    .mssi_sync (mssi_sync),
    .ssi_sync_out (rx_ssi_sync_out),
    .ssi_sync_in (rx_ssi_sync_out),
    .ssi_rst (adc_1_ssi_rst)
  );

  adrv9001_rx_link #(
    .CMOS_LVDS_N (CMOS_LVDS_N)
  ) i_rx_1_link (
    .adc_rst (rx1_rst),
    .adc_clk_div (adc_1_clk_div),
    .adc_data_0 (adc_1_data_0),
    .adc_data_1 (adc_1_data_1),
    .adc_data_2 (adc_1_data_2),
    .adc_data_3 (adc_1_data_3),
    .adc_data_strobe (adc_1_data_strobe),
    .adc_valid (adc_1_valid),
    // ADC interface
    .rx_clk (rx1_clk),
    .rx_data_valid (rx1_data_valid),
    .rx_data_i (rx1_data_i),
    .rx_data_q (rx1_data_q),
    .rx_single_lane (rx1_single_lane),
    .rx_sdr_ddr_n (rx1_sdr_ddr_n)
  );

  adrv9001_rx
    #(.CMOS_LVDS_N (CMOS_LVDS_N),
      .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
      .NUM_LANES (NUM_LANES),
      .DRP_WIDTH (DRP_WIDTH),
      .IODELAY_CTRL (0),
      .IO_DELAY_GROUP ({IO_DELAY_GROUP,"_rx"})
    ) i_rx_2_phy (
    .rx_dclk_in_n_NC (rx2_dclk_in_n_NC),
    .rx_dclk_in_p_dclk_in (rx2_dclk_in_p_dclk_in),
    .rx_idata_in_n_idata0 (rx2_idata_in_n_idata0),
    .rx_idata_in_p_idata1 (rx2_idata_in_p_idata1),
    .rx_qdata_in_n_qdata2 (rx2_qdata_in_n_qdata2),
    .rx_qdata_in_p_qdata3 (rx2_qdata_in_p_qdata3),
    .rx_strobe_in_n_NC (rx2_strobe_in_n_NC),
    .rx_strobe_in_p_strobe_in (rx2_strobe_in_p_strobe_in),

    .adc_rst (rx2_rst),
    .adc_clk (adc_2_clk),
    .adc_clk_div (adc_2_clk_div),
    .adc_data_0 (adc_2_data_0),
    .adc_data_1 (adc_2_data_1),
    .adc_data_2 (adc_2_data_2),
    .adc_data_3 (adc_2_data_3),
    .adc_data_strobe (adc_2_data_strobe),
    .adc_valid (adc_2_valid),

    .up_clk (up_clk),
    .up_adc_dld (up_rx2_dld),
    .up_adc_dwdata (up_rx2_dwdata),
    .up_adc_drdata (up_rx2_drdata),
    .delay_clk (delay_clk),
    .delay_rst (delay_rx2_rst),
    .delay_locked (delay_rx2_locked),

    .mssi_sync (1'b0),
    .ssi_sync_out (),
    .ssi_sync_in (rx_ssi_sync_out),
    .ssi_rst (adc_2_ssi_rst)
  );

  adrv9001_rx_link #(
    .CMOS_LVDS_N (CMOS_LVDS_N)
  ) i_rx_2_link (
    .adc_rst (rx2_rst),
    .adc_clk_div (adc_2_clk_div),
    .adc_data_0 (adc_2_data_0),
    .adc_data_1 (adc_2_data_1),
    .adc_data_2 (adc_2_data_2),
    .adc_data_3 (adc_2_data_3),
    .adc_data_strobe (adc_2_data_strobe),
    .adc_valid (adc_2_valid),
    // ADC interface
    .rx_clk (rx2_clk),
    .rx_data_valid (rx2_data_valid),
    .rx_data_i (rx2_data_i),
    .rx_data_q (rx2_data_q),
    .rx_single_lane (rx2_single_lane),
    .rx_sdr_ddr_n (rx2_sdr_ddr_n)
  );

  adrv9001_tx #(
   .CMOS_LVDS_N (CMOS_LVDS_N),
   .NUM_LANES (TX_NUM_LANES),
   .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
   .USE_RX_CLK_FOR_TX (USE_RX_CLK_FOR_TX)
  ) i_tx_1_phy (

   .ref_clk (ref_clk),
   .up_clk (up_clk),

   .tx_output_enable(tx_output_enable),

   .tx_dclk_out_n_NC (tx1_dclk_out_n_NC),
   .tx_dclk_out_p_dclk_out (tx1_dclk_out_p_dclk_out),
   .tx_dclk_in_n_NC (tx1_dclk_in_n_NC),
   .tx_dclk_in_p_dclk_in (tx1_dclk_in_p_dclk_in),
   .tx_idata_out_n_idata0 (tx1_idata_out_n_idata0),
   .tx_idata_out_p_idata1 (tx1_idata_out_p_idata1),
   .tx_qdata_out_n_qdata2 (tx1_qdata_out_n_qdata2),
   .tx_qdata_out_p_qdata3 (tx1_qdata_out_p_qdata3),
   .tx_strobe_out_n_NC (tx1_strobe_out_n_NC),
   .tx_strobe_out_p_strobe_out (tx1_strobe_out_p_strobe_out),

   .rx_clk_div (adc_1_clk_div),
   .rx_clk (adc_1_clk),
   .rx_ssi_rst (adc_1_ssi_rst),

   .dac_rst (tx1_rst),
   .dac_clk_div (dac_1_clk_div),

   .dac_data_0 (dac_1_data_0),
   .dac_data_1 (dac_1_data_1),
   .dac_data_2 (dac_1_data_2),
   .dac_data_3 (dac_1_data_3),
   .dac_data_strb (dac_1_data_strobe),
   .dac_data_clk (dac_1_data_clk),
   .dac_data_valid (dac_1_data_valid),

   .mssi_sync (mssi_sync)
  );

  adrv9001_tx_link #(
    .CMOS_LVDS_N (CMOS_LVDS_N),
    .CLK_DIV_IS_FAST_CLK (FPGA_TECHNOLOGY >= 100)
  ) i_tx_1_link (
    .dac_clk_div (dac_1_clk_div),
    .dac_data_0 (dac_1_data_0),
    .dac_data_1 (dac_1_data_1),
    .dac_data_2 (dac_1_data_2),
    .dac_data_3 (dac_1_data_3),
    .dac_data_strobe (dac_1_data_strobe),
    .dac_data_clk (dac_1_data_clk),
    .dac_data_valid (dac_1_data_valid),
    // DAC interface
    .tx_clk (tx1_clk),
    .tx_rst (tx1_rst),
    .tx_data_valid (tx1_data_valid),
    .tx_data_i (tx1_data_i),
    .tx_data_q (tx1_data_q),
    .tx_sdr_ddr_n (tx1_sdr_ddr_n),
    .tx_single_lane (tx1_single_lane)
  );

 adrv9001_tx #(
   .CMOS_LVDS_N (CMOS_LVDS_N),
   .NUM_LANES (TX_NUM_LANES),
   .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
   .USE_RX_CLK_FOR_TX (USE_RX_CLK_FOR_TX)
  ) i_tx_2_phy (

   .ref_clk (ref_clk),
   .up_clk (up_clk),

   .tx_output_enable(tx_output_enable),

   .tx_dclk_out_n_NC (tx2_dclk_out_n_NC),
   .tx_dclk_out_p_dclk_out (tx2_dclk_out_p_dclk_out),
   .tx_dclk_in_n_NC (tx2_dclk_in_n_NC),
   .tx_dclk_in_p_dclk_in (tx2_dclk_in_p_dclk_in),
   .tx_idata_out_n_idata0 (tx2_idata_out_n_idata0),
   .tx_idata_out_p_idata1 (tx2_idata_out_p_idata1),
   .tx_qdata_out_n_qdata2 (tx2_qdata_out_n_qdata2),
   .tx_qdata_out_p_qdata3 (tx2_qdata_out_p_qdata3),
   .tx_strobe_out_n_NC (tx2_strobe_out_n_NC),
   .tx_strobe_out_p_strobe_out (tx2_strobe_out_p_strobe_out),

   .rx_clk_div (adc_2_clk_div),
   .rx_clk (adc_2_clk),
   .rx_ssi_rst (adc_2_ssi_rst),

   .dac_rst (tx2_rst),
   .dac_clk_div (dac_2_clk_div),

   .dac_data_0 (dac_2_data_0),
   .dac_data_1 (dac_2_data_1),
   .dac_data_2 (dac_2_data_2),
   .dac_data_3 (dac_2_data_3),
   .dac_data_strb (dac_2_data_strobe),
   .dac_data_clk (dac_2_data_clk),
   .dac_data_valid (dac_2_data_valid),

   .mssi_sync (mssi_sync)
  );

  adrv9001_tx_link #(
    .CMOS_LVDS_N (CMOS_LVDS_N),
    .CLK_DIV_IS_FAST_CLK (FPGA_TECHNOLOGY >= 100)
  ) i_tx_2_link (
    .dac_clk_div (dac_2_clk_div),
    .dac_data_0 (dac_2_data_0),
    .dac_data_1 (dac_2_data_1),
    .dac_data_2 (dac_2_data_2),
    .dac_data_3 (dac_2_data_3),
    .dac_data_strobe (dac_2_data_strobe),
    .dac_data_clk (dac_2_data_clk),
    .dac_data_valid (dac_2_data_valid),
    // DAC interface
    .tx_clk (tx2_clk),
    .tx_rst (tx2_rst),
    .tx_data_valid (tx2_data_valid),
    .tx_data_i (tx2_data_i),
    .tx_data_q (tx2_data_q),
    .tx_sdr_ddr_n (tx2_sdr_ddr_n),
    .tx_single_lane (tx2_single_lane)
  );

endmodule