-------------------------------------------------------------------------------
--  th9958_sprite.vhd
--  sprite for TH9958
--
--  Copyright (C) 2008 Takayuki Hara
--  All rights reserved.
-------------------------------------------------------------------------------
--
--  Redistribution and use of this software or any derivative works,
--  are permitted provided that the following conditions are met:
--
--  1. Redistributions of source code must retain the above copyright
--     notice, this list of conditions and the following disclaimer.
--  2. Redistributions in binary form must reproduce the above
--     copyright notice, this list of conditions and the following
--     disclaimer in the documentation and/or other materials
--     provided with the distribution.
--  3. Redistributions may not be sold, nor may they be used in a 
--     commercial product or activity without specific prior written
--     permission.
--
--  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
--  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
--  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
--  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
--  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
--  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
--  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
--  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
--  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
--  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
--  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
--  POSSIBILITY OF SUCH DAMAGE.
--
-------------------------------------------------------------------------------

LIBRARY IEEE;
	USE IEEE.STD_LOGIC_1164.ALL;
	USE IEEE.STD_LOGIC_UNSIGNED.ALL;
	USE IEEE.STD_LOGIC_ARITH.ALL;

ENTITY TH9958_SPRITE IS
	PORT(
		CLK					: IN	STD_LOGIC;
		RESET_N				: IN	STD_LOGIC;
		ENABLE				: IN	STD_LOGIC;

		SCR_X				: IN	STD_LOGIC_VECTOR(  9 DOWNTO 0 );
		SCR_Y				: IN	STD_LOGIC_VECTOR(  7 DOWNTO 0 );
		ACT_X				: IN	STD_LOGIC;
		ACT_Y				: IN	STD_LOGIC;

		SPR_ADR				: OUT	STD_LOGIC_VECTOR( 16 DOWNTO 0 );
		SPR_REQ				: OUT	STD_LOGIC;
		SPR_ACK				: IN	STD_LOGIC;
		SPR_LATCH			: IN	STD_LOGIC;
		SPR_Q				: IN	STD_LOGIC_VECTOR(  7 DOWNTO 0 );

		CLR_5S				: IN	STD_LOGIC;

		S_5S				: OUT	STD_LOGIC;
		S_5TH_SP			: OUT	STD_LOGIC_VECTOR(  4 DOWNTO 0 );

		REG_MAG				: IN	STD_LOGIC;
		REG_SI				: IN	STD_LOGIC;
		REG_LN				: IN	STD_LOGIC;
		REG_SPA_L			: IN	STD_LOGIC_VECTOR(  5 DOWNTO 0 );
		REG_SPA_H			: IN	STD_LOGIC_VECTOR(  1 DOWNTO 0 );

		SP_MODE				: IN	STD_LOGIC
	);
END TH9958_SPRITE;

ARCHITECTURE RTL OF TH9958_SPRITE IS

	TYPE INFO_ARRAY IS ARRAY( 0 TO 7 ) OF STD_LOGIC_VECTOR( 8 DOWNTO 0 );
	SIGNAL RAM_INFO			: INFO_ARRAY;

	SIGNAL FF_VRAM_Q		: STD_LOGIC_VECTOR(  7 DOWNTO 0 );
	SIGNAL FF_STATE			: STD_LOGIC;
	SIGNAL FF_DISP_CNT		: STD_LOGIC_VECTOR(  3 DOWNTO 0 );
	SIGNAL FF_WE			: STD_LOGIC;
	SIGNAL FF_D				: STD_LOGIC_VECTOR(  8 DOWNTO 0 );
	SIGNAL FF_UNDISP		: STD_LOGIC;
	SIGNAL FF_5S			: STD_LOGIC;
	SIGNAL FF_5TH_SP		: STD_LOGIC_VECTOR(  4 DOWNTO 0 );

	SIGNAL W_SP_REQ_S1		: STD_LOGIC;
	SIGNAL W_SP_REQ_S2		: STD_LOGIC;
	SIGNAL W_SPA_S1			: STD_LOGIC_VECTOR( 16 DOWNTO 0 );
	SIGNAL W_REL_Y			: STD_LOGIC_VECTOR(  8 DOWNTO 0 );
	SIGNAL W_REL_MASK		: STD_LOGIC_VECTOR(  1 DOWNTO 0 );
	SIGNAL W_MODE			: STD_LOGIC_VECTOR(  1 DOWNTO 0 );
	SIGNAL W_CMP			: STD_LOGIC_VECTOR(  8 DOWNTO 3 );
	SIGNAL W_ACT			: STD_LOGIC;
	SIGNAL W_WE				: STD_LOGIC;
	SIGNAL W_FULL			: STD_LOGIC;
	SIGNAL W_REL_SEL		: STD_LOGIC_VECTOR(  3 DOWNTO 0 );
	SIGNAL W_UNDISP_LINE	: STD_LOGIC_VECTOR(  7 DOWNTO 0 );
	SIGNAL W_UNDISP_SP		: STD_LOGIC;
BEGIN

	S_5S		<= FF_5S;

	W_SP_REQ_S1	<= '1' WHEN( SCR_X( 4 DOWNTO 0 ) = "10101" )ELSE '0';
	W_SP_REQ_S2	<= '1' WHEN( SCR_X( 2 DOWNTO 0 ) = "001"   )ELSE '0';
	SPR_REQ		<= W_SP_REQ_S1 WHEN( FF_STATE = '0' )ELSE W_SP_REQ_S2;

	W_SPA_S1	<= REG_SPA_H & REG_SPA_L & "00" & SCR_X( 9 DOWNTO 5 ) & "00";
	SPR_ADR		<= W_SPA_S1;	-- ★暫定

	W_REL_Y		<= ('0' & FF_VRAM_Q) - ('0' & SCR_Y);

	W_MODE		<= REG_MAG & REG_SI;
	WITH W_MODE SELECT W_REL_MASK <=
		"00"	WHEN "11",
		"10"	WHEN "10",
		"10"	WHEN "01",
		"11"	WHEN "00",
		"XX"	WHEN OTHERS;

	W_UNDISP_LINE		<= CONV_STD_LOGIC_VECTOR( 216, 8 ) WHEN( REG_LN = '1' )ELSE CONV_STD_LOGIC_VECTOR( 208, 8 );
	W_UNDISP_SP			<= '1' WHEN( FF_VRAM_Q = W_UNDISP_LINE )ELSE '0';

	PROCESS( RESET_N, CLK )
	BEGIN
		IF( RESET_N = '0' )THEN
			FF_UNDISP <= '0';
		ELSIF( CLK'EVENT AND CLK = '1' )THEN
			IF( ENABLE = '1' )THEN
				IF( FF_STATE = '1' )THEN
					FF_UNDISP <= '0';
				ELSIF( W_UNDISP_SP = '1' )THEN
					FF_UNDISP <= '1';
				END IF;
			END IF;
		END IF;
	END PROCESS;

	W_CMP( 4 DOWNTO 3 )	<= W_REL_MASK AND W_REL_Y( 4 DOWNTO 3 );
	W_CMP( 8 DOWNTO 5 )	<= W_REL_Y( 8 DOWNTO 5 );

	W_ACT		<= (NOT (W_UNDISP_SP OR FF_UNDISP)) WHEN( W_CMP = 0 )ELSE '0';
	W_FULL		<= ((NOT SP_MODE) AND FF_DISP_CNT(2)) OR FF_DISP_CNT(3);
	W_WE		<= W_ACT AND (NOT W_FULL);
	W_REL_SEL	<= W_REL_Y( 3 DOWNTO 0 ) WHEN( REG_MAG = '0' )ELSE W_REL_Y( 4 DOWNTO 1 );

	PROCESS( RESET_N, CLK )
	BEGIN
		IF( RESET_N = '0' )THEN
			FF_VRAM_Q <= (OTHERS => '0');
		ELSIF( CLK'EVENT AND CLK = '1' )THEN
			IF( ENABLE = '1' )THEN
				IF( SPR_LATCH = '1' )THEN
					FF_VRAM_Q <= SPR_Q;
				END IF;
			END IF;
		END IF;
	END PROCESS;

	PROCESS( RESET_N, CLK )
	BEGIN
		IF( RESET_N = '0' )THEN
			FF_STATE <= '0';
		ELSIF( CLK'EVENT AND CLK = '1' )THEN
			IF( ENABLE = '1' )THEN
				IF(    SCR_X = "0000000000" )THEN
					FF_STATE <= '0';
				ELSIF( SCR_X = "1111111111" )THEN
					FF_STATE <= '1';
				END IF;
			END IF;
		END IF;
	END PROCESS;

	PROCESS( RESET_N, CLK )
	BEGIN
		IF( RESET_N = '0' )THEN
			FF_DISP_CNT <= (OTHERS => '0');
		ELSIF( CLK'EVENT AND CLK = '1' )THEN
			IF( ENABLE = '1' )THEN
				IF( SCR_X = 0 )THEN
					FF_DISP_CNT <= (OTHERS => '0');
				ELSIF( FF_WE = '1' )THEN
					FF_DISP_CNT <= FF_DISP_CNT + 1;
				END IF;
			END IF;
		END IF;
	END PROCESS;

	PROCESS( RESET_N, CLK )
	BEGIN
		IF( RESET_N = '0' )THEN
			FF_WE <= '0';
			FF_D  <= (OTHERS => '0');
		ELSIF( CLK'EVENT AND CLK = '1' )THEN
			IF( ENABLE = '1' )THEN
				IF( SCR_X( 4 DOWNTO 0 ) = "11001" )THEN
					FF_WE <= W_WE;
					FF_D  <= W_REL_SEL & SCR_X( 9 DOWNTO 5 );
				ELSE
					FF_WE <= '0';
					FF_D  <= (OTHERS => '0');
				END IF;
			END IF;
		END IF;
	END PROCESS;

	PROCESS( RESET_N, CLK )
	BEGIN
		IF( RESET_N = '0' )THEN
			FF_5S <= '0';
		ELSIF( CLK'EVENT AND CLK = '1' )THEN
			IF( ENABLE = '1' )THEN
				IF( CLR_5S = '1' )THEN
					FF_5S <= '0';
				ELSIF( (W_ACT AND W_FULL) = '1' )THEN
					FF_5S <= '1';
				END IF;
			END IF;
		END IF;
	END PROCESS;

	PROCESS( RESET_N, CLK )
	BEGIN
		IF( RESET_N = '0' )THEN
			FF_5TH_SP <= "00000";
		ELSIF( CLK'EVENT AND CLK = '1' )THEN
			IF( ENABLE = '1' )THEN
				IF( CLR_5S = '1' )THEN
					FF_5TH_SP <= "00000";
				ELSIF( ((NOT FF_5S) AND W_ACT AND W_FULL) = '1' )THEN
					FF_5TH_SP <= SCR_X( 9 DOWNTO 5 );
				END IF;
			END IF;
		END IF;
	END PROCESS;
END RTL;