//
// Copyright 2018 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: n3xx_mgt_channel_wrapper
//
// Description:
//
//   Aurora/10 GbE wrapper for up to 4 QSFP lanes  -or-
//   Aurora/1 GbE/10 GbE/White Rabbit wrapper for 1 SFP+ lane
//
// Parameters:
//
//   PROTOCOL         : Must be {10GbE, Aurora, Disabled}
//   LANES            : Number of lanes of to instantiate (1, 2, 3, or 4)
//   REG_BASE         : Base register address
//   PORTNUM_BASE     : Base port number for discovery
//   MDIO_EN          : Enable MDIO port
//   MDIO_PHYADDR     : MDIO address to use
//   REG_DWIDTH       : Width of regport address bus
//   REG_AWIDTH       : Width of regport data bus
//   GT_COMMON        : Use GT Common ports on MGT
//   BYTE_MTU         : Log base 2 of the MTU size in bytes
//   RFNOC_PROTOVER   : RFNoC protocol version to be reported by transport
//                      adapters.
//   NODE_INST        : RFNoC transport adapter node instance for this port
//

`default_nettype none
module n3xx_mgt_channel_wrapper #(
  parameter        PROTOCOL         = "10GbE",
  parameter        LANES            = 2,
  parameter        REG_BASE         = 32'h0,
  parameter        PORTNUM_BASE     = 4,
  parameter        MDIO_EN          = 1,
  parameter [ 4:0] MDIO_PHYADDR     = 5'd0,
  parameter        REG_DWIDTH       = 32,
  parameter        REG_AWIDTH       = 14,
  parameter        GT_COMMON        = 1,
  parameter        BYTE_MTU         = $clog2(8192),
  parameter [15:0] RFNOC_PROTOVER   = {8'd1, 8'd0},
  parameter        NODE_INST_BASE   = 0
)(
  // Resets
  input  wire                    areset,
  input  wire                    bus_rst,

  // Clocks
  input  wire                    gt_refclk,
  input  wire                    gb_refclk,
  input  wire                    misc_clk,
  input  wire                    bus_clk,
  input  wire                    user_clk,
  input  wire                    sync_clk,

  //Axi-lite
  input  wire                    s_axi_aclk,
  input  wire                    s_axi_aresetn,
  input  wire [REG_AWIDTH-1:0]   s_axi_awaddr,
  input  wire                    s_axi_awvalid,
  output wire                    s_axi_awready,

  input  wire [REG_DWIDTH-1:0]   s_axi_wdata,
  input  wire [REG_DWIDTH/8-1:0] s_axi_wstrb,
  input  wire                    s_axi_wvalid,
  output wire                    s_axi_wready,

  output wire [1:0]              s_axi_bresp,
  output wire                    s_axi_bvalid,
  input  wire                    s_axi_bready,

  input  wire [REG_AWIDTH-1:0]   s_axi_araddr,
  input  wire                    s_axi_arvalid,
  output wire                    s_axi_arready,

  output wire [REG_DWIDTH-1:0]   s_axi_rdata,
  output wire [1:0]              s_axi_rresp,
  output wire                    s_axi_rvalid,
  input  wire                    s_axi_rready,

  // Serial lanes (high-speed IO)
  output wire [LANES-1:0]        txp,
  output wire [LANES-1:0]        txn,
  input  wire [LANES-1:0]        rxp,
  input  wire [LANES-1:0]        rxn,

  // Low-speed IO (QSFP+ and SFP+ module signals)
  input  wire                    mod_present_n,
  input  wire                    mod_rxlos,
  input  wire                    mod_tx_fault,
  output wire                    mod_tx_disable,
  input  wire                    mod_reset_n,
  input  wire                    mod_int_n,
  output wire                    mod_lpmode,
  output wire                    mod_sel_n,

  // Timebase Outputs
  output wire                    mod_pps,
  output wire                    mod_refclk,

  // GT Common
  output wire                    qpllreset,
  input  wire                    qplllock,
  input  wire                    qplloutclk,
  input  wire                    qplloutrefclk,
  input  wire                    qpllrefclklost,

  // Aurora MMCM
  input  wire                    mmcm_locked,
  output wire                    gt_pll_lock,
  output wire                    gt_tx_out_clk_unbuf,

  // AXIS output interface
  output wire [(LANES*64)-1:0]   e2v_tdata,
  output wire [LANES-1:0]        e2v_tlast,
  output wire [LANES-1:0]        e2v_tvalid,
  input  wire [LANES-1:0]        e2v_tready,
  // AXIS input interface
  input  wire [(LANES*64)-1:0]   v2e_tdata,
  input  wire [LANES-1:0]        v2e_tlast,
  input  wire [LANES-1:0]        v2e_tvalid,
  output wire [LANES-1:0]        v2e_tready,

  // CPU
  output wire [LANES*64-1:0]     e2c_tdata,
  output wire [LANES*8-1:0]      e2c_tkeep,
  output wire [LANES-1:0]        e2c_tlast,
  output wire [LANES-1:0]        e2c_tvalid,
  input  wire [LANES-1:0]        e2c_tready,

  input  wire [LANES*64-1:0]     c2e_tdata,
  input  wire [LANES*8-1:0]      c2e_tkeep,
  input  wire [LANES-1:0]        c2e_tlast,
  input  wire [LANES-1:0]        c2e_tvalid,
  output wire [LANES-1:0]        c2e_tready,

  // MISC
  output wire [LANES*32-1:0]     port_info,
  input wire [15:0]              device_id,

  // Sideband White Rabbit Control
  input  wire                    wr_reset_n,
  input  wire                    wr_refclk,

  output wire                    wr_dac_sclk,
  output wire                    wr_dac_din,
  output wire                    wr_dac_clr_n,
  output wire                    wr_dac_cs_n,
  output wire                    wr_dac_ldac_n,

  output wire                    wr_eeprom_scl_o,
  input  wire                    wr_eeprom_scl_i,
  output wire                    wr_eeprom_sda_o,
  input  wire                    wr_eeprom_sda_i,

  input  wire                    wr_uart_rx,
  output wire                    wr_uart_tx,

  // WR AXI Control
  output wire                    wr_axi_aclk,
  input  wire                    wr_axi_aresetn,
  input  wire [31:0]             wr_axi_awaddr,
  input  wire                    wr_axi_awvalid,
  output wire                    wr_axi_awready,
  input  wire [REG_DWIDTH-1:0]   wr_axi_wdata,
  input  wire [REG_DWIDTH/8-1:0] wr_axi_wstrb,
  input  wire                    wr_axi_wvalid,
  output wire                    wr_axi_wready,
  output wire [1:0]              wr_axi_bresp,
  output wire                    wr_axi_bvalid,
  input  wire                    wr_axi_bready,
  input  wire [31:0]             wr_axi_araddr,
  input  wire                    wr_axi_arvalid,
  output wire                    wr_axi_arready,
  output wire [REG_DWIDTH-1:0]   wr_axi_rdata,
  output wire [1:0]              wr_axi_rresp,
  output wire                    wr_axi_rvalid,
  input  wire                    wr_axi_rready,
  output wire                    wr_axi_rlast,

  output wire [LANES-1:0]        link_up,
  output wire [LANES-1:0]        activity
);

  //--------------------------------------------------------------
  // QSFP module I/O
  //--------------------------------------------------------------
  assign mod_reset_n  = 1'b1;
  assign mod_sel_n = 1'b0;
  assign mod_lpmode   = 1'b0;

  //--------------------------------------------------------------
  // Common clocking
  //--------------------------------------------------------------

  wire [LANES-1:0]  qpllreset_ln;
  wire [LANES-1:0]  gt_tx_out_clk;
  wire [LANES-1:0]  gt_pll_lock_ln;

  assign qpllreset = |qpllreset_ln;
  assign gt_tx_out_clk_unbuf = gt_tx_out_clk[0];
  assign gt_pll_lock = gt_pll_lock_ln[0];

  //--------------------------------------------------------------
  // Register bus
  //--------------------------------------------------------------
  localparam REG_BLOCK_SIZE = 20'h4000;

  // AXI4-Lite to RegPort (PS to PL Register Access)
  wire                    reg_wr_req;
  wire  [REG_AWIDTH-1:0]  reg_wr_addr;
  wire  [REG_DWIDTH-1:0]  reg_wr_data;
  wire                    reg_rd_req;
  wire  [REG_AWIDTH-1:0]  reg_rd_addr;
  wire                    reg_rd_resp;
  wire  [REG_DWIDTH-1:0]  reg_rd_data;

  axil_regport_master #(
    .DWIDTH         (REG_DWIDTH),   // Width of the AXI4-Lite data bus (must be 32 or 64)
    .AWIDTH         (REG_AWIDTH),   // Width of the address bus
    .WRBASE         (0),        // Write address base
    .RDBASE         (0),        // Read address base
    .TIMEOUT        (10)        // log2(timeout). Read will timeout after (2^TIMEOUT - 1) cycles
  ) mgt_reg_mst_i (
    // Clock and reset
    .s_axi_aclk     (s_axi_aclk),
    .s_axi_aresetn  (s_axi_aresetn),
    // AXI4-Lite: Write address port (domain: s_axi_aclk)
    .s_axi_awaddr   (s_axi_awaddr),
    .s_axi_awvalid  (s_axi_awvalid),
    .s_axi_awready  (s_axi_awready),
    // AXI4-Lite: Write data port (domain: s_axi_aclk)
    .s_axi_wdata    (s_axi_wdata),
    .s_axi_wstrb    (s_axi_wstrb),
    .s_axi_wvalid   (s_axi_wvalid),
    .s_axi_wready   (s_axi_wready),
    // AXI4-Lite: Write response port (domain: s_axi_aclk)
    .s_axi_bresp    (s_axi_bresp),
    .s_axi_bvalid   (s_axi_bvalid),
    .s_axi_bready   (s_axi_bready),
    // AXI4-Lite: Read address port (domain: s_axi_aclk)
    .s_axi_araddr   (s_axi_araddr),
    .s_axi_arvalid  (s_axi_arvalid),
    .s_axi_arready  (s_axi_arready),
    // AXI4-Lite: Read data port (domain: s_axi_aclk)
    .s_axi_rdata    (s_axi_rdata),
    .s_axi_rresp    (s_axi_rresp),
    .s_axi_rvalid   (s_axi_rvalid),
    .s_axi_rready   (s_axi_rready),
    // Register port: Write port (domain: reg_clk)
    .reg_clk        (bus_clk),
    .reg_wr_req     (reg_wr_req),
    .reg_wr_addr    (reg_wr_addr),
    .reg_wr_data    (reg_wr_data),
    .reg_wr_keep    (/*unused*/),
    // Register port: Read port (domain: reg_clk)
    .reg_rd_req     (reg_rd_req),
    .reg_rd_addr    (reg_rd_addr),
    .reg_rd_resp    (reg_rd_resp),
    .reg_rd_data    (reg_rd_data)
  );

  wire [LANES-1:0]      reg_rd_resp_flat;
  wire [(LANES*REG_DWIDTH)-1:0] reg_rd_data_flat;
  wire [LANES-1:0]      mod_pps_flat;
  wire [LANES-1:0]      mod_refclk_flat;

  // NOTE: Connecting WR signals of first lane only
  assign mod_pps = mod_pps_flat[0];
  assign mod_refclk = mod_refclk_flat[0];

  regport_resp_mux #(
    .WIDTH      (REG_DWIDTH),
    .NUM_SLAVES (LANES)
  ) reg_resp_mux_i(
    .clk(bus_clk), .reset(bus_rst),
    .sla_rd_resp(reg_rd_resp_flat), .sla_rd_data(reg_rd_data_flat),
    .mst_rd_resp(reg_rd_resp), .mst_rd_data(reg_rd_data)
  );

  //--------------------------------------------------------------
  // Lanes
  //--------------------------------------------------------------

  genvar l;
  generate
    for (l = 0; l < LANES; l = l + 1) begin: lanes
      n3xx_mgt_wrapper #(
        .PROTOCOL         (PROTOCOL),
        .REG_BASE         (REG_BASE + (REG_BLOCK_SIZE * l)),
        .REG_DWIDTH       (REG_DWIDTH),   // Width of the AXI4-Lite data bus (must be 32 or 64)
        .REG_AWIDTH       (REG_AWIDTH),   // Width of the address bus
        .GT_COMMON        (GT_COMMON),
        .MDIO_EN          (MDIO_EN),
        .MDIO_PHYADDR     (MDIO_PHYADDR),
        .BYTE_MTU         (BYTE_MTU),
        .RFNOC_PROTOVER   (RFNOC_PROTOVER),
        .PORTNUM          (PORTNUM_BASE + l),
        .NODE_INST        (NODE_INST_BASE + l)
      ) lane_i (
        //must reset all channels on quad when sfp1 gtx core is reset
        .areset         (areset),
        .gt_refclk      (gt_refclk),
        .gb_refclk      (gb_refclk),
        .misc_clk       (misc_clk),
        .user_clk       (user_clk),
        .sync_clk       (sync_clk),

        .bus_rst        (bus_rst),
        .bus_clk        (bus_clk),

        //RegPort
        .reg_wr_req     (reg_wr_req),
        .reg_wr_addr    (reg_wr_addr),
        .reg_wr_data    (reg_wr_data),
        .reg_rd_req     (reg_rd_req),
        .reg_rd_addr    (reg_rd_addr),
        .reg_rd_resp    (reg_rd_resp_flat[l]),
        .reg_rd_data    (reg_rd_data_flat[l*REG_DWIDTH +: REG_DWIDTH]),

        .txp            (txp[l]),
        .txn            (txn[l]),
        .rxp            (rxp[l]),
        .rxn            (rxn[l]),

        .mod_present_n  (mod_present_n),
        .mod_rxlos      (mod_rxlos),
        .mod_tx_fault   (mod_tx_fault),
        .mod_tx_disable (mod_tx_disable),

        .qpllrefclklost (qpllrefclklost),
        .qplllock       (qplllock),
        .qplloutclk     (qplloutclk),
        .qplloutrefclk  (qplloutrefclk),
        .qpllreset      (qpllreset_ln[l]),

        .mmcm_locked    (mmcm_locked),
        .gt_pll_lock    (gt_pll_lock_ln[l]),
        .gt_tx_out_clk_unbuf(gt_tx_out_clk[l]),

        // Vita router interface (Synchronous to bus_clk)
        .e2v_tdata      (e2v_tdata[l*64 +: 64]),
        .e2v_tlast      (e2v_tlast[l]),
        .e2v_tvalid     (e2v_tvalid[l]),
        .e2v_tready     (e2v_tready[l]),

        .v2e_tdata      (v2e_tdata[l*64 +: 64]),
        .v2e_tlast      (v2e_tlast[l]),
        .v2e_tvalid     (v2e_tvalid[l]),
        .v2e_tready     (v2e_tready[l]),

        // CPU
        .e2c_tdata      (e2c_tdata[l*64 +: 64]),
        .e2c_tkeep      (e2c_tkeep[l*8 +: 8]),
        .e2c_tlast      (e2c_tlast[l]),
        .e2c_tvalid     (e2c_tvalid[l]),
        .e2c_tready     (e2c_tready[l]),

        .c2e_tdata      (c2e_tdata[l*64 +: 64]),
        .c2e_tkeep      (c2e_tkeep[l*8 +: 8]),
        .c2e_tlast      (c2e_tlast[l]),
        .c2e_tvalid     (c2e_tvalid[l]),
        .c2e_tready     (c2e_tready[l]),

        .port_info      (port_info[l*32 +: 32]),
        .device_id      (device_id),

        // Timebase Outputs
        .mod_pps(mod_pps_flat[l]),
        .mod_refclk(mod_refclk_flat[l]),

        // Sideband White Rabbit Control
        .wr_reset_n     (wr_reset_n),
        .wr_refclk      (wr_refclk),

        .wr_dac_sclk    (wr_dac_sclk),
        .wr_dac_din     (wr_dac_din),
        .wr_dac_clr_n   (wr_dac_clr_n),
        .wr_dac_cs_n    (wr_dac_cs_n),
        .wr_dac_ldac_n  (wr_dac_ldac_n),

        .wr_eeprom_scl_o(wr_eeprom_scl_o),
        .wr_eeprom_scl_i(wr_eeprom_scl_i),
        .wr_eeprom_sda_o(wr_eeprom_sda_o),
        .wr_eeprom_sda_i(wr_eeprom_sda_o),

        .wr_uart_rx     (wr_uart_rx),
        .wr_uart_tx     (wr_uart_tx),

        // WR AXI Control
        .wr_axi_aclk    (wr_axi_aclk),
        .wr_axi_aresetn (wr_axi_aresetn),
        .wr_axi_awaddr  (wr_axi_awaddr),
        .wr_axi_awvalid (wr_axi_awvalid),
        .wr_axi_awready (wr_axi_awready),
        .wr_axi_wdata   (wr_axi_wdata),
        .wr_axi_wstrb   (wr_axi_wstrb),
        .wr_axi_wvalid  (wr_axi_wvalid),
        .wr_axi_wready  (wr_axi_wready),
        .wr_axi_bresp   (wr_axi_bresp),
        .wr_axi_bvalid  (wr_axi_bvalid),
        .wr_axi_bready  (wr_axi_bready),
        .wr_axi_araddr  (wr_axi_araddr),
        .wr_axi_arvalid (wr_axi_arvalid),
        .wr_axi_arready (wr_axi_arready),
        .wr_axi_rdata   (wr_axi_rdata),
        .wr_axi_rresp   (wr_axi_rresp),
        .wr_axi_rvalid  (wr_axi_rvalid),
        .wr_axi_rready  (wr_axi_rready),
        .wr_axi_rlast   (wr_axi_rlast),

        .link_up        (link_up[l]),
        .activity       (activity[l])
      );
    end
  endgenerate

endmodule
`default_nettype wire
