----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    11:48:48 11/10/2009 
-- Design Name: 
-- Module Name:    w5300_modul - 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;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library FACT_FAD_lib;
use FACT_FAD_lib.fad_definitions.ALL;

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

ENTITY w5300_modul IS
  generic(
    RAM_ADDR_WIDTH : integer := 14
  );
   PORT( 
      clk            : IN     std_logic;
      wiz_reset      : OUT    std_logic                     := '1';
      addr           : OUT    std_logic_vector (9 DOWNTO 0);
      data           : INOUT  std_logic_vector (15 DOWNTO 0);
      cs             : OUT    std_logic                     := '1';
      wr             : OUT    std_logic                     := '1';
      led            : OUT    std_logic_vector (7 DOWNTO 0) := (OTHERS => '0');
      rd             : OUT    std_logic                     := '1';
      int            : IN     std_logic;
      write_length   : IN     std_logic_vector (16 DOWNTO 0);
      ram_start_addr : IN     std_logic_vector (RAM_ADDR_WIDTH-1 DOWNTO 0);
      ram_data       : IN     std_logic_vector (15 DOWNTO 0);
      ram_addr       : OUT    std_logic_vector (RAM_ADDR_WIDTH-1 DOWNTO 0);
      data_valid     : IN     std_logic;
	  data_valid_ack : OUT    std_logic := '0';
      busy           : OUT    std_logic                     := '1';
      write_header_flag, write_end_flag : IN std_logic;
      fifo_channels : IN std_logic_vector (3 downto 0);
      s_trigger : OUT std_logic := '0';
      new_config : OUT std_logic := '0';
      config_started : in std_logic;
      config_addr : out std_logic_vector (7 downto 0);
      config_data : inout std_logic_vector (15 downto 0) := (others => 'Z');
      config_wr_en : out std_logic := '0';
      config_rd_en : out std_logic := '0';
      config_busy : in std_logic;
      

      
      denable : out std_logic := '0'; -- default domino wave off
      dwrite_enable : out std_logic := '0'; -- default DWRITE low.
      sclk_enable : out std_logic := '1'; -- default DWRITE HIGH.
      ps_direction : out std_logic := '1'; -- default phase shift upwards
      ps_do_phase_shift : out std_logic := '0'; --pulse this to phase shift once
      ps_reset : out std_logic := '0' -- pulse this to reset the variable phase shift
   );

-- Declarations

END w5300_modul ;

architecture Behavioral of w5300_modul is

type state_init_type is (INTERRUPT, RESET, WRITE_REG, READ_REG, WRITE_DATA,
                         INIT, IM, MT, STX, STX1, STX2, STX3, SRX, SRX1, SRX2, SRX3, MAC, MAC1, MAC2, GW, GW1, SNM, SNM1, IP, IP1, TIMEOUT, RETRY,
                         SI, SI1, SI2, SI3, SI4, SI5, SI6,	ESTABLISH, EST1, CONFIG, MAIN, CHK_RECEIVED, READ_DATA);
type state_write_type is (WR_START, WR_LENGTH, WR_WAIT1, WR_01, WR_02, WR_03, WR_04, WR_05, WR_06, WR_07, WR_08, WR_FIFO, WR_FIFO1, WR_ADC, WR_ADC1, WR_ADC2,
                          WR_ENDFLAG, WR_ENDFLAG1, WR_ENDFLAG2, WR_ENDFLAG3); 
type state_interrupt_1_type is (IR1_01, IR1_02, IR1_03, IR1_04);
type state_interrupt_2_type is (IR2_01, IR2_02, IR2_03, IR2_04, IR2_05, IR2_06);
type state_read_data_type is (RD_1, RD_2, RD_3, RD_4, RD_5, RD_6, RD_WAIT, RD_WAIT1, RD_END);

signal RST_TIME : std_logic_vector(19 downto 0) := X"7A120";

signal par_addr : std_logic_vector (9 downto 0) := (OTHERS => '0');
signal par_data : std_logic_vector (15 downto 0) := (OTHERS => '0');
signal data_read : std_logic_vector (15 downto 0) := (OTHERS => '0');
signal adc_data_addr : std_logic_vector (RAM_ADDR_WIDTH-1 DOWNTO 0);

signal state_init, next_state , next_state_tmp : state_init_type := RESET;
signal count : std_logic_vector (2 downto 0) := "000";
signal state_write : state_write_type := WR_START;
signal state_interrupt_1 : state_interrupt_1_type := IR1_01;
signal state_interrupt_2 : state_interrupt_2_type := IR2_01;
signal state_read_data : state_read_data_type := RD_1;

signal interrupt_ignore : std_logic := '1';
signal int_flag : std_logic := '0';
signal ram_access : std_logic := '0';

signal zaehler : std_logic_vector (19 downto 0) := (OTHERS => '0');
signal data_cnt : integer := 0;
signal drs_cnt : integer :=0;
signal channel_cnt : integer range 0 to 9 :=0;
signal socket_cnt : std_logic_vector (2 downto 0) := "000";
signal roi_max : std_logic_vector (10 downto 0);
signal data_end : integer := 0;

signal socket_tx_free : std_logic_vector (31 downto 0) := (others => '0');
signal write_length_bytes : std_logic_vector (16 downto 0);

signal socket_rx_received : std_logic_vector (31 downto 0) := (others => '0');
signal chk_recv_cntr : integer range 0 to 10000 := 0;
signal rx_packets_cnt : std_logic_vector (15 downto 0);
signal next_packet_data : std_logic := '0';
signal new_config_flag : std_logic := '0';

signal trigger_stop : std_logic := '1';

signal local_write_length   : std_logic_vector (16 DOWNTO 0);
signal local_ram_start_addr : std_logic_vector (RAM_ADDR_WIDTH-1 DOWNTO 0);
signal local_ram_addr       : std_logic_vector (RAM_ADDR_WIDTH-1 downto 0);
signal local_socket_nr      : std_logic_vector (2 DOWNTO 0);
signal local_write_header_flag, local_write_end_flag : std_logic;
signal local_fifo_channels : std_logic_vector (3 downto 0);

begin

  --synthesis translate_off
  RST_TIME <= X"00120";
  --synthesis translate_on

	w5300_init_proc : process (clk, int)
	begin
		
		if rising_edge (clk) then

			-- Interrupt low
			if (int = '0') and (interrupt_ignore = '0') then
				case state_interrupt_1 is
					when IR1_01 =>
						int_flag <= '1';
						busy <= '1';
						state_interrupt_1 <= IR1_02;
					when IR1_02 =>
						state_interrupt_1 <= IR1_03;
					when IR1_03 =>
						state_init <= INTERRUPT;
						socket_cnt <= "000";
						ram_access <= '0';
						zaehler <= X"00000";
						count <= "000";
						int_flag <= '0';
						interrupt_ignore <= '1';
						state_interrupt_1 <= IR1_04;
					when others =>
						null;
				end case;
			end if; -- int = '0'
			
			if int_flag = '0' then
				case state_init is
					-- Interrupt
					when INTERRUPT =>
						case state_interrupt_2 is
							when IR2_01 =>
								par_addr <= W5300_IR;
								state_init <= READ_REG;
								next_state <= INTERRUPT;
								state_interrupt_2 <= IR2_02;
							when IR2_02 =>
								if (data_read (conv_integer(socket_cnt)) = '1') then -- Sx Interrupt
									state_interrupt_2 <= IR2_03;
								else
                  socket_cnt <= socket_cnt + 1;
                  if (socket_cnt = 7) then
                    state_interrupt_2 <= IR2_06;
                  else
                    state_interrupt_2 <= IR2_02;
                  end if; 
								end if;
							when IR2_03 =>
								par_addr <= W5300_S0_IR + socket_cnt * W5300_S_INC; -- Sx Interrupt Register
								state_init <= READ_REG;
								next_state <= INTERRUPT;
								state_interrupt_2 <= IR2_04;
							when IR2_04 =>
								par_addr <= W5300_S0_IR + socket_cnt * W5300_S_INC;
								par_data <= data_read; -- clear Interrupts
								state_init <= WRITE_REG;
								next_state <= INTERRUPT;
								state_interrupt_2 <= IR2_05;
							when IR2_05 =>
								par_addr <= W5300_S0_CR + socket_cnt * W5300_S_INC;
								par_data <= X"0010"; -- CLOSE
								state_init <= WRITE_REG;
								next_state <= INTERRUPT;
								socket_cnt <= socket_cnt + 1;
								if (socket_cnt = 7) then
								  state_interrupt_2 <= IR2_06;
								else
								  state_interrupt_2 <= IR2_01;
								end if; 

							when IR2_06 =>
								state_interrupt_1 <= IR1_01;
								state_interrupt_2 <= IR2_01;
								socket_cnt <= "000";
								state_init <= RESET;
						end case;
						
					-- reset W5300
					when RESET =>
						zaehler <= zaehler + 1;
            wiz_reset <= '0';
            led <= X"FF";
						if (zaehler >= X"00064") then -- wait 2µs
							wiz_reset <= '1';
						end if;	
						if (zaehler = RST_TIME) then -- wait 10ms
							zaehler <= X"00000";
							socket_cnt <= "000";
							count <= "000";
							ram_access <= '0';
							interrupt_ignore <= '0';
							rd <= '1';
							wr <= '1';
							cs <= '1';
							state_write <= WR_START;
							state_init <= INIT;
						end if;
						
					-- Init
					when INIT =>
						par_addr <= W5300_MR;
						par_data <= X"0000";
						state_init <= WRITE_REG;
						next_state <= IM;
						
					-- Interrupt Mask
					when IM =>
						par_addr <= W5300_IMR;
						par_data <= X"00FF"; -- S0-S7 Interrupts
						state_init <= WRITE_REG;
						next_state <= MT;
						
					-- Memory Type
					when MT =>
					  par_addr <=	W5300_MTYPER;
					  par_data <= X"7FFF"; -- 8K RX, 120K TX-Buffer
					  state_init <= WRITE_REG;
					  next_state <= STX;
					  
					-- Socket TX Memory Size
					when STX =>
					  par_data <= X"0F0F"; -- 15K TX

					 	par_addr <= W5300_TMS01R;
					 	state_init <=WRITE_REG;
					 	next_state <= STX1;
          when STX1 =>
            par_addr <= W5300_TMS23R;
            state_init <=WRITE_REG;
            next_state <= STX2;
          when STX2 =>
            par_addr <= W5300_TMS45R;
            state_init <=WRITE_REG;
            next_state <= STX3;
          when STX3 =>
            par_addr <= W5300_TMS67R;
            state_init <=WRITE_REG;
            next_state <= SRX;
			 		
          -- Socket RX Memory Size
          when SRX =>
            par_data <= X"0101"; -- 1K RX
             
            par_addr <= W5300_RMS01R;
            state_init <=WRITE_REG;
            next_state <= SRX1;
          when SRX1 =>
            par_addr <= W5300_RMS23R;
            state_init <=WRITE_REG;
            next_state <= SRX2;
          when SRX2 =>
            par_addr <= W5300_RMS45R;
            state_init <=WRITE_REG;
            next_state <= SRX3;
          when SRX3 =>
            par_addr <= W5300_RMS67R;
            state_init <=WRITE_REG;
            next_state <= MAC;
	  
					-- MAC
					when MAC =>
						par_addr <= W5300_SHAR;
						par_data <= MAC_ADDRESS (0);
						state_init <= WRITE_REG;
						next_state <= MAC1;
					when MAC1 =>
						par_addr <= W5300_SHAR + 2;
						par_data <= MAC_ADDRESS (1);
						state_init <= WRITE_REG;
						next_state <= MAC2;
					when MAC2 =>
						par_addr <= W5300_SHAR + 4;
						par_data <= MAC_ADDRESS (2);
						state_init <= WRITE_REG;
						next_state <= GW;
						
					-- Gateway
					when GW =>
						par_addr <= W5300_GAR;
						par_data (15 downto 8) <= conv_std_logic_vector(GATEWAY (0),8);
						par_data (7 downto 0) <= conv_std_logic_vector(GATEWAY (1),8);
						state_init <= WRITE_REG;
						next_state <= GW1;
					when GW1 =>
						par_addr <= W5300_GAR + 2;
						par_data (15 downto 8) <= conv_std_logic_vector(GATEWAY (2),8);
						par_data (7 downto 0) <= conv_std_logic_vector(GATEWAY (3),8);
						state_init <= WRITE_REG;
						next_state <= SNM;
						
					-- Subnet Mask
					when SNM =>
						par_addr <= W5300_SUBR;
						par_data (15 downto 8) <= conv_std_logic_vector(NETMASK (0),8);
						par_data (7 downto 0) <= conv_std_logic_vector(NETMASK (1),8);
						state_init <= WRITE_REG;
						next_state <= SNM1;
					when SNM1 =>
						par_addr <= W5300_SUBR + 2;
						par_data (15 downto 8) <= conv_std_logic_vector(NETMASK (2),8);
						par_data (7 downto 0) <= conv_std_logic_vector(NETMASK (3),8);
						state_init <= WRITE_REG;
						next_state <= IP;
					-- Own IP-Address
					when IP =>
						par_addr <= W5300_SIPR;
						par_data (15 downto 8) <= conv_std_logic_vector(IP_ADDRESS (0),8);
						par_data (7 downto 0) <= conv_std_logic_vector(IP_ADDRESS (1),8);
						state_init <= WRITE_REG;
						next_state <= IP1;
					when IP1 =>
						par_addr <= W5300_SIPR + 2;
						par_data (15 downto 8) <= conv_std_logic_vector(IP_ADDRESS (2),8);
						par_data (7 downto 0) <= conv_std_logic_vector(IP_ADDRESS (3),8);
						state_init <= WRITE_REG;
						next_state <= TIMEOUT;
					when TIMEOUT =>
						par_addr <=	W5300_RTR;
						par_data <= X"07D0"; -- 0x07D0 = 200ms
						state_init <= WRITE_REG;
						next_state <= RETRY;
					when RETRY =>
						par_addr <=	W5300_RCR;
						par_data <= X"0008";
						state_init <= WRITE_REG;
						next_state <= SI;

					-- Socket Init
					when SI =>
						par_addr <= W5300_S0_MR + socket_cnt * W5300_S_INC;
						par_data <= X"0101"; -- ALIGN, TCP
						state_init <= WRITE_REG;
						next_state <= SI1;
					-- Sx Interrupt Mask
					when SI1 =>
						par_addr <= W5300_S0_IMR + socket_cnt * W5300_S_INC;
						par_data <= X"000A"; -- TIMEOUT, DISCON
						state_init <= WRITE_REG;
						next_state <= SI2;
					when SI2 =>
						par_addr <= W5300_S0_PORTR + socket_cnt * W5300_S_INC;
						par_data <= conv_std_logic_vector(FIRST_PORT + unsigned (socket_cnt), 16);
						state_init <= WRITE_REG;
						next_state <= SI3;
					when SI3 =>
						par_addr <= W5300_S0_CR + socket_cnt * W5300_S_INC;
						par_data <= X"0001"; -- OPEN
						state_init <= WRITE_REG;
						next_state <= SI4;
					when SI4 =>
						par_addr <= W5300_S0_SSR + socket_cnt * W5300_S_INC;
						state_init <= READ_REG;
						next_state <= SI5;
					when SI5 =>
						if (data_read (7 downto 0) = X"13") then -- is open?
							state_init <= SI6;
						else
							state_init <= SI4;
						end if;
					when SI6 =>
						par_addr <= W5300_S0_CR + socket_cnt * W5300_S_INC;
						par_data <= X"0002"; -- LISTEN
						state_init <= WRITE_REG;
						socket_cnt <= socket_cnt + 1;
						if (socket_cnt = 7) then
						  socket_cnt <= "000";
						  next_state <= ESTABLISH; -- All Sockets open
						else
						  next_state <= SI; -- Next Socket
						end if;
				  -- End Socket Init
						
					when ESTABLISH =>
						par_addr <= W5300_S0_SSR + socket_cnt * W5300_S_INC;
						state_init <= READ_REG;
						next_state <= EST1;
					when EST1 =>
						led <= data_read (7 downto 0);
						case data_read (7 downto 0) is
							when X"17" => -- established
                if (socket_cnt = 7) then
                  socket_cnt <= "000";
                  busy <= '0';
                  state_init <= MAIN;
                else
                  socket_cnt <= socket_cnt + 1;
                  state_init <= ESTABLISH;
                end if;
							when others =>
								state_init <= ESTABLISH;
						end case;
					
					when CONFIG =>
            led <= X"F0";
					  new_config <= '1';
					  if (config_started = '1') then
					    led <= X"0F";
					    new_config <= '0';
					    busy <= '0';
					    state_init <= MAIN;
					  end if;
					
          -- main "loop"
					when MAIN =>
      					  ps_do_phase_shift <= '0';
      					  ps_reset <= '0';
            if (trigger_stop = '1') then
					    s_trigger <= '0';
					  end if;
            if (chk_recv_cntr = 1000) then
              chk_recv_cntr <= 0;
              state_read_data <= RD_1;
              state_init <= READ_DATA;
              busy <= '1';
            else
              busy <= '0';
              data_valid_ack <= '0';
              chk_recv_cntr <= chk_recv_cntr + 1;  
  						  if (data_valid = '1') then
  						    data_valid_ack <= '1';
                local_write_length <= write_length;
                local_ram_start_addr <= ram_start_addr;
                local_ram_addr <= (others => '0');
                local_write_header_flag <= write_header_flag;
                local_write_end_flag <= write_end_flag;
                local_fifo_channels <= fifo_channels;
							  next_state <= MAIN;
							  state_init <= WRITE_DATA;
							  busy <= '1';
              end if;
						end if;

					-- read data from socket 0  
          when READ_DATA =>
            case state_read_data is
              when RD_1 =>
                par_addr <= W5300_S0_RX_RSR;
                state_init <= READ_REG;
                next_state <= READ_DATA;
                state_read_data <= RD_2;
              when RD_2 =>
                socket_rx_received (31 downto 16) <= data_read;
                par_addr <= W5300_S0_RX_RSR + X"2";
                state_init <= READ_REG;
                next_state <= READ_DATA;
                state_read_data <= RD_3;
              when RD_3 =>
                socket_rx_received (15 downto 0) <= data_read;
                state_read_data <= RD_4;
              when RD_4 =>
                if (socket_rx_received (16 downto 0) > ('0' & X"000")) then
                  rx_packets_cnt <= socket_rx_received (16 downto 1); -- socket_rx_received / 2
                  state_read_data <= RD_5;
                else
                  busy <= '0';
                  state_init <= MAIN;
                end if;
              when RD_5 =>
                if (rx_packets_cnt > 0) then
                  rx_packets_cnt <= rx_packets_cnt - '1';
                  par_addr <= W5300_S0_RX_FIFOR;
                  state_init <= READ_REG;
                  next_state <= READ_DATA;
                  state_read_data <= RD_6;
                else
                  state_read_data <= RD_END;
--                  if (new_config_flag = '1') then
--                    new_config_flag <= '0';
--                    state_init <= CONFIG;
--                  else
--                    busy <= '0';
--                    state_init <= MAIN;
--                  end if;
                end if;
              when RD_6 =>
                led <= data_read (15 downto 8);
                -- read command
                if (next_packet_data = '0') then
                  case data_read (15 downto 8) is
                    when CMD_TRIGGER =>
                      trigger_stop <= '1';
                      s_trigger <= '1';
                      state_read_data <= RD_WAIT;
                    when CMD_DWRITE_RUN =>
                      dwrite_enable <= '1';
                      state_read_data <= RD_WAIT;
                    when CMD_DWRITE_STOP =>
                      dwrite_enable <= '0';
                      state_read_data <= RD_WAIT;
                    when CMD_SCLK_ON =>
                      sclk_enable <= '1';
                      state_read_data <= RD_WAIT;
                    when CMD_SCLK_OFF =>
                      sclk_enable <= '0';
                      state_read_data <= RD_WAIT;
                    when CMD_DENABLE =>
                      denable <= '1';
                      state_read_data <= RD_WAIT;
                    when CMD_DDISABLE =>
                      denable <= '0';
                      state_read_data <= RD_WAIT;
                    when CMD_TRIGGER_C =>
                      trigger_stop <= '0';
                      s_trigger <= '1';
                      state_read_data <= RD_WAIT;
                    when CMD_TRIGGER_S =>
                      trigger_stop <= '1';
                      state_read_data <= RD_WAIT;
                    -- phase shift commands here:
                    when CMD_PS_DO =>
                      ps_do_phase_shift <= '1';
                      state_read_data <= RD_WAIT;
                    when CMD_PS_DIRINC =>
                      ps_direction <= '1';
                      state_read_data <= RD_WAIT;
                    when CMD_PS_RESET =>
                      ps_reset <= '1';
                      state_read_data <= RD_WAIT;
                    when CMD_PS_DIRDEC =>
                      ps_direction <= '0';
                      state_read_data <= RD_WAIT;
                    when CMD_WRITE =>
                      next_packet_data <= '1';
                      config_addr <= data_read (7 downto 0);
                      state_read_data <= RD_5;
                    when others =>
                      state_read_data <= RD_5;
                  end case;
                -- read data
                else
                  if (config_busy = '0') then
                    config_data <= data_read;
                    config_wr_en <= '1';
                    new_config_flag <= '1';
                    next_packet_data <= '0';
                    state_read_data <= RD_WAIT;
                  end if;
                end if;
              when RD_WAIT =>
                state_read_data <= RD_WAIT1;
              when RD_WAIT1 =>
                config_data <= (others => 'Z');
                config_wr_en <= '0';
                state_read_data <= RD_5;
              when RD_END =>
                par_addr <= W5300_S0_CR;
                par_data <= X"0040"; -- RECV
                state_init <= WRITE_REG;
                if (new_config_flag = '1') then
                  new_config_flag <= '0';
                  next_state <= CONFIG;
                else
--                busy <= '0';
                  next_state <= MAIN;
                end if;

            end case; -- state_data_read
                
    

					when WRITE_DATA =>
						case state_write is
						  when WR_START =>
						    if (local_write_header_flag = '1') then
						      ram_addr <= local_ram_start_addr + 5; -- Address of Trigger-ID (15 downto 0) ????
						    end if;
						    state_write <= WR_WAIT1;
						  when WR_WAIT1 =>
						    state_write <= WR_LENGTH;
							when WR_LENGTH =>
							  if (local_write_header_flag = '1') then
							    local_socket_nr <= ram_data (2 downto 0);
							  end if;
								next_state_tmp <= next_state;
								write_length_bytes <= local_write_length (15 downto 0) & '0'; -- shift left (*2)
								data_cnt <= 0;
								state_write <= WR_01;
							-- Check FIFO Size
							when WR_01 =>
								par_addr <= W5300_S0_TX_FSR + local_socket_nr * W5300_S_INC;
								state_init <= READ_REG;
								next_state <= WRITE_DATA;
								state_write <= WR_02;
							when WR_02 =>
								socket_tx_free (31 downto 16) <= data_read;
								par_addr <= W5300_S0_TX_FSR + (local_socket_nr * W5300_S_INC) + X"2";
								state_init <= READ_REG;
								next_state <= WRITE_DATA;
								state_write <= WR_03;
							when WR_03 =>
								socket_tx_free (15 downto 0) <= data_read;
								state_write <= WR_04;
							when WR_04 =>
								if (socket_tx_free (16 downto 0) < write_length_bytes) then
									state_write <= WR_01;
								else
								  if (local_write_header_flag = '1') then
									  state_write <= WR_FIFO;
									else
									  state_write <= WR_ADC;
									end if; 
								end if;
							
							-- Fill FIFO

							-- Write Header
							when WR_FIFO =>
                ram_addr <= local_ram_start_addr + local_ram_addr;
							  state_write <= WR_FIFO1;
							when WR_FIFO1 =>
 								data_cnt <= data_cnt + 1;
								if (data_cnt < PACKAGE_HEADER_LENGTH) then --???
								  local_ram_addr <= local_ram_addr + 1;
								  if (data_cnt = 2 or data_cnt = 5 or data_cnt = 8 ) then -- skip empty words
								    local_ram_addr <= local_ram_addr + 2;
								  end if;
								  if (data_cnt = 9) then -- skip empty words
								    local_ram_addr <= local_ram_addr + 4;
								  end if;  
									par_addr <= W5300_S0_TX_FIFOR + local_socket_nr * W5300_S_INC;
									ram_access <= '1';
									state_init <= WRITE_REG;
									next_state <= WRITE_DATA;
									state_write <= WR_FIFO;
								else
									state_write <= WR_ADC;
								end if;
							-- End Write Header
							
							-- Write ADC-Data
							---- Start...
							when WR_ADC =>
							  adc_data_addr <= local_ram_start_addr + local_ram_addr;
							  drs_cnt <= 0;
							  channel_cnt <= 1;
                data_cnt <= 0;
							  roi_max <= (others => '0');
							  data_end <= 3;
							  state_write <= WR_ADC1;

							---- Write Channel
							when WR_ADC1 =>
							  -- read ROI and set end of Channel-Data
							  if (data_cnt = 3) then
							    data_end <= conv_integer (ram_data) + 3;
							    if (ram_data > roi_max) then
							      roi_max <= ram_data (10 downto 0);
							    end if;
							  end if;
							  ram_addr <= adc_data_addr + drs_cnt + (data_cnt * 4);
                state_write <= WR_ADC2;
							when WR_ADC2 =>
                if (data_cnt < data_end) then
                  par_addr <= W5300_S0_TX_FIFOR + local_socket_nr * W5300_S_INC;
                  ram_access <= '1';
                  state_init <= WRITE_REG;
                  next_state <= WRITE_DATA;
                  data_cnt <= data_cnt + 1;
                  state_write <= WR_ADC1;
                else
                  -- Next DRS
                  if (drs_cnt < 3) then
                    drs_cnt <= drs_cnt + 1;
                    data_cnt <= 0;
                    data_end <= 3;
                    state_write <= WR_ADC1;
                  else
                    -- Next Channel
                    if (channel_cnt < local_fifo_channels) then
                      channel_cnt <= channel_cnt + 1;
                      roi_max <= (others => '0');
                      drs_cnt <= 0;
                      data_cnt <= 0;
                      data_end <= 3;
                      adc_data_addr <= adc_data_addr + ((conv_integer(roi_max) + 3) * 4);
                      state_write <= WR_ADC1;
                    else
                      -- Ready
                      if (local_write_end_flag = '1') then
                        state_write <= WR_ENDFLAG;
                      else
                        state_write <= WR_05;
                      end if;
                    end if;
                  end if;    
                end if;
							-- End Write ADC-Data

              -- Write End Package Flag
              when WR_ENDFLAG =>
                ram_addr <= adc_data_addr + ((conv_integer(roi_max) + 3) * 4);
                state_write <= WR_ENDFLAG1;
              when WR_ENDFLAG1 =>
                par_addr <= W5300_S0_TX_FIFOR + local_socket_nr * W5300_S_INC;
                ram_access <= '1';
                state_init <= WRITE_REG;
                next_state <= WRITE_DATA;
                state_write <= WR_ENDFLAG2;
              when WR_ENDFLAG2 =>
                ram_addr <= adc_data_addr + ((conv_integer(roi_max) + 3) * 4) + 1;
                state_write <= WR_ENDFLAG3;
              when WR_ENDFLAG3 =>
                state_init <= WRITE_REG;
                next_state <= WRITE_DATA;
                state_write <= WR_05;
              
              -- End Write End Package Flag

              --Send FIFO
							when WR_05 =>
							  ram_access <= '0';
								par_addr <= W5300_S0_TX_WRSR + local_socket_nr * W5300_S_INC;
								par_data <= (0 => write_length_bytes (16), others => '0');
								state_init <= WRITE_REG;
								state_write <= WR_06;
							when WR_06 =>
								par_addr <= W5300_S0_TX_WRSR + (local_socket_nr * W5300_S_INC) + X"2";
								par_data <= write_length_bytes (15 downto 0);
								state_init <= WRITE_REG;
								state_write <= WR_07;
							when WR_07 =>
								par_addr <= W5300_S0_CR + local_socket_nr * W5300_S_INC;
								par_data <= X"0020"; -- Send
								state_init <= WRITE_REG;
								state_write <= WR_08;
							when others =>
--							busy <= '0';
								state_init <= next_state_tmp;
								state_write <= WR_START;
						end case;
						-- End WRITE_DATA
						
					when READ_REG =>
						case count is
							when "000" =>
								cs <= '0';
								rd <= '0';
								wr <= '1';
								data <= (others => 'Z'); -- !!!!!!!!!!
								count <= "001";
								addr <= par_addr;
							when "001" =>
								count <= "010";
							when "010" =>
								count <= "100";
							when "100" =>
								data_read <= data;
								count <= "110";
							when "110" =>
								count <= "111";
							when "111" =>
								cs <= '1';
								rd <= '1';
								count <= "000";
								state_init <= next_state;
							when others =>
								null;
						end case;
					
					when WRITE_REG =>
						case count is
							when "000" =>
								cs <= '0';
								wr <= '0';
								rd <= '1';
								addr <= par_addr; 
								if (ram_access = '1') then
									data <= ram_data;
								else
									data <= par_data;
								end if;
								count <= "100";
							when "100" =>
								count <= "101";
							when "101" =>
								count <= "110";
							when "110" =>
								cs <= '1';
								wr <= '1';
								state_init <= next_state;
								count <= "000";
							when others =>
								null;
						end case;
					
					when others =>
						null;
				end case;
			end if; -- int_flag = '0'

		end if; -- rising_edge (clk)

	end process w5300_init_proc;

end Behavioral;

