dakies/OSS_Verilog huggingface dataset:
module upack2_underflow_tb;
  parameter VCD_FILE = {`__FILE__,"cd"};
  parameter NUM_OF_CHANNELS = 8;
  parameter SAMPLES_PER_CHANNEL = 4;

  `include "tb_base.v"

  initial
  begin
    #1500000
    if (failed == 1'b0)
      $display("SUCCESS");
    else
      $display("FAILED");
    $finish;
  end

  localparam NUM_OF_PORTS = SAMPLES_PER_CHANNEL * NUM_OF_CHANNELS;

  reg fifo_rd_en = 1'b1;
  wire [NUM_OF_PORTS*8-1:0] fifo_rd_data;
  wire fifo_rd_valid;
  wire fifo_rd_underflow;

  reg s_axis_valid = 1'b1;
  wire s_axis_ready;
  reg [NUM_OF_PORTS*8-1:0] s_axis_data = {NUM_OF_PORTS*8{1'b1}};

  reg [NUM_OF_CHANNELS-1:0] enable = {NUM_OF_CHANNELS{1'b1}};
  integer counter = 0;

  always @(posedge clk) begin
    if (fifo_rd_underflow == 1'b1 && fifo_rd_data != 'h00) begin
      failed <= 1'b1;
    end
    if (fifo_rd_valid == 1'b1 && fifo_rd_data != {NUM_OF_PORTS*8{1'b1}}) begin
      failed <= 1'b1;
    end
  end

  always @(posedge clk) begin
    if (reset == 1'b1) begin
      counter <= 0;
      s_axis_valid <= 1'b1;
    end else begin
      if (s_axis_valid == 1'b0) begin
        if (counter == 8) begin
          s_axis_valid <= 1'b1;
        end
        counter <= counter + 1;
      end else if (s_axis_ready == 1'b1) begin
        s_axis_valid <= 1'b0;
        counter <= 0;
      end
    end
  end

  always @(posedge clk) begin
    fifo_rd_en <= $random & 1;
  end

  util_upack2_impl #(
    .NUM_OF_CHANNELS(NUM_OF_CHANNELS),
    .SAMPLES_PER_CHANNEL(SAMPLES_PER_CHANNEL),
    .SAMPLE_DATA_WIDTH(8)
  ) i_unpack (
    .clk(clk),
    .reset(reset),

    .enable(enable),

    .fifo_rd_en({NUM_OF_CHANNELS{fifo_rd_en}}),
    .fifo_rd_data(fifo_rd_data),
    .fifo_rd_valid(fifo_rd_valid),
    .fifo_rd_underflow(fifo_rd_underflow),

    .s_axis_valid(s_axis_valid),
    .s_axis_ready(s_axis_ready),
    .s_axis_data(s_axis_data)
  );

endmodule
module pack_network #(
  parameter PORT_ADDRESS_WIDTH = 1,
  parameter MUX_ORDER = 1,
  parameter MIN_STAGE = 1,
  parameter NUM_STAGES = 1,
  parameter PACK = 0,
  parameter PORT_DATA_WIDTH = 16
) (
  input clk,
  input ce_ctrl,

  input [PORT_ADDRESS_WIDTH-1:0] rotate,
  input [2**PORT_ADDRESS_WIDTH*PORT_ADDRESS_WIDTH-1:0] prefix_count,

  input [PORT_DATA_WIDTH * 2**PORT_ADDRESS_WIDTH-1:0] data_in,
  output [PORT_DATA_WIDTH * 2**PORT_ADDRESS_WIDTH-1:0] data_out
);

  localparam CTRL_WIDTH = 2**PORT_ADDRESS_WIDTH * NUM_STAGES * MUX_ORDER;

  wire [CTRL_WIDTH-1:0] ctrl_s;
  reg [CTRL_WIDTH-1:0] ctrl = 'h00;
  wire [CTRL_WIDTH-1:0] ctrl_;

  pack_ctrl #(
    .PORT_ADDRESS_WIDTH (PORT_ADDRESS_WIDTH),
    .MUX_ORDER (MUX_ORDER),
    .MIN_STAGE (MIN_STAGE),
    .NUM_STAGES (NUM_STAGES),
    .PACK (PACK)
  ) i_ctrl (
    .rotate(rotate),
    .prefix_count(prefix_count),
    .ctrl(ctrl_s)
  );

  always @(posedge clk) begin
    if (ce_ctrl == 1'b1) begin
      ctrl <= ctrl_s;
    end
  end

  /*
   * Special optimization for 2-MUXes. In this case both control signals are
   * the same.
   */
  generate
    genvar i;
    if (MUX_ORDER == 1) begin
      for (i = 1; i < CTRL_WIDTH; i = i + 2) begin: gen_ctrl
        assign ctrl_[i] = ctrl[i];
        assign ctrl_[i-1] = ~ctrl[i];
      end
    end else begin
      assign ctrl_ = ctrl;
    end
  endgenerate

  pack_interconnect #(
    .PORT_DATA_WIDTH (PORT_DATA_WIDTH),
    .PORT_ADDRESS_WIDTH (PORT_ADDRESS_WIDTH),
    .MUX_ORDER (MUX_ORDER),
    .NUM_STAGES (NUM_STAGES),
    .PACK (PACK)
  ) i_interconnect (
    .ctrl(ctrl_),

    .data_in(data_in),
    .data_out(data_out)
  );

endmodule
module pack_ctrl #(
  parameter PORT_ADDRESS_WIDTH = 2,
  parameter MUX_ORDER = 1,
  parameter MIN_STAGE = 0,
  parameter NUM_STAGES = 2,
  parameter PACK = 0
) (
  input [PORT_ADDRESS_WIDTH-1:0] rotate,
  input [2**PORT_ADDRESS_WIDTH*PORT_ADDRESS_WIDTH-1:0] prefix_count,

  output [2**PORT_ADDRESS_WIDTH*MUX_ORDER*NUM_STAGES-1:0] ctrl
);

  /*
   * This module computes the control bits that are used to configure the MUXes
   * in the pack interconect network. The controls are configured according to
   * the specified global rotation and the prefix count of each of the outputs.
   */

  localparam NUM_OF_PORTS = 2**PORT_ADDRESS_WIDTH;

  wire [NUM_OF_PORTS*MUX_ORDER*NUM_STAGES-1:0] ctrl1;
  reg [NUM_OF_PORTS*MUX_ORDER*NUM_STAGES-1:0] ctrl2;

  generate
  genvar i, j, k;
  integer n;

  localparam z = 2**MUX_ORDER;

  /* This part is magic */
  for (i = 0; i < NUM_STAGES; i = i + 1) begin: ctrl_gen_outer
    localparam k0 = 2**(PORT_ADDRESS_WIDTH - MUX_ORDER*(i+1)-MIN_STAGE);
    localparam k1 = 2**(MUX_ORDER*(1+i)+MIN_STAGE);

    for (j = 0; j < NUM_OF_PORTS; j = j + 1) begin: ctrl_gen_inner
      /* Offset in the ctrl signal */
      localparam s = (i*NUM_OF_PORTS+j)*MUX_ORDER;
      localparam m = (j % k1) * k0;
      localparam n = j / k1;

      if (MUX_ORDER == 1 && j % 2 == 0) begin
        /* This is an optimization that only works for 2:1 MUXes */
        assign ctrl1[s] = ~ctrl1[s+1];
      end else begin
        assign ctrl1[s+:MUX_ORDER] = (j - (prefix_count[m*PORT_ADDRESS_WIDTH+:PORT_ADDRESS_WIDTH] + n - rotate) / k0) % z;
      end
    end
  end

  if (PACK == 0 || MUX_ORDER == 1) begin
    /* For 2:1 MUXes pack and unpack control is the same */
    assign ctrl = ctrl1;
  end else begin
    /*
     * Transform demux control into mux control. The implementation here uses a
     * priority encoder.
     */
    for (i = 0; i < NUM_STAGES*NUM_OF_PORTS; i = i + z) begin: demux_gen_outer
      localparam base = i*MUX_ORDER;
      for (k = 0; k < z; k = k + 1) begin: demux_gen_inner
        always @(ctrl1) begin
          ctrl2[base+k*MUX_ORDER+:MUX_ORDER] <= {MUX_ORDER{1'b1}};
          for (n = 0; n < z; n = n + 1) begin
            if (ctrl1[base+n*MUX_ORDER+:MUX_ORDER] == k) begin
              ctrl2[base+k*MUX_ORDER+:MUX_ORDER] <= n[MUX_ORDER-1:0];
            end
          end
        end
      end
    end
    assign ctrl = ctrl2;
  end
  endgenerate

endmodule
module adrv9001_rx #(
  parameter CMOS_LVDS_N = 0,
  parameter FPGA_TECHNOLOGY = 0,
  parameter NUM_LANES = 3,
  parameter DRP_WIDTH = 5,
  parameter IODELAY_CTRL = 0,
  parameter IO_DELAY_GROUP = "dev_if_delay_group"
) (
  // device interface
  input                   rx_dclk_in_n_NC,
  input                   rx_dclk_in_p_dclk_in,
  input                   rx_idata_in_n_idata0,
  input                   rx_idata_in_p_idata1,
  input                   rx_qdata_in_n_qdata2,
  input                   rx_qdata_in_p_qdata3,
  input                   rx_strobe_in_n_NC,
  input                   rx_strobe_in_p_strobe_in,

  // internal reset and clocks
  input                   adc_rst,
  output                  adc_clk,
  output                  adc_clk_div,
  output      [7:0]       adc_data_0,
  output      [7:0]       adc_data_1,
  output      [7:0]       adc_data_2,
  output      [7:0]       adc_data_3,
  output      [7:0]       adc_data_strobe,
  output                  adc_valid,

  // delay interface (for IDELAY macros)
  input                             up_clk,
  input   [NUM_LANES-1:0]           up_adc_dld,
  input   [DRP_WIDTH*NUM_LANES-1:0] up_adc_dwdata,
  output  [DRP_WIDTH*NUM_LANES-1:0] up_adc_drdata,
  input                   delay_clk,
  input                   delay_rst,
  output                  delay_locked,

  input                   mssi_sync,
  output                  ssi_sync_out,
  input                   ssi_sync_in,
  output                  ssi_rst
);

  reg [3:0] valid_gen = 4'b0001;

  wire [4:0] gpio_in;
  wire [39:0] deser_out;

  periphery_clk_buf rx_clk_buf(
    .inclk (rx_dclk_in_p_dclk_in),
    .outclk (rx_clk)
  );

  assign gpio_in = {rx_strobe_in_p_strobe_in,
                    rx_qdata_in_p_qdata3,
                    rx_qdata_in_n_qdata2,
                    rx_idata_in_p_idata1,
                    rx_idata_in_n_idata0};

  assign {adc_data_strobe,
          adc_data_3,
          adc_data_2,
          adc_data_1,
          adc_data_0} = deser_out;

  genvar i;
  generate
    for (i = 0; i <= 4; i = i + 1) begin: g_ddr_i

      reg [7:0] shift_reg = 8'b0;
      wire [1:0] gpio_out;

      // DDR input
      adrv9001_gpio_in gpio_rx_in (
        .ck (rx_clk),
        .dout (gpio_out),
        .pad_in (gpio_in[i])
      );

      // Temporal ordering:
      //   MSB - oldest received bit;
      //   LSB - newest received bit;
      always @(posedge rx_clk) begin
        shift_reg <= {shift_reg[5:0],gpio_out[0],gpio_out[1]};
      end

      assign deser_out[i*8+:8] = shift_reg;

    end
  endgenerate

  always @(posedge rx_clk) begin
    if (adc_rst) begin
      valid_gen <= 4'b0001;
    end else begin
      valid_gen <= {valid_gen[2:0],valid_gen[3]};
    end
  end

  assign adc_valid = valid_gen[3];
  // No clock divider, qualifier used instead
  assign adc_clk_div = rx_clk;
  assign adc_clk = rx_clk;

  // Drive unused signals
  assign delay_locked = 'b0;
  assign up_adc_drdata = 'b0;

  assign ssi_sync_out = 'b0;
  assign ssi_rst = 'b0;

endmodule
module adrv9001_tx #(
  parameter CMOS_LVDS_N = 0,
  parameter NUM_LANES = 4,
  parameter FPGA_TECHNOLOGY = 0,
  parameter USE_RX_CLK_FOR_TX = 0
) (
  input                   ref_clk,
  input                   up_clk,

  input                   mssi_sync,
  input                   tx_output_enable,

  // physical interface (transmit)
  output                  tx_dclk_out_n_NC,
  output                  tx_dclk_out_p_dclk_out,
  input                   tx_dclk_in_n_NC,
  input                   tx_dclk_in_p_dclk_in,
  output                  tx_idata_out_n_idata0,
  output                  tx_idata_out_p_idata1,
  output                  tx_qdata_out_n_qdata2,
  output                  tx_qdata_out_p_qdata3,
  output                  tx_strobe_out_n_NC,
  output                  tx_strobe_out_p_strobe_out,

  input                   rx_clk_div,
  input                   rx_clk,
  input                   rx_ssi_rst,

  // internal resets and clocks

  input                   dac_rst,
  output                  dac_clk_div,

  input       [7:0]       dac_data_0,
  input       [7:0]       dac_data_1,
  input       [7:0]       dac_data_2,
  input       [7:0]       dac_data_3,
  input       [7:0]       dac_data_strb,
  input       [7:0]       dac_data_clk,
  input                   dac_data_valid
);

  wire [6*8-1:0] serdes_in;
  wire [5:0] gpio_out;

  periphery_clk_buf tx_clk_buf(
    .inclk (tx_dclk_in_p_dclk_in),
    .outclk (tx_clk)
  );

  assign serdes_in = {dac_data_clk,
                      dac_data_strb,
                      dac_data_3,
                      dac_data_2,
                      dac_data_1,
                      dac_data_0};

  assign {tx_dclk_out_p_dclk_out,
          tx_strobe_out_p_strobe_out,
          tx_qdata_out_p_qdata3,
          tx_qdata_out_n_qdata2,
          tx_idata_out_p_idata1,
          tx_idata_out_n_idata0} = gpio_out;

  genvar i;
  generate
    for (i = 0; i <= 5; i = i + 1) begin: g_ddr_o

      reg [7:0] shift_reg = 8'b0;
      wire [1:0] gpio_in;

      // DDR output
      adrv9001_gpio_out gpio_tx_out (
        .ck(tx_clk),
        .din(gpio_in),
        .pad_out(gpio_out[i])
      );

      always @(posedge tx_clk) begin
        if (dac_data_valid) begin
          shift_reg <= serdes_in[i*8+:8];
        end else begin
          shift_reg <= {shift_reg[5:0],2'b0};
        end
      end
      // Order of transmission:
      // gpio_in[0] - first
      // gpio_in[1] - last
      assign gpio_in = {shift_reg[6],shift_reg[7]};

    end
  endgenerate

  // No clock divider, qualifier used instead
  assign dac_clk_div = tx_clk;
  assign dac_clk = tx_clk;

endmodule
module axi_read_slave #(
  parameter DATA_WIDTH = 32,
  parameter READ_ACCEPTANCE = 4,
  parameter MIN_LATENCY = 48,
  parameter MAX_LATENCY = 48
) (
  input clk,
  input reset,

  input arvalid,
  output arready,
  input [31:0] araddr,
  input [7:0] arlen,
  input [2:0] arsize,
  input [1:0] arburst,
  input [2:0] arprot,
  input [3:0] arcache,

  output rvalid,
  input rready,
  output [DATA_WIDTH-1:0] rdata,
  output [1:0] rresp,
  output rlast
);

reg [DATA_WIDTH-1:0] data = 'h00;

wire [31:0] beat_addr;

assign rresp = 2'b00;
assign rdata = data;

always @(*) begin: gen_data
  integer i;
  for (i = 0; i < DATA_WIDTH; i = i + 8) begin
    data[i+:8] <= beat_addr[7:0] + i / 8;
  end
end

axi_slave #(
  .DATA_WIDTH(DATA_WIDTH),
  .ACCEPTANCE(READ_ACCEPTANCE),
  .MIN_LATENCY(MIN_LATENCY),
  .MAX_LATENCY(MAX_LATENCY)
) i_axi_slave (
  .clk(clk),
  .reset(reset),

  .valid(arvalid),
  .ready(arready),
  .addr(araddr),
  .len(arlen),
  .size(arsize),
  .burst(arburst),
  .prot(arprot),
  .cache(arcache),

  .beat_stb(rvalid),
  .beat_ack(rvalid & rready),
  .beat_last(rlast),
  .beat_addr(beat_addr)
);

endmodule
module axi_slave #(
  parameter DATA_WIDTH = 32,
  parameter ACCEPTANCE = 3,
  parameter MIN_LATENCY = 16,
  parameter MAX_LATENCY = 32
) (
  input clk,
  input reset,

  input valid,
  output ready,
  input [31:0] addr,
  input [7:0] len,
  input [2:0] size,
  input [1:0] burst,
  input [2:0] prot,
  input [3:0] cache,

  output beat_stb,
  input beat_ack,
  output [31:0] beat_addr,
  output beat_last
);

reg [31:0] timestamp = 'h00;

always @(posedge clk) begin
  if (reset == 1'b1) begin
    timestamp <= 'h00;
  end else begin
    timestamp <= timestamp + 1'b1;
  end
end

reg [32+32+8-1:0] req_fifo[0:15];
reg [3:0] req_fifo_rd = 'h00;
reg [3:0] req_fifo_wr = 'h00;
wire [3:0] req_fifo_level = req_fifo_wr - req_fifo_rd;

assign ready = req_fifo_level < ACCEPTANCE;

always @(posedge clk) begin
  if (reset == 1'b1) begin
    req_fifo_wr <= 'h00;
  end else begin
    if (valid == 1'b1 && ready == 1'b1) begin
      req_fifo[req_fifo_wr][71:40] <= timestamp + {$random} % (MAX_LATENCY - MIN_LATENCY + 1) + MIN_LATENCY;
      req_fifo[req_fifo_wr][39:0] <= {addr,len};
      req_fifo_wr <= req_fifo_wr + 1'b1;
    end
  end
end

reg [7:0] beat_counter = 'h00;

assign beat_stb = req_fifo_level != 0 && timestamp > req_fifo[req_fifo_rd][71:40];
assign beat_last = beat_stb ? beat_counter == req_fifo[req_fifo_rd][0+:8] : 1'b0;
assign beat_addr = req_fifo[req_fifo_rd][8+:32] + beat_counter * DATA_WIDTH / 8;

always @(posedge clk) begin
  if (reset == 1'b1) begin
    beat_counter <= 'h00;
    req_fifo_rd <= 'h00;
  end else begin
    if (beat_ack == 1'b1) begin
      if (beat_last == 1'b1) begin
        beat_counter <= 'h00;
        req_fifo_rd <= req_fifo_rd + 1'b1;
      end else begin
        beat_counter <= beat_counter + 1'b1;
      end
    end
  end
end

endmodule
module axi_write_slave #(
  parameter DATA_WIDTH = 32,
  parameter WRITE_ACCEPTANCE = 3
) (
  input clk,
  input reset,

  input awvalid,
  output awready,
  input [31:0] awaddr,
  input [7:0] awlen,
  input [2:0] awsize,
  input [1:0] awburst,
  input [2:0] awprot,
  input [3:0] awcache,

  input wvalid,
  output wready,
  input [DATA_WIDTH-1:0] wdata,
  input [DATA_WIDTH/8-1:0] wstrb,
  input wlast,

  output reg bvalid,
  input bready,
  output [1:0] bresp
);

wire beat_last;

axi_slave #(
  .ACCEPTANCE(WRITE_ACCEPTANCE)
) i_axi_slave (
  .clk(clk),
  .reset(reset),

  .valid(awvalid),
  .ready(awready),
  .addr(awaddr),
  .len(awlen),
  .size(awsize),
  .burst(awburst),
  .prot(awprot),
  .cache(awcache),

  .beat_stb(wready),
  .beat_ack(wvalid & wready),
  .beat_last(beat_last)
);

reg [4:0] resp_count = 'h00;
wire [4:0] resp_count_next;
reg [DATA_WIDTH-1:0] data_cmp = 'h00;
reg failed = 'b0;

assign bresp = 2'b00;

wire resp_count_dec = bvalid & bready;
wire resp_count_inc = wvalid & wready & beat_last;
assign resp_count_next = resp_count - resp_count_dec + resp_count_inc;

always @(posedge clk) begin
  if (reset == 1'b1) begin
    resp_count <= 'h00;
  end else begin
    resp_count <= resp_count - resp_count_dec + resp_count_inc;
  end
end

always @(posedge clk) begin
  if (reset == 1'b1) begin
    bvalid <= 1'b0;
  end else if (bvalid == 1'b0 || bready == 1'b1) begin
    if (resp_count_next != 'h00) begin
      bvalid <= {$random} % 4 == 0;
    end else begin
      bvalid <= 1'b0;
    end
  end
end

integer byte_count;

always @(*) begin: count
  integer i;
  byte_count = 0;
  for (i = 0; i < DATA_WIDTH / 8; i = i + 1) begin
    byte_count = byte_count + wstrb[i];
  end
end

always @(posedge clk) begin: gen_data_cmp
  integer i;
  if (reset) begin
    for (i = 0; i < DATA_WIDTH; i = i + 8) begin
      data_cmp[i+:8] <= i/8;
    end
    failed <= 'b0;
  end else if (wvalid & wready) begin
    for (i = 0; i < DATA_WIDTH; i = i + 8) begin
      if (data_cmp[i+:8] !== wdata[i+:8] && wstrb[i/8] == 1'b1) begin
        failed <= 1'b1;
      end
      data_cmp[i+:8] <= data_cmp[i+:8] + byte_count;
    end
  end
end

endmodule
module axi_dacfifo_address_buffer #(

  parameter ADDRESS_WIDTH = 4,
  parameter DATA_WIDTH = 16)(

  input                         clk,
  input                         rst,
  input                         wea,
  input      [DATA_WIDTH-1:0]   din,

  input                         rea,
  output     [DATA_WIDTH-1:0]   dout);

  reg   [ADDRESS_WIDTH-1:0]     waddr;
  reg   [ADDRESS_WIDTH-1:0]     raddr;


  always @(posedge clk) begin
    if (rst == 1'b1) begin
      waddr <= 0;
      raddr <= 0;
    end else begin
      waddr <= (wea == 1'b1) ? waddr + 1'b1 : waddr;
      raddr <= (rea == 1'b1) ? raddr + 1'b1 : raddr;
    end
  end

  ad_mem #(
    .DATA_WIDTH (DATA_WIDTH),
    .ADDRESS_WIDTH (ADDRESS_WIDTH))
  i_mem (
    .clka (clk),
    .wea (wea),
    .addra (waddr),
    .dina (din),
    .clkb (clk),
    .reb (1'b1),
    .addrb (raddr),
    .doutb (dout));

endmodule
module ad_data_clk #(

  parameter   SINGLE_ENDED = 0) (

  input               rst,
  output              locked,

  input               clk_in_p,
  input               clk_in_n,
  output              clk);

  // internal signals

  wire                clk_ibuf_s;

  // defaults

  assign locked = 1'b1;

  // instantiations

  generate
  if (SINGLE_ENDED == 1) begin
  IBUFG i_rx_clk_ibuf (
    .I (clk_in_p),
    .O (clk_ibuf_s));
  end else begin
  IBUFGDS i_rx_clk_ibuf (
    .I (clk_in_p),
    .IB (clk_in_n),
    .O (clk_ibuf_s));
  end
  endgenerate

  BUFG i_clk_gbuf (
    .I (clk_ibuf_s),
    .O (clk));

endmodule
module ad_mul #(

  parameter   A_DATA_WIDTH = 17,
  parameter   B_DATA_WIDTH = 17,
  parameter   DELAY_DATA_WIDTH = 16) (

  // data_p = data_a * data_b;

  input                                     clk,
  input   [               A_DATA_WIDTH-1:0] data_a,
  input   [               B_DATA_WIDTH-1:0] data_b,
  output  [A_DATA_WIDTH + B_DATA_WIDTH-1:0] data_p,

  // delay interface

  input       [(DELAY_DATA_WIDTH-1):0]  ddata_in,
  output  reg [(DELAY_DATA_WIDTH-1):0]  ddata_out);


  // internal registers

  reg     [(DELAY_DATA_WIDTH-1):0]    p1_ddata = 'd0;
  reg     [(DELAY_DATA_WIDTH-1):0]    p2_ddata = 'd0;

  // a/b reg, m-reg, p-reg delay match

  always @(posedge clk) begin
    p1_ddata <= ddata_in;
    p2_ddata <= p1_ddata;
    ddata_out <= p2_ddata;
  end

  MULT_MACRO #(
    .LATENCY (3),
    .WIDTH_A (A_DATA_WIDTH),
    .WIDTH_B (B_DATA_WIDTH))
  i_mult_macro (
    .CE (1'b1),
    .RST (1'b0),
    .CLK (clk),
    .A (data_a),
    .B (data_b),
    .P (data_p));

endmodule
module ad_serdes_clk #(

  parameter       FPGA_TECHNOLOGY = 0,
  parameter       DDR_OR_SDR_N = 1,
  parameter       CLKIN_DS_OR_SE_N = 1,
  parameter       SERDES_FACTOR = 8,
  parameter       MMCM_OR_BUFR_N = 1,
  parameter       MMCM_CLKIN_PERIOD  = 1.667,
  parameter       MMCM_VCO_DIV  = 6,
  parameter       MMCM_VCO_MUL = 12.000,
  parameter       MMCM_CLK0_DIV = 2.000,
  parameter       MMCM_CLK1_DIV = 6) (

  // clock and divided clock

  input           rst,
  input           clk_in_p,
  input           clk_in_n,
  output          clk,
  output          div_clk,
  output          out_clk,
  output          loaden,
  output  [ 7:0]  phase,

  // drp interface

  input           up_clk,
  input           up_rstn,
  input           up_drp_sel,
  input           up_drp_wr,
  input   [11:0]  up_drp_addr,
  input   [31:0]  up_drp_wdata,
  output  [31:0]  up_drp_rdata,
  output          up_drp_ready,
  output          up_drp_locked);

  localparam BUFR_DIVIDE = (DDR_OR_SDR_N == 1'b1) ? SERDES_FACTOR / 2 : SERDES_FACTOR;

  // internal signals

  wire            clk_in_s;

  // defaults

  assign loaden = 'd0;
  assign phase = 'd0;
  assign up_drp_rdata[31:16] = 'd0;

  // instantiations

  generate
  if (CLKIN_DS_OR_SE_N == 1) begin
    IBUFGDS i_clk_in_ibuf (
      .I (clk_in_p),
      .IB (clk_in_n),
      .O (clk_in_s));
  end else begin
    IBUF IBUF_inst (
        .O(clk_in_s),
        .I(clk_in_p));
  end
  endgenerate

  generate
  if (MMCM_OR_BUFR_N == 1) begin
    ad_mmcm_drp #(
      .FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
      .MMCM_CLKIN_PERIOD (MMCM_CLKIN_PERIOD),
      .MMCM_CLKIN2_PERIOD (MMCM_CLKIN_PERIOD),
      .MMCM_VCO_DIV (MMCM_VCO_DIV),
      .MMCM_VCO_MUL (MMCM_VCO_MUL),
      .MMCM_CLK0_DIV (MMCM_CLK0_DIV),
      .MMCM_CLK0_PHASE (0.0),
      .MMCM_CLK1_DIV (MMCM_CLK1_DIV),
      .MMCM_CLK1_PHASE (0.0),
      .MMCM_CLK2_DIV (MMCM_CLK0_DIV),
      .MMCM_CLK2_PHASE (90.0))
    i_mmcm_drp (
      .clk (clk_in_s),
      .clk2 (1'b0),
      .clk_sel (1'b1),
      .mmcm_rst (rst),
      .mmcm_clk_0 (clk),
      .mmcm_clk_1 (div_clk),
      .mmcm_clk_2 (out_clk),
      .up_clk (up_clk),
      .up_rstn (up_rstn),
      .up_drp_sel (up_drp_sel),
      .up_drp_wr (up_drp_wr),
      .up_drp_addr (up_drp_addr),
      .up_drp_wdata (up_drp_wdata[15:0]),
      .up_drp_rdata (up_drp_rdata[15:0]),
      .up_drp_ready (up_drp_ready),
      .up_drp_locked (up_drp_locked));
    end
  endgenerate

  generate
  if (MMCM_OR_BUFR_N == 0) begin
    BUFIO i_clk_buf (
      .I (clk_in_s),
      .O (clk));

    BUFR #(.BUFR_DIVIDE(BUFR_DIVIDE)) i_div_clk_buf (
      .CLR (1'b0),
      .CE (1'b1),
      .I (clk_in_s),
      .O (div_clk));

    assign out_clk = clk;
    assign up_drp_rdata[15:0] = 'd0;
    assign up_drp_ready = 'd0;
    assign up_drp_locked = 'd0;

  end
  endgenerate

endmodule
module util_clkdiv (
  input   clk,
  input   clk_sel,
  output  clk_out
 );

parameter SIM_DEVICE = "7SERIES";
parameter SEL_0_DIV = "4";
parameter SEL_1_DIV = "2";

  wire clk_div_sel_0_s;
  wire clk_div_sel_1_s;

generate if (SIM_DEVICE == "7SERIES") begin

  BUFR #(
    .BUFR_DIVIDE(SEL_0_DIV),
    .SIM_DEVICE("7SERIES")
  ) clk_divide_sel_0 (
    .I(clk),
    .CE(1),
    .CLR(0),
    .O(clk_div_sel_0_s));

  BUFR #(
    .BUFR_DIVIDE(SEL_1_DIV),
    .SIM_DEVICE("7SERIES")
  ) clk_divide_sel_1 (
    .I(clk),
    .CE(1),
    .CLR(0),
    .O(clk_div_sel_1_s));

end else if (SIM_DEVICE == "ULTRASCALE") begin

  BUFGCE_DIV #(
    .BUFGCE_DIVIDE(SEL_0_DIV)
  ) clk_divide_sel_0 (
    .I(clk),
    .CE(1),
    .CLR(0),
    .O(clk_div_sel_0_s));

  BUFGCE_DIV #(
    .BUFGCE_DIVIDE(SEL_1_DIV)
  ) clk_divide_sel_1 (
    .I(clk),
    .CE(1),
    .CLR(0),
    .O(clk_div_sel_1_s));

end endgenerate

  BUFGMUX_CTRL i_div_clk_gbuf (
    .I0(clk_div_sel_0_s), // 1-bit input: Clock input (S=0)
    .I1(clk_div_sel_1_s), // 1-bit input: Clock input (S=1)
    .S(clk_sel),
    .O (clk_out));

endmodule  // util_clkdiv
module axi_adxcvr_mstatus (

  input           up_rstn,
  input           up_clk,

  input           up_pll_locked_in,
  input           up_rst_done_in,
  input           up_pll_locked,
  input           up_rst_done,
  output          up_pll_locked_out,
  output          up_rst_done_out);

  // parameters

  parameter   integer XCVR_ID = 0;
  parameter   integer NUM_OF_LANES = 8;

  // internal registers

  reg             up_pll_locked_int = 'd0;
  reg             up_rst_done_int = 'd0;

  // internal signals

  wire            up_pll_locked_s;
  wire            up_rst_done_s;

  // daisy-chain the signals

  assign up_pll_locked_out = up_pll_locked_int;
  assign up_rst_done_out = up_rst_done_int;

  assign up_pll_locked_s = (XCVR_ID < NUM_OF_LANES) ? up_pll_locked : 1'b1;
  assign up_rst_done_s = (XCVR_ID < NUM_OF_LANES) ? up_rst_done : 1'b1;

  always @(negedge up_rstn or posedge up_clk) begin
    if (up_rstn == 1'b0) begin
      up_pll_locked_int <= 1'd0;
      up_rst_done_int <= 1'd0;
    end else begin
      up_pll_locked_int <= up_pll_locked_in & up_pll_locked_s;
      up_rst_done_int <= up_rst_done_in & up_rst_done_s;
    end
  end

endmodule
module axi_adxcvr_mdrp (

  input           up_rstn,
  input           up_clk,

  input   [ 7:0]  up_sel,
  input           up_enb,
  output          up_enb_out,
  input   [15:0]  up_rdata_in,
  input           up_ready_in,
  input   [15:0]  up_rdata,
  input           up_ready,
  output  [15:0]  up_rdata_out,
  output          up_ready_out);

  // parameters

  parameter   integer XCVR_ID = 0;
  parameter   integer NUM_OF_LANES = 8;

  // internal registers

  reg     [15:0]  up_rdata_int = 'd0;
  reg             up_ready_int = 'd0;
  reg             up_ready_mi = 'd0;
  reg     [15:0]  up_rdata_i = 'd0;
  reg             up_ready_i = 'd0;
  reg     [15:0]  up_rdata_m = 'd0;
  reg             up_ready_m = 'd0;

  // internal signals

  wire            up_ready_s;
  wire    [15:0]  up_rdata_mi_s;
  wire            up_ready_mi_s;

  // disable if not selected

  assign up_rdata_out = up_rdata_int;
  assign up_ready_out = up_ready_int;

  assign up_enb_out = (up_sel == 8'hff || up_sel == XCVR_ID) ? up_enb : 1'b0;

  always @(negedge up_rstn or posedge up_clk) begin
    if (up_rstn == 1'b0) begin
      up_rdata_int <= 16'd0;
      up_ready_int <= 1'b0;
    end else begin
      case (up_sel)
        8'hff: begin
          up_rdata_int <= up_rdata_mi_s;
          up_ready_int <= up_ready_mi_s & ~up_ready_mi;
        end
        XCVR_ID: begin
          up_rdata_int <= up_rdata;
          up_ready_int <= up_ready;
        end
        default: begin
          up_rdata_int <= up_rdata_in;
          up_ready_int <= up_ready_in;
        end
      endcase
    end
  end

  always @(negedge up_rstn or posedge up_clk) begin
    if (up_rstn == 1'b0) begin
      up_ready_mi <= 1'b0;
    end else begin
      up_ready_mi <= up_ready_mi_s;
    end
  end

  assign up_rdata_mi_s = up_rdata_m | up_rdata_i;
  assign up_ready_mi_s = up_ready_m & up_ready_i;

  always @(negedge up_rstn or posedge up_clk) begin
    if (up_rstn == 1'b0) begin
      up_rdata_i <= 16'd0;
      up_ready_i <= 1'b0;
    end else begin
      if (up_ready_in == 1'b1) begin
        up_rdata_i <= up_rdata_in;
        up_ready_i <= 1'b1;
      end else if (up_enb == 1'b1) begin
        up_rdata_i <= 16'd0;
        up_ready_i <= 1'b0;
      end
    end
  end

  generate
  if (XCVR_ID < NUM_OF_LANES) begin
  always @(negedge up_rstn or posedge up_clk) begin
    if (up_rstn == 1'b0) begin
      up_rdata_m <= 16'd0;
      up_ready_m <= 1'b0;
    end else begin
      if (up_ready == 1'b1) begin
        up_rdata_m <= up_rdata;
        up_ready_m <= 1'b1;
      end else if (up_enb == 1'b1) begin
        up_rdata_m <= 16'd0;
        up_ready_m <= 1'b0;
      end
    end
  end
  end else begin
  always @(negedge up_rstn or posedge up_clk) begin
    if (up_rstn == 1'b0) begin
      up_rdata_m <= 16'd0;
      up_ready_m <= 1'b0;
    end else begin
      up_rdata_m <= 16'd0;
      up_ready_m <= 1'b1;
    end
  end
  end
  endgenerate

endmodule
module axi_adcfifo_adc #(

  parameter   ADC_DATA_WIDTH = 128,
  parameter   AXI_DATA_WIDTH = 512) (

  // fifo interface

  input                   adc_rst,
  input                   adc_clk,
  input                   adc_wr,
  input       [ADC_DATA_WIDTH-1:0]  adc_wdata,
  output  reg             adc_wovf,
  output  reg             adc_dwr,
  output  reg [AXI_DATA_WIDTH-1:0]  adc_ddata,

  // axi interface

  input                   axi_drst,
  input                   axi_clk,
  input       [ 3:0]      axi_xfer_status);

  localparam  ADC_MEM_RATIO = AXI_DATA_WIDTH/ADC_DATA_WIDTH;

  // internal registers

  reg     [  2:0]                 adc_wcnt_int  = 'd0;

  // internal signals

  wire    [  3:0]                 adc_xfer_status_s;

  // write interface: supports only 64, 128, 256 and 512 against 512

  always @(posedge adc_clk) begin
    if (adc_rst == 1'b1) begin
      adc_wovf <= 'd0;
      adc_wcnt_int <= 'd0;
      adc_dwr <= 'd0;
      adc_ddata <= 'd0;
    end else begin
      adc_wovf <= | adc_xfer_status_s;
      adc_dwr <= (ADC_MEM_RATIO == 8) ? adc_wr & adc_wcnt_int[0] & adc_wcnt_int[1] & adc_wcnt_int[2] :
                 (ADC_MEM_RATIO == 4) ? adc_wr & adc_wcnt_int[0] & adc_wcnt_int[1] :
                 (ADC_MEM_RATIO == 2) ? adc_wr & adc_wcnt_int[0] :
                 (ADC_MEM_RATIO == 1) ? adc_wr : 'd0;
      if (adc_wr == 1'b1) begin
        adc_wcnt_int <= adc_wcnt_int + 1'b1;
        case (ADC_MEM_RATIO)
          8: begin
            adc_ddata[((ADC_DATA_WIDTH*8)-1):(ADC_DATA_WIDTH*7)] <= adc_wdata;
            adc_ddata[((ADC_DATA_WIDTH*7)-1):(ADC_DATA_WIDTH*0)] <=
              adc_ddata[((ADC_DATA_WIDTH*8)-1):(ADC_DATA_WIDTH*1)];
          end
          4: begin
            adc_ddata[((ADC_DATA_WIDTH*4)-1):(ADC_DATA_WIDTH*3)] <= adc_wdata;
            adc_ddata[((ADC_DATA_WIDTH*3)-1):(ADC_DATA_WIDTH*0)] <=
              adc_ddata[((ADC_DATA_WIDTH*4)-1):(ADC_DATA_WIDTH*1)];
          end
          2: begin
            adc_ddata[((ADC_DATA_WIDTH*2)-1):(ADC_DATA_WIDTH*1)] <= adc_wdata;
            adc_ddata[((ADC_DATA_WIDTH*1)-1):(ADC_DATA_WIDTH*0)] <=
              adc_ddata[((ADC_DATA_WIDTH*2)-1):(ADC_DATA_WIDTH*1)];
          end
          1: begin
            adc_ddata <= adc_wdata;
          end
          default: begin
            adc_ddata <= 'd0;
          end
        endcase
      end
    end
  end

  // instantiations

  up_xfer_status #(.DATA_WIDTH(4)) i_xfer_status (
    .up_rstn (~adc_rst),
    .up_clk (adc_clk),
    .up_data_status (adc_xfer_status_s),
    .d_rst (axi_drst),
    .d_clk (axi_clk),
    .d_data_status (axi_xfer_status));

endmodule
module jesd204_ilas_config_static #(
  parameter DID = 8'h00,
  parameter BID = 4'h0,
  parameter L = 5'h3,
  parameter SCR = 1'b1,
  parameter F = 8'h01,
  parameter K = 5'h1f,
  parameter M = 8'h3,
  parameter N = 5'h0f,
  parameter CS = 2'h0,
  parameter NP = 5'h0f,
  parameter SUBCLASSV = 3'h1,
  parameter S = 5'h00,
  parameter JESDV = 3'h1,
  parameter CF = 5'h00,
  parameter HD = 1'b1,
  parameter NUM_LANES = 1
) (
  input clk,

  input [1:0] ilas_config_addr,
  input ilas_config_rd,
  output reg [32*NUM_LANES-1:0] ilas_config_data
);

wire [31:0] ilas_mem[0:3];

assign ilas_mem[0][15:0] = 8'h00;
assign ilas_mem[0][23:16] = DID;         // DID
assign ilas_mem[0][27:24] = BID;         // BID
assign ilas_mem[0][31:28] = 4'h0;        // ADJCNT
assign ilas_mem[1][4:0] = 5'h00;         // LID
assign ilas_mem[1][5] = 1'b0;            // PHADJ
assign ilas_mem[1][6] = 1'b0;            // ADJDIR
assign ilas_mem[1][7] = 1'b0;            // X
assign ilas_mem[1][12:8] = L;            // L
assign ilas_mem[1][14:13] = 2'b00;       // X
assign ilas_mem[1][15] = SCR;            // SCR
assign ilas_mem[1][23:16] = F;           // F
assign ilas_mem[1][28:24] = K;           // K
assign ilas_mem[1][31:29] = 3'b000;      // X
assign ilas_mem[2][7:0] = M;             // M
assign ilas_mem[2][12:8] = N;            // N
assign ilas_mem[2][13] = 1'b0;           // X
assign ilas_mem[2][15:14] = CS;          // CS
assign ilas_mem[2][20:16] = NP;          // N'
assign ilas_mem[2][23:21] = SUBCLASSV;   // SUBCLASSV
assign ilas_mem[2][28:24] = S;           // S
assign ilas_mem[2][31:29] = JESDV;       // JESDV
assign ilas_mem[3][4:0] = CF;            // CF
assign ilas_mem[3][6:5] = 2'b00;         // X
assign ilas_mem[3][7] = HD;              // HD
assign ilas_mem[3][23:8] = 16'h0000;     // X
assign ilas_mem[3][31:24] = ilas_mem[0][23:16] + ilas_mem[0][31:24] +
  ilas_mem[1][4:0] + ilas_mem[1][5] + ilas_mem[1][6] + ilas_mem[1][12:8] +
  ilas_mem[1][15] + ilas_mem[1][23:16] + ilas_mem[1][28:24] +
  ilas_mem[2][7:0] + ilas_mem[2][12:8] + ilas_mem[2][15:14] +
  ilas_mem[2][20:16] + ilas_mem[2][23:21] + ilas_mem[2][28:24] +
  ilas_mem[2][31:29] + ilas_mem[3][4:0] + ilas_mem[3][7];

generate
genvar i;

for (i = 0; i < NUM_LANES; i = i + 1) begin: gen_lane
  always @(posedge clk) begin
    if (ilas_config_rd == 1'b1) begin
      ilas_config_data[i*32+31:i*32] <= ilas_mem[ilas_config_addr];

      /* Overwrite special cases */
      case (ilas_config_addr)
      'h1: ilas_config_data[i*32+4:i*32] <= i;
      'h3: ilas_config_data[i*32+31:i*32+24] <= ilas_mem[ilas_config_addr][31:24] + i;
      endcase
    end
  end
end
endgenerate

endmodule
module jesd204_tx_static_config #(
  parameter NUM_LANES = 1,
  parameter NUM_LINKS = 1,
  parameter OCTETS_PER_FRAME = 1,
  parameter FRAMES_PER_MULTIFRAME = 32,
  parameter NUM_CONVERTERS = 1,
  parameter N = 16,
  parameter NP = 16,
  parameter HIGH_DENSITY = 1,
  parameter SCR = 1,
  parameter LINK_MODE = 1  // 2 - 64B/66B;  1 - 8B/10B
) (
  input clk,

  output [NUM_LANES-1:0] cfg_lanes_disable,
  output [NUM_LINKS-1:0] cfg_links_disable,
  output [7:0] cfg_beats_per_multiframe,
  output [7:0] cfg_octets_per_frame,
  output [7:0] cfg_lmfc_offset,
  output cfg_sysref_oneshot,
  output cfg_sysref_disable,
  output cfg_continuous_cgs,
  output cfg_continuous_ilas,
  output cfg_skip_ilas,
  output [7:0] cfg_mframes_per_ilas,
  output cfg_disable_char_replacement,
  output cfg_disable_scrambler,

  input ilas_config_rd,
  input [1:0] ilas_config_addr,
  output [32*NUM_LANES-1:0] ilas_config_data
);

/* Only 4 is supported at the moment for 8b/10b and 8 for 64b */
localparam DATA_PATH_WIDTH = LINK_MODE == 2 ? 8 : 4;

assign cfg_beats_per_multiframe = (FRAMES_PER_MULTIFRAME * OCTETS_PER_FRAME / DATA_PATH_WIDTH) - 1;
assign cfg_octets_per_frame = OCTETS_PER_FRAME - 1;
assign cfg_lmfc_offset = 3;
assign cfg_sysref_oneshot = 1'b0;
assign cfg_sysref_disable = 1'b0;
assign cfg_continuous_cgs = 1'b0;
assign cfg_continuous_ilas = 1'b0;
assign cfg_skip_ilas = 1'b0;
assign cfg_mframes_per_ilas = 3;
assign cfg_disable_scrambler = SCR ? 1'b0 : 1'b1;
assign cfg_disable_char_replacement = cfg_disable_scrambler;
assign cfg_lanes_disable = {NUM_LANES{1'b0}};
assign cfg_links_disable = {NUM_LINKS{1'b0}};

jesd204_ilas_config_static #(
  .DID(8'h00),
  .BID(5'h00),
  .L(NUM_LANES - 1),
  .SCR(SCR),
  .F(OCTETS_PER_FRAME - 1),
  .K(FRAMES_PER_MULTIFRAME - 1),
  .M(NUM_CONVERTERS - 1),
  .N(N),
  .NP(NP),
  .SUBCLASSV(3'h1),
  .S(5'h00),
  .JESDV(3'h1),
  .CF(5'h00),
  .HD(HIGH_DENSITY),
  .NUM_LANES(NUM_LANES)
) i_ilas_config (
  .clk(clk),
  .ilas_config_addr(ilas_config_addr),
  .ilas_config_rd(ilas_config_rd),
  .ilas_config_data(ilas_config_data)
);

endmodule
module ad_ip_jesd204_tpl_dac_pn #(
  parameter DATA_PATH_WIDTH = 4,
  parameter CONVERTER_RESOLUTION = 16
) (
  input clk,
  input reset,

  output [DATA_PATH_WIDTH*CONVERTER_RESOLUTION-1:0] pn7_data,
  output [DATA_PATH_WIDTH*CONVERTER_RESOLUTION-1:0] pn15_data
);

  localparam CR = CONVERTER_RESOLUTION;
  localparam DW = DATA_PATH_WIDTH * CR - 1;

  /* We need at least enough bits to store the PN state */
  localparam PN7_W = DW > 6 ? DW : 6;
  localparam PN15_W = DW > 14 ? DW : 14;

  reg [PN7_W:0] pn7_state = {PN7_W+1{1'b1}};
  reg [PN15_W:0] pn15_state = {PN15_W+1{1'b1}};

  wire [DW:0] pn7;
  wire [DW+7:0] pn7_full_state;
  wire [PN7_W:0] pn7_reset;

  wire [DW:0] pn15;
  wire [DW+15:0] pn15_full_state;
  wire [PN15_W:0] pn15_reset;

  /* PN7 x^7 + x^6 + 1 */
  assign pn7 = pn7_full_state[7+:DW+1] ^ pn7_full_state[6+:DW+1];
  assign pn7_full_state = {pn7_state[6:0],pn7};

  /* PN15 x^15 + x^14 + 1 */
  assign pn15 = pn15_full_state[15+:DW+1] ^ pn15_full_state[14+:DW+1];
  assign pn15_full_state = {pn15_state[14:0],pn15};

  assign pn7_reset[PN7_W-:7] = {7{1'b1}};
  assign pn15_reset[PN15_W-:15] = {15{1'b1}};

  generate
    if (PN7_W >= 7) begin
      assign pn7_reset[PN7_W-7:0] = pn7_reset[PN7_W:7] ^ pn7_reset[PN7_W-1:6];
    end

    if (PN15_W >= 15) begin
      assign pn15_reset[PN15_W-15:0] = pn15_reset[PN15_W:15] ^ pn15_reset[PN15_W-1:14];
    end
  endgenerate

  always @(posedge clk) begin
    if (reset == 1'b1) begin
      pn7_state <= pn7_reset;
      pn15_state <= pn15_reset;
    end else begin
      pn7_state <= pn7_full_state[PN7_W:0];
      pn15_state <= pn15_full_state[PN15_W:0];
    end
  end

  generate
     /*
     * The first sample contains the first MSB of the PN sequence, but the first
     * sample is also in the LSB of the output data. So extract data at the MSB
     * sample of the PN state and put it into the LSB sample of the output data.
     */
    genvar i;
    for (i = 0; i <= DW; i = i + CR) begin: g_pn_swizzle
      assign pn7_data[i+:CR] = pn7_state[PN7_W-i-:CR];
      assign pn15_data[i+:CR] = pn15_state[PN15_W-i-:CR];
    end
  endgenerate

endmodule
module ad_ip_jesd204_tpl_adc_deframer #(
  parameter NUM_LANES = 1,
  parameter NUM_CHANNELS = 4,
  parameter BITS_PER_SAMPLE = 16,
  parameter CONVERTER_RESOLUTION = 14,
  parameter SAMPLES_PER_FRAME = 1,
  parameter OCTETS_PER_BEAT = 8,
  parameter LINK_DATA_WIDTH = OCTETS_PER_BEAT * 8 * NUM_LANES,
  parameter ADC_DATA_WIDTH = LINK_DATA_WIDTH * CONVERTER_RESOLUTION / BITS_PER_SAMPLE
) (
  // jesd interface
  // clk is (line-rate/40)

  input clk,
  input [OCTETS_PER_BEAT-1:0] link_sof,
  input [LINK_DATA_WIDTH-1:0] link_data,

   // adc data output

   output [ADC_DATA_WIDTH-1:0] adc_data
 );


  localparam SAMPLES_PER_BEAT = ADC_DATA_WIDTH / CONVERTER_RESOLUTION;
  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;
  localparam FRAMES_PER_BEAT = OCTETS_PER_BEAT * 8 / BITS_PER_LANE_PER_FRAME;

  wire [LINK_DATA_WIDTH-1:0] link_data_s;
  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] adc_data_msb;

  // data multiplex

  genvar i;
  genvar j;
  generate
    /* Reorder octets MSB first */
    for (i = 0; i < LINK_DATA_WIDTH; i = i + 8) begin: g_adc_data
      assign link_data_msb_s[i+:8] = link_data_s[LINK_DATA_WIDTH-1-i-:8];
    end

    /* Slice lanes into frames */
    ad_perfect_shuffle #(
      .NUM_GROUPS (NUM_LANES),
      .WORDS_PER_GROUP (FRAMES_PER_BEAT),
      .WORD_WIDTH (BITS_PER_LANE_PER_FRAME)
    ) i_lanes_to_frames (
      .data_in (link_data_msb_s),
      .data_out (frame_data_s)
    );

    /* Slice frames into channels */
    ad_perfect_shuffle #(
      .NUM_GROUPS (FRAMES_PER_BEAT),
      .WORDS_PER_GROUP (NUM_CHANNELS),
      .WORD_WIDTH (BITS_PER_CHANNEL_PER_FRAME)
    ) i_frames_to_channels (
      .data_in (frame_data_s),
      .data_out (adc_data_msb)
    );

    /* Reorder samples LSB first and remove tail bits */
    for (i = 0; i < SAMPLES_PER_BEAT; i = i + 1) begin: g_dac_data_msb
      localparam src_w = BITS_PER_SAMPLE;
      localparam dst_w = CONVERTER_RESOLUTION;
      localparam src_msb = LINK_DATA_WIDTH - 1 - i * src_w ;
      localparam dst_lsb = i * dst_w;

      assign adc_data[dst_lsb+:dst_w] = adc_data_msb[src_msb-:dst_w];
    end
  endgenerate

  // frame-alignment

  generate
  genvar n;
  for (n = 0; n < NUM_LANES; n = n + 1) begin: g_xcvr_if
    localparam DW = OCTETS_PER_BEAT * 8;
    ad_xcvr_rx_if #(
      .OCTETS_PER_BEAT (OCTETS_PER_BEAT)
    ) i_xcvr_if (
      .rx_clk (clk),
      .rx_ip_sof (link_sof),
      .rx_ip_data (link_data[n*DW+:DW]),
      .rx_sof (),
      .rx_data (link_data_s[n*DW+:DW])
    );
  end
  endgenerate

endmodule
module ad_ip_jesd204_tpl_adc_channel #(
  parameter CONVERTER_RESOLUTION = 14,
  parameter DATA_PATH_WIDTH = 2,
  parameter TWOS_COMPLEMENT = 1,
  parameter BITS_PER_SAMPLE = 16
) (
  input clk,

  input [CONVERTER_RESOLUTION*DATA_PATH_WIDTH-1:0] raw_data,

  output [BITS_PER_SAMPLE*DATA_PATH_WIDTH-1:0] fmt_data,

  // Configuration and status
  input dfmt_enable,
  input dfmt_type,
  input dfmt_sign_extend,

  input [3:0] pn_seq_sel,
  output pn_oos,
  output pn_err
);

  localparam OCTETS_PER_SAMPLE = BITS_PER_SAMPLE / 8;

  // instantiations

  ad_ip_jesd204_tpl_adc_pnmon #(
    .CONVERTER_RESOLUTION (CONVERTER_RESOLUTION),
    .DATA_PATH_WIDTH (DATA_PATH_WIDTH),
    .TWOS_COMPLEMENT (TWOS_COMPLEMENT)
  ) i_pnmon (
    .clk (clk),
    .data (raw_data),

    .pn_seq_sel (pn_seq_sel),
    .pn_oos (pn_oos),
    .pn_err (pn_err)
  );

  generate
  genvar n;
  for (n = 0; n < DATA_PATH_WIDTH; n = n + 1) begin: g_datafmt
    ad_datafmt #(
      .DATA_WIDTH (CONVERTER_RESOLUTION),
      .OCTETS_PER_SAMPLE (OCTETS_PER_SAMPLE)
    ) i_ad_datafmt (
      .clk (clk),

      .valid (1'b1),
      .data (raw_data[n*CONVERTER_RESOLUTION+:CONVERTER_RESOLUTION]),
      .valid_out (),
      .data_out (fmt_data[n*BITS_PER_SAMPLE+:BITS_PER_SAMPLE]),

      .dfmt_enable (dfmt_enable),
      .dfmt_type (dfmt_type),
      .dfmt_se (dfmt_sign_extend)
    );
  end
  endgenerate

endmodule
module ad_ip_jesd204_tpl_adc_pnmon #(
  parameter CONVERTER_RESOLUTION = 16,
  parameter DATA_PATH_WIDTH = 1,
  parameter TWOS_COMPLEMENT = 1
) (
  input clk,

  // data interface
  input [CONVERTER_RESOLUTION*DATA_PATH_WIDTH-1:0] data,

  // pn out of sync and error
  output pn_oos,
  output pn_err,

  // processor interface PN9 (0x0), PN23 (0x1)
  input [3:0] pn_seq_sel
);

  localparam DW = DATA_PATH_WIDTH*CONVERTER_RESOLUTION-1;

  // Max width of largest PN and data width
  localparam PN_W = DW > 22 ? DW : 22;

  // internal registers
  reg [PN_W:0] pn_data_pn = 'd0;

  // internal signals
  wire [PN_W:0] pn_data_pn_s;
  wire [DW:0] pn_data_in_s;
  wire [PN_W:0] pn_data_init;

  wire [DW:0] pn23;
  wire [DW+23:0] full_state_pn23;
  wire [DW:0] pn9;
  wire [DW+9:0] full_state_pn9;

  // pn sequence select
  generate if (PN_W > DW) begin
    reg [PN_W-DW-1:0] pn_data_in_d = 'd0;
    always @(posedge clk) begin
      pn_data_in_d <= pn_data_in_s[PN_W-DW-1:0];
    end
    assign pn_data_init = {pn_data_in_d, pn_data_in_s};
  end else begin
    assign pn_data_init = pn_data_in_s;
  end
  endgenerate

  assign pn_data_pn_s = (pn_oos == 1'b1) ? pn_data_init : pn_data_pn;

  wire tc = TWOS_COMPLEMENT ? 1'b1 : 1'b0;

  generate
  genvar i;
  for (i = 0; i < DATA_PATH_WIDTH; i = i + 1) begin: g_pn_swizzle
    localparam src_lsb = i * CONVERTER_RESOLUTION;
    localparam src_msb = src_lsb + CONVERTER_RESOLUTION - 1;
    localparam dst_lsb = (DATA_PATH_WIDTH - i - 1) * CONVERTER_RESOLUTION;
    localparam dst_msb = dst_lsb + CONVERTER_RESOLUTION - 1;

    assign pn_data_in_s[dst_msb] = (~tc) ^ data[src_msb];
    assign pn_data_in_s[dst_msb-1:dst_lsb] = data[src_msb-1:src_lsb];
  end
  endgenerate

  // PN23 x^23 + x^18 + 1
  assign pn23 = full_state_pn23[23+:DW+1] ^ full_state_pn23[18+:DW+1];
  assign full_state_pn23 = {pn_data_pn_s[22:0],pn23};

  // PN9 x^9 + x^5 + 1
  assign pn9 = full_state_pn9[9+:DW+1] ^ full_state_pn9[5+:DW+1];
  assign full_state_pn9 = {pn_data_pn_s[8:0],pn9};

  always @(posedge clk) begin
    if (pn_seq_sel == 4'd0) begin
      pn_data_pn <= PN_W > DW ? {pn_data_pn[PN_W-DW-1:0],pn9} : pn9;
    end else begin
      pn_data_pn <= PN_W > DW ? {pn_data_pn[PN_W-DW-1:0],pn23} : pn23;
    end
  end


  // pn oos & pn err

  ad_pnmon #(
    .DATA_WIDTH (DW+1)
  ) i_pnmon (
    .adc_clk (clk),
    .adc_valid_in (1'b1),
    .adc_data_in (pn_data_in_s),
    .adc_data_pn (pn_data_pn[DW:0]),
    .adc_pn_oos (pn_oos),
    .adc_pn_err (pn_err)
  );

endmodule
module ad_ip_jesd204_tpl_adc_core #(
  parameter NUM_LANES = 1,
  parameter NUM_CHANNELS = 1,
  parameter SAMPLES_PER_FRAME = 1,
  parameter CONVERTER_RESOLUTION = 14,
  parameter 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 TWOS_COMPLEMENT = 1
) (
  input clk,

  input [NUM_CHANNELS-1:0] dfmt_enable,
  input [NUM_CHANNELS-1:0] dfmt_sign_extend,
  input [NUM_CHANNELS-1:0] dfmt_type,

  input [NUM_CHANNELS*4-1:0] pn_seq_sel,
  output [NUM_CHANNELS-1:0] pn_err,
  output [NUM_CHANNELS-1:0] pn_oos,

  output [NUM_CHANNELS-1:0] adc_valid,
  output [DMA_DATA_WIDTH-1:0] adc_data,

  input adc_sync,
  output adc_sync_status,
  input adc_sync_in,
  output adc_rst_sync,

  input link_valid,
  output link_ready,
  input [OCTETS_PER_BEAT-1:0] link_sof,
  input [LINK_DATA_WIDTH-1:0] link_data
);
  // 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;

  wire [ADC_DATA_WIDTH-1:0] raw_data_s;

  reg adc_sync_armed = 1'b0;
  reg adc_sync_in_d1 = 1'b0;
  reg adc_sync_d1 = 1'b0;

  assign link_ready = 1'b1;
  assign adc_valid = {NUM_CHANNELS{link_valid}};
  assign adc_sync_status = adc_sync_armed;
  assign adc_rst_sync = adc_sync_armed;

  always @(posedge clk) begin
    adc_sync_in_d1 <= adc_sync_in;
    adc_sync_d1 <= adc_sync;
    if ((~adc_sync_d1 & adc_sync) == 1'b1) begin
      adc_sync_armed <= ~adc_sync_armed;
    end else if ((~adc_sync_in_d1 & adc_sync_in) == 1'b1) begin
      adc_sync_armed <= 1'b0;
    end
  end

  // synchronization logic

  ad_ip_jesd204_tpl_adc_deframer #(
    .NUM_LANES (NUM_LANES),
    .NUM_CHANNELS (NUM_CHANNELS),
    .BITS_PER_SAMPLE (BITS_PER_SAMPLE),
    .CONVERTER_RESOLUTION  (CONVERTER_RESOLUTION),
    .SAMPLES_PER_FRAME (SAMPLES_PER_FRAME),
    .OCTETS_PER_BEAT (OCTETS_PER_BEAT),
    .LINK_DATA_WIDTH (LINK_DATA_WIDTH),
    .ADC_DATA_WIDTH (ADC_DATA_WIDTH)
  ) i_deframer (
    .clk (clk),
    .link_sof (link_sof),
    .link_data (link_data),
    .adc_data (raw_data_s)
  );

  generate
  genvar i;
  for (i = 0; i < NUM_CHANNELS; i = i + 1) begin: g_channel
    ad_ip_jesd204_tpl_adc_channel #(
      .DATA_PATH_WIDTH (DATA_PATH_WIDTH),
      .CONVERTER_RESOLUTION (CONVERTER_RESOLUTION),
      .TWOS_COMPLEMENT (TWOS_COMPLEMENT),
      .BITS_PER_SAMPLE (BITS_PER_SAMPLE)
    ) i_channel (
      .clk (clk),

      .raw_data (raw_data_s[CDW_RAW*i+:CDW_RAW]),
      .fmt_data (adc_data[CDW_FMT*i+:CDW_FMT]),

      .dfmt_enable (dfmt_enable[i]),
      .dfmt_sign_extend (dfmt_sign_extend[i]),
      .dfmt_type (dfmt_type[i]),

      .pn_seq_sel (pn_seq_sel[i*4+:4]),
      .pn_err (pn_err[i]),
      .pn_oos (pn_oos[i])
    );
  end
  endgenerate

endmodule
module jesd204_ilas_monitor #(
  parameter DATA_PATH_WIDTH = 4
) (
  input clk,
  input reset,

  input [DATA_PATH_WIDTH*8-1:0] data,
  input [DATA_PATH_WIDTH-1:0] charisk28,

  output reg ilas_config_valid,
  output reg [1:0] ilas_config_addr,
  output reg [DATA_PATH_WIDTH*8-1:0] ilas_config_data,

  output data_ready_n
);

reg [3:0] multi_frame_counter = 'h00;
reg [7:0] frame_counter = 'h00;
reg [7:0] length = 'h00;

localparam STATE_ILAS = 1'b1;
localparam STATE_DATA = 1'b0;

reg state = STATE_ILAS;
reg next_state;
reg prev_was_last = 1'b0;
reg frame_length_error = 1'b0;

assign data_ready_n = next_state;

always @(*) begin
  next_state = state;
  if (reset == 1'b0 && prev_was_last == 1'b1) begin
    if (charisk28[0] != 1'b1 || data[7:5] != 3'h0) begin
      next_state = STATE_DATA;
    end
  end
end

always @(posedge clk) begin
  if (reset == 1'b1) begin
    state <= STATE_ILAS;
  end else begin
    state <= next_state;
  end
end

always @(posedge clk) begin
  if (reset == 1'b1 || (charisk28[3] == 1'b1 && data[31:29] == 3'h3)) begin
    prev_was_last <= 1'b1;
  end else begin
    prev_was_last <= 1'b0;
  end
end

always @(posedge clk) begin
  if (reset == 1'b1) begin
    multi_frame_counter <= 'h00;
  end else if (charisk28[0] == 1'b1 && data[7:5] == 3'h0 && state == STATE_ILAS) begin
    multi_frame_counter <= multi_frame_counter + 1'b1;
  end
end

always @(posedge clk) begin
  if (reset == 1'b1) begin
    length <= 'h00;
  end else if (prev_was_last == 1'b1) begin
    if (length == 'h00) begin
      length <= frame_counter;
    end
  end
end

always @(posedge clk) begin
  frame_length_error <= 1'b0;
  if (prev_was_last == 1'b1) begin
    if (length != 'h00 && length != frame_counter) begin
      frame_length_error <= 1'b1;
    end
  end
end

always @(posedge clk) begin
  if (prev_was_last == 1'b1) begin
    frame_counter <= 'h00;
  end else begin
    frame_counter <= frame_counter + 1'b1;
  end
end

always @(posedge clk) begin
  if (reset == 1'b1) begin
    ilas_config_valid <= 1'b0;
  end else if (state == STATE_ILAS) begin
    if (charisk28[1] == 1'b1 && data[15:13] == 3'h4) begin
      ilas_config_valid <= 1'b1;
    end else if (ilas_config_addr == 'h3) begin
      ilas_config_valid <= 1'b0;
    end
  end
end

always @(posedge clk) begin
  if (ilas_config_valid == 1'b0) begin
    ilas_config_addr <= 1'b0;
  end else if (ilas_config_valid == 1'b1) begin
    ilas_config_addr <= ilas_config_addr + 1'b1;
  end
end

always @(posedge clk) begin
  ilas_config_data <= data;
end

endmodule