library ieee;
use ieee.std_logic_1164.all;

use work.phy_pkg.all;
use work.wishbone_pkg.all;
use work.wr_fabric_pkg.all;
use work.endpoint_pkg.all;
use work.genram_pkg.all;

entity minic_ep_combo is
  generic(
    g_memsize_log2 : integer := 14
    );
  port(
    clk_sys_i : in std_logic;
    clk_ref_i : in std_logic;

    rst_n_i : in std_logic;

    phy_o : out t_phy_in;
    phy_i : in  t_phy_out;

    slave_i : in  t_wishbone_slave_in;
    slave_o : out t_wishbone_slave_out
    );

end minic_ep_combo;

architecture struct of minic_ep_combo is

  component xwr_mini_nic
    generic (
      g_interface_mode       : t_wishbone_interface_mode;
      g_address_granularity  : t_wishbone_address_granularity;
      g_memsize_log2         : integer;
      g_buffer_little_endian : boolean);
    port (
      clk_sys_i           : in  std_logic;
      rst_n_i             : in  std_logic;
      mem_data_o          : out std_logic_vector(31 downto 0);
      mem_addr_o          : out std_logic_vector(g_memsize_log2-1 downto 0);
      mem_data_i          : in  std_logic_vector(31 downto 0);
      mem_wr_o            : out std_logic;
      src_o               : out t_wrf_source_out;
      src_i               : in  t_wrf_source_in;
      snk_o               : out t_wrf_sink_out;
      snk_i               : in  t_wrf_sink_in;
      txtsu_port_id_i     : in  std_logic_vector(4 downto 0);
      txtsu_frame_id_i    : in  std_logic_vector(16 - 1 downto 0);
      txtsu_tsval_i       : in  std_logic_vector(28 + 4 - 1 downto 0);
      txtsu_tsincorrect_i : in  std_logic;
      txtsu_stb_i         : in  std_logic;
      txtsu_ack_o         : out std_logic;
      wb_i                : in  t_wishbone_slave_in;
      wb_o                : out t_wishbone_slave_out);
  end component;
  
  signal ep_src_out : t_wrf_source_out;
  signal ep_src_in  : t_wrf_source_in;
  signal ep_snk_out : t_wrf_sink_out;
  signal ep_snk_in  : t_wrf_sink_in;

  constant c_NUM_WB_SLAVES : integer := 3;

  constant c_SLAVE_ENDPOINT : integer := 2;
  constant c_SLAVE_MINIC     : integer := 1;
  constant c_SLAVE_BUF       : integer := 0;

  constant c_cnx_base_addr : t_wishbone_address_array(c_NUM_WB_SLAVES-1 downto 0) :=
    (
      x"00000000",
      x"00008000",
      x"00010000" 
      );         

  constant c_cnx_base_mask : t_wishbone_address_array(c_NUM_WB_SLAVES-1 downto 0) :=
    (x"00018000",
     x"00018000",
     x"00018000");

  signal cnx_master_in  : t_wishbone_master_in_array(c_NUM_WB_SLAVES-1 downto 0);
  signal cnx_master_out : t_wishbone_master_out_array(c_NUM_WB_SLAVES-1 downto 0);

  signal mem_data_out : std_logic_vector(31 downto 0);
  signal mem_addr_out : std_logic_vector(g_memsize_log2-1 downto 0);
  signal mem_data_in  : std_logic_vector(31 downto 0);
  signal mem_wr       : std_logic;
  signal host_we      : std_logic;
begin  -- struct

  U_Intercon : xwb_crossbar
    generic map (
      g_num_masters => 1,
      g_num_slaves  => c_NUM_WB_SLAVES,
      g_registered  => true,
      g_address     => c_cnx_base_addr,
      g_mask        => c_cnx_base_mask)
    port map (
      clk_sys_i  => clk_sys_i,
      rst_n_i    => rst_n_i,
      slave_i(0) => slave_i,
      slave_o(0) => slave_o,
      master_i   => cnx_master_in,
      master_o   => cnx_master_out);


  
  U_Minic : xwr_mini_nic
    generic map (
      g_interface_mode       => PIPELINED,
      g_address_granularity  => BYTE,
      g_memsize_log2         => g_memsize_log2,
      g_buffer_little_endian => true)
    port map (
      clk_sys_i           => clk_sys_i,
      rst_n_i             => rst_n_i,
      mem_data_o          => mem_data_out,
      mem_addr_o          => mem_addr_out,
      mem_data_i          => mem_data_in,
      mem_wr_o            => mem_wr,
      src_o               => ep_snk_in,
      src_i               => ep_snk_out,
      snk_o               => ep_src_in,
      snk_i               => ep_src_out,
      txtsu_port_id_i     => "00000",
      txtsu_frame_id_i    => x"0000",
      txtsu_tsval_i       => x"00000000",
      txtsu_tsincorrect_i => '0',
      txtsu_stb_i         => '0',
      wb_i                => cnx_master_out(c_SLAVE_MINIC),
      wb_o                => cnx_master_in(c_SLAVE_MINIC));

  U_Endpoint : xwr_endpoint
    generic map (
      g_interface_mode      => PIPELINED,
      g_address_granularity => BYTE,
      g_simulation          => false,
      g_tx_force_gap_length => 0,
      g_pcs_16bit           => false,
      g_rx_buffer_size      => 1024,
      g_with_rx_buffer      => true,
      g_with_flow_control   => false,
      g_with_timestamper    => true,
      g_with_dpi_classifier => false,
      g_with_vlans          => false,
      g_with_rtu            => false,
      g_with_leds           => false,
      g_with_dmtd           => false)
    port map (
      clk_ref_i          => clk_ref_i,
      clk_sys_i          => clk_sys_i,
      clk_dmtd_i         => clk_ref_i,
      rst_n_i            => rst_n_i,
      pps_csync_p1_i     => '0',
      pps_valid_i        => '0',
      phy_rst_o          => phy_o.rst,
      phy_loopen_o       => phy_o.loopen,
      phy_ref_clk_i      => clk_ref_i,
      phy_tx_data_o      => phy_o.tx_d,
      phy_tx_k_o         => phy_o.tx_k,
      phy_tx_disparity_i => phy_i.tx_disparity,
      phy_tx_enc_err_i   => phy_i.tx_error,
      phy_rx_data_i      => phy_i.rx_d,
      phy_rx_clk_i       => phy_i.rx_clk,
      phy_rx_k_i         => phy_i.rx_k,
      phy_rx_enc_err_i   => phy_i.rx_error,
      phy_rx_bitslide_i  => phy_i.rx_bitslide,

      src_o => ep_src_out,
      src_i => ep_src_in,
      snk_o => ep_snk_out,
      snk_i => ep_snk_in,

      wb_i => cnx_master_out(c_SLAVE_ENDPOINT),
      wb_o => cnx_master_in(c_SLAVE_ENDPOINT));

  U_RAM : generic_dpram
    generic map (
      g_data_width       => 32,
      g_size             => 2**g_memsize_log2,
      g_with_byte_enable => false,
      g_dual_clock       => false)
    port map (
      rst_n_i => rst_n_i,
      clka_i  => clk_sys_i,
      bwea_i  => "0000",
      wea_i   => host_we,
      aa_i    => cnx_master_out(c_SLAVE_BUF).adr(g_memsize_log2+1 downto 2),
      da_i    => cnx_master_out(c_SLAVE_BUF).dat,
      qa_o    => cnx_master_in(c_SLAVE_BUF).dat,
      clkb_i  => clk_sys_i,
      bweb_i  => "0000",
      web_i   => mem_wr,
      ab_i    => mem_addr_out,
      db_i    => mem_data_out,
      qb_o    => mem_data_in);

  host_we <= cnx_master_out(c_SLAVE_BUF).cyc and cnx_master_out(c_SLAVE_BUF).stb and cnx_master_out(c_SLAVE_BUF).we;

  cnx_master_in(c_SLAVE_BUF).stall <= '0';
  cnx_master_in(c_SLAVE_BUF).err   <= '0';
  cnx_master_in(c_SLAVE_BUF).rty   <= '0';

  p_gen_ack : process(clk_sys_i)
  begin
    if rising_edge(clk_sys_i) then
      cnx_master_in(c_SLAVE_BUF).ack <= cnx_master_out(c_SLAVE_BUF).cyc and cnx_master_out(c_SLAVE_BUF).stb;
    end if;
  end process;
  

  
end struct;
