----------------------------------------------------------------------------------
-- Company: University of Connecticut
-- Engineer: Igor Senderovich
-- 
-- Create Date:    04:14:41 10/01/2007 
-- Design Name: 
-- Module Name:    WriteSpacket - behavioral 
-- Description:    Assembles S-type packet - reports ADC/Temperature values
----------------------------------------------------------------------------------

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

library FPGA_BasicComp;
use FPGA_BasicComp.BasicComp.all;

entity WriteSpacket is
    port ( Clk : in  std_logic;
	   Go : in std_logic;
	   Done : out std_logic;
	   LocStamp : in std_logic_vector (7 downto 0);
	   RAM_EN : out std_logic;
	   RAM_ADDR_tri : out std_logic_vector (9 downto 0);
	   RAM_WE_tri : out std_logic_vector (1 downto 0);
	   RAM_DI_tri : out std_logic_vector (15 downto 0);
	   RAM_DO : in std_logic_vector (15 downto 0);
	   TxRx_Go : out std_logic;
	   TxRx_Rd_tri : out std_logic;
	   TxRx_A_tri : out std_logic_vector (7 downto 0);
	   TxRx_D_tri : out std_logic_vector (7 downto 0);
	   TxRx_Q : in std_logic_vector (7 downto 0);
	   TxRx_Done : in std_logic);
end WriteSpacket;

architecture behavioral of WriteSpacket is

	type stage_t is (S0,S1,S2,S3,S4,S5,S6,S7,S8,S9,SA,SB,SC);
	signal stage : stage_t := S0;

	signal counter_2b : std_logic_vector (1 downto 0);
	signal counter_6b : std_logic_vector (5 downto 0);
	signal buffer_addr : std_logic_vector (7 downto 0);
	signal Done_reg : std_logic := '0';

	signal RAM_EN_reg : std_logic := '0';
	signal RAM_ADDR_reg : std_logic_vector (9 downto 0) := (others => '0');
	signal RAM_WE_reg : std_logic_vector (1 downto 0) := (others => '0');

	signal TxRx_Go_reg : std_logic := '0';
	signal TxRx_Rd_reg : std_logic := '0';
	signal TxRx_A_reg : std_logic_vector (7 downto 0) := (others => '0');
	signal TxRx_D_reg : std_logic_vector (7 downto 0) := (others => '0');
begin
	RAM_EN <= RAM_EN_reg;
	RAM_ADDR_tri <= RAM_ADDR_reg when (RAM_EN_reg = '1') else (others => 'Z');
	RAM_WE_tri <= RAM_WE_reg when (RAM_EN_reg = '1') else (others => 'Z');
	RAM_DI_tri <= (others => 'Z');

	TxRx_Go <= TxRx_Go_reg;
	TxRx_Rd_tri <= TxRx_Rd_reg when (TxRx_Go_reg = '1') else 'Z';
	TxRx_A_tri <= TxRx_A_reg when (TxRx_Go_reg = '1') else (others => 'Z');
	TxRx_D_tri <= TxRx_D_reg when (TxRx_Go_reg = '1') else (others => 'Z');

	Sequencer : process (Clk)
		variable op_complete_var : std_logic;
	begin
		if rising_edge(Clk) then
			stage <= stage;
			counter_2b <= (others => '0');
			counter_6b <= (others => '0');
			buffer_addr <= (others => '0');
			Done_reg <= '0';
			-- disable RAM when not in use
			RAM_EN_reg <= '0';
			RAM_ADDR_reg <= (others => '0');
			RAM_WE_reg <= (others => '0');
			-- disable MuxIntel when not in use
			TxRx_Go_reg <= '0';
			TxRx_Rd_reg <= '0';
			TxRx_A_reg <= (others => '0');
			TxRx_D_reg <= (others => '0');

			op_complete_var := TxRx_Go_reg and TxRx_Done;

			case stage is
			    when S0 =>
				if (Go = '1') then
					stage <= S1;
				end if;

			-------------------------------------------------------
			-- Write the first 4 bytes into the transmit buffer.
			-- 	2 bytes - packet payload length (0x002e)
			-- 	2 bytes - packet identifier (LocStamp & 0x53)
			-------------------------------------------------------

			    when S1 =>
				TxRx_A_reg <= X"08";
				TxRx_D_reg <= X"00";
				TxRx_Rd_reg <= '0';
				TxRx_Go_reg <= not TxRx_Done;
				buffer_addr <= X"0c";
				if (op_complete_var = '1') then
					stage <= S2;
				end if;
			    when S2 =>
				TxRx_A_reg <= X"09";
				TxRx_D_reg <= buffer_addr;
				TxRx_Rd_reg <= '0';
				TxRx_Go_reg <= not TxRx_Done;
				buffer_addr <= buffer_addr;
				counter_2b <= counter_2b;
				if (op_complete_var = '1') then
					stage <= S3;
				end if;
			    when S3 =>
				TxRx_A_reg <= X"04";
				case counter_2b is
				    when "00" =>
					TxRx_D_reg <= X"00";
				    when "01" =>
					TxRx_D_reg <= X"2e";
				    when "10" =>
					TxRx_D_reg <= LocStamp;
				    when others =>
					TxRx_D_reg <= X"53";
				end case;
				TxRx_Rd_reg <= '0';
				TxRx_Go_reg <= not TxRx_Done;
				buffer_addr <= buffer_addr;
				counter_2b <= counter_2b;
				if (op_complete_var = '1') then
					buffer_addr <= buffer_addr + 1;
					counter_2b <= counter_2b + 1;
					if (counter_2b = "11") then 
						stage <= S4;
					else
						stage <=  S2;
					end if;
				end if;

			-------------------------------------------------------
			-- Follow this with the temperature and ADC data as:
			--	 2 bytes - temperature value
			--	 2 bytes - ADC channel 0 value
			--	30 bytes - ADC channels 1..15 values
			--	12 bytes - 0 (padding up to minimum length)
			-------------------------------------------------------

			    when S4 =>
				RAM_EN_reg <= '1';
				RAM_ADDR_reg <= (others => '0');
				buffer_addr <= buffer_addr;
				counter_2b <= "00";
				stage <= S5;
			    when S5 =>
				RAM_EN_reg <= '1';
				RAM_ADDR_reg <= RAM_ADDR_reg;
				TxRx_A_reg <= X"09";
				TxRx_D_reg <= buffer_addr;
				TxRx_Rd_reg <= '0';
				TxRx_Go_reg <= not TxRx_Done;
				buffer_addr <= buffer_addr;
				counter_2b <= counter_2b;
				if (op_complete_var = '1') then
					stage <= S6;
				end if;
			    when S6 =>
				RAM_EN_reg <= '1';
				RAM_ADDR_reg <= RAM_ADDR_reg;
				-- RAM_DO is valid at the first clock in S6 because the
				-- RAM_ADDR and RAM_EN lines were set up in S4 and S5.
				TxRx_A_reg <= X"04";
				if (buffer_addr(0) = '0') then
					TxRx_D_reg <= RAM_DO(15 downto 8);
				else
					TxRx_D_reg <= RAM_DO(7 downto 0);
				end if;
				TxRx_Rd_reg <= '0';
				TxRx_Go_reg <= not TxRx_Done;
				buffer_addr <= buffer_addr;
				counter_2b <= counter_2b;
				if (op_complete_var = '1') then
					buffer_addr <= buffer_addr + 1;
					counter_2b <= counter_2b + 1;
					if (counter_2b(0) = '1') then
						stage <= S7;
					else
						stage <= S5;
					end if;
				end if;
			    when S7 =>
				RAM_EN_reg <= '1';
				RAM_ADDR_reg <= "00001" & counter_6b(5 downto 1);
				buffer_addr <= buffer_addr;
				counter_6b <= counter_6b;
				stage <= S8;
			    when S8 =>
				RAM_EN_reg <= '1';
				RAM_ADDR_reg <= RAM_ADDR_reg;
				TxRx_A_reg <= X"09";
				TxRx_D_reg <= buffer_addr;
				TxRx_Rd_reg <= '0';
				TxRx_Go_reg <= not TxRx_Done;
				buffer_addr <= buffer_addr;
				counter_6b <= counter_6b;
				if (op_complete_var = '1') then
					stage <= S9;
				end if;
			    when S9 =>
				RAM_EN_reg <= '1';
				RAM_ADDR_reg <= RAM_ADDR_reg;
				-- RAM_D0 is valid at the first clock in S9 because the
				-- RAM_ADDR and RAM_EN lines were set up in S7 and S8.
				TxRx_A_reg <= X"04";
				if (buffer_addr(0) = '0') then
					TxRx_D_reg <= RAM_DO(15 downto 8);
				else
					TxRx_D_reg <= RAM_DO(7 downto 0);
				end if;
				TxRx_Rd_reg <= '0';
				TxRx_Go_reg <= not TxRx_Done;
				buffer_addr <= buffer_addr;
				counter_6b <= counter_6b;
				if (op_complete_var = '1') then
					buffer_addr <= buffer_addr + 1;
					counter_6b <= counter_6b + 1;
					if (counter_6b = X"2D") then
						stage <= SA;
					else
						stage <= S7;
					end if;
				end if;

			-------------------------------------------------------
			-- Pad to 64 bytes by setting TXENDH:TXENDL to 0x003F
			-- and letting the chip append the final 4-byte CRC.
			-------------------------------------------------------

			    when SA =>
				TxRx_A_reg <= X"57";
				TxRx_D_reg <= X"00";
				TxRx_Rd_reg <= '0';
				TxRx_Go_reg <= not TxRx_Done;
				if (op_complete_var = '1') then
					stage <= SB;
				end if;
			    when SB =>
				TxRx_A_reg <= X"58";
				TxRx_D_reg <= X"3B";
				TxRx_Rd_reg <= '0';
				TxRx_Go_reg <= not TxRx_Done;
				if (op_complete_var = '1') then
					stage <= SC;
				end if;
			    when SC =>
				if (Go = '1') then
					Done_reg <= '1';
				else
					stage <= S0;
				end if;
			end case;
		else
			stage <= stage;
			Done_reg <= Done_reg;
			counter_2b <= counter_2b;
			counter_6b <= counter_6b;
			buffer_addr <= buffer_addr;
			RAM_EN_reg <= RAM_EN_reg;
			RAM_ADDR_reg <= RAM_ADDR_reg;
			RAM_WE_reg <= RAM_WE_reg;
			TxRx_Go_reg <= TxRx_Go_reg;
			TxRx_Rd_reg <= TxRx_Rd_reg;
			TxRx_A_reg <= TxRx_A_reg;
			TxRx_D_reg <= TxRx_D_reg;
		end if;
	end process;

	Done <= Done_reg;

end behavioral;
