----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    08:27:43 08/26/2006 
-- Design Name: 
-- Module Name:    ac_out - 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.NUMERIC_STD.ALL;

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

entity ac_in is
    Port (
		rst 			: in  std_logic;
		clk 			: in  std_logic;
		sync_frame	 	: out std_logic;
		sync_status	 	: out std_logic;
		slot_valid		: out unsigned(0 to 12);
		stat_addr		: out unsigned (19 downto 0);
		stat_data		: out unsigned (19 downto 0);
		pcm_out_addr	: in  unsigned (3 downto 0);
		pcm_out_data	: out unsigned (19 downto 0);
		ac_reset		: in  std_logic; 
		ac_bit_clk		: in  std_logic;
		ac_sdata_in		: in  std_logic;
		ac_ssync		: in  std_logic
		);
end ac_in;

architecture Behavioral of ac_in is
	
------------------------------------------------------------------
COMPONENT singleshot
GENERIC (mode : integer);
PORT(
	rst : IN std_logic;
	clk : IN std_logic;
	input : IN std_logic;          
	output : OUT std_logic
	);
END COMPONENT;

------------------------------------------------------------------
type sac_t is (ac_idle, ac_tag, ac_data);
subtype bitcnt_t is integer range 0 to 19;
subtype slotcnt_t is integer range 0 to 12;
subtype slot_valid_t is UNSIGNED(0 to 12);
subtype tag_t is UNSIGNED(15 downto 0);
subtype slot_t is UNSIGNED(19 downto 0);
type slot_array_t is array (natural range <>) of slot_t;

signal data_array : slot_array_t (1 to 12);
signal tag : tag_t;
 
signal sac, snac : sac_t;
signal bitcnt : bitcnt_t;
signal bitcnt_rst, bitcnt_en : STD_LOGIC;
signal slotcnt : slotcnt_t;
signal slotcnt_rst, slotcnt_en : STD_LOGIC;

signal rx_reg : slot_t;
signal stat_read, host_update : STD_LOGIC; 
signal sync_end, slot_end, last_slot, start_of_frame : STD_LOGIC; 

------------------------------------------------------------------
function GetSlotValid(data : tag_t) return slot_valid_t is
variable res : slot_valid_t := (others => '0');
begin
	res := (others => '0');
	for i in slot_valid_t'range loop
		res(i) := data(data'left-i);
	end loop;
	return res;	
	
end GetSlotValid;

------------------------------------------------------------------
begin

-------------------------------------------------------------
-- proc_status_flags
-------------------------------------------------------------
proc_status_flags:
process (rst, clk, host_update, tag, data_array)
begin
	if rising_edge(clk) then
		sync_status <= '0';
		if rst = '1' then
			slot_valid <= (others => '0');
			stat_addr <= (others => '0');
			stat_data <= (others => '0');
		elsif host_update = '1' then
			sync_status <= '1';
			slot_valid <= GetSlotValid(tag);
			stat_addr <= data_array(1);
			stat_data <= data_array(2);
		end if;
	end if;	
end process;	

-------------------------------------------------------------
-- proc_pcm_data
-------------------------------------------------------------
proc_pcm_data:
process (clk, pcm_out_addr, data_array)
variable slot_id : integer range 0 to 12;
begin
	pcm_out_data <= (others => '-');
	slot_id := to_integer(pcm_out_addr);
	if (slot_id > 2) then
		pcm_out_data <= data_array(slot_id);
	end if;	
end process;			
	
-------------------------------------------------------------
-- proc_read_data
-------------------------------------------------------------
proc_read_data : 
process (ac_reset, ac_bit_clk, slot_end, slotcnt)
begin

	if ac_reset = '1' then
		stat_read <= '0';
	elsif rising_edge(ac_bit_clk) then
		stat_read <= '0';
		if slot_end = '1' and slotcnt /= 0 then
			data_array(slotcnt) <= rx_reg;
			if slotcnt = 2 then
				stat_read <= '1';
			end if;
		end if;	
	end if;	
end process;

-------------------------------------------------------------
-- proc_read_stat
-------------------------------------------------------------
proc_read_tag : 
process (ac_reset, ac_bit_clk, sync_end)
begin

	if ac_reset = '1' then
		tag <= (others => '0');
	elsif rising_edge(ac_bit_clk) then
		if sync_end = '1' then
			tag <= rx_reg(15 downto 0);
		end if;	
	end if;	

end process;

-------------------------------------------------------------
-- proc_slot_count
-------------------------------------------------------------
proc_slot_count:
process (slotcnt_rst, ac_bit_clk, slotcnt_en, slotcnt)
begin
	if rising_edge(ac_bit_clk) then
		if slotcnt_rst = '1' then
			slotcnt <= slotcnt_t'low;
		elsif slotcnt_en = '1' then
			if slotcnt /= slotcnt_t'high then
				slotcnt <= slotcnt + 1;
			else
				slotcnt <= slotcnt_t'low;
			end if;
		end if;
	end if;
end process;	

-------------------------------------------------------------
-- proc_bit_count
-------------------------------------------------------------
proc_bit_count:
process (bitcnt_rst, ac_bit_clk, bitcnt_en, bitcnt)
begin
	if rising_edge(ac_bit_clk) then
		if bitcnt_rst = '1' then
			bitcnt <= bitcnt_t'low;
		elsif bitcnt_en = '1' then
			if bitcnt /= bitcnt_t'high then
				bitcnt <= bitcnt + 1;
			else
				bitcnt <= bitcnt_t'low;
			end if;
		end if;
	end if;
end process;	

------------------------------------------------------------------
proc_ac_fsm:
process (bitcnt, slotcnt, sac, ac_ssync)
begin
	snac <= sac;
	bitcnt_rst <= '0';
	bitcnt_en <= '1';
	slotcnt_rst <= '0';
	slotcnt_en <= '0';
	slot_end <= '0';
	sync_end <= '0';
	last_slot <= '0';
	start_of_frame <= '0';
	
	if bitcnt = 19 then 
		slot_end <= '1';
	end if;	
	if slotcnt = 12 and bitcnt = 19 then
		last_slot <= '1';
	end if;	
	
	case sac is
	
		when ac_idle => 
			bitcnt_rst <= '1';
			slotcnt_rst <= '1';
			if (ac_ssync = '1') then
				snac <= ac_tag;
			end if;	

		when ac_tag =>
			if (bitcnt = 0) then
				start_of_frame <= '1';
			elsif (bitcnt = 15) then
				slotcnt_en <= '1';
				bitcnt_rst <= '1';
				sync_end <= '1';
				if (ac_ssync = '0') then
					snac <= ac_data;
				else	
					snac <= ac_idle;
				end if;	
			end if;	

		when ac_data =>
			if bitcnt = 19 then 
				slotcnt_en <= '1';
				if slotcnt = 12 then
					slotcnt_rst <= '1';
					snac <= ac_tag;
				end if;	
			end if;	
		when others => null;
	end case;	
end process;

proc_ac_fsm_next:
process (ac_reset, ac_bit_clk, snac)
begin
	if ac_reset = '1' then
		sac <= ac_idle;
	elsif rising_edge(ac_bit_clk) then
		sac <= snac;
	end if;
end process;	

-------------------------------------------------------------
-- Receive Shift Register
-------------------------------------------------------------
process (ac_reset, ac_bit_clk, ac_sdata_in)
begin
	if ac_reset = '1' then
		rx_reg <= (others => '0');
	elsif falling_edge(ac_bit_clk) then  
		rx_reg <= rx_reg(rx_reg'left-1 downto 0) & ac_sdata_in;
	end if;	
end process;

------------------------------------------------------------------
singleshot_inst1: singleshot 
GENERIC MAP (
	mode => 0)		
PORT MAP(
	rst => rst,
	clk => clk,
	input => stat_read,
	output => host_update
);

singleshot_inst2: singleshot 
GENERIC MAP (
	mode => 1)		
PORT MAP(
	rst => rst,
	clk => clk,
	input => start_of_frame,
	output => sync_frame
);

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

end Behavioral;

