----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 01/28/2020 02:01:43 PM
-- Design Name: 
-- Module Name: udp_registers_sim - Behavioral
-- Project Name: 
-- Target Devices: 
-- Tool Versions: 
-- Description: 
-- 
-- Dependencies: 
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- 
----------------------------------------------------------------------------------


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity rdma_adc_app_sim is
--  Port ( );
end;

architecture Behavioral of rdma_adc_app_sim is
   signal clk        : std_logic := '0';
   signal data_clk        : std_logic := '0';
   signal reset      : std_logic := '1';
   
   constant LC_HOST_MAC       : std_logic_vector(47 downto 0) := x"111111111111";
   constant LC_HOST_IP        : std_logic_vector(31 downto 0) := x"22222222";
   constant LC_HOST_NET_MASK  : std_logic_vector(31 downto 0) := x"33333333";
   constant LC_RX_SRC_UDP     : std_logic_vector(15 downto 0) := x"4444";
   constant LC_RX_SRC_IP      : std_logic_vector(31 downto 0) := x"55555555";
   constant LC_RX_SRC_MAC     : std_logic_vector(47 downto 0) := x"666666666666";
   constant LC_DATA_CNT       : std_logic_vector(63 downto 0) := x"0000000000000001";
   
   signal packet_length       : std_logic_vector(15 downto 0);
   
   signal s_axis_tvalid           : std_logic := '0';
   signal s_axis_tready           : std_logic := '0';
   signal s_axis_tlast            : std_logic := '0';
   signal s_axis_tkeep            : std_logic_vector(63 downto 0) := (others => '0');
   signal s_axis_tdata            : std_logic_vector(511 downto 0) := (others => '0');
   
   signal data_axis_tvalid        : std_logic := '0';
   signal data_axis_tready        : std_logic := '0';
   signal data_axis_tlast         : std_logic := '0';
   signal data_axis_tkeep         : std_logic_vector(31 downto 0) := (others => '0');
   signal data_axis_tdata         : std_logic_vector(255 downto 0) := (others => '0');
   
   signal cnt                    : natural := 0;

   -- magic number
   constant LC_MAGIC_NUMBER               : std_logic_vector(27 downto 0) := x"dfc1dfc";
   -- message type
   constant LC_WRITE                      : std_logic_vector(3 downto 0) := "0001";
   constant LC_READ                       : std_logic_vector(3 downto 0) := "0010";
   constant LC_INFO                       : std_logic_vector(3 downto 0) := "0011";
   constant LC_RESP                       : std_logic_vector(3 downto 0) := "0100";
   constant LC_ERR                        : std_logic_vector(3 downto 0) := "1000";
   -- register addresses
   constant LC_REG_DST_IP                 : std_logic_vector(31 downto 0) := x"00000000";
   constant LC_REG_DST_MAC_HIGH           : std_logic_vector(31 downto 0) := x"00000001";
   constant LC_REG_DST_MAC_LOW            : std_logic_vector(31 downto 0) := x"00000002";
   constant LC_REG_DST_UDP                : std_logic_vector(31 downto 0) := x"00000003";
   constant LC_REG_DST_QP                 : std_logic_vector(31 downto 0) := x"00000004";
   constant LC_REG_FIRST_PSN              : std_logic_vector(31 downto 0) := x"00000005";
   constant LC_REG_Q_KEY                  : std_logic_vector(31 downto 0) := x"00000006";
   constant LC_REG_CONTROL                : std_logic_vector(31 downto 0) := x"00000007";
   constant LC_REG_STATUS                 : std_logic_vector(31 downto 0) := x"00000008";
   constant LC_REG_STAT_WORD_CNT_HIGH     : std_logic_vector(31 downto 0) := x"00000009";
   constant LC_REG_STAT_WORD_CNT_LOW      : std_logic_vector(31 downto 0) := x"0000000a";
   constant LC_REG_ID                     : std_logic_vector(31 downto 0) := x"0000000b";
   -- registers default values
   constant LC_REG_DEF_DST_IP             : std_logic_vector(31 downto 0) := x"00000000";
   constant LC_REG_DEF_DST_MAC_HIGH       : std_logic_vector(31 downto 0) := x"00000000";
   constant LC_REG_DEF_DST_MAC_LOW        : std_logic_vector(31 downto 0) := x"00000000";
   constant LC_REG_DEF_DST_UDP            : std_logic_vector(31 downto 0) := x"00000000";
   constant LC_REG_DEF_DST_QP             : std_logic_vector(31 downto 0) := x"00000000";
   constant LC_REG_DEF_FIRST_PSN          : std_logic_vector(31 downto 0) := x"00000000";
   constant LC_REG_DEF_Q_KEY              : std_logic_vector(31 downto 0) := x"00000000";
   constant LC_REG_DEF_CONTROL            : std_logic_vector(31 downto 0) := x"00000000";
   constant LC_REG_DEF_ID                 : std_logic_vector(31 downto 0) := x"dfc0cec0";
   -- error codes
   constant LC_ERR_REG_NOT_EXIST          : std_logic_vector(31 downto 0) := x"00000001";
   constant LC_ERR_OVERFLOW               : std_logic_vector(31 downto 0) := x"00000010";


   signal m_axis_adc_ch0_tvalid  : std_logic;
   signal m_axis_adc_ch0_tready  : std_logic;
   signal m_axis_adc_ch0_tlast   : std_logic;
   signal m_axis_adc_ch0_tkeep   : std_logic_vector(63 downto 0);
   signal m_axis_adc_ch0_tdata   : std_logic_vector(511 downto 0);
  
   signal m_axis_adc_ch1_tvalid  : std_logic;
   signal m_axis_adc_ch1_tready  : std_logic;
   signal m_axis_adc_ch1_tlast   : std_logic;
   signal m_axis_adc_ch1_tkeep   : std_logic_vector(63 downto 0);
   signal m_axis_adc_ch1_tdata   : std_logic_vector(511 downto 0);
   
   constant LC_LAST_CYCLE_TKEEP  : std_logic_vector(31 downto 0) := (others => '1');
   constant LC_DATA_CYCLES       : std_logic_vector(7 downto 0) := (others => '0'); 
   constant LC_PAUSE_CYCLES      : std_logic_vector(63 downto 0) := (others => '0');
  
   signal m_axis_tready           : std_logic := '0'; 
begin
   clk <= not clk after 2ns;
   data_clk <= not data_clk after 1.25ns;
   reset <= '0' after 10ns;
   
   process(CLK) 
      begin 
         if rising_edge(CLK) then
            if reset = '1' then 
               s_axis_tvalid <= '0';                                  
               s_axis_tlast  <= '0';                                  
               s_axis_tkeep  <= (others => '0');  
               s_axis_tdata  <= (others => '0'); 
            else 
               s_axis_tkeep <= (others => '0');  
               s_axis_tdata <= (others => '0');  
               s_axis_tvalid <= '0';                                
               s_axis_tlast  <= '0';  
               if cnt < 5 then 
                  cnt <= cnt + 1;
                  s_axis_tkeep <= (others => '0');  
                  s_axis_tdata <= (others => '0');  
                  s_axis_tvalid <= '0';                                
                  s_axis_tlast  <= '0';  
                  packet_length <= x"0000";
               elsif cnt = 5 then
                  if (s_axis_tvalid and s_axis_tready) = '1' then 
                     cnt <= cnt + 1;
                  else
                     s_axis_tvalid <= '1';                                  
                     s_axis_tlast  <= '1';              
                     -- GET INFO         
--                     packet_length <= x"0004";
--                     s_axis_tkeep(3 downto 0)  <= (others => '1');  
--                     s_axis_tdata(31 downto 0)  <= LC_MAGIC_NUMBER & LC_INFO; 
                     -- WRITE REGISTERS
                     packet_length <= x"0014";
                     s_axis_tkeep(27 downto 0)  <= (others => '1');  
                     s_axis_tdata(223 downto 0)  <= x"0000dfc0" & LC_REG_DST_UDP & x"00000001" & LC_REG_CONTROL & x"01010101" & LC_REG_DST_IP & LC_MAGIC_NUMBER & LC_WRITE; 
                     -- WRITE ERROR REGISTERS
--                     packet_length <= x"0014";
--                     s_axis_tkeep(19 downto 0)  <= (others => '1');  
--                     s_axis_tdata(159 downto 0)  <= x"0000dfcd" & x"ffffffff" & x"ffffffff" & LC_REG_DST_IP & LC_MAGIC_NUMBER & LC_WRITE; 
                     -- READ REGISTERS
                     packet_length <= x"001c";
                  end if;   
               
               elsif cnt < 1000 then
                  cnt <= cnt + 1;
                  s_axis_tkeep <= (others => '0');  
                  s_axis_tdata <= (others => '0');  
                  s_axis_tvalid <= '0';                                
                  s_axis_tlast  <= '0';  
                  packet_length <= x"0000";
               elsif cnt = 1000 then
                  if (s_axis_tvalid and s_axis_tready) = '1' then 
                     cnt <= cnt + 1;
                  else
                     s_axis_tvalid <= '1';                                  
                     s_axis_tlast  <= '1';              
                     -- GET INFO         
                     packet_length <= x"0004";
                     s_axis_tkeep(3 downto 0)  <= (others => '1');  
                     s_axis_tdata(31 downto 0)  <= LC_MAGIC_NUMBER & LC_INFO;
                  end if;               
               elsif cnt < 1200 then
                  cnt <= cnt + 1;
                  s_axis_tkeep <= (others => '0');  
                  s_axis_tdata <= (others => '0');  
                  s_axis_tvalid <= '0';                                
                  s_axis_tlast  <= '0';  
                  packet_length <= x"0000";              
               else 
                  cnt <= 0;
               end if;
            end if;
         end if;
      end process;

   adc_sim_axis_generator_inst: entity work.axis_gen
   generic map (
      g_stream_width       => 256
   )
   port map(
      CLK                  => data_clk,
      RESET                => reset,
      M_AXIS_TVALID        => data_axis_tvalid,
      M_AXIS_TREADY        => '1',--data_axis_tready,
      M_AXIS_TLAST         => data_axis_tlast,
      M_AXIS_TKEEP         => data_axis_tkeep,
      M_AXIS_TDATA         => data_axis_tdata,
      -- VIO control
      LAST_CYCLE_TKEEP     => LC_LAST_CYCLE_TKEEP,
      DATA_CYCLES          => LC_DATA_CYCLES,     
      PAUSE_CYCLES         => LC_PAUSE_CYCLES,    
      CONTINUOUS           => '1'
   );

   transform_adc_stream_inst: entity work.transform_adc_stream
     port map(
         -- Input clock and reset
         S_CLK                => data_clk,
         S_RESET              => reset,
         -- input stream
         S_AXIS_TVALID        => data_axis_tvalid,
         S_AXIS_TDATA         => data_axis_tdata,
         -- Output clock and reset
         M_CLK                => clk,
         M_RESET              => reset,
         -- output stream channel 0
         M_AXIS_CH0_TVALID    => m_axis_adc_ch0_tvalid,
         M_AXIS_CH0_TREADY    => m_axis_adc_ch0_tready,
         M_AXIS_CH0_TDATA     => m_axis_adc_ch0_tdata,
         -- output stream channel 1
         M_AXIS_CH1_TVALID    => m_axis_adc_ch1_tvalid,
         M_AXIS_CH1_TREADY    => m_axis_adc_ch1_tready,
         M_AXIS_CH1_TDATA     => m_axis_adc_ch1_tdata 
      );

   rdma_adc_app_inst: entity work.rdma_adc_app
   generic map(
      g_adc_eth_clk_same      => true,
      g_packet_length         => 64,
      g_threshold_words       => 64,
      g_roce_qp_num           => x"aaaaaa",
      g_reg_udp_port          => x"dfcc", 
      g_roce_udp_port         => x"dfce"
   )
   port map(
      ------------   UDP 100G Interface    ---------
      -- Core clock and reset
      ETH_RESET               => reset,
      ETH_CLK                 => clk,
      -- Host net info --
      HOST_MAC                => x"111111111111",
      HOST_IP                 => x"22222222",
      HOST_NET_MASK           => x"33333333",
      -- RX Datapath --
      S_AXIS_UDP_TVALID       => s_axis_tvalid,
      S_AXIS_UDP_TREADY       => s_axis_tready,
      S_AXIS_UDP_TLAST        => s_axis_tlast, 
      S_AXIS_UDP_TKEEP        => s_axis_tkeep, 
      S_AXIS_UDP_TDATA        => s_axis_tdata, 
      -- RX net info
      RX_DST_UDP              => x"dfcc",
      RX_SRC_UDP              => x"dfcd",
      RX_SRC_IP               => x"44444444",
      RX_SRC_MAC              => x"555555555555",
      RX_PACKET_LENGTH        => packet_length,
      -- TX Datapath --
      M_AXIS_UDP_TVALID       => open,
      M_AXIS_UDP_TREADY       => m_axis_tready,
      M_AXIS_UDP_TLAST        => open,
      M_AXIS_UDP_TKEEP        => open,
      M_AXIS_UDP_TDATA        => open,
      -- TX net info
      TX_SRC_UDP              => open,
      TX_DST_UDP              => open,
      TX_DST_IP               => open,
      TX_DST_MAC              => open,
      -- Packet divided user signal 
      PACKET_DIVIDED          => '0',

      ------------   ADC Interface    --------- 
      -- Core clock and reset
      ADC_RESET               => reset,
      ADC_CLK                 => clk,
      -- ADC data
      S_AXIS_ADC_TVALID       => m_axis_adc_ch0_tvalid, --data_axis_tvalid,
      S_AXIS_ADC_TREADY       => m_axis_adc_ch0_tready, --data_axis_tready,
      S_AXIS_ADC_TLAST        => '0', --data_axis_tlast, 
      S_AXIS_ADC_TKEEP        => x"ffffffffffffffff", --data_axis_tkeep, 
      S_AXIS_ADC_TDATA        => m_axis_adc_ch0_tdata --data_axis_tdata
    );



      
--   udp_registers_inst: entity work.udp_registers
--   generic map(
--      g_udp_port              => x"dfcc"
--   )
--   port map(
--      ------------   UDP 100G Interface    ---------
--      -- Core clock and reset
--      RESET                   => reset,
--      CLK                     => clk,
--      -- Host info
--      HOST_MAC                => LC_HOST_MAC,
--      HOST_IP                 => LC_HOST_IP,
--      HOST_NET_MASK           => LC_HOST_NET_MASK,
--      -- RX Datapath --
--      S_AXIS_TVALID           => s_axis_tvalid,
--      S_AXIS_TREADY           => s_axis_tready,
--      S_AXIS_TLAST            => s_axis_tlast,
--      S_AXIS_TKEEP            => s_axis_tkeep,
--      S_AXIS_TDATA            => s_axis_tdata,
--      -- RX net info
--      RX_DST_UDP              => open,
--      RX_SRC_UDP              => LC_RX_SRC_UDP,
--      RX_SRC_IP               => LC_RX_SRC_IP,
--      RX_SRC_MAC              => LC_RX_SRC_MAC,
--      RX_PACKET_LENGTH        => packet_length,
--      -- TX Datapath --
--      M_AXIS_TVALID           => open,
--      M_AXIS_TREADY           => m_axis_tready,
--      M_AXIS_TLAST            => open,
--      M_AXIS_TKEEP            => open,
--      M_AXIS_TDATA            => open,
--      -- TX net info
--      TX_SRC_UDP              => open,
--      TX_DST_UDP              => open,
--      TX_DST_IP               => open,
--      TX_DST_MAC              => open,
--      -- control signals
--      REG_CHANNEL_RUN         => open,
--      REG_CHANNEL_CLEAR       => open,
--      REG_CHANNEL_OVERFLOW    => '0',   
--      REG_CHANNEL_WORD_CNT    => LC_DATA_CNT,
--      -- packets related signals
--      -- mac/ip/udp
--      REG_ROCE_TX_DEST_IP     => open,
--      REG_ROCE_TX_DEST_MAC    => open,
--      REG_ROCE_TX_DEST_UDP    => open,
--      -- roce
--      REG_ROCE_TX_DEST_QP     => open,
--      REG_ROCE_TX_PSN         => open,
--      REG_ROCE_TX_Q_KEY       => open
--    );

   m_axis_tready <= '1'; --not m_axis_tready after 100ns;

end Behavioral;
