----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    14:14:37 07/11/2012 
-- Design Name: 
-- Module Name:    Pulse_generator - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 

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

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

entity 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
           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 in (pulse sequence)
           PULSE_OUT :    out  STD_LOGIC_VECTOR(pg_channel_number-1 downto 0);	-- generated pulse sequence
			  FINISH :	     out  STD_LOGIC		-- finish "message" back to NQR_ML505_top
			 );
end Pulse_generator;

architecture Behavioral of Pulse_generator is


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

-- Pulse generator timer for making pulse/delay intervals
	component Pulse_generator_timer is
		Generic ( pg_timer_width : natural
					);
		Port ( CLK : 	  	  in   STD_LOGIC;
				 RST : 	  	  in   STD_LOGIC;
				 LOAD : 	  	  in   STD_LOGIC;
				 DATA_IN : 	  in   STD_LOGIC_VECTOR(pg_timer_width-1 downto 0);
				 FINISH_CNT : out  STD_LOGIC
				);
	end component;
	
	
-- Pulse generator RAM for storing pulse sequence
	component Pulse_generator_RAM is
		Generic ( pg_address_width : natural;
					 pg_address_number : natural;
					 pg_data_length : natural
					);
		Port ( CLK :		in   STD_LOGIC;
				 ADDRESS :  in   STD_LOGIC_VECTOR(pg_address_width-1 downto 0);
				 DATA_IN :  in   STD_LOGIC_VECTOR(pg_data_length-1 downto 0);
				 WE :       in   STD_LOGIC;
				 RW : 		in   STD_LOGIC;
				 DATA_OUT : out  STD_LOGIC_VECTOR(pg_data_length-1 downto 0)
			   );
	end component;

	
----------------------------------------------------------------------------------
-- SIGNALS declaration
----------------------------------------------------------------------------------
	
	signal state_Reg : STD_LOGIC_VECTOR(1 downto 0) := "00";		-- signal for state machine
	
	signal timer_load_Reg : STD_LOGIC := '0';
	signal timer_data_Reg : STD_LOGIC_VECTOR(pg_timer_width-1 downto 0) := (others => '0');
	signal timer_finish_Reg : STD_LOGIC := '0';		-- signals for controlling timer counter
	
	signal ram_address_Reg : STD_LOGIC_VECTOR(pg_address_width-1 downto 0) := (others => '0');
	signal ram_next_address_Reg : STD_LOGIC_VECTOR(pg_address_width-1 downto 0) := (others => '0');
	signal ram_data_out_Reg : STD_LOGIC_VECTOR(pg_data_length-1 downto 0) := (others => '0');		-- signals for RAM
	
	signal data_end_Reg : STD_LOGIC := '0';
	signal data_pulse_Reg : STD_LOGIC_VECTOR(pg_channel_number-1 downto 0) := (others => '0');
	signal last_pulse_Reg :	STD_LOGIC := '0';
	signal pulse_out_enable : STD_LOGIC := '0';		-- signals for controlling pulse sequence
	


begin


-- Pulse generator timer
	Unit_4a : Pulse_generator_timer
		Generic map ( pg_timer_width => pg_timer_width
						 )
		Port map ( CLK => CLK,
					  RST => RST,
					  LOAD => timer_load_Reg,
					  DATA_IN => timer_data_Reg,
					  FINISH_CNT => timer_finish_Reg
					 );


-- Pulse generator RAM			 
	Unit_4b : Pulse_generator_RAM
		Generic map ( pg_address_width => pg_address_width,
						  pg_address_number => pg_address_number,
						  pg_data_length => pg_data_length
						 )
		Port map ( CLK => CLK,
					  ADDRESS => ram_address_Reg,
					  DATA_IN => DATA_IN,
					  WE => WE,
					  RW => RW,
					  DATA_OUT => ram_data_out_Reg
					 );
	
	
	
	process (CLK) begin
		if rising_edge(CLK) then
			if (RW = '1') then
				ram_address_Reg <= ram_next_address_Reg;		-- in READ mode take address of RAM from inside counter
			else
				ram_address_Reg <= ADDRESS;		-- in WRITE mode take address of RAM from outside
			end if;
      end if;
	end process;
	
	
	
	process (CLK) begin
		if rising_edge(CLK) then
			if (ENABLE = '0' or RST = '1') then
				PULSE_OUT <= (others => '0');		-- in nonENABLE mode on output is zero pulse sequence
			elsif (pulse_out_enable = '1') then
				PULSE_OUT <= data_pulse_Reg;		-- in ENABLE mode on output is pulse sequence stored in RAM
			end if;
      end if;
	end process;
	
	
	
	data_end_Reg <= ram_data_out_Reg(ram_data_out_Reg'HIGH);		-- if '1' => last pulse sequence
	timer_data_Reg <= ram_data_out_Reg(pg_channel_number+pg_timer_width-1 downto pg_channel_number); 	-- data (time) for timer
	data_pulse_Reg <= ram_data_out_Reg(pg_channel_number-1 downto 0);		-- pulse sequence
	
	
	process (CLK) begin
		if rising_edge(CLK) then
			if (ENABLE = '0' or RST = '1') then
				ram_next_address_Reg <= (others => '0');
				FINISH <= '0';
				pulse_out_enable <= '0';
				timer_load_Reg <= '0';
			   last_pulse_Reg <= '0';
				state_Reg <= "00";
			else
	
				case state_Reg is

					when "00" =>  ram_next_address_Reg <= (others => '0');
									  pulse_out_enable <= '0';
									  timer_load_Reg <= '0';
									  last_pulse_Reg <= '0';
									  FINISH <= '0';
				
									  if (ENABLE = '0') then 
										  state_Reg <= "00";
									  else 
										  state_Reg <= "01";
									  end if;
													
					when "01" =>  pulse_out_enable <= '1';		-- enable PG out and load new data to timer counter
									  timer_load_Reg <= '1';
										
									  if (data_end_Reg = '1') then
										  last_pulse_Reg <= '1';		-- check end of pulse sequence
									  else
										  last_pulse_Reg <= '0';
--										  ram_next_address_Reg <= ram_next_address_Reg + 1;	-- prepare data from next address
										  ram_next_address_Reg <= STD_LOGIC_VECTOR(UNSIGNED(ram_next_address_Reg) + 1);	-- prepare data from next address
									  end if;
										
									  FINISH <= '0';
									  state_Reg <= "10";

					when "10" =>  pulse_out_enable <= '0';
									  timer_load_Reg <= '0';
									  FINISH <= '0';
					
									  if (timer_finish_Reg = '0') then	-- waiting for timer counter (interval of pulses/delays)
										  state_Reg <= "10";
									  else
										  state_Reg <= "11";
									  end if;
									  
					when "11" =>  pulse_out_enable <= '0';
									  timer_load_Reg <= '0';
									  
									  if (last_pulse_Reg = '1') then		-- check end of pulse sequence
										  FINISH <= '1';		-- send FINISH "message" back to NQR_ML505_top
										  state_Reg <= "11";
									  else
										  FINISH <= '0';
										  state_Reg <= "01";		-- go to generate next pulses/delays
									  end if;									 
										
					when others =>  state_Reg <= "00";
									
				end case;
		
			end if;
		end if;
	end process;	
	


end Behavioral;

