-----------------------------------------------------------------------
-- $Header: D:\usr\cvsroot/VHDL/lib/JBUS/src/busmaster_async.vhd,v 1.2 2013/08/04 17:58:37 jens Exp $
-----------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

use work.utils_pkg.all;
use work.busmaster_types.all;

------------------------------------------------------------------
entity busmaster_async is
	Generic
	(
		DATA_WIDTH			: natural := 32;
		FIFO_DEPTH			: natural := 4
	);
	Port 
	(
		clk					: in std_logic;
		rst					: in std_logic;

		cmd_cycle_finished	: out std_logic;
		cmd_cycle_en		: in std_logic;
		cmd_rdy				: out std_logic;
		cmd_we				: in std_logic;
		
		cmd_in				: in bm_cmd_t;
		
		din					: in unsigned(DATA_WIDTH-1 downto 0);
		din_rdy				: out std_logic;
		din_we				: in std_logic;

		dout				: out unsigned(DATA_WIDTH-1 downto 0);
		dout_vld			: out std_logic;
		dout_re				: in std_logic;
		
		-- J-BUS signals
		RST_I				: in  STD_LOGIC;
		CLK_I				: in  STD_LOGIC;
		ACK_I				: in std_logic;
		SRDY_I				: in std_logic;
		MDAT_I				: in unsigned(DATA_WIDTH-1 downto 0);
		MDAT_O				: out unsigned(DATA_WIDTH-1 downto 0);
		ADDR_O				: out unsigned(31 downto 0);
		SEL_O				: out unsigned(DATA_WIDTH/8-1 downto 0);
		WE_O				: out std_logic;
		CYC_O				: out std_logic;
		STB_O				: out std_logic;
		MRDY_O				: out std_logic
	);
	end busmaster_async;

architecture Behavioral of busmaster_async is

	-- Bus Command FIFO
	signal cmd_fifo_din		: unsigned(32+DATA_WIDTH/8+1-1 downto 0);
	signal cmd_fifo_dout	: unsigned(32+DATA_WIDTH/8+1-1 downto 0);
	signal cmd_fifo_re		: std_logic;
	signal cmd_fifo_we		: std_logic;
	signal cmd_fifo_full	: std_logic;
	signal cmd_fifo_empty	: std_logic;
	
	-- Bus Read FIFO
	signal read_fifo_re		: std_logic;
	signal read_fifo_we		: std_logic;
	signal read_fifo_full	: std_logic;
	signal read_fifo_empty	: std_logic;
	signal write_fifo_re	: std_logic;
	signal write_fifo_we	: std_logic;
	signal write_fifo_full	: std_logic;
	signal write_fifo_empty	: std_logic;
	signal cycle_busy		: std_logic;
	signal cmd_en			: std_logic;
	signal cmd_read_en		: std_logic;
	signal read_cnt			: integer range 0 to 65535;
	signal write			: std_logic;

	signal jbus_cycle_busy	: std_logic;

	type jbus_state_t is (init, ready, start, wait_finish, finish1, finish2, finish3);
	signal jbus_state		: jbus_state_t;
	signal jbus_state_next	: jbus_state_t;
	
begin

	cmd_en				<= cmd_cycle_en and cmd_we and not cmd_fifo_full;
	cmd_read_en			<= cmd_en and not cmd_in.rw;
	write				<= cmd_fifo_dout(32+DATA_WIDTH/8);
	
	dout_vld			<= not read_fifo_empty;
	MRDY_O				<= not read_fifo_full;
	read_fifo_we		<= ACK_I and jbus_cycle_busy;
	read_fifo_re		<= dout_re;
	ADDR_O				<= cmd_fifo_dout(31 downto 0);
	SEL_O				<= cmd_fifo_dout(32+DATA_WIDTH/8-1 downto 32);
	WE_O				<= write;
	
	cmd_fifo_din		<= cmd_in.rw & cmd_in.sel & cmd_in.addr;
	
	cmd_rdy				<= not cmd_fifo_full;
	
	cmd_fifo_we			<= cmd_en;
	cmd_fifo_re			<= SRDY_I and jbus_cycle_busy;
	
	din_rdy				<= not write_fifo_full;
	write_fifo_we		<= din_we;
	write_fifo_re		<= SRDY_I and jbus_cycle_busy and write and not cmd_fifo_empty;
	
	CYC_O				<= jbus_cycle_busy;
	STB_O				<= not cmd_fifo_empty;
	
	
-- J-Bus domain
proc_JBUS_to_local_cmd_cycle_finished:
	process(clk)
	begin
		if rising_edge(clk) then
			cmd_cycle_finished	 <= not jbus_cycle_busy;
		end if;
	end process;	

proc_JBUS_cycle:
	process(CLK_I)
	begin
		if rising_edge(CLK_I) then
			jbus_cycle_busy	 <= cycle_busy;
		end if;
	end process;	

proc_bus_read_counter:
	process(clk)
	begin
		if rising_edge(clk) then
			if rst = '1' then
				read_cnt	<= 0;
			elsif cmd_read_en = '1' and read_fifo_empty = '1' then
				read_cnt <= read_cnt + 1;
			elsif cmd_read_en = '0' and read_fifo_empty = '0' and dout_re = '1' then
				read_cnt <= read_cnt - 1;
			end if;	
		end if;
	end process;	

jbus_state_fsm_next:
	process(clk)
	begin
		if rising_edge(clk) then
			if rst = '1' then
				jbus_state	 <= init;
			else
				jbus_state	 <= jbus_state_next;
			end if;
		end if;
	end process;	

jbus_state_fsm:
	process(jbus_state, cmd_we, cmd_fifo_empty, write_fifo_empty, read_cnt)
	begin

		cycle_busy	 		<= '0';
		jbus_state_next		<= jbus_state;
		
		case jbus_state is 
		
		when init =>
			jbus_state_next		<= ready;
		
		when ready =>
			if cmd_we = '1' or cmd_fifo_empty = '0' then
				jbus_state_next		<= start;
			end if;
				
		when start =>
			cycle_busy	 <= '1';
			if cmd_fifo_empty = '0' then
				jbus_state_next		<= wait_finish;
			end if;

		when wait_finish =>
			cycle_busy	 <= '1';
			if read_cnt = 0 and cmd_fifo_empty = '1' and write_fifo_empty = '1' then
				jbus_state_next		<= finish1;
			end if;
			
		-- Quick and dirty hack
		-- avoid buscycle to finish even if data available,
		-- caused by latency of async-FIFO empty flag
		when finish1 =>
			jbus_state_next		<= finish2;
		
		when finish2 =>
			jbus_state_next		<= finish3;

		when finish3 =>
			jbus_state_next		<= ready;
			if cmd_fifo_empty = '0' then
				jbus_state_next		<= wait_finish;
			end if;
		-- Quick and dirty hack

		when others =>
		jbus_state_next		<= ready;
		
		end case;
	end process;	

-- Bus READ FIFO
inst_BM_READ_FIFO: entity work.fifo_async
	GENERIC MAP
	(
		addr_width			=> NextExpBaseTwo(FIFO_DEPTH),
		data_width			=> DATA_WIDTH,
		do_last_read_update	=> true
	)
	PORT MAP
	(
		rst			=>	rst,
		clk_r		=>	clk,
		clk_w		=>	CLK_I,
		we			=>	read_fifo_we,
		re			=>	read_fifo_re,
		fifo_full	=>	read_fifo_full,
		fifo_empty	=>	read_fifo_empty,
		fifo_afull	=>	open,
		fifo_aempty	=>	open,
		data_r		=>  dout,
		data_w		=>  MDAT_I
	);
	
-- Bus WRITE FIFO
inst_BM_WRITE_FIFO: entity work.fifo_async
	GENERIC MAP
	(
		addr_width			=> NextExpBaseTwo(FIFO_DEPTH),
		data_width			=> DATA_WIDTH,
		do_last_read_update	=> false
	)
	PORT MAP
	(
		rst			=>	rst,
		clk_r		=>	CLK_I,
		clk_w		=>	clk,
		we			=>	write_fifo_we,
		re			=>	write_fifo_re,
		fifo_full	=>	write_fifo_full,
		fifo_empty	=>	write_fifo_empty,
		fifo_afull	=>	open,
		fifo_aempty	=>	open,
		data_r		=>  MDAT_O,
		data_w		=>  din
	);

-- Bus command FIFO
inst_BM_CMD_FIFO: entity work.fifo_async
	GENERIC MAP
	(
		addr_width			=> NextExpBaseTwo(FIFO_DEPTH),
		data_width			=> cmd_fifo_din'length,
		do_last_read_update	=> false
	)
	PORT MAP
	(
		rst			=>	rst,
		clk_r		=>	CLK_I,
		clk_w		=>	clk,
		we			=>	cmd_fifo_we,
		re			=>	cmd_fifo_re,
		fifo_full	=>	cmd_fifo_full,
		fifo_empty	=>	cmd_fifo_empty,
		fifo_afull	=>	open,
		fifo_aempty	=>	open,
		data_r		=>  cmd_fifo_dout,
		data_w		=>  cmd_fifo_din
	);

end Behavioral;
