----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    12:11:54 07/09/2012 
-- Design Name: 
-- Module Name:    NQR_ML505_top - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 

----------------------------------------------------------------------------------
-- LIBRARY
----------------------------------------------------------------------------------
library unisim;
use unisim.vcomponents.ALL;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

----------------------------------------------------------------------------------

entity NQR_ML505_top is
	 Generic ( dds_data_length : natural := 40;
				  dds_bus_width : natural := 8;			-- length of data and bus width (parallel interface) to setup DDS chip
				  pg_data_length : natural := 64;		-- length of data send to and stored in pulse generator RAM
				  pg_channel_number : natural := 32;	-- number of available pulse channels
				  pg_address_width : natural := 13;		
				  pg_address_number : natural := 8192;	-- number of address bits and address of pulse generator RAM
				  pg_timer_width: natural := 31			-- number of bits of pulse generator timer counter
				 );
    Port (
			  -- Main signals
			  CLK : 	 	     in   STD_LOGIC;
			  RST : 		     in	 STD_LOGIC;
			  
			  -- EMAC0 clock signal
			  GTX_CLK_0	:    out  STD_LOGIC;

			  -- EMAC0 MII interface
			  MII_COL_0 : 	  in   STD_LOGIC;
			  MII_CRS_0 : 	  in   STD_LOGIC;
			  MII_TXD_0 :    out  STD_LOGIC_VECTOR(7 downto 0);
			  MII_TX_EN_0 :  out  STD_LOGIC;
			  MII_TX_ER_0 :  out  STD_LOGIC;
			  MII_TX_CLK_0 : in   STD_LOGIC;
			  MII_RXD_0 :    in   STD_LOGIC_VECTOR(3 downto 0);
			  MII_RX_DV_0 :  in   STD_LOGIC;
			  MII_RX_ER_0 :  in   STD_LOGIC;
			  MII_RX_CLK_0 : in   STD_LOGIC;
      
			  -- PHY asynchronous reset
			  PHY_RESET :    out  STD_LOGIC;
			  
			  -- Measured FID signal
			  FID :			  in	 STD_LOGIC_VECTOR(11 downto 0);	-- data in from ADC
			  CLK_ADC :		  out  STD_LOGIC;		-- 80 MHz clock signal from PLL
			  
			  -- External DDS signals
			  DATA_OUT_DDS : out  STD_LOGIC_VECTOR(dds_bus_width-1 downto 0);		-- data out to external DDS chip
			  RST_DDS :      out  STD_LOGIC;
			  W_CLK_DDS :    out  STD_LOGIC;
			  FQ_UD_DDS :    out  STD_LOGIC;		-- reset, word load clock and frequency update pins of external DDS chip			  
			  
			  -- DAC (Internal DDS) signals
			  DATA_OUT_DAC : out  STD_LOGIC_VECTOR(9 downto 0);		-- data out to DAC chip 
			  CLK_DAC :	  	  out  STD_LOGIC;		-- 160 MHz clock signal from PLL
			  
			  -- VGA signals
			  DATA_OUT_VGA : out  STD_LOGIC_VECTOR(3 downto 0) := (others => '0');		-- data out to VGA chip 
			  DENB_VGA :	  out  STD_LOGIC := '0';		-- data enable signal

			  -- PG signals
			  Tx_Gate :      out  STD_LOGIC := '0';	-- pulse signal for gating transmitted frequency
			  Rx_Gate :      out  STD_LOGIC := '0';	-- pulse signal for gating receive signal
			  Amp_Gate : 	  out  STD_LOGIC := '0'		-- pulse signal for gating power amplifier
			 );
end NQR_ML505_top;

architecture Behavioral of NQR_ML505_top is


----------------------------------------------------------------------------------
-- COMPONENTS declaration
----------------------------------------------------------------------------------

-- Digital Clock Manager to Phase Lock Loop: in 27 MHz (CLK); out 20 MHz (CLK_20M), 80 MHz (CLK_80M), 100 MHz (CLK_100M) and 160 MHz (CLK_160M)
	component PLL_IPCore
		Port ( CLKIN_IN : 		 in   STD_LOGIC;		-- 27 MHz clock from onboard generator
				 RST_IN : 			 in   STD_LOGIC; 
				 CLKIN_IBUFG_OUT : out  STD_LOGIC;
				 CLKOUT0_OUT : 	 out  STD_LOGIC;		-- 20 MHz
				 CLKOUT1_OUT : 	 out  STD_LOGIC;		-- 80 MHz
				 CLKOUT2_OUT : 	 out  STD_LOGIC;		-- 100 MHz
				 CLKOUT3_OUT : 	 out  STD_LOGIC		-- 160 MHz
				);
	end component;
	
	
-- Internal Direct Digital Synthesizer (DDS)
	component Internal_DDS
		Port ( CLK :  in   STD_LOGIC;
				 SINE : out  STD_LOGIC_VECTOR(9 downto 0)		-- output sine 20 MHz signal
				);
	end component;
	

-- PC-FPGA Communication over UDP protocol
	component Ethernet_IPCore_top is
		Port ( RESET : 		   	in	  STD_LOGIC;		-- asynchronous reset
				 MII_COL_0 : 	   	in   STD_LOGIC;
				 MII_CRS_0 : 	   	in   STD_LOGIC;
				 MII_TXD_0 :      	out  STD_LOGIC_VECTOR(3 downto 0);
				 MII_TX_EN_0 :    	out  STD_LOGIC;
				 MII_TX_ER_0 :    	out  STD_LOGIC;
			    MII_TX_CLK_0 :   	in   STD_LOGIC;
				 MII_RXD_0 :      	in   STD_LOGIC_VECTOR(3 downto 0);
				 MII_RX_DV_0 :    	in   STD_LOGIC;
				 MII_RX_ER_0 :    	in   STD_LOGIC;
				 MII_RX_CLK_0 :   	in   STD_LOGIC;		-- EMAC0 MII interface
				 TX_CLIENT_CLK :     out  STD_LOGIC;		-- EMAC0 client interface
				 RX_VALID_DATA_OUT : out  STD_LOGIC;
				 RX_DATA_OUT :       out  STD_LOGIC_VECTOR(7 downto 0);
				 TX_START_ENABLE :   in   STD_LOGIC;
				 TX_DATA_TRANS	:     out  STD_LOGIC;
				 TX_DATA_LENGTH : 	in   STD_LOGIC_VECTOR(15 downto 0);
				 TX_DATA_IN : 			in   STD_LOGIC_VECTOR(7 downto 0)		-- UDP-IP Core interface
				);
	end component;
	
	
-- External Direct Digital Synthesizer (External DDS)
	component DDS_control
		Generic ( dds_data_length : natural;
					 dds_bus_width : natural
				  );
		Port ( CLK : 		 in   STD_LOGIC;		-- 20 MHz clock from PLL
				 RST : 		 in   STD_LOGIC;
				 ENABLE :    in   STD_LOGIC;		-- enable (start) direct digital synthesizer
				 DATA_IN :   in   STD_LOGIC_VECTOR(dds_data_length-1 downto 0);		-- data in (frequency setting)
				 RST_DDS :   out  STD_LOGIC;
				 W_CLK_DDS : out  STD_LOGIC;
				 FQ_UD_DDS : out  STD_LOGIC;		-- reset, word load clock and frequency update pins of external DDS chip
				 DATA_OUT :  out  STD_LOGIC_VECTOR(dds_bus_width-1 downto 0);			-- data out (to external DDS chip)
				 READY : 	 out  STD_LOGIC		-- ready "message"
				);
	end component;
	
	
-- Pulse generator (PG)	
	component Pulse_generator is
		Generic ( pg_data_length : natural;
					 pg_channel_number : natural;
					 pg_address_width : natural;
					 pg_address_number : natural;
					 pg_timer_width : natural
				   );
		Port ( CLK : 		    in   STD_LOGIC;		-- 100 MHz clock from PLL
				 RST : 		  	 in   STD_LOGIC;
				 ENABLE : 	    in	STD_LOGIC;		-- enable (start) pulse generator
				 WE :           in   STD_LOGIC;		-- write enable
				 RW :		  	    in   STD_LOGIC;		-- read/write data (pulse sequence)
				 ADDRESS :      in   STD_LOGIC_VECTOR(pg_address_width-1 downto 0);		-- address of RAM to store data in
				 DATA_IN :	    in   STD_LOGIC_VECTOR(pg_data_length-1 downto 0);			-- data (pulse sequence)
				 PULSE_OUT :    out  STD_LOGIC_VECTOR(pg_channel_number-1 downto 0);		-- generated pulse sequence
				 FINISH :       out  STD_LOGIC		-- finish "message"
			   );
	end component;
	
	
-- Pulse generator FIFO RAM (PG FIFO)
	component PG_FIFO_IPCore
		Port ( WR_CLK : in   STD_LOGIC;		-- clock signal from Ethernet Core
				 RD_CLK : in   STD_LOGIC;		-- 100 MHz clock from PLL (same as CLK for pulse generator)
				 RST : 	 in   STD_LOGIC;
				 DIN :    in   STD_LOGIC_VECTOR(7 downto 0);		-- data in (from UDP-IP Core)
				 DOUT :   out  STD_LOGIC_VECTOR(63 downto 0);	-- data out (to pulse generator RAM)
				 WR_EN :  in   STD_LOGIC;
				 RD_EN :  in   STD_LOGIC;		-- write enable and read enable signal
				 FULL :   out  STD_LOGIC;
				 EMPTY :  out  STD_LOGIC		-- full and empty flag
				);
	end component;
	
	
-- IQ demodulator
	component IQ_demodulator is
		Port ( CLK : 		 in   STD_LOGIC;		-- 80 MHz clock from PLL
				 RST : 		 in   STD_LOGIC;
				 SIGNAL_IN : in   STD_LOGIC_VECTOR(11 downto 0);	-- signal input (sampled FID from ADC)
				 I_OUT : 	 out  STD_LOGIC_VECTOR(11 downto 0);
				 Q_OUT : 	 out  STD_LOGIC_VECTOR(11 downto 0);	-- in-phase and quadrature output
				 RDY : 		 out  STD_LOGIC
				);
	end component;
	
	
-- Lowpass FIR filter	
	component FIR_IPCore
		Port ( CLK: 	in   STD_LOGIC;		-- 80 MHz clock from PLL		
				 DIN_1: 	in   STD_LOGIC_VECTOR(11 downto 0);
				 DIN_2: 	in   STD_LOGIC_VECTOR(11 downto 0);
				 DOUT_1: out  STD_LOGIC_VECTOR(11 downto 0);
				 DOUT_2: out  STD_LOGIC_VECTOR(11 downto 0);		-- input and output data buses
				 ND: 		in   STD_LOGIC;
			    RFD: 	out  STD_LOGIC;
				 RDY: 	out  STD_LOGIC		-- new data, ready for input data and output data ready
				);
	end component;
	
	
-- Decimation CIC filter	
	component CIC_IPCore
		Port ( CLK:  	 in   STD_LOGIC;		-- 80 MHz clock from PLL	
				 DIN:  	 in   STD_LOGIC_VECTOR(11 downto 0);
				 DOUT: 	 out  STD_LOGIC_VECTOR(11 downto 0);	-- input and output data bus
				 ND: 	 	 in   STD_LOGIC;
				 RFD:  	 out 	STD_LOGIC;
				 RDY:  	 out 	STD_LOGIC		-- new data, ready for input data and output data ready
				);
	end component;
	
	
-- CIC FIFO RAM
	component CIC_FIFO_IPCore
		Port ( CLK : 		   in   STD_LOGIC;		-- 80 MHz clock from PLL	
				 RST : 	 		in   STD_LOGIC;
				 DIN :    		in   STD_LOGIC_VECTOR(11 downto 0);		-- data in (from CIC filter IPCore)
				 WR_EN :  		in   STD_LOGIC;
				 RD_EN :  		in   STD_LOGIC;		-- write enable and read enable signal
				 DOUT :   		out  STD_LOGIC_VECTOR(11 downto 0);		-- data out (to FFT IPCore)
				 FULL :   		out  STD_LOGIC;
				 ALMOST_FULL : out  STD_LOGIC;
				 EMPTY :  		out  STD_LOGIC		-- full, almost full and empty flag
				);
	end component;
	
	
-- Fast Fourier Transform (FFT)
	component FFT_IPCore
		Port ( CLK : 		  	 in   STD_LOGIC;		-- 80 MHz clock from PLL	
				 START : 	  	 in   STD_LOGIC;		-- start transform
				 UNLOAD :	  	 in	STD_LOGIC;		-- unload transformed data in natural mode
				 XN_RE : 	  	 in   STD_LOGIC_VECTOR(11 downto 0);
				 XN_IM : 	  	 in   STD_LOGIC_VECTOR(11 downto 0);		-- real and imaginary input
				 FWD_INV : 	  	 in   STD_LOGIC;
				 FWD_INV_WE : 	 in   STD_LOGIC;		-- select FFT or IFFT and write enable
				 RFD : 		  	 out  STD_LOGIC;		-- ready for input data
				 XN_INDEX :   	 out  STD_LOGIC_VECTOR(9 downto 0);		-- index of input data
				 XK_INDEX :   	 out  STD_LOGIC_VECTOR(9 downto 0);		-- index of output data
				 XK_RE : 	  	 out  STD_LOGIC_VECTOR(22 downto 0);
				 XK_IM : 	  	 out  STD_LOGIC_VECTOR(22 downto 0);	-- real and imaginary output
				 BUSY : 		  	 out  STD_LOGIC;
				 EDONE : 	  	 out  STD_LOGIC;
				 DONE : 		  	 out  STD_LOGIC;
				 DV : 		  	 out  STD_LOGIC		-- busy, edone, done and output data valid
				);
	end component;
	
	
-- CORDIC IPCore for computing magnitude - absolute value (CORDIC ABS)
	component ABS_IPCore
		Port ( CLK : 	in   STD_LOGIC;		-- 80 MHz clock from PLL
				 X_IN : 	in   STD_LOGIC_VECTOR(23 downto 0);
				 Y_IN : 	in   STD_LOGIC_VECTOR(23 downto 0);		-- real and imaginary input
				 X_OUT : out  STD_LOGIC_VECTOR(23 downto 0);		-- absolute value of input signal (magnitude spectrum)
				 ND :		in	  STD_LOGIC;		-- new data on input port
				 RDY : 	out  STD_LOGIC			-- output data ready
				);
	end component;
	
	
-- Rx Accumulator (Rx Acc)	
	component Rx_accumulator
		Port ( CLK : 		  in   STD_LOGIC;		-- 80 MHz clock from PLL
				 RST : 		  in   STD_LOGIC;
				 WE : 		  in	 STD_LOGIC;
			    UNLOAD : 	  in	 STD_LOGIC;		-- write enable and unload signal
				 DATA_IN : 	  in   STD_LOGIC_VECTOR(23 downto 0);		-- data input (from ABS IPCore)
				 ACC_NUMBER : out  STD_LOGIC_VECTOR(31 downto 0);		-- number of accumulated data
				 DATA_OUT :   out  STD_LOGIC_VECTOR(31 downto 0);		-- accumulated data output (to Divider IPCore)
				 DV : 		  out  STD_LOGIC		-- data valid signal
				);
	end component;
	

-- Divider	
	component Divider_IPCore
		Port ( CLK : 		  in 	 STD_LOGIC;		-- 80 MHz clock from PLL
				 RFD : 		  out  STD_LOGIC;
				 DIVIDEND :   in 	 STD_LOGIC_VECTOR(31 downto 0);
				 DIVISOR : 	  in 	 STD_LOGIC_VECTOR(31 downto 0);
				 QUOTIENT :   out  STD_LOGIC_VECTOR(31 downto 0);
				 FRACTIONAL : out  STD_LOGIC_VECTOR(31 downto 0)
				);
	end component;
	
	
-- Receiver FIFO RAM (Rx FIFO)
	component Rx_FIFO_IPCore
		Port ( WR_CLK : 		in   STD_LOGIC;		-- 80 MHz clock from PLL
				 RD_CLK : 		in   STD_LOGIC;		-- clock signal from Ethernet Core
				 RST : 	 		in   STD_LOGIC;
				 DIN :    		in   STD_LOGIC_VECTOR(31 downto 0);	-- data in (accumulated power spectrum from Divider IPCore)
				 WR_EN :  		in   STD_LOGIC;
				 RD_EN :  		in   STD_LOGIC;		-- write enable and read enable signal
				 DOUT :   		out  STD_LOGIC_VECTOR(7 downto 0);		-- data out (to UDP-IP Core)
				 FULL :   		out  STD_LOGIC;
				 EMPTY :  		out  STD_LOGIC			-- full and empty flag
				);
	end component;
	
	
----------------------------------------------------------------------------------
-- SIGNALS declaration
----------------------------------------------------------------------------------

-- CLKs
	signal CLK_20M, CLK_80M, CLK_100M, CLK_160M: STD_LOGIC := '0';		-- clock signals 20, 80, 100 and 160 MHz
	signal CLK_Tx : STD_LOGIC := '0';	-- clock signal from Ethernet PHY chip
	signal tx_clk_0, rx_clk_0 : STD_LOGIC := '0';	-- clock signals from Ethernet PHY chip

-- (A)synchronous reset
	signal RST_Reg	: STD_LOGIC := '0';
	
-- RUN signal
	signal RUN_Reg	: STD_LOGIC := '0';	-- signal for stop receive data from PC when device is in measuring state
	
-- PC-FPGA
-- Rx
	signal rx_valid_data_out_Reg : STD_LOGIC := '0';	-- output data valid signal
	signal rx_data_out_Reg : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');		-- received data
-- Tx
	signal tx_start_enable_Reg : STD_LOGIC := '0';
	signal tx_data_trans_Reg : STD_LOGIC := '0';		-- start and data trans signal
	signal tx_data_length_Reg : STD_LOGIC_VECTOR(15 downto 0) := (others => '0');		-- data length signal
	signal tx_trans_bytes_Reg : STD_LOGIC_VECTOR(15 downto 0) := (others => '0');		-- number of transmitted bytes
	
-- External DDS
	signal dds_data_in_Reg : STD_LOGIC_VECTOR(dds_data_length-1 downto 0) := (others => '0');	-- signal for data (frequency setting)
	signal dds_enable_Reg : STD_LOGIC := '0';
	signal dds_ready_Reg : STD_LOGIC := '0';		-- enable and ready signal for direct digital synthesizer
	
-- PG
	signal pg_address_Reg : STD_LOGIC_VECTOR(pg_address_width-1 downto 0) := (others => '0');	-- signal for RAMīs address
	signal pg_data_in_Reg : STD_LOGIC_VECTOR(pg_data_length-1 downto 0) := (others => '0');	-- signal for data (pulse sequence)
	signal pg_pulse_sequence_Reg : STD_LOGIC_VECTOR(pg_channel_number -1 downto 0) := (others => '0');  -- pulses generated by PG
	signal pg_we_Reg : STD_LOGIC := '0';
	signal pg_rw_Reg : STD_LOGIC := '0';
	signal pg_enable_Reg : STD_LOGIC := '0';
	signal pg_finish_Reg : STD_LOGIC := '0';		-- write enable, read/write, enable and finish signal for pulse generator
	
-- PG FIFO
	signal pg_fifo_we_Reg : STD_LOGIC := '0';
	signal pg_fifo_re_Reg : STD_LOGIC := '0';			-- write enable and read enable signal
	signal pg_fifo_empty_Reg : STD_LOGIC := '0';		-- empty flag
	signal pg_receive_finish : STD_LOGIC := '0';		-- finish signal (last PG data send from MATLAB)
	signal pg_data_finish_Reg : STD_LOGIC := '0';	-- finish signal (end of writing data from FIFO to PG RAM)
	
-- IQ demodulator
	signal fid_Reg : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');		-- sampled FID signal
	signal i_signal_Reg : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');
	signal q_signal_Reg : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');		-- in-phase and quadrature signal
	signal iq_rdy_Reg : STD_LOGIC := '0';
	
-- FIR filter
	signal fir_i_filter_Reg : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');
	signal fir_q_filter_Reg : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');	-- in-phase and quadrature signal
	signal fir_rdy_Reg : STD_LOGIC := '0';	 -- data out ready signal
	
-- CIC filters
	signal cic_i_filter_Reg : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');
	signal cic_q_filter_Reg : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');	-- in-phase and quadrature signal
	signal cic_i_rdy_Reg : STD_LOGIC := '0';
	signal cic_q_rdy_Reg : STD_LOGIC := '0';	-- data out ready signals
	
-- CIC FIFOs
	signal cic_i_fifo_data_out_Reg : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');
	signal cic_q_fifo_data_out_Reg : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');	-- in-phase and quadrature signal
	signal cic_i_fifo_alm_full_Reg : STD_LOGIC := '0';
	signal cic_q_fifo_alm_full_Reg : STD_LOGIC := '0';		-- almost full flags
	
-- FFT
	signal fft_enable_Reg :  STD_LOGIC := '0';
	signal fft_start_Reg : STD_LOGIC := '0';
	signal fft_unload_Reg : STD_LOGIC := '0';		-- enable, start and unload signal
	signal fft_real_out_Reg : STD_LOGIC_VECTOR(22 downto 0) := (others => '0');
	signal fft_imag_out_Reg : STD_LOGIC_VECTOR(22 downto 0) := (others => '0');	-- transformed signals (output from FFT)
	signal fft_rfd_Reg : STD_LOGIC := '0';
	signal fft_done_Reg : STD_LOGIC := '0';
	signal fft_dv_Reg : STD_LOGIC := '0';		-- ready for data, done and output data valid signal
	
-- CORDIC ABS
	signal abs_real_in_Reg : STD_LOGIC_VECTOR(23 downto 0) := (others => '0');
	signal abs_imag_in_Reg : STD_LOGIC_VECTOR(23 downto 0) := (others => '0');		-- resized signals from FFT IPCore
	signal abs_data_out_Reg : STD_LOGIC_VECTOR(23 downto 0) := (others => '0');	-- magnitude of transformed signal
	signal abs_rdy_Reg : STD_LOGIC := '0';		-- output data ready signal

-- Rx Acc
	signal rx_acc_nmb_Reg : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');	-- number of accumulated data
	signal rx_acc_data_out_Reg : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');	-- accumulated data out (to Divider IPCore)
	signal rx_acc_unload_Reg : STD_LOGIC := '0';		-- unload signal	
	
-- Divider
	signal divider_data_out_Reg : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');	-- divided data out (to Rx FIFO IPCore)
	signal divider_dv_cnt_Reg : STD_LOGIC_VECTOR(11 downto 0) := (others => '0');	  -- count for control data valid signal
	signal divider_dv_Reg : STD_LOGIC := '0';	  -- data valid signal
	
-- Rx FIFO
	signal rx_fifo_re_Reg : STD_LOGIC := '0';			-- read enable signal
	signal rx_fifo_data_in_Reg : STD_LOGIC_VECTOR(31 downto 0) := (others => '0');	-- data in (from Divider IPCore)
	signal rx_fifo_data_out_Reg : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');	-- data out (to UDP-IP Core)
	signal rx_fifo_empty_Reg : STD_LOGIC := '0';		-- empty flag
	
-- Finite state machines
	type pg_data_state is (idle, write_data_1, write_data_2);
	signal pg_data_fsm : pg_data_state := idle;

	type rx_state is (idle, dds_data_1, dds_data_2, dds_data_3, dds_data_4, vga_data_1, vga_data_2, wait_pg_data,
							byte_nmb_1, byte_nmb_2, byte_nmb_3, byte_nmb_4, byte_nmb_5, byte_nmb_6, byte_nmb_7, byte_nmb_8);
	signal rx_fsm : rx_state := idle;
	
	type rx_fsm_state is (idle, enable_tx, wait_tx, transmit);
	signal fsm_state : rx_fsm_state := idle;
	
	type main_state is (idle, reset_1, reset_2, dds_start, pg_start);
	signal main_fsm : main_state := idle;	



begin
			
 
 
	PHY_RESET <= not RST;		-- asynchronous reset to PHY
	
	ibufg_phy_tx_0 : IBUFG port map (I => MII_TX_CLK_0, O => tx_clk_0);
   ibufg_phy_rx_0 : IBUFG port map (I => MII_RX_CLK_0, O => rx_clk_0);
	
	CLK_ADC <= CLK_80M;			-- 80 MHz clock signal to ADC
	CLK_DAC <= CLK_160M;			-- 160 MHz clock signal to DAC
	
	
	process (CLK_80M) begin						-- receiver gate
		if rising_edge(CLK_80M) then
			if (pg_pulse_sequence_Reg(30) = '1') then				
				fid_Reg <= FID;
			else
				fid_Reg <= (others => '0');
			end if;
		end if;
	end process;
	
			
-- DCM to PLL
	Unit_1 : PLL_IPCore
		Port map ( CLKIN_IN => CLK,
					  RST_IN => '0',
					  CLKIN_IBUFG_OUT => open,
					  CLKOUT0_OUT => CLK_20M,
					  CLKOUT1_OUT => CLK_80M,
					  CLKOUT2_OUT => CLK_100M,
					  CLKOUT3_OUT => CLK_160M
					 );
					 

-- Internal DDS
	Unit_2 : Internal_DDS
		Port map ( CLK => CLK_160M,
					  SINE => DATA_OUT_DAC
					 );
				
				
-- PC-FPGA				 
	Unit_3 : Ethernet_IPCore_top
		Port map ( RESET => RST,
					  MII_COL_0 => MII_COL_0,
					  MII_CRS_0 => MII_CRS_0,
					  MII_TXD_0 => MII_TXD_0(3 downto 0),
					  MII_TX_EN_0 => MII_TX_EN_0,
					  MII_TX_ER_0 => MII_TX_ER_0,
					  MII_TX_CLK_0 => tx_clk_0,
					  MII_RXD_0 => MII_RXD_0,
					  MII_RX_DV_0 => MII_RX_DV_0,
					  MII_RX_ER_0 => MII_RX_ER_0,
					  MII_RX_CLK_0 => rx_clk_0,
					  TX_CLIENT_CLK => CLK_Tx,
					  RX_VALID_DATA_OUT => rx_valid_data_out_Reg,
					  RX_DATA_OUT => rx_data_out_Reg,
					  TX_START_ENABLE => tx_start_enable_Reg,
					  TX_DATA_TRANS => tx_data_trans_Reg,
					  TX_DATA_LENGTH => tx_data_length_Reg,
					  TX_DATA_IN => rx_fifo_data_out_Reg
					 );
					 
	GTX_CLK_0 <= '0';
	MII_TXD_0(7 downto 4) <= "0000";		-- connect unused pins of PHY to log 0
				
				
-- External DDS
	Unit_4 : DDS_control
	 Generic map ( dds_data_length => dds_data_length,
					   dds_bus_width => dds_bus_width
					 )
	 Port map ( CLK => CLK_20M,
					RST => RST_Reg,
					ENABLE => dds_enable_Reg,
					DATA_IN => dds_data_in_Reg,
					RST_DDS => RST_DDS,
					W_CLK_DDS => W_CLK_DDS,
					FQ_UD_DDS => FQ_UD_DDS,
					DATA_OUT => DATA_OUT_DDS,
					READY => dds_ready_Reg
				  );				 
				
				
-- PG			
	Unit_5 : Pulse_generator
		Generic map ( pg_data_length => pg_data_length,
						  pg_channel_number => pg_channel_number,
						  pg_address_width => pg_address_width,
						  pg_address_number => pg_address_number,
						  pg_timer_width => pg_timer_width
						 )
		Port map ( CLK => CLK_100M,
					  RST => RST_Reg,
					  ENABLE => pg_enable_Reg,
					  WE => pg_we_Reg,
					  RW => pg_rw_Reg,
					  ADDRESS => pg_address_Reg,
					  DATA_IN => pg_data_in_Reg,
					  PULSE_OUT => pg_pulse_sequence_Reg,
					  FINISH => pg_finish_Reg
					 );
					 
	Tx_Gate <= pg_pulse_sequence_Reg(31);		-- mapping control pulses from pulse sequence
	Rx_Gate <= pg_pulse_sequence_Reg(30);
	fft_enable_Reg <= pg_pulse_sequence_Reg(30);
	Amp_Gate <= pg_pulse_sequence_Reg(29);


-- PG FIFO
	Unit_6 : PG_FIFO_IPCore
		Port map ( WR_CLK => CLK_Tx,
					  RD_CLK => CLK_100M,
					  RST => RST_Reg,
					  DIN => rx_data_out_Reg,
					  WR_EN => pg_fifo_we_Reg,
					  RD_EN => pg_fifo_re_Reg,
					  DOUT => pg_data_in_Reg,
					  FULL => open,
					  EMPTY => pg_fifo_empty_Reg
					 );
					 
					 
-- IQ demodulator
	Unit_7 : IQ_demodulator
		Port map ( CLK => CLK_80M,
					  RST => RST_Reg,
					  SIGNAL_IN => fid_Reg,
					  I_OUT => i_signal_Reg,
					  Q_OUT => q_signal_Reg,
					  RDY => iq_rdy_Reg
					 );
					 
					 
-- FIR filter
	Unit_8 : FIR_IPCore
		Port map ( CLK => CLK_80M,
					  DIN_1 => i_signal_Reg,
					  DIN_2 => q_signal_Reg,
					  DOUT_1 => fir_i_filter_Reg,
					  DOUT_2 => fir_q_filter_Reg,
					  ND => iq_rdy_Reg,
					  RFD => open,
					  RDY => fir_rdy_Reg
					 );
					 
					 
-- CIC filters
	Unit_9a : CIC_IPCore
		Port map ( CLK => CLK_80M,
					  DIN => fir_i_filter_Reg,
					  DOUT => cic_i_filter_Reg,
					  ND => fir_rdy_Reg,
					  RDY => cic_i_rdy_Reg,
					  RFD => open
					 );
					 
	Unit_9b : CIC_IPCore
		Port map ( CLK => CLK_80M,
					  DIN => fir_q_filter_Reg,
					  DOUT => cic_q_filter_Reg,
					  ND => fir_rdy_Reg,
					  RDY => cic_q_rdy_Reg,
					  RFD => open
					 );
					 
					 
-- CIC FIFOs
	Unit_10a : CIC_FIFO_IPCore
		Port map ( CLK => CLK_80M,
					  RST => RST_Reg,
					  DIN => cic_i_filter_Reg,
					  WR_EN => cic_i_rdy_Reg,
					  RD_EN => fft_rfd_Reg,
					  DOUT => cic_i_fifo_data_out_Reg,
					  FULL => open,
					  ALMOST_FULL => cic_i_fifo_alm_full_Reg,
					  EMPTY => open
					 );
					 
	Unit_10b : CIC_FIFO_IPCore
		Port map ( CLK => CLK_80M,
					  RST => RST_Reg,
					  DIN => cic_q_filter_Reg,
					  WR_EN => cic_q_rdy_Reg,
					  RD_EN => fft_rfd_Reg,
					  DOUT => cic_q_fifo_data_out_Reg,
					  FULL => open,
					  ALMOST_FULL => cic_q_fifo_alm_full_Reg,
					  EMPTY => open
					 );
					 

-- FFT
	Unit_11 : FFT_IPCore
		Port map ( CLK => CLK_80M,
					  START => fft_start_Reg,
					  UNLOAD => fft_unload_Reg,
					  XN_RE => cic_i_fifo_data_out_Reg,
					  XN_IM => cic_q_fifo_data_out_Reg,
					  FWD_INV => '1',
					  FWD_INV_WE => '0',
					  RFD => fft_rfd_Reg,
					  XN_INDEX => open,
					  XK_INDEX => open,
					  XK_RE => fft_real_out_Reg,
					  XK_IM => fft_imag_out_Reg,
					  BUSY => open,
					  EDONE => open,
					  DONE => fft_done_Reg,
					  DV => fft_dv_Reg
					 );
					 
	process (CLK_80M) begin
		if rising_edge(CLK_80M) then
			fft_start_Reg <= '0';				-- start transform when CIC FIFOs are almost full
			
			if (fft_enable_Reg = '1' and cic_i_fifo_alm_full_Reg = '1' and cic_q_fifo_alm_full_Reg = '1') then
				fft_start_Reg <= '1';
			end if;
		end if;
	end process;
	
	process (CLK_80M) begin
		if rising_edge(CLK_80M) then
			fft_unload_Reg <= '0';				-- unload data in natural order when transform was finished
			
			if (fft_done_Reg = '1') then
				fft_unload_Reg <= '1';
			end if;
		end if;
	end process;	
	
	
-- CORDIC ABS
	Unit_12 : ABS_IPCore
		Port map ( CLK => CLK_80M,
					  X_IN => abs_real_in_Reg,
					  Y_IN => abs_imag_in_Reg,
					  X_OUT => abs_data_out_Reg,
					  ND => fft_dv_Reg,
					  RDY => abs_rdy_Reg
					 );
					 
	abs_real_in_Reg <= STD_LOGIC_VECTOR(resize(SIGNED(fft_real_out_Reg),24));
	abs_imag_in_Reg <= STD_LOGIC_VECTOR(resize(SIGNED(fft_imag_out_Reg),24));		-- resize (scale) data to CORDIC input range

		
-- Rx Acc
	Unit_13 : Rx_accumulator
		Port map ( CLK => CLK_80M,
					  RST => RST_Reg,
					  WE => abs_rdy_Reg,
					  UNLOAD => rx_acc_unload_Reg,
					  DATA_IN => abs_data_out_Reg,
					  ACC_NUMBER => rx_acc_nmb_Reg,
					  DATA_OUT => rx_acc_data_out_Reg,
					  DV => open
					 );	
					 
	process (CLK_80M) begin
		if rising_edge(CLK_80M) then
			if (RST_Reg = '1') then
				rx_acc_unload_Reg <= '0';		-- unload data from Rx Accumulator when pulse sequences were finished		
				
			elsif (pg_finish_Reg = '1') then
				rx_acc_unload_Reg <= '1';
			end if;
			
		end if;
	end process;


-- Divider
	Unit_14 : Divider_IPCore
		Port map ( CLK => CLK_80M,
					  RFD => open,
					  DIVIDEND => rx_acc_data_out_Reg,
					  DIVISOR => rx_acc_nmb_Reg,
					  QUOTIENT => divider_data_out_Reg,
					  FRACTIONAL => open
					 );
					 
	process (CLK_80M) begin
		if rising_edge(CLK_80M) then
			if (RST_Reg = '1') then
				divider_dv_cnt_Reg <= (others => '0');			-- assert DV signal in right time
				divider_dv_Reg <= '0';								-- (due to latency of Divider IPCore and number of accumulation)
				rx_fifo_data_in_Reg <= (others => '0');
				
			elsif (rx_acc_unload_Reg = '1') then
				divider_dv_Reg <= '0';
				rx_fifo_data_in_Reg <= (others => '0');
			
				if (divider_dv_cnt_Reg < X"462") then
					divider_dv_cnt_Reg <= STD_LOGIC_VECTOR(UNSIGNED(divider_dv_cnt_Reg) + 1);
					
					if (divider_dv_cnt_Reg > X"021" and divider_dv_cnt_Reg < X"422") then
						divider_dv_Reg <= '1';
						rx_fifo_data_in_Reg <= divider_data_out_Reg;		-- send divided data to Rx FIFO
					elsif (divider_dv_cnt_Reg >= X"422") then
						divider_dv_Reg <= '1';
						rx_fifo_data_in_Reg <= rx_acc_nmb_Reg;				-- send number of accumulation to Rx FIFO
					end if;
				end if;
			end if;
			
		end if;
	end process;
	
	
-- Rx FIFO
	Unit_15 : Rx_FIFO_IPCore
		Port map ( WR_CLK => CLK_80M,
					  RD_CLK => CLK_Tx,
					  RST => RST_Reg,
					  DIN => rx_fifo_data_in_Reg,
					  WR_EN => divider_dv_Reg,
					  RD_EN => rx_fifo_re_Reg,
					  DOUT => rx_fifo_data_out_Reg,
					  FULL => open,
					  EMPTY => rx_fifo_empty_Reg
					 );




	process (CLK_100M) begin
		if rising_edge(CLK_100M) then
			if (RST_Reg = '1') then
				pg_rw_Reg <= '1';
				pg_we_Reg <= '0';
				pg_address_Reg <= (others => '0');
				pg_fifo_re_Reg	<= '0';
				pg_data_finish_Reg <= '0';
				pg_data_fsm <= idle;
			else
			
				case pg_data_fsm is
				
					when idle =>			pg_we_Reg <= '0';
												pg_address_Reg <= (others => '0');
												pg_data_finish_Reg <= '0';
						
												if (pg_fifo_empty_Reg = '0') then		-- wait until data for PG is received
													pg_rw_Reg <= '0';
													pg_fifo_re_Reg	<= '1';
													pg_data_fsm <= write_data_1;
												else
													pg_rw_Reg <= '1';
													pg_fifo_re_Reg	<= '0';
													pg_data_fsm <= idle;
												end if;
												
					when write_data_1 => pg_rw_Reg <= '0';
												pg_we_Reg <= '1';
												pg_fifo_re_Reg	<= '0';
												pg_data_finish_Reg <= '0';
												pg_data_fsm <= write_data_2;
										
					when write_data_2 =>	pg_we_Reg <= '0';
																									 -- write received data to PG RAM
												if (pg_fifo_empty_Reg = '1') then
													if (pg_data_in_Reg(pg_data_in_Reg'HIGH) = '1') then
														pg_rw_Reg <= '1';
														pg_fifo_re_Reg	<= '0';
														pg_data_finish_Reg <= '1';
														pg_data_fsm <= write_data_2;
													else
														pg_rw_Reg <= '0';
														pg_fifo_re_Reg	<= '0';
														pg_data_finish_Reg <= '0';
														pg_data_fsm <= write_data_2;
													end if;
												else
													pg_rw_Reg <= '0';
													pg_address_Reg <= STD_LOGIC_VECTOR(UNSIGNED(pg_address_Reg) + 1);
													pg_fifo_re_Reg	<= '1';
													pg_data_finish_Reg <= '0';
													pg_data_fsm <= write_data_1;
												end if;
				
				end case;
				
			end if;
		end if;	
	end process;


	
	process (CLK_Tx) begin
		if rising_edge(CLK_Tx) then
			if (RUN_Reg = '1' or RST_Reg = '1') then
				pg_fifo_we_Reg <= '0';
				pg_receive_finish <= '0';
				DATA_OUT_VGA <= (others => '0');
				DENB_VGA <= '0';
				rx_fsm <= idle;
			else
			
				case rx_fsm is
				
					when idle =>			pg_fifo_we_Reg <= '0';
												pg_receive_finish <= '0';
												DATA_OUT_VGA <= (others => '0');
												DENB_VGA <= '0';
											
												if (rx_valid_data_out_Reg = '1') then		-- wait until data for DDS is received
													rx_fsm <= dds_data_1;
												else
													rx_fsm <= idle;
												end if;
												
					when dds_data_1 =>	pg_fifo_we_Reg <= '0';					-- receiving DDS setting word
												pg_receive_finish <= '0';
												dds_data_in_Reg(39 downto 24) <= STD_LOGIC_VECTOR(X"00" & UNSIGNED(rx_data_out_Reg));
												DATA_OUT_VGA <= (others => '0');
												DENB_VGA <= '0';
												rx_fsm <= dds_data_2;
												
					when dds_data_2 =>	pg_fifo_we_Reg <= '0';
												pg_receive_finish <= '0';
												dds_data_in_Reg(23 downto 16) <= rx_data_out_Reg;
												DATA_OUT_VGA <= (others => '0');
												DENB_VGA <= '0';
												rx_fsm <= dds_data_3;
												
					when dds_data_3 =>	pg_fifo_we_Reg <= '0';
												pg_receive_finish <= '0';
												dds_data_in_Reg(15 downto 8) <= rx_data_out_Reg;
												DATA_OUT_VGA <= (others => '0');
												DENB_VGA <= '0';
												rx_fsm <= dds_data_4;
												
					when dds_data_4 =>	pg_fifo_we_Reg <= '0';
												pg_receive_finish <= '0';
												dds_data_in_Reg(7 downto 0) <= rx_data_out_Reg;
												DATA_OUT_VGA <= (others => '0');
												DENB_VGA <= '0';
												rx_fsm <= vga_data_1;
												
					when vga_data_1 =>	pg_fifo_we_Reg <= '0';
												pg_receive_finish <= '0';
												DATA_OUT_VGA <= (others => '0');
												DENB_VGA <= '1';
											
												if (rx_valid_data_out_Reg = '1') then		-- wait until data for VGA is received
													rx_fsm <= vga_data_2;
												else
													rx_fsm <= vga_data_1;
												end if;
												
					when vga_data_2 =>	pg_fifo_we_Reg <= '0';					-- receiving VGA control word
												pg_receive_finish <= '0';
												DATA_OUT_VGA <= rx_data_out_Reg(3 downto 0);
												DENB_VGA <= '1';
												rx_fsm <= wait_pg_data;

					when wait_pg_data => pg_receive_finish <= '0';			-- wait until data for PG is received
												DENB_VGA <= '0';
							
												if (rx_valid_data_out_Reg = '1') then
													pg_fifo_we_Reg <= '1';
													rx_fsm <= byte_nmb_1;
												else
													pg_fifo_we_Reg <= '0';
													rx_fsm <= wait_pg_data;
												end if;
												
					when byte_nmb_1 =>   pg_fifo_we_Reg <= '1';				-- receiving data for pulse generator
												DENB_VGA <= '0';
												rx_fsm <= byte_nmb_2;
					
												if (rx_data_out_Reg(rx_data_out_Reg'HIGH) = '1') then
													pg_receive_finish <= '1';
												else
													pg_receive_finish <= '0';
												end if;
												
					when byte_nmb_2 =>   pg_fifo_we_Reg <= '1';
												DENB_VGA <= '0';
												rx_fsm <= byte_nmb_3;

					when byte_nmb_3 =>   pg_fifo_we_Reg <= '1';
												DENB_VGA <= '0';
												rx_fsm <= byte_nmb_4;
												
					when byte_nmb_4 =>   pg_fifo_we_Reg <= '1';
												DENB_VGA <= '0';
												rx_fsm <= byte_nmb_5;
												
					when byte_nmb_5 =>   pg_fifo_we_Reg <= '1';
												DENB_VGA <= '0';
												rx_fsm <= byte_nmb_6;												
												
					when byte_nmb_6 =>   pg_fifo_we_Reg <= '1';
												DENB_VGA <= '0';
												rx_fsm <= byte_nmb_7;
												
					when byte_nmb_7 =>   pg_fifo_we_Reg <= '1';
												DENB_VGA <= '0';
												rx_fsm <= byte_nmb_8;
												
					when byte_nmb_8 =>   pg_fifo_we_Reg <= '0';
												DENB_VGA <= '0';
					
												if (pg_receive_finish = '1') then
													rx_fsm <= idle;
											   else
													rx_fsm <= wait_pg_data;
												end if;
				
				end case;
				
			end if;
		end if;
	end process;
	
	
	
	process (CLK_Tx) begin
		if rising_edge(CLK_Tx) then
			if (RST_Reg = '1') then
				rx_fifo_re_Reg <= '0';
				tx_data_length_Reg <= (others => '0');
				tx_start_enable_Reg <= '0';
				tx_trans_bytes_Reg <= (others => '0');
				fsm_state <= idle;
			else
			
				case fsm_state is
				
					when idle =>		 rx_fifo_re_Reg <= '0';
											 tx_trans_bytes_Reg <= (others => '0');
					
											 if (rx_fifo_empty_Reg = '0') then		-- waiting for data from Divider IPCore
												 tx_data_length_Reg <= X"0100";		-- set transmit data length to 256 B
												 tx_start_enable_Reg <= '1';
												 fsm_state <= enable_tx;
											 else
												 tx_data_length_Reg <= (others => '0');
												 tx_start_enable_Reg <= '0';
												 fsm_state <= idle;
											 end if;
				
					when enable_tx =>	 rx_fifo_re_Reg <= '0';						-- enable transmitter
											 tx_start_enable_Reg <= '0';
											 tx_trans_bytes_Reg <= (others => '0');
											 fsm_state <= wait_tx;
											
					when wait_tx =>	 tx_start_enable_Reg <= '0';				-- wait for user data transmit phase
					
											 if (tx_data_trans_Reg = '1') then
												 rx_fifo_re_Reg <= '1';
												 tx_trans_bytes_Reg <= STD_LOGIC_VECTOR(UNSIGNED(tx_trans_bytes_Reg) + 1);
												 fsm_state <= transmit;
											 else
												 rx_fifo_re_Reg <= '0';
												 tx_trans_bytes_Reg <= (others => '0');
												 fsm_state <= wait_tx;
											 end if;
											
					when transmit =>	 tx_start_enable_Reg <= '0';

											 if (tx_trans_bytes_Reg = X"0100") then	 -- go to idle state when 256 B was trasmitted
												 rx_fifo_re_Reg <= '0';
												 fsm_state <= idle;
											 else
												 rx_fifo_re_Reg <= '1';
												 tx_trans_bytes_Reg <= STD_LOGIC_VECTOR(UNSIGNED(tx_trans_bytes_Reg) + 1);
												 fsm_state <= transmit;
											 end if;
					
				end case;
			end if;
		end if;
	end process;



	process (CLK_80M) begin
		if rising_edge(CLK_80M) then
			if (RST = '1') then
				RST_Reg <= '0';
				RUN_Reg <= '0';
				dds_enable_Reg <= '0';
				pg_enable_Reg <= '0';
				main_fsm <= idle;
			else
			
				case main_fsm is
					
					when idle =>   	 RST_Reg <= '0';
											 dds_enable_Reg <= '0';
											 pg_enable_Reg <= '0'; 
					
											 if (pg_data_finish_Reg = '1') then		-- wait until all data for PG was received
												 RUN_Reg <= '1';
												 main_fsm <= reset_1;
											 else
												 RUN_Reg <= '0';
												 main_fsm <= idle;
											 end if;
											 
					when reset_1 =>	 RST_Reg <= '1';					-- reset the system components
											 RUN_Reg <= '1';
											 dds_enable_Reg <= '0';
											 pg_enable_Reg <= '0';
											 main_fsm <= reset_2;

					when reset_2 => 	 RST_Reg <= '0';
											 RUN_Reg <= '1';
											 dds_enable_Reg <= '1';
											 pg_enable_Reg <= '0';
											 main_fsm <= dds_start;
										
					when dds_start =>  RST_Reg <= '0';
											 RUN_Reg <= '1';
					
											 if (dds_ready_Reg = '1') then		-- set external DDS
												 dds_enable_Reg <= '0';
												 pg_enable_Reg <= '1';
												 main_fsm <= pg_start;
											 else
												 dds_enable_Reg <= '1';
												 pg_enable_Reg <= '0';
												 main_fsm <= dds_start;
											 end if;
											
					when pg_start =>   RST_Reg <= '0';
											 RUN_Reg <= '1';							 -- run PG and measuring process
											 dds_enable_Reg <= '0';
					
											 if (pg_finish_Reg = '1') then
												 pg_enable_Reg <= '0';
												 main_fsm <= idle;
											 else
												 pg_enable_Reg <= '1';
												 main_fsm <= pg_start;
										end if;
				
				end case;
				
			end if;			
		end if;
	end process;



end Behavioral;

