----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    15:41:12 06/05/2007 
-- 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_out is
    Port (
		rst				: in  std_logic;
		clk				: in  std_logic;
		sync_tx		 	: out std_logic;
		cmd_addr 		: in  unsigned (19 downto 0);
		cmd_data		: in  unsigned (19 downto 0);
		cmd_we			: in  std_logic;
		pcm_in_addr		: in  unsigned (3 downto 0);
		pcm_in_data		: in  unsigned (19 downto 0);
		pcm_in_we		: in  std_logic;
		ac_reset		: in  std_logic; 
		ac_bit_clk		: in  std_logic;
		ac_sdata_out	: out std_logic;
		ac_ssync		: out std_logic
	);
end ac_out;

architecture Behavioral of ac_out 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;

------------------------------------------------------------------
subtype tag_t is UNSIGNED(15 downto 0);
subtype slot_valid_t is UNSIGNED(1 to 12);
signal slot_valid : slot_valid_t;
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 tx_reg : UNSIGNED(19 downto 0);
signal last_slot, ssync : STD_LOGIC;

type sac_t is (ac_idle, ac_tag, ac_data);
signal sac, snac : sac_t;
 
subtype bitcnt_t is integer range 0 to 19;
subtype slotcnt_t is integer range 0 to 12;

signal bitcnt : bitcnt_t;
signal bitcnt_rst, bitcnt_en : STD_LOGIC;
signal slotcnt : slotcnt_t;
signal slotcnt_rst, slotcnt_en : STD_LOGIC;

signal slot_start : STD_LOGIC; 

------------------------------------------------------------------
function CreateTag(slot_valid : slot_valid_t) return tag_t is
variable tag : tag_t := (others => '0');
begin

	tag := (others => '0');
	for i in slot_valid_t'range loop
		tag(15-i) := slot_valid(i);
		if slot_valid(i) = '1' then
			tag(15) := '1';
		end if;	
	end loop;
	tag(0) := '0';	-- ID0 
	tag(1) := '0';	-- ID1
	tag(2) := '0';	-- Reserved
--	tag(15) := '1';	-- Frame is valid
	return tag;	
	
end CreateTag;

begin

------------------------------------------------------------------
proc_slot_reg:
process (clk, cmd_addr, cmd_data, cmd_we, pcm_in_data, pcm_in_we, pcm_in_addr, last_slot)
variable slot_id : integer range 0 to 12;
begin
	slot_id := to_integer(pcm_in_addr);
	if rising_edge(clk) then
		if rst = '1' then
			for i in data_array'range(1) loop
				data_array(i) <= (others => '0');
			end loop;
			slot_valid <= (others => '0');
		elsif last_slot = '1' then
			slot_valid <= (others => '0');
		else
			if cmd_we = '1' then
				slot_valid(1) <= '1';
				slot_valid(2) <= '1';
				data_array(1) <= cmd_addr;
				data_array(2) <= cmd_data;
			end if;
			if pcm_in_we = '1' then
				if (slot_id > 2) then
					data_array(slot_id) <= pcm_in_data;
					slot_valid(slot_id) <= '1';
				end if;	
			end if;
		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)
begin
	snac <= sac;
	bitcnt_rst <= '0';
	bitcnt_en <= '1';
	slotcnt_rst <= '0';
	slotcnt_en <= '0';
	slot_start <= '0';
	ssync <= '0';
	
	if bitcnt = 0 then 
		slot_start <= '1';
	end if;	
	
	case sac is
	
		when ac_idle => 
			bitcnt_rst <= '1';
			slotcnt_rst <= '1';
			snac <= ac_tag;

		when ac_tag =>
			ssync <= '1';
			if (bitcnt = 15) then
				slotcnt_en <= '1';
				bitcnt_rst <= '1';
				snac <= ac_data;
			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;	

------------------------------------------------------------------
proc_tx_shift_reg:
process (ac_reset, ac_bit_clk, tx_reg, ssync, slot_valid, data_array)
begin

	if ac_reset = '1' then
		tx_reg <= (others => '0');
	elsif rising_edge(ac_bit_clk) then
		last_slot <= '0';
		if slot_start = '1' then
			if ssync = '1' then
				tx_reg <= CreateTag(slot_valid) & "0000";
			else	
				if slotcnt /= 0 then
					tx_reg <= data_array(slotcnt);
					if slotcnt = 12 then
						last_slot <= '1';
					end if;	
				end if;	
			end if;	
		else	
			tx_reg <= tx_reg(tx_reg'left-1 downto 0) & '0';
		end if;
	end if;	
end process;

------------------------------------------------------------------
proc_ac_sync_out:
process (ac_reset, ac_bit_clk, ssync, tx_reg)
begin
	if ac_reset = '1' then
		ac_ssync <= '0';
		ac_sdata_out <= '0';
	elsif rising_edge(ac_bit_clk) then
		ac_ssync <= ssync;
		ac_sdata_out <= tx_reg(tx_reg'left);
	end if;
end process;	

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

end Behavioral;
