// (C) 2001-2018 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.


`timescale 1 ps/1 ps

module alt_xcvr_native_rcfg_opt_logic_cylqohi #(
  // Parameters for the embedded reconfiguration logic
  parameter                                 dbg_user_identifier           = 0,
  parameter                                 duplex_mode                   = "duplex",
  parameter                                 dbg_embedded_debug_enable     = 0,
  parameter                                 dbg_capability_reg_enable     = 0,
  parameter                                 dbg_prbs_soft_logic_enable    = 0,
  parameter                                 dbg_odi_soft_logic_enable     = 0,
  parameter                                 dbg_stat_soft_logic_enable    = 0,
  parameter                                 dbg_ctrl_soft_logic_enable    = 0,

  // Parameter for enabling the PCIe DFE IP
  parameter                                 enable_pcie_dfe_ip            = 0,
  parameter                                 disable_continuous_dfe        = 0,
  parameter                                 sim_reduced_counters          = 0,
  parameter                                 enable_hip                    = 0,

  // Parameters for the AVMM masters and split interface
  parameter                                 CHANNELS                      = 1,
  parameter                                 RECONFIG_SHARED               = 0,
  parameter                                 JTAG_ENABLED                  = 0,    // Can only be enabled when using a shared reconfig interface
  parameter                                 ADME_SLAVE_MAP                = "altera_xcvr_native_a10",
  parameter                                 ADME_ASSGN_MAP                = " ",
  parameter                                 RCFG_EMB_STRM_ENABLED         = 0,    // Enable the embedded reconfiguration streamer logic
  parameter                                 RCFG_PROFILE_CNT              = 2,    // Number of configuration profiles for embedded streamer

  // The following are not intended to be directly set
  parameter                                 IFACES                        = RECONFIG_SHARED ? 1 : CHANNELS,
  parameter                                 ADDR_BITS                     = 10,
  parameter                                 SEL_BITS                      = (RECONFIG_SHARED ? altera_xcvr_native_a10_functions_h::clogb2_alt_xcvr_native_a10(CHANNELS-1) : 0),
  parameter                                 DATA_WIDTH                    = 32

) (
  // User reconfig interface ports
  input  [IFACES-1:0]                          reconfig_clk,
  input  [IFACES-1:0]                          reconfig_reset,
  input  [IFACES-1:0]                          reconfig_write,
  input  [IFACES-1:0]                          reconfig_read,
  input  [IFACES*(ADDR_BITS+SEL_BITS)-1:0]     reconfig_address,
  input  [IFACES*DATA_WIDTH-1:0]               reconfig_writedata,
  output [IFACES*DATA_WIDTH-1:0]               reconfig_readdata,
  output [IFACES-1:0]                          reconfig_waitrequest,

  // AVMM ports to transceiver Split bychannel
  output [CHANNELS-1:0]                        avmm_clk,
  output [CHANNELS-1:0]                        avmm_reset,
  output [CHANNELS-1:0]                        avmm_write,
  output [CHANNELS-1:0]                        avmm_read,
  output [CHANNELS*ADDR_BITS-1:0]              avmm_address,
  output [CHANNELS*8-1:0]                      avmm_writedata,
  input  [CHANNELS*8-1:0]                      avmm_readdata,
  input  [CHANNELS-1:0]                        avmm_waitrequest,

  // input signals for PCIe DFE IP
  input                                        ltssm_detect_quiet,
  input                                        ltssm_detect_active,
  input                                        ltssm_rcvr_phase_two,
  input  [1:0]                                 pcie_rate,
  input                                        hip_reduce_counters,

  // input signals from the PHY for PRBSerror accumulation
  input  [CHANNELS-1:0]                        prbs_err_signal,
  input  [CHANNELS-1:0]                        prbs_done_signal,

  // input rx_clkout
  input  [CHANNELS-1:0]                        in_rx_clkout,

  // input status signals
  input  [CHANNELS-1:0]                        in_rx_is_lockedtoref,
  input  [CHANNELS-1:0]                        in_rx_is_lockedtodata,
  input  [CHANNELS-1:0]                        in_tx_cal_busy,
  input  [CHANNELS-1:0]                        in_rx_cal_busy,
  input  [CHANNELS-1:0]                        in_avmm_busy,

  // input control signals
  input  [CHANNELS-1:0]                        in_rx_prbs_err_clr,
  input  [CHANNELS-1:0]                        in_set_rx_locktoref,
  input  [CHANNELS-1:0]                        in_set_rx_locktodata,
  input  [CHANNELS-1:0]                        in_en_serial_lpbk,
  input  [CHANNELS-1:0]                        in_rx_analogreset,
  input  [CHANNELS-1:0]                        in_rx_digitalreset,
  input  [CHANNELS-1:0]                        in_tx_analogreset,
  input  [CHANNELS-1:0]                        in_tx_digitalreset,
  
  // output control signals to the phy
  output [CHANNELS-1:0]                        out_prbs_err_clr,
  output [CHANNELS-1:0]                        out_set_rx_locktoref,
  output [CHANNELS-1:0]                        out_set_rx_locktodata,
  output [CHANNELS-1:0]                        out_en_serial_lpbk,
  output [CHANNELS-1:0]                        out_rx_analogreset,
  output [CHANNELS-1:0]                        out_rx_digitalreset,
  output [CHANNELS-1:0]                        out_tx_analogreset,
  output [CHANNELS-1:0]                        out_tx_digitalreset,
  output [CHANNELS-1:0]                        out_tx_cal_busy_mask,
  output [CHANNELS-1:0]                        out_rx_cal_busy_mask
);

/**********************************************************************/
// Per Instance instantiations and assignments
/**********************************************************************/
localparam CHANNEL_SEL_WIDTH = altera_xcvr_native_a10_functions_h::clogb2_alt_xcvr_native_a10(CHANNELS-1);
localparam ENABLED_JTAG_MASTERS = 1 + dbg_odi_soft_logic_enable + JTAG_ENABLED + RCFG_EMB_STRM_ENABLED + enable_pcie_dfe_ip;
localparam RCFG_EMB_STRM_CFG_SEL_WIDTH = altera_xcvr_native_a10_functions_h::clogb2_alt_xcvr_native_a10(RCFG_PROFILE_CNT-1);


// Raw rmbedded reconfig signals (always independent)
wire [CHANNELS-1:0]             rcfg_emb_strm_write;
wire [CHANNELS-1:0]             rcfg_emb_strm_read;
wire [CHANNELS*ADDR_BITS-1:0]   rcfg_emb_strm_address;
wire [CHANNELS*DATA_WIDTH-1:0]  rcfg_emb_strm_writedata;
wire [CHANNELS-1:0]             rcfg_emb_strm_waitrequest;

// User AVMM signals expanded to independent channels
wire [CHANNELS-1:0]             split_user_write;
wire [CHANNELS-1:0]             split_user_read;
wire [CHANNELS*ADDR_BITS-1:0]   split_user_address;
wire [CHANNELS*DATA_WIDTH-1:0]  split_user_writedata;
wire [CHANNELS-1:0]             split_user_waitrequest;

// ODI AVMM signals 
wire [CHANNELS-1:0]             odi_write;
wire [CHANNELS-1:0]             odi_read;
wire [CHANNELS*ADDR_BITS-1:0]   odi_address;
wire [CHANNELS*DATA_WIDTH-1:0]  odi_writedata;
wire [CHANNELS-1:0]             odi_waitrequest;

// PCIe DFE ip
wire [CHANNELS-1:0]             split_pcie_dfe_write;
wire [CHANNELS-1:0]             split_pcie_dfe_read;
wire [CHANNELS*ADDR_BITS-1:0]   split_pcie_dfe_address;
wire [CHANNELS*DATA_WIDTH-1:0]  split_pcie_dfe_writedata;
wire [CHANNELS-1:0]             split_pcie_dfe_waitrequest;
wire                            pcie_dfe_avmm_lock;

// JTAG signals expanded to independent channels
wire [CHANNELS-1:0]             split_jtag_write;
wire [CHANNELS-1:0]             split_jtag_read;
wire [CHANNELS*ADDR_BITS-1:0]   split_jtag_address;
wire [CHANNELS*DATA_WIDTH-1:0]  split_jtag_writedata;
wire [CHANNELS-1:0]             split_jtag_waitrequest;

// Additional arbitration signals for soft CSR
wire [CHANNELS-1:0]             chnl_write;
wire [CHANNELS-1:0]             chnl_read;
wire [CHANNELS-1:0]             chnl_busy;
wire [CHANNELS-1:0]             chnl_waitrequest;
wire [CHANNELS*8-1:0]           chnl_readdata;

// embedded reconfig signals
wire [CHANNELS-1:0]             rcfg_emb_strm_busy;
wire [CHANNELS-1:0]             rcfg_emb_strm_chan_sel;
wire [CHANNELS*RCFG_EMB_STRM_CFG_SEL_WIDTH-1:0]   rcfg_emb_strm_cfg_sel;
wire [CHANNELS-1:0]             rcfg_emb_strm_bcast_en;
wire [CHANNELS-1:0]             rcfg_emb_strm_cfg_load;

// Read_write signals to assist with prioritizing arbitrarion
wire [CHANNELS-1:0]             user_read_write;
wire [CHANNELS-1:0]             odi_read_write;
wire [CHANNELS-1:0]             pcie_dfe_read_write;
wire [CHANNELS-1:0]             jtag_read_write;
wire [CHANNELS-1:0]             rcfg_emb_strm_read_write;

// Wires for converting between data widths
wire [CHANNELS*DATA_WIDTH-1:0]  expanded_avmm_readdata;
wire [CHANNELS*DATA_WIDTH-1:0]  expanded_avmm_writedata;

// Wires for control and status signals between the various masters
wire [CHANNELS-1:0]             odi_done;
wire [CHANNELS-1:0]             prbs_done_sync;
wire [CHANNELS*50-1:0]          prbs_err_count;
wire [CHANNELS*50-1:0]          prbs_bit_count;
wire [CHANNELS*50-1:0]          odi_err_count;
wire [CHANNELS*50-1:0]          odi_bit_count;


// Wires for qmap cleanup
wire lcl_g_arbiter_dis;
wire lcl_g_avmm_csr_dis;
wire lcl_ground;

// Warning Removal
assign lcl_g_avmm_csr_dis   = &{1'b0,
                                rcfg_emb_strm_busy,
                                prbs_done_sync,
                                odi_done,
                                prbs_err_count,
                                prbs_bit_count,
                                odi_bit_count,
                                odi_err_count};
assign lcl_g_arbiter_dis    = &{1'b0, 
                                rcfg_emb_strm_address, 
                                rcfg_emb_strm_writedata, 
                                odi_address, 
                                odi_writedata,
                                split_pcie_dfe_address,
                                split_pcie_dfe_writedata,
                                split_jtag_address, 
                                split_jtag_writedata,
                                user_read_write,
                                odi_read_write,
                                pcie_dfe_read_write,
                                jtag_read_write,
                                rcfg_emb_strm_read_write};
assign lcl_ground           = &{1'b0,
                                lcl_g_avmm_csr_dis,
                                lcl_g_arbiter_dis};

// Generate variable for channel numbers
genvar ig;


/**********************************************************************/
// Generate Statement for the Shared vs Split user interface
/**********************************************************************/
generate
  // Expand the AVMM signals from the channel to the 32-bit interface of the user
  for(ig=0;ig<CHANNELS;ig=ig+1) begin: g_expanded_avmm_signals
    assign  expanded_avmm_readdata [ig*DATA_WIDTH +: DATA_WIDTH] = {24'd0,chnl_readdata [ig*8 +: 8]};
    assign  avmm_writedata [ig*8 +: 8]                           = expanded_avmm_writedata   [ig*DATA_WIDTH +: 8];
  end


  /**********************************************************************/
  // Split the reconfig interface to the independent channel when using shared reconfig
  /**********************************************************************/
  if(!RECONFIG_SHARED) begin : g_not_shared
    // Signals are already split, so wire straight through
    assign avmm_clk                                             = reconfig_clk;
    assign avmm_reset                                           = reconfig_reset;

    assign split_user_write                                     = reconfig_write;
    assign split_user_read                                      = reconfig_read;
    assign split_user_address                                   = reconfig_address;
    assign split_user_writedata                                 = reconfig_writedata;
    assign reconfig_readdata                                    = expanded_avmm_readdata;
    assign reconfig_waitrequest                                 = ({CHANNELS{lcl_ground}} | split_user_waitrequest);

  // If we are using a shared interface
  end else begin : g_shared
    wire [CHANNEL_SEL_WIDTH-1:0]                                 rcfg_if_sel;

    // Generate interface select based on upper address bits
    assign rcfg_if_sel                                          = reconfig_address[ADDR_BITS+:CHANNEL_SEL_WIDTH];
    assign reconfig_readdata                                    = expanded_avmm_readdata[rcfg_if_sel*DATA_WIDTH +: DATA_WIDTH];
    assign reconfig_waitrequest                                 = split_user_waitrequest[rcfg_if_sel];

    for(ig=0;ig<CHANNELS;ig=ig+1) begin : g_shared
      // Split shared signals to independent channels
      assign avmm_clk             [ig]                          = reconfig_clk;
      assign avmm_reset           [ig]                          = reconfig_reset;

      assign split_user_write     [ig]                          = reconfig_write & (rcfg_if_sel == ig) | lcl_ground;
      assign split_user_read      [ig]                          = reconfig_read  & (rcfg_if_sel == ig);
      assign split_user_address   [ig*ADDR_BITS +: ADDR_BITS]   = reconfig_address[0+:ADDR_BITS];
      assign split_user_writedata [ig*DATA_WIDTH +: DATA_WIDTH] = reconfig_writedata;
    end
  end //End g_not_shared
endgenerate


/**********************************************************************/
// Embedded JTAG Debug Master (ADME)
/**********************************************************************/
generate if(JTAG_ENABLED) begin : g_jtag

    // Set the slave type for the ADME.  Since the span needs to be a string, 2^(total addr_bits) will
    // give the max value, however since the adme uses byte alignment, shift the span by two bits.
    localparam set_slave_span = altera_xcvr_native_a10_functions_h::int2str_alt_xcvr_native_a10(2**(ADDR_BITS+CHANNEL_SEL_WIDTH+2));
    localparam set_slave_map  = {"{typeName ",ADME_SLAVE_MAP," address 0x0 span ",set_slave_span," hpath {}",ADME_ASSGN_MAP,"}"};

    // Raw JTAG signals
    wire                                     jtag_write;
    wire                                     jtag_read;
    wire [(ADDR_BITS+CHANNEL_SEL_WIDTH)-1:0] jtag_address;
    wire [DATA_WIDTH-1:0]                    jtag_writedata;
    wire [DATA_WIDTH-1:0]                    jtag_readdata;
    wire                                     jtag_waitrequest;
    wire                                     jtag_readdatavalid;
    wire [CHANNEL_SEL_WIDTH-1:0]             jtag_if_sel;

    // Generate channel select based on upper address bits
    assign jtag_if_sel                                          = jtag_address[ADDR_BITS+:CHANNEL_SEL_WIDTH];
    assign jtag_readdata                                        = expanded_avmm_readdata[jtag_if_sel*DATA_WIDTH +: DATA_WIDTH];
    assign jtag_waitrequest                                     = split_jtag_waitrequest[jtag_if_sel];

    // Split shared signals to independent channels
    for(ig=0;ig<CHANNELS;ig=ig+1) begin: g_expanded_avmm_signals
      assign split_jtag_write     [ig]                          = jtag_write & (jtag_if_sel == ig);
      assign split_jtag_read      [ig]                          = jtag_read  & (jtag_if_sel == ig);
      assign split_jtag_address   [ig*ADDR_BITS +: ADDR_BITS]   = jtag_address[0+:ADDR_BITS];
      assign split_jtag_writedata [ig*DATA_WIDTH +: DATA_WIDTH] = jtag_writedata[DATA_WIDTH-1:0];
    end

    // When doing RTL sims, remove the altera_debug_master_endpoint, as 
    // there is no RTL simulation model.  Pre and Post Fit sims are ok.
    `ifdef ALTERA_RESERVED_QIS
      altera_debug_master_endpoint
      #(
        .ADDR_WIDTH                            ( (ADDR_BITS+CHANNEL_SEL_WIDTH) ),
        .DATA_WIDTH                            ( DATA_WIDTH                    ),
        .HAS_RDV                               ( 0                             ),
        .SLAVE_MAP                             ( set_slave_map                 ),
        .PREFER_HOST                           ( " "                           ),
        .CLOCK_RATE_CLK                        ( 0                             )
      ) adme (
        .clk                                   ( reconfig_clk                  ),
        .reset                                 ( reconfig_reset                ),
        .master_write                          ( jtag_write                    ),
        .master_read                           ( jtag_read                     ),
        .master_address                        ( jtag_address                  ),
        .master_writedata                      ( jtag_writedata                ),
        .master_waitrequest                    ( jtag_waitrequest              ),
        .master_readdatavalid                  ( jtag_readdatavalid            ),
        .master_readdata                       ( jtag_readdata                 )
      );
    `else
      assign jtag_write                         = 1'b0;
      assign jtag_read                          = 1'b0;
      assign jtag_address                       = {(ADDR_BITS+CHANNEL_SEL_WIDTH){1'b0}};
      assign jtag_writedata                     = {DATA_WIDTH{1'b0}};
    `endif

  // If we have not enabled the ADME
  end else begin : g_jtag_disable
    assign split_jtag_write                     = {CHANNELS{1'b0}};
    assign split_jtag_read                      = {CHANNELS{1'b0}};
    assign split_jtag_address                   = {(CHANNELS*ADDR_BITS){1'b0}};
    assign split_jtag_writedata                 = {(CHANNELS*DATA_WIDTH){1'b0}};
  end 
endgenerate // End g_jtag


/**********************************************************************/
// Enable the PCIe DFE IP
/**********************************************************************/
generate if(enable_pcie_dfe_ip) begin : g_pcie_dfe_ip
    // Raw JTAG signals
    wire                                     pcie_dfe_write;
    wire                                     pcie_dfe_read;
    wire [(ADDR_BITS+CHANNEL_SEL_WIDTH)-1:0] pcie_dfe_address;
    wire [DATA_WIDTH-1:0]                    pcie_dfe_writedata;
    wire [DATA_WIDTH-1:0]                    pcie_dfe_readdata;
    wire                                     pcie_dfe_waitrequest;
    wire [CHANNEL_SEL_WIDTH-1:0]             pcie_dfe_if_sel;

    // Generate channel select based on upper address bits
    assign pcie_dfe_if_sel                                          = pcie_dfe_address[ADDR_BITS+:CHANNEL_SEL_WIDTH];
    assign pcie_dfe_readdata                                        = expanded_avmm_readdata[pcie_dfe_if_sel*DATA_WIDTH +: DATA_WIDTH];
    assign pcie_dfe_waitrequest                                     = split_pcie_dfe_waitrequest[pcie_dfe_if_sel];

    // Split shared signals to independent channels
    for(ig=0;ig<CHANNELS;ig=ig+1) begin: g_expanded_avmm_signals
      assign split_pcie_dfe_write     [ig]                          = pcie_dfe_write & (pcie_dfe_if_sel == ig);
      assign split_pcie_dfe_read      [ig]                          = pcie_dfe_read  & (pcie_dfe_if_sel == ig);
      assign split_pcie_dfe_address   [ig*ADDR_BITS +: ADDR_BITS]   = pcie_dfe_address[0+:ADDR_BITS];
      assign split_pcie_dfe_writedata [ig*DATA_WIDTH +: DATA_WIDTH] = pcie_dfe_writedata[DATA_WIDTH-1:0];
    end


    altera_xcvr_native_pcie_dfe_ip #(
      .num_channels           ( CHANNELS                                   ),
      .disable_continuous_dfe ( disable_continuous_dfe                     ),
      .enable_hip             ( enable_hip                                 ),
      .sim_reduced_counters   ( sim_reduced_counters                       ),
      .avmm_sel_bits          ( CHANNEL_SEL_WIDTH                          ),
      .avmm_addr_bits         ( ADDR_BITS                                  )
    ) altera_xcvr_native_pcie_dfe_ip_inst ( 
      .clock                  (  reconfig_clk                              ),
      .reset                  (  reconfig_reset                            ),
      .ltssm_detect_quiet     (  ltssm_detect_quiet                        ),
      .ltssm_detect_active    (  ltssm_detect_active                       ),
      .ltssm_rcvr_phase_two   (  ltssm_rcvr_phase_two                      ),
      .pcie_rate_sw           (  pcie_rate                                 ),
      
      // HIP only port for reduced counters
      .hip_reduce_counters    (  hip_reduce_counters                       ),

      // Reconfig Interface to the transceiver
      .xcvr_rcfg_waitrequest  (  pcie_dfe_waitrequest                      ),
      .xcvr_rcfg_readdata     (  pcie_dfe_readdata                         ),
      .xcvr_rcfg_lock         (  pcie_dfe_avmm_lock                        ),
      .xcvr_rcfg_read         (  pcie_dfe_read                             ),
      .xcvr_rcfg_write        (  pcie_dfe_write                            ),
      .xcvr_rcfg_address      (  pcie_dfe_address                          ),
      .xcvr_rcfg_writedata    (  pcie_dfe_writedata                        )
    );

  end else begin : g_disable_pcie_dfe_ip
    assign pcie_dfe_avmm_lock                       = 1'b0;
    assign split_pcie_dfe_write                     = {CHANNELS{1'b0}};
    assign split_pcie_dfe_read                      = {CHANNELS{1'b0}};
    assign split_pcie_dfe_address                   = {(CHANNELS*ADDR_BITS){1'b0}};
    assign split_pcie_dfe_writedata                 = {(CHANNELS*DATA_WIDTH){1'b0}};
  end
endgenerate


/**********************************************************************/
// Embedded Reconfig Streamer
/**********************************************************************/
generate if(RCFG_EMB_STRM_ENABLED) begin : g_rcfg_strm_enable //TODO check to see if there is parameter redundancy

      alt_xcvr_native_rcfg_strm_top_cylqohi #(
        .xcvr_rcfg_interfaces                  ( CHANNELS                        ),
        .xcvr_rcfg_addr_width                  ( ADDR_BITS                       ),
        .xcvr_rcfg_data_width                  ( DATA_WIDTH                      ),
        .rcfg_profile_cnt                      ( RCFG_PROFILE_CNT                )
      )rcfg_strm_top_inst(
        .clk                                   ( reconfig_clk[0]                 ), // All clock bits should be driven by the same source if using independent interface
        .reset                                 ( |reconfig_reset                 ), // Any reset bit will reset the reconfig streamer
        .cfg_sel                               ( rcfg_emb_strm_cfg_sel           ),
        .bcast_en                              ( rcfg_emb_strm_bcast_en          ),
        .cfg_load                              ( rcfg_emb_strm_cfg_load          ),
        .chan_sel                              ( rcfg_emb_strm_chan_sel          ),
        .stream_busy                           ( rcfg_emb_strm_busy              ),
        .xcvr_reconfig_write                   ( rcfg_emb_strm_write             ),
        .xcvr_reconfig_read                    ( rcfg_emb_strm_read              ),
        .xcvr_reconfig_address                 ( rcfg_emb_strm_address           ),
        .xcvr_reconfig_writedata               ( rcfg_emb_strm_writedata         ),
        .xcvr_reconfig_readdata                ( expanded_avmm_readdata          ),
        .xcvr_reconfig_waitrequest             ( rcfg_emb_strm_waitrequest       )
      );

    // If we disable the reconfig streamer
    end else begin: g_rcfg_strm_disable
      assign  rcfg_emb_strm_write               = {CHANNELS{1'b0}};
      assign  rcfg_emb_strm_read                = {CHANNELS{1'b0}};
      assign  rcfg_emb_strm_address             = {(CHANNELS*ADDR_BITS){1'b0}};
      assign  rcfg_emb_strm_writedata           = {CHANNELS{32'b0}};
      assign  rcfg_emb_strm_busy                = {CHANNELS{1'b0}};
  end
endgenerate // End g_rcfg_strm_enable


/**********************************************************************/
// AVMM Master read/write signals.
/**********************************************************************/
assign user_read_write          = split_user_read     | split_user_write;       // Bits asserted for corresponding channels from/to which user avmm is currently reading/writing
assign jtag_read_write          = split_jtag_read     | split_jtag_write;       // Bits asserted for corresponding channels from/to which jtag is currently reading/writing
assign rcfg_emb_strm_read_write = rcfg_emb_strm_read  | rcfg_emb_strm_write;    // Bits asserted for corresponding channels from/to which embedded streamer is currently reading/writing
assign odi_read_write           = odi_read            | odi_write;
assign pcie_dfe_read_write      = split_pcie_dfe_read | split_pcie_dfe_write | {CHANNELS{pcie_dfe_avmm_lock}};

/**********************************************************************/
// AVMM Arbiter.  Instantiated once per channel, however to handle streaming
// broadcast, the channel-wise instantiation is handled within the arbiter.
/**********************************************************************/
generate if (ENABLED_JTAG_MASTERS > 1) begin: g_arbiber_enable
    alt_xcvr_native_rcfg_arb #(
      .total_masters                                 ( 5                         ),
      .channels                                      ( CHANNELS                  ),
      .address_width                                 ( ADDR_BITS                 ),
      .data_width                                    ( DATA_WIDTH                )
    ) alt_xcvr_rcfg_arb (
      // Basic AVMM inputs 
      .reconfig_clk                                  ( avmm_clk                        ), 
      .reconfig_reset                                ( avmm_reset                      ), 

      // User AVMM input
      .user_read                                     ( split_user_read                 ),
      .user_write                                    ( split_user_write                ),
      .user_address                                  ( split_user_address              ),
      .user_writedata                                ( split_user_writedata            ),
      .user_read_write                               ( user_read_write                 ),
      .user_waitrequest                              ( split_user_waitrequest          ),
     
      // Reconfig Steamer AVMM input
      .strm_read                                     ( rcfg_emb_strm_read              ),
      .strm_write                                    ( rcfg_emb_strm_write             ),
      .strm_address                                  ( rcfg_emb_strm_address           ),
      .strm_writedata                                ( rcfg_emb_strm_writedata         ),
      .strm_read_write                               ( rcfg_emb_strm_read_write        ),
      .strm_waitrequest                              ( rcfg_emb_strm_waitrequest       ),
     
      // ODI AVMM input
      .odi_read                                      ( odi_read                        ),
      .odi_write                                     ( odi_write                       ),
      .odi_address                                   ( odi_address                     ),
      .odi_writedata                                 ( odi_writedata                   ),
      .odi_read_write                                ( odi_read_write                  ),
      .odi_waitrequest                               ( odi_waitrequest                 ),
     
      // ADME AVMM input
      .jtag_read                                     ( split_jtag_read                 ),
      .jtag_write                                    ( split_jtag_write                ),
      .jtag_address                                  ( split_jtag_address              ),
      .jtag_writedata                                ( split_jtag_writedata            ),
      .jtag_read_write                               ( jtag_read_write                 ),
      .jtag_waitrequest                              ( split_jtag_waitrequest          ),

      // PCIe DFE
      .pcie_dfe_read                                 ( split_pcie_dfe_read             ),
      .pcie_dfe_write                                ( split_pcie_dfe_write            ),
      .pcie_dfe_address                              ( split_pcie_dfe_address          ),
      .pcie_dfe_writedata                            ( split_pcie_dfe_writedata        ),
      .pcie_dfe_read_write                           ( pcie_dfe_read_write             ),
      .pcie_dfe_waitrequest                          ( split_pcie_dfe_waitrequest      ),
     
      // AVMM output the channel and the CSR
      .avmm_waitrequest                              ( chnl_waitrequest                ),
      .avmm_read                                     ( chnl_read                       ),
      .avmm_write                                    ( chnl_write                      ),
      .avmm_address                                  ( avmm_address                    ),
      .avmm_writedata                                ( expanded_avmm_writedata         )
    );
  end else begin: g_arbiter_disable
    // Pass through signals
    assign split_user_waitrequest                    = chnl_waitrequest;
    assign chnl_read                                 = split_user_read;
    assign chnl_write                                = split_user_write;
    assign expanded_avmm_writedata                   = split_user_writedata;
    assign avmm_address                              = split_user_address;

  end
endgenerate // End g_arbiter


/**********************************************************************/
// Per Channel instantiations and assignments
/**********************************************************************/
generate for(ig=0;ig<CHANNELS;ig=ig+1) begin: g_optional_chnl_reconfig_logic

wire [CHANNELS-1:0]             csr_prbs_snapshot;
wire [CHANNELS-1:0]             csr_prbs_count_en;
wire [CHANNELS-1:0]             csr_odi_count_en;
wire [CHANNELS-1:0]             csr_odi_snap;
wire [CHANNELS-1:0]             csr_odi_reset;

    /**********************************************************************/
    // Instantiate the Soft CSR
    /**********************************************************************/
    if(dbg_embedded_debug_enable) begin: g_avmm_csr_enabled

      // Instantiate wires as part of generate to avoid warnings about unused wires.
      // AVMM reconfiguration signals for embedded debug
      wire [CHANNELS-1:0]             debug_write;
      wire [CHANNELS-1:0]             debug_read;
      wire [CHANNELS-1:0]             debug_waitrequest;
      wire [CHANNELS*8-1:0]           debug_readdata;
      
      // avmm arbitration for soft csr and channel
      assign debug_read       [ig]      = (avmm_address[ig*ADDR_BITS+9]) ? chnl_read          [ig]      : 1'b0;
      assign debug_write      [ig]      = (avmm_address[ig*ADDR_BITS+9]) ? chnl_write         [ig]      : 1'b0;
      assign avmm_read        [ig]      = (avmm_address[ig*ADDR_BITS+9]) ? 1'b0                         : chnl_read         [ig];
      assign avmm_write       [ig]      = (avmm_address[ig*ADDR_BITS+9]) ? 1'b0                         : chnl_write        [ig];
      assign chnl_waitrequest [ig]      = (avmm_address[ig*ADDR_BITS+9]) ? debug_waitrequest  [ig]      : avmm_waitrequest  [ig];
      assign chnl_readdata    [ig*8+:8] = (avmm_address[ig*ADDR_BITS+9]) ? debug_readdata     [ig*8+:8] : avmm_readdata     [ig*8+:8];


      alt_xcvr_native_avmm_csr #(
        .channels                            ( CHANNELS                            ),
        .channel_num                         ( ig                                  ),
        .dbg_user_identifier                 ( dbg_user_identifier                 ),
        .duplex_mode                         ( duplex_mode                         ),
        .dbg_capability_reg_enable           ( dbg_capability_reg_enable           ),
        .dbg_prbs_soft_logic_enable          ( dbg_prbs_soft_logic_enable          ),
        .dbg_odi_soft_logic_enable           ( dbg_odi_soft_logic_enable           ),
        .dbg_stat_soft_logic_enable          ( dbg_stat_soft_logic_enable          ),
        .dbg_ctrl_soft_logic_enable          ( dbg_ctrl_soft_logic_enable          ),
        .rcfg_emb_strm_enable                ( RCFG_EMB_STRM_ENABLED               ),
        .rcfg_emb_strm_cfg_sel_width         ( RCFG_EMB_STRM_CFG_SEL_WIDTH         )
      ) embedded_debug_soft_csr (
        // avmm signals
        .avmm_clk                            ( avmm_clk                 [ig]       ),
        .avmm_reset                          ( avmm_reset               [ig]       ),
        .avmm_address                        ( avmm_address      [ig*ADDR_BITS+:9] ),
        .avmm_writedata                      ( avmm_writedata           [ig*8+:8]  ),
        .avmm_write                          ( debug_write              [ig]       ),
        .avmm_read                           ( debug_read               [ig]       ),
        .avmm_readdata                       ( debug_readdata           [ig*8+:8]  ),
        .avmm_waitrequest                    ( debug_waitrequest        [ig]       ),

        // prbs control signals
        .prbs_err                            ( prbs_err_count           [ig*50+:50]),
        .prbs_bit                            ( prbs_bit_count           [ig*50+:50]),
        .prbs_done                           ( prbs_done_sync           [ig]       ),
        .prbs_snap                           ( csr_prbs_snapshot        [ig]       ),
        .prbs_count_en                       ( csr_prbs_count_en        [ig]       ),
        .prbs_reset                          ( out_prbs_err_clr         [ig]       ),

        // odi ctrl signals
        .odi_bit                             ( odi_bit_count            [ig*50+:50]),
        .odi_err                             ( odi_err_count            [ig*50+:50]),
        .odi_done                            ( odi_done                 [ig]       ),
        .odi_count_en                        ( csr_odi_count_en         [ig]       ),
        .odi_reset                           ( csr_odi_reset            [ig]       ),               
        .odi_snap                            ( csr_odi_snap             [ig]       ),

        // input status signals from the channel
        .rx_is_lockedtodata                  ( in_rx_is_lockedtodata    [ig]       ),
        .rx_is_lockedtoref                   ( in_rx_is_lockedtoref     [ig]       ),
        .tx_cal_busy                         ( in_tx_cal_busy           [ig]       ),
        .rx_cal_busy                         ( in_rx_cal_busy           [ig]       ),
        .avmm_busy                           ( in_avmm_busy             [ig]       ),

        // input control signals
        .rx_prbs_err_clr                     ( in_rx_prbs_err_clr       [ig]       ),
        .set_rx_locktoref                    ( in_set_rx_locktoref      [ig]       ),
        .set_rx_locktodata                   ( in_set_rx_locktodata     [ig]       ),
        .serial_loopback                     ( in_en_serial_lpbk        [ig]       ),
        .rx_analogreset                      ( in_rx_analogreset        [ig]       ),
        .rx_digitalreset                     ( in_rx_digitalreset       [ig]       ),
        .tx_analogreset                      ( in_tx_analogreset        [ig]       ),
        .tx_digitalreset                     ( in_tx_digitalreset       [ig]       ),
        
        // embedded reconfig signals
        .rcfg_emb_strm_busy                  ( rcfg_emb_strm_busy       [ig]       ),
        .rcfg_emb_strm_chan_sel              ( rcfg_emb_strm_chan_sel   [ig]       ),
        .rcfg_emb_strm_cfg_sel               ( rcfg_emb_strm_cfg_sel    [ig*RCFG_EMB_STRM_CFG_SEL_WIDTH+:RCFG_EMB_STRM_CFG_SEL_WIDTH]),
        .rcfg_emb_strm_bcast_en              ( rcfg_emb_strm_bcast_en   [ig]       ),
        .rcfg_emb_strm_cfg_load              ( rcfg_emb_strm_cfg_load   [ig]       ),


        // output control signals to the channel
        .csr_set_lock_to_data                ( out_set_rx_locktodata    [ig]       ),
        .csr_set_lock_to_ref                 ( out_set_rx_locktoref     [ig]       ),
        .csr_en_loopback                     ( out_en_serial_lpbk       [ig]       ),
        .csr_rx_analogreset                  ( out_rx_analogreset       [ig]       ),
        .csr_rx_digitalreset                 ( out_rx_digitalreset      [ig]       ),
        .csr_tx_analogreset                  ( out_tx_analogreset       [ig]       ),
        .csr_tx_digitalreset                 ( out_tx_digitalreset      [ig]       ),
        .csr_tx_cal_busy_mask                ( out_tx_cal_busy_mask     [ig]       ),
        .csr_rx_cal_busy_mask                ( out_rx_cal_busy_mask     [ig]       )
      );

    end else begin: g_avmm_csr_disable
      // do a pass though for control signals when no embedded debug
      assign out_prbs_err_clr       [ig]  = in_rx_prbs_err_clr     [ig];
      assign out_set_rx_locktoref   [ig]  = in_set_rx_locktoref    [ig];
      assign out_set_rx_locktodata  [ig]  = in_set_rx_locktodata   [ig];
      assign out_en_serial_lpbk     [ig]  = in_en_serial_lpbk      [ig];
      assign out_rx_analogreset     [ig]  = in_rx_analogreset      [ig];
      assign out_rx_digitalreset    [ig]  = in_rx_digitalreset     [ig];
      assign out_tx_analogreset     [ig]  = in_tx_analogreset      [ig];
      assign out_tx_digitalreset    [ig]  = in_tx_digitalreset     [ig];
      assign out_tx_cal_busy_mask   [ig]  = 1'b1;
      assign out_rx_cal_busy_mask   [ig]  = 1'b1;

      // assign these signals to ground when no embedded debug
      assign avmm_read        [ig]        = chnl_read              [ig];
      assign avmm_write       [ig]        = chnl_write             [ig];
      assign chnl_waitrequest [ig]        = avmm_waitrequest       [ig];  
      assign chnl_readdata    [ig*8+:8]   = avmm_readdata          [ig*8+:8];
    end


    /**********************************************************************/
    // Instantiate the PRBS accumulators
    /**********************************************************************/
    if(dbg_prbs_soft_logic_enable == 1) begin: g_prbs_accumulators_enable
      alt_xcvr_native_prbs_accum prbs_soft_accumulators (
        .avmm_clk                            ( avmm_clk           [ig]             ),
        .avmm_reset                          ( avmm_reset         [ig]             ),

        // Control signals from CSR
        .prbs_reset                          ( out_prbs_err_clr   [ig]             ),
        .prbs_snapshot                       ( csr_prbs_snapshot  [ig]             ),
        .prbs_counter_en                     ( csr_prbs_count_en  [ig]             ),

        // Status signals from PRBS
        .prbs_done_sync                      ( prbs_done_sync     [ig]             ),
        .prbs_err_count                      ( prbs_err_count     [ig*50+:50]      ),
        .prbs_bit_count                      ( prbs_bit_count     [ig*50+:50]      ),

        // Signals from the transceiver
        .rx_clkout                           ( in_rx_clkout       [ig]             ),
        .prbs_err_signal                     ( prbs_err_signal    [ig]             ),
        .prbs_done_signal                    ( prbs_done_signal   [ig]             )
      );

    // If PRBS is not enabled
    end else begin: g_prbs_accumulators_disable
      assign prbs_err_count[ig*50+:50]   = 50'b0;
      assign prbs_bit_count[ig*50+:50]   = 50'b0;
      assign prbs_done_sync[ig]          = 1'b0;
    end // End g_prbs_accumulators


    /**********************************************************************/
    // Instantiate the ODI accumulators
    /**********************************************************************/
    if(dbg_odi_soft_logic_enable == 1) begin: g_odi_accelerator_enable
      alt_xcvr_native_odi_accel #(
        .DATA_WIDTH                          ( DATA_WIDTH                          )
      ) odi_soft_accelerator (
        .avmm_clk                            ( avmm_clk          [ig]              ),
        .avmm_reset                          ( avmm_reset        [ig]              ),
        
        // AVMM signals to the transceiver
        .odi_read                            ( odi_read          [ig]              ),
        .odi_write                           ( odi_write         [ig]              ),
        .odi_address                         ( odi_address       [ig*ADDR_BITS+:ADDR_BITS] ),
        .odi_writedata                       ( odi_writedata     [ig*DATA_WIDTH+:DATA_WIDTH]),
        .odi_readdata                        ( avmm_readdata     [ig*8+:8]         ),
        .odi_waitrequest                     ( odi_waitrequest   [ig]              ),

        // Control signals from CSR
        .odi_count_en                        ( csr_odi_count_en  [ig]              ),
        .odi_snap                            ( csr_odi_snap      [ig]              ),
        .odi_reset                           ( csr_odi_reset     [ig]              ),

        // Status signals from ODI
        .odi_done                            ( odi_done          [ig]              ),
        .odi_bit_count                       ( odi_bit_count     [ig*50+:50]       ),
        .odi_err_count                       ( odi_err_count     [ig*50+:50]       )
      );

    end else begin: g_odi_accelerator_disable
      assign odi_read[ig]                             = 1'b0;
      assign odi_write[ig]                            = 1'b0;
      assign odi_done[ig]                             = 1'b0;
      assign odi_bit_count[ig*50+:50]                 = 50'b0;
      assign odi_err_count[ig*50+:50]                 = 50'b0;
      assign odi_address[ig*ADDR_BITS+:ADDR_BITS]     = {ADDR_BITS{1'b0}};
      assign odi_writedata[ig*DATA_WIDTH+:DATA_WIDTH] = {DATA_WIDTH{1'b0}};
    end // End g_odi_accelerator

  end // End for Loop for channels
endgenerate

endmodule

