----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    21:35:02 05/06/2020 
-- Design Name: 
-- Module Name:    Sweep - 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 primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Sweep is
    Port ( CLK : in  STD_LOGIC;
           RESET : in  STD_LOGIC;
			  NPOINTS : in STD_LOGIC_VECTOR (12 downto 0);
           CONFIG_ADDRESS : out  STD_LOGIC_VECTOR (12 downto 0);
           CONFIG_DATA : in  STD_LOGIC_VECTOR (95 downto 0);
			  USER_NSAMPLES : in STD_LOGIC_VECTOR (12 downto 0);
			  NSAMPLES : out STD_LOGIC_VECTOR (12 downto 0);
           SAMPLING_BUSY : in STD_LOGIC;
			  SAMPLING_DONE : in  STD_LOGIC;
			  START_SAMPLING : out STD_LOGIC;
			  PORT_SELECT : out STD_LOGIC;
			  BAND_SELECT : out STD_LOGIC;
			  -- fixed part of source/LO registers
           MAX2871_DEF_4 : in  STD_LOGIC_VECTOR (31 downto 0);
           MAX2871_DEF_3 : in  STD_LOGIC_VECTOR (31 downto 0);
           MAX2871_DEF_1 : in  STD_LOGIC_VECTOR (31 downto 0);
           MAX2871_DEF_0 : in  STD_LOGIC_VECTOR (31 downto 0);
			  -- assembled source/LO registers
			  SOURCE_REG_4 : out  STD_LOGIC_VECTOR (31 downto 0);
           SOURCE_REG_3 : out  STD_LOGIC_VECTOR (31 downto 0);
           SOURCE_REG_1 : out  STD_LOGIC_VECTOR (31 downto 0);
           SOURCE_REG_0 : out  STD_LOGIC_VECTOR (31 downto 0);
			  LO_REG_4 : out  STD_LOGIC_VECTOR (31 downto 0);
           LO_REG_3 : out  STD_LOGIC_VECTOR (31 downto 0);
           LO_REG_1 : out  STD_LOGIC_VECTOR (31 downto 0);
           LO_REG_0 : out  STD_LOGIC_VECTOR (31 downto 0);
			  RELOAD_PLL_REGS : out STD_LOGIC;
			  PLL_RELOAD_DONE : in STD_LOGIC;
			  PLL_LOCKED : in STD_LOGIC;
			  SWEEP_HALTED : out STD_LOGIC;
			  SWEEP_RESUME : in STD_LOGIC;
			  
			  ATTENUATOR : out STD_LOGIC_VECTOR(6 downto 0);
			  SOURCE_FILTER : out STD_LOGIC_VECTOR(1 downto 0);
			  
			  --SETTLING_TIME : in STD_LOGIC_VECTOR (15 downto 0);
			  
			  EXCITE_PORT1 : in STD_LOGIC;
			  EXCITE_PORT2 : in STD_LOGIC;
			  
			  -- Debug signals
			  DEBUG_STATUS : out STD_LOGIC_VECTOR (10 downto 0);
			  RESULT_INDEX : out STD_LOGIC_VECTOR (15 downto 0)
			  );
end Sweep;

architecture Behavioral of Sweep is
	signal point_cnt : unsigned(12 downto 0);
	type Point_states is (TriggerSetup, SettingUp, SettlingPort1, ExcitingPort1, SettlingPort2, ExcitingPort2, NextPoint, Done);
	signal state : Point_states;
	signal settling_cnt : unsigned(15 downto 0);
	signal settling_time : unsigned(15 downto 0);
	signal config_reg : std_logic_vector(95 downto 0);
begin
	
	CONFIG_ADDRESS <= std_logic_vector(point_cnt);
	
	-- assemble registers
	-- source register 0: N divider and fractional division value
	SOURCE_REG_0 <= MAX2871_DEF_0(31) & "000000000" & config_reg(6 downto 0) & config_reg(27 downto 16) & "000";
	-- source register 1: Modulus value
	SOURCE_REG_1 <= MAX2871_DEF_1(31 downto 15) & config_reg(39 downto 28) & "001";
	-- source register 3: VCO selection
	SOURCE_REG_3 <= config_reg(12 downto 7) & MAX2871_DEF_3(25 downto 3) & "011";
	-- output power A passed on from default registers, output B disabled
	SOURCE_REG_4 <= MAX2871_DEF_4(31 downto 23) & config_reg(15 downto 13) & MAX2871_DEF_4(19 downto 9) & "000" & MAX2871_DEF_4(5 downto 3) & "100";
	
	-- LO register 0: N divider and fractional division value
	LO_REG_0 <= MAX2871_DEF_0(31) & "000000000" & config_reg(54 downto 48) & config_reg(75 downto 64) & "000";
	-- LO register 1: Modulus value
	LO_REG_1 <= MAX2871_DEF_1(31 downto 15) & config_reg(87 downto 76) & "001";
	-- LO register 3: VCO selection
	LO_REG_3 <= config_reg(60 downto 55) & MAX2871_DEF_3(25 downto 3) & "011";
	-- both outputs enabled at +5dbm
	LO_REG_4 <= MAX2871_DEF_4(31 downto 23) & config_reg(63 downto 61) & MAX2871_DEF_4(19 downto 9) & "111111100";
	
	ATTENUATOR <= config_reg(46 downto 40);
	SOURCE_FILTER <= config_reg(89 downto 88);
	BAND_SELECT <= config_reg(47);
							
	NSAMPLES <= USER_NSAMPLES when config_reg(92 downto 90) = "000" else
					std_logic_vector(to_unsigned(6, 13)) when config_reg(92 downto 90) = "001" else
					std_logic_vector(to_unsigned(19, 13)) when config_reg(92 downto 90) = "010" else
					std_logic_vector(to_unsigned(57, 13)) when config_reg(92 downto 90) = "011" else
					std_logic_vector(to_unsigned(190, 13)) when config_reg(92 downto 90) = "100" else
					std_logic_vector(to_unsigned(571, 13)) when config_reg(92 downto 90) = "101" else
					std_logic_vector(to_unsigned(1904, 13)) when config_reg(92 downto 90) = "110" else
					std_logic_vector(to_unsigned(5712, 13));
	
	DEBUG_STATUS(10 downto 8) <= "000" when state = TriggerSetup else
											"001" when state = SettingUp else
											"010" when state = SettlingPort1 else
											"011" when state = ExcitingPort1 else
											"100" when state = SettlingPort2 else
											"101" when state = ExcitingPort2 else
											"110" when state = Done else
											"111";
	DEBUG_STATUS(7) <= PLL_RELOAD_DONE;
	DEBUG_STATUS(6) <= PLL_RELOAD_DONE and PLL_LOCKED;
	DEBUG_STATUS(5) <= SAMPLING_BUSY;
	DEBUG_STATUS(4 downto 0) <= (others => '1');

	config_reg <= CONFIG_DATA;

	process(CLK, RESET)
	begin
		if rising_edge(CLK) then
			if RESET = '1' then
				point_cnt <= (others => '0');
				state <= TriggerSetup;
				START_SAMPLING <= '0';
				RELOAD_PLL_REGS <= '0';
				SWEEP_HALTED <= '0';
				RESULT_INDEX <= (others => '1');
			else
				case state is
					when TriggerSetup =>
						RELOAD_PLL_REGS <= '1';
						if PLL_RELOAD_DONE = '0' then
							state <= SettingUp;
						end if;
					when SettingUp =>
						-- highest bit in config_reg determines whether the sweep should be halted prior to sampling
						SWEEP_HALTED <= config_reg(95);
						RELOAD_PLL_REGS <= '0';
						case config_reg(94 downto 93) is 
							when "00" => settling_time <= to_unsigned(2048, 16); -- 20us
							when "01" => settling_time <= to_unsigned(6144, 16); -- 60us
							when "10" => settling_time <= to_unsigned(18432, 16); -- 180us
							when others => settling_time <= to_unsigned(55296, 16); -- 540us
						end case;
						settling_cnt <= settling_time;
						if PLL_RELOAD_DONE = '1' and PLL_LOCKED = '1' then
							-- check if halted sweep is resumed
							if config_reg(95) = '0' or SWEEP_RESUME = '1' then
								SWEEP_HALTED <= '0';
								if EXCITE_PORT1 = '1' then
									state <= SettlingPort1;
								else
									state <= SettlingPort2;
								end if;
							end if;
						end if;
					when SettlingPort1 =>
						PORT_SELECT <= '1';
						-- wait for settling time to elapse
						if settling_cnt > 0 then
							settling_cnt <= settling_cnt - 1;
						else
							START_SAMPLING <= '1';
							if SAMPLING_BUSY = '1' then
								state <= ExcitingPort1;
							end if;
						end if;
					when ExcitingPort1 =>
						-- wait for sampling to finish
						START_SAMPLING <= '0';
						if SAMPLING_BUSY = '0' then
							RESULT_INDEX <= "000" & std_logic_vector(point_cnt);
							if EXCITE_PORT2 = '1' then
								state <= SettlingPort2;
							else
								state <= NextPoint;
							end if;
							settling_cnt <= settling_time;
						end if;
					when SettlingPort2 =>
						PORT_SELECT <= '0';
						-- wait for settling time to elapse
						if settling_cnt > 0 then
							settling_cnt <= settling_cnt - 1;
						else
							START_SAMPLING <= '1';
							if SAMPLING_BUSY = '1' then
								state <= ExcitingPort2;
							end if;
						end if;
					when ExcitingPort2 =>
						-- wait for sampling to finish
						START_SAMPLING <= '0';
						RESULT_INDEX <= "100" & std_logic_vector(point_cnt);
						if SAMPLING_BUSY = '0' then
							state <= NextPoint;
						end if;
					when NextPoint =>
						if point_cnt < unsigned(NPOINTS) then
							point_cnt <= point_cnt + 1;
							state <= TriggerSetup;
							-- initial port depends on whether port 1 is exited
							PORT_SELECT <= EXCITE_PORT1;
						else 
							point_cnt <= (others => '0');
							state <= Done;
						end if;					
					when others =>
				end case;
			end if;
		end if;
	end process;
end Behavioral;

