//***************************************************************************************** 
// Description: GPL162xx serial PPU API
// Plateform: GPL162xx, unSP IDE 
// Edited and Created by Generalplus Technology Co., Ltd.
//
// Update History:
// 2007/08/27	Add new API function "fnShow_Bmp_HVGA()" 
// 2007/08/29	Add const int C_SeaHoffset_VGA[]
//				Modify "Sea_Hoffset()" for VGA mode 
// 2007/09/19	Modify "Paint_Sprite()" to support the 2.5D sprite 
//				which consists of multi-characters. 
// 2007/09/21	Modify "Paint_Sprite()" to fix the display bug of 2.5D sprite with multi-characters 
//				when one or more characters are transparent.  
// 2007/09/26   Add new API functions "TVFrameEndIrqON()", "TVFrameEndIrqOFF()", and "ClearTVFrameEndIRQ()".
// 2007/09/27   Add new API functions "tv_lpf_on()" and "tv_lpf_off()".
//				Modify "Paint_Sprite()" to fix the display bug of 2.5D sprite with multi-characters 
//				when the sprite has negative coordinate.

// 2007/10/18   Add FIQ and IRQ on/off to "MyMemSet" and "SetDMACopy0".
//				Add "GetResAddress()" API.
// 2007/10/23   Add "ppu_on" and "ppu_off".
// 2007/10/30   Modify tv_init function: Add NTSC-J Non-interlaced and PAL_B Non-interlaced mode.
// 2007/11/01   Allocate C_SeaHoffset and C_SeaHoffset_VGA start from 0x28000.
// 2007/11/05   Modify SetDMACopy0() to check if the DAM source is in CS0 Boot Mapping area
// 2007/11/13   Modify SetTextRotate() and SetText25D() to solve the shake problem of TEXT if zoom scale <= 0.5.
// 2007/11/26   Add "WaitBlanking2()".
// 2007/11/29   Move TextNumberArray,TextAttributeArray,Sprite Array declartion out from PPUDrv
//				Add "InitPPUDrv" to initialize the number array lenght of each TEXT and max spirte number
//				Add PPU_Driver_Version which return by InitPPUDrv, High Byte: Main Version, Low Byte: Sub Version
// 2007/12/04   Modify "WaitBlanking" and "WaitBlanking2()" to activate "cpu_done" flag in line-base mode.
//              Modify "VBLK_Service" to add ppu service for VGA interlaced mode in line-base mode.
// 2007/12/11   Modify "FlipEffect", Add one parameter FlipBuffer, the flipbuffer should located by user.
// 2007/12/13   Add "TextAttribInRAM_Initial".
// 2008/01/22	Add "SetTextChar0AutoTransparentMode"
// 2008/04/11	Add "Update_Sprite"
// 2008/07/09	1. Diable 27MHz before TV enable, and Enable 27MHz after TV enable
//				2. Modify TV QVGA NTSC P_TV_HPost from 0xf007 to 0xf005
//              3. Modify TV QVGA PAL  P_TV_HPost from 0x0907 to 0x0905
//              these 3 items will solve the TV glitch problem (reference to GPL162XX Application Note)
// 2008/10/03	1. Modity the tv setting of NTSC QVGA Non-Interlace mode. (SC Freq)
//      		  from:{0x815E,0x5A00,0x7600,0x0000,0x6D4E,0x7B00,0x8E00,0xF005,0x2100},  //7: NTSC-J (Non-Interlaced)  		
//      			to:{0x815E,0x5A00,0x7600,0x0000,0x6D4E,0x1F00,0x7C00,0xF005,0x2100},  //7: NTSC-J (Non-Interlaced)  
// 2008/10/13	1. Modity the tv setting of NTSC QVGA Non-Interlace mode. (SC Freq)
//      		  from:{0x815E,0x5A00,0x7600,0x0000,0x6D4E,0x1F00,0x7C00,0xF005,0x2100},  //7: NTSC-J (Non-Interlaced)  		
//      			to:{0x815E,0x5A00,0x7600,0x0000,0x6D4E,0xB800,0x1E00,0xF005,0x2100},  //7: NTSC-J (Non-Interlaced)  
//***************************************************************************************** 
#ifndef __POINTER_32__
#error PPU Driver can ONLY be used in FAR Pointer, Please check Project->Setting->Option->Pointer
#endif
//=========================================================================================
// Header File Included Area
//=========================================================================================
#include	"PPUSystem.h"                       
#include	"PPUDrv.h"
#include 	"..\GPL951_Body.h"

//=========================================================================================
// Contant Defintion Area
//=========================================================================================
void cmd_delay(unsigned int i);
//=========================================================================================
// Global Variable Defintion Area
//=========================================================================================
extern int 	Text1IndexTable[];	//Text1 index table (number array)	 		
extern int 	Text2IndexTable[];	//Text2 index table (number array)	 		
extern int 	Text3IndexTable[];	//Text3 index table (number array)	 		 		
extern int 	Text1AttrTable[];	//Text1 attribute table (attribute array)
extern int 	Text2AttrTable[];	//Text2 attribute table (attribute array)
extern int 	Text3AttrTable[];	//Text3 attribute table (attribute array)
extern SPRITE	Sprite_Buff[];	//Sprite structure
extern int	SpriteBuf0[];	//Sprite buffer 0
extern int	SpriteBuf1[];	//Sprite buffer 1
int				spriteFlag;	//Sprite data update flag
int				textScroll; //Text scrolling flag
int 			text1_x, text1_y, text2_x, text2_y, text3_x, text3_y;	//Text scrolling position 
int             TextModeFlag; //Text mode update flag
int				Text1Mode, Text2Mode, Text3Mode; //Text mode value
U32             ptrTxPalette0, ptrTxPalette1, ptrSpPalette0, ptrSpPalette1;
//int             HoffsetBuff[240];	//Horizontal offset buffer
//int             Text3CosSinBuff[480];	//Text3 cosine and sine buffer
int 			TxPaletteFlag0;	//Text palette 0 update flag
int 			SpPaletteFlag0;	//Sprite palette 0 update flag
int 			TxPaletteFlag1;	//Text palette 1 update flag
int 			SpPaletteFlag1;	//Sprite palette 1 update flag
int             HoffsetFlag;	//Horizontal offset update flag
int				HCmpFlag;	//Horizontal compression update flag
int				LineMode;	//Line mode value
int 			HCmpValue;	//Horizontal compression value
U32				ptrHCmpTable;	//Horizontal compression value table
int				VCmpFlag;	//Vertical compression update flag
int				VCmpValue;	//Vertical compression value
int				VCmpOffset;	//Vertical compression offset value
int				VCmpStep;	//Vertical compression step value
int				Text3RotateFlag;	//Text3 rotation update flag
int				Text25dFlag;	//Text3 2.5d update flag
int             Text3CenterX;	//Text3 X rotation center
int             Text3CenterY;	//Text3 Y rotation center
int             Text3OffsetX;	//Text3 X offset value
int             Text3OffsetY;	//Text3 Y offset value
//U32				FrameBuff0, FrameBuff1, FrameBuff2;	//frame buffer address  
U16 			old_game_time, game_time; //game time
int             Scrolling_H1, Scrolling_V1;	//Text1 horizontal/vertical start character
int             Scrolling_H2, Scrolling_V2;	//Text2 horizontal/vertical start character
int             Scrolling_H3, Scrolling_V3;	//Text3 horizontal/vertical start character		
int 			iHoffsetCount;	//counter for Sea offset
int 			fb_switch;	//frame buffer switch status 
int				ppu_flag, tv_flag;	//PPU/TV active flag
U16				ppu_count;	//PPU frame counter	
int				FadeInFlag, FadeOutFlag;	//Fade in/out flag
U16				FadePeriod;	//frame interval for fade effect
int				cpu_done; //CPU done flag for frame base mode
U16             FadeCount; //Frame counter of fade effect
int				text1_index_length;
int				text2_index_length;
int				text3_index_length;
int				sp_number_max;
//=========================================================================================
// Constant Table Area
//=========================================================================================
const int C_SIN_TABLE[] = {		//sine data table (0, 1,..., 359 degreed)
	     0,     18,     36,     54,     71,     89,    107,    125,    143,    160,    178,    195,    213,    230,    248, 
	   265,    282,    299,    316,    333,    350,    367,    384,    400,    416,    433,    449,    465,    481,    496, 
	   512,    527,    543,    558,    573,    587,    602,    616,    630,    644,    658,    672,    685,    698,    711, 
	   724,    737,    749,    761,    773,    784,    796,    807,    818,    828,    839,    849,    859,    868,    878, 
	   887,    896,    904,    912,    920,    928,    935,    943,    949,    956,    962,    968,    974,    979,    984, 
	   989,    994,    998,   1002,   1005,   1008,   1011,   1014,   1016,   1018,   1020,   1022,   1023,   1023,   1024, 
	  1024,   1024,   1023,   1023,   1022,   1020,   1018,   1016,   1014,   1011,   1008,   1005,   1002,    998,    994, 
	   989,    984,    979,    974,    968,    962,    956,    949,    943,    935,    928,    920,    912,    904,    896, 
	   887,    878,    868,    859,    849,    839,    828,    818,    807,    796,    784,    773,    761,    749,    737, 
	   724,    711,    698,    685,    672,    658,    644,    630,    616,    602,    587,    573,    558,    543,    527, 
	   512,    496,    481,    465,    449,    433,    416,    400,    384,    367,    350,    333,    316,    299,    282, 
	   265,    248,    230,    213,    195,    178,    160,    143,    125,    107,     89,     71,     54,     36,     18, 
	     0,    -18,    -36,    -54,    -71,    -89,   -107,   -125,   -143,   -160,   -178,   -195,   -213,   -230,   -248, 
	  -265,   -282,   -299,   -316,   -333,   -350,   -367,   -384,   -400,   -416,   -433,   -449,   -465,   -481,   -496, 
	  -512,   -527,   -543,   -558,   -573,   -587,   -602,   -616,   -630,   -644,   -658,   -672,   -685,   -698,   -711, 
	  -724,   -737,   -749,   -761,   -773,   -784,   -796,   -807,   -818,   -828,   -839,   -849,   -859,   -868,   -878, 
	  -887,   -896,   -904,   -912,   -920,   -928,   -935,   -943,   -949,   -956,   -962,   -968,   -974,   -979,   -984, 
	  -989,   -994,   -998,  -1002,  -1005,  -1008,  -1011,  -1014,  -1016,  -1018,  -1020,  -1022,  -1023,  -1023,  -1024, 
	 -1024,  -1024,  -1023,  -1023,  -1022,  -1020,  -1018,  -1016,  -1014,  -1011,  -1008,  -1005,  -1002,   -998,   -994, 
	  -989,   -984,   -979,   -974,   -968,   -962,   -956,   -949,   -943,   -935,   -928,   -920,   -912,   -904,   -896, 
	  -887,   -878,   -868,   -859,   -849,   -839,   -828,   -818,   -807,   -796,   -784,   -773,   -761,   -749,   -737, 
	  -724,   -711,   -698,   -685,   -672,   -658,   -644,   -630,   -616,   -602,   -587,   -573,   -558,   -543,   -527, 
	  -512,   -496,   -481,   -465,   -449,   -433,   -416,   -400,   -384,   -367,   -350,   -333,   -316,   -299,   -282, 
	  -265,   -248,   -230,   -213,   -195,   -178,   -160,   -143,   -125,   -107,    -89,    -71,    -54,    -36,    -18
	};

const int C_COS_TABLE[] = {		//cosine data table (0, 1,..., 359 degreed)
	  1024,   1024,   1023,   1023,   1022,   1020,   1018,   1016,   1014,   1011,   1008,   1005,   1002,    998,    994, 
	   989,    984,    979,    974,    968,    962,    956,    949,    943,    935,    928,    920,    912,    904,    896, 
	   887,    878,    868,    859,    849,    839,    828,    818,    807,    796,    784,    773,    761,    749,    737, 
	   724,    711,    698,    685,    672,    658,    644,    630,    616,    602,    587,    573,    558,    543,    527, 
	   512,    496,    481,    465,    449,    433,    416,    400,    384,    367,    350,    333,    316,    299,    282, 
	   265,    248,    230,    213,    195,    178,    160,    143,    125,    107,     89,     71,     54,     36,     18, 
	     0,    -18,    -36,    -54,    -71,    -89,   -107,   -125,   -143,   -160,   -178,   -195,   -213,   -230,   -248, 
	  -265,   -282,   -299,   -316,   -333,   -350,   -367,   -384,   -400,   -416,   -433,   -449,   -465,   -481,   -496, 
	  -512,   -527,   -543,   -558,   -573,   -587,   -602,   -616,   -630,   -644,   -658,   -672,   -685,   -698,   -711, 
	  -724,   -737,   -749,   -761,   -773,   -784,   -796,   -807,   -818,   -828,   -839,   -849,   -859,   -868,   -878, 
	  -887,   -896,   -904,   -912,   -920,   -928,   -935,   -943,   -949,   -956,   -962,   -968,   -974,   -979,   -984, 
	  -989,   -994,   -998,  -1002,  -1005,  -1008,  -1011,  -1014,  -1016,  -1018,  -1020,  -1022,  -1023,  -1023,  -1024, 
	 -1024,  -1024,  -1023,  -1023,  -1022,  -1020,  -1018,  -1016,  -1014,  -1011,  -1008,  -1005,  -1002,   -998,   -994, 
	  -989,   -984,   -979,   -974,   -968,   -962,   -956,   -949,   -943,   -935,   -928,   -920,   -912,   -904,   -896, 
	  -887,   -878,   -868,   -859,   -849,   -839,   -828,   -818,   -807,   -796,   -784,   -773,   -761,   -749,   -737, 
	  -724,   -711,   -698,   -685,   -672,   -658,   -644,   -630,   -616,   -602,   -587,   -573,   -558,   -543,   -527, 
	  -512,   -496,   -481,   -465,   -449,   -433,   -416,   -400,   -384,   -367,   -350,   -333,   -316,   -299,   -282, 
	  -265,   -248,   -230,   -213,   -195,   -178,   -160,   -143,   -125,   -107,    -89,    -71,    -54,    -36,    -18, 
	     0,     18,     36,     54,     71,     89,    107,    125,    143,    160,    178,    195,    213,    230,    248, 
	   265,    282,    299,    316,    333,    350,    367,    384,    400,    416,    433,    449,    465,    481,    496, 
	   512,    527,    543,    558,    573,    587,    602,    616,    630,    644,    658,    672,    685,    698,    711, 
	   724,    737,    749,    761,    773,    784,    796,    807,    818,    828,    839,    849,    859,    868,    878, 
	   887,    896,    904,    912,    920,    928,    935,    943,    949,    956,    962,    968,    974,    979,    984, 
	   989,    994,    998,   1002,   1005,   1008,   1011,   1014,   1016,   1018,   1020,   1022,   1023,   1023,   1024
	};

const int C_SeaHoffset[] = {		
		0x0000,0x0000,0x0000,0x0001,0x0001,0x0001,0x0001,0x0001,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0003,
		0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,
		0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0003,0x0003,0x0003,0x0003,
		0x0003,0x0003,0x0003,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0001,0x0001,0x0001,0x0001,0x0001,0x0000,
		0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x01ff,0x01ff,0x01ff,0x01ff,0x01ff,0x01fe,0x01fe,0x01fe,0x01fe,
		0x01fe,0x01fe,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,
		0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,
		0x01fe,0x01fe,0x01fe,0x01fe,0x01fe,0x01fe,0x01ff,0x01ff,0x01ff,0x01ff,0x01ff,0x0000,0x0000,0x0000,0x0000,
		0x0000,0x0000,0x0000,0x0001,0x0001,0x0001,0x0001,0x0001,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0003,
		0x0003,0x0003,0x0003,0x0003,0x0003,0x0003,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,
		0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0003,0x0003,0x0003,0x0003,
		0x0003,0x0003,0x0003,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0001,0x0001,0x0001,0x0001,0x0001,0x0000,
		0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x01ff,0x01ff,0x01ff,0x01ff,0x01ff,0x01fe,0x01fe,0x01fe,0x01fe,
		0x01fe,0x01fe,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,
		0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,0x01fd,
		0x01fe,0x01fe,0x01fe,0x01fe,0x01fe,0x01fe,0x01ff,0x01ff,0x01ff,0x01ff,0x01ff,0x0000,0x0000,0x0000,0x0000,
	};

const int C_SeaHoffset_VGA[] = {		
		0x0000<<1,0x0000<<1,0x0000<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0003<<1,
		0x0003<<1,0x0003<<1,0x0003<<1,0x0003<<1,0x0003<<1,0x0003<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,
		0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0003<<1,0x0003<<1,0x0003<<1,0x0003<<1,
		0x0003<<1,0x0003<<1,0x0003<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0000<<1,
		0x0000<<1,0x0000<<1,0x0000<<1,0x0000<<1,0x0000<<1,0x0000<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x01fe<<1,0x01fe<<1,0x01fe<<1,0x01fe<<1,
		0x01fe<<1,0x01fe<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,
		0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,
		0x01fe<<1,0x01fe<<1,0x01fe<<1,0x01fe<<1,0x01fe<<1,0x01fe<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x0000<<1,0x0000<<1,0x0000<<1,0x0000<<1,
		0x0000<<1,0x0000<<1,0x0000<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0003<<1,
		0x0003<<1,0x0003<<1,0x0003<<1,0x0003<<1,0x0003<<1,0x0003<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,
		0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0004<<1,0x0003<<1,0x0003<<1,0x0003<<1,0x0003<<1,
		0x0003<<1,0x0003<<1,0x0003<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0002<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0001<<1,0x0000<<1,
		0x0000<<1,0x0000<<1,0x0000<<1,0x0000<<1,0x0000<<1,0x0000<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x01fe<<1,0x01fe<<1,0x01fe<<1,0x01fe<<1,
		0x01fe<<1,0x01fe<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,
		0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,0x01fd<<1,
		0x01fe<<1,0x01fe<<1,0x01fe<<1,0x01fe<<1,0x01fe<<1,0x01fe<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x01ff<<1,0x0000<<1,0x0000<<1,0x0000<<1,0x0000<<1,
	};

  	 	
const int SPCell[]={ 8, 16, 32, 64};
const int SHFBIT[]={ 3, 4, 5, 6};
const int PPU_Driver_Version = 0x0105;

//====================================================================================================
//	Description:	Set the value to memory
//	Function:		MyMemSet()
//	Syntax:			void	MyMemSet(U32 DestMem, S16 value, U32 num);
//	Input Paramter:	U32 DestMem : Start address of target memory
//					S16 Value: Data value	
//					U32 Num: Data number to write to memory (words)
//	Return: 		None			
//====================================================================================================
void	MyMemSet(U32 DestMem, S16 Value, U32 Num)
{
	S16 data;
	
	if (Num!=0)
	{	
	data = Value;
	asm("fiq off");
	asm("irq off");
	while ((*P_DMA_INT & 0x0100) == 1)	// check DMA0 is idle?
	{}
	*P_DMA_Ctrl0= 0x200;
   	*P_DMA_SRC_AddrL0 = (U16)(U32)&data;
   	*P_DMA_SRC_AddrH0 = 0;
   	*P_DMA_TAR_AddrL0 = DestMem&0xffff;
   	*P_DMA_TAR_AddrH0 = DestMem>>16;
   	*P_DMA_TCountL0   = Num&0xffff;
   	*P_DMA_TCountH0   = Num>>16;   
   	*P_DMA_Ctrl0      = 0x0089;
   	while ((*P_DMA_INT & 0x0001) == 0) 
   	{}
   	*P_DMA_INT        = 0x0001;
   	asm("fiq on");
	asm("irq on");
	}
};

//================================================================================
//	Description:	Use DMA channel 0 to transfer data
//	Function:		SetDMACopy0()
//	Syntax:			void	SetDMACopy0(U32 SrcMem, U32 DestMem, U32 Num);
//	Input Paramter:	U32 SrcMem: Start address of source memory
//					U32 DestMem: Start address of target memory
//					U32 Num: DMA Transfer data number (words)
//	Return: 		none
//  Note:	After transfering one data, both source and destination address will increase one.
//================================================================================
void	SetDMACopy0(U32 SrcMem, U32 DestMem, U32 Num)                           
{
	U16 map_sel;
	U16 src_bank;
	U16 src_offset;
	
	asm("fiq off");
	asm("irq off");

	src_bank = SrcMem>>16;

	while ((*P_DMA_INT & 0x0100) == 1)	// check DMA0 is idle?
	{}
	*P_DMA_Ctrl0= 0x200;
   	*P_DMA_SRC_AddrL0 = SrcMem&0xffff;
   	*P_DMA_SRC_AddrH0 = src_bank;
   	*P_DMA_TAR_AddrL0 = DestMem&0xffff;
   	*P_DMA_TAR_AddrH0 = DestMem>>16;
   	*P_DMA_TCountL0   = Num&0xffff;
   	*P_DMA_TCountH0   = Num>>16;   
   	*P_DMA_Ctrl0      = 0x0009;
   	while ((*P_DMA_INT & 0x0001) == 0) 
   	{}
   	*P_DMA_INT        = 0x0001;
   	asm("fiq on");
	asm("irq on");
};
	
//====================================================================================================
//	Description:	Set color palette by manual data (all same data)
//	Function:		SetColorPalette()
//	Syntax:			void	SetColorPalette(int col_st, int col_end, int value, int pal_sel);
//	Input Paramter:	int col_st:		Palette start index address
//					int col_end:	Palette end index address
//					int value:		Palette data value
//                  int pal_sel:    Palette selection
//									0: Text Palette 0
//									1: Sprite Palette 0 
//   								2: Text Palette 1
//   								3: Sprite Palette 1
//	Return: 		none
//  Note: 			The new palette data will be updated to palette RAM directly.
//====================================================================================================
void	SetColorPalette(int col_st, int col_end, int value, int pal_sel)
{
	int	i;
	int *ptr;
	
	ptr = (int *)P_Palette_ADDR;
	P_Palette_Control_B -> B.Bank = pal_sel;
	for (i=col_st; i<=col_end; i++)
		*(ptr + i) = value;
	P_Palette_Control_B -> B.Bank = 0;
};

//====================================================================================================
//	Description:	Write color palette data to palette RAM
//	Function:		WriteColorPalette()
//	Syntax:			void	WriteColorPalette(void);
//	Input Paramter:	none
//	Return: 		none
//	Note:			The new palette data will be updated from buffer to palette RAM.
//====================================================================================================
void	WriteColorPalette(void)
{
	if (TxPaletteFlag0)
	{
		P_Palette_Control_B -> B.Bank = 0;
		SetDMACopy0(ptrTxPalette0, (U32)P_Palette_ADDR, 256);
		P_Palette_Control_B -> B.Bank = 0;
		TxPaletteFlag0 = 0;
	}				
	
	if (TxPaletteFlag1)
	{
		P_Palette_Control_B -> B.Bank = 2;
		SetDMACopy0(ptrTxPalette1, (U32)P_Palette_ADDR, 256);
		P_Palette_Control_B -> B.Bank = 0;
		TxPaletteFlag1 = 0;
	}													
		
	if (SpPaletteFlag0)
	{
		P_Palette_Control_B -> B.Bank = 1;
		SetDMACopy0(ptrSpPalette0, (U32)P_Palette_ADDR, 256);
		P_Palette_Control_B -> B.Bank = 0;
		SpPaletteFlag0 = 0;
	}				
	
	if (SpPaletteFlag1)
	{
		P_Palette_Control_B -> B.Bank = 3;
		SetDMACopy0(ptrSpPalette1, (U32)P_Palette_ADDR, 256);
		P_Palette_Control_B -> B.Bank = 0;
		SpPaletteFlag1 = 0;
	}													
};	

//====================================================================================================
//	Description:	Set one palette color to be transparent
//	Function:		SetOneTransparentColor()
//	Syntax:			void	SetOneTransparentColor(int pal_index, int value, int pal_sel);
//	Input Paramter:	int pal_index:	palette index address
//					int value:	0: clear transparent 
//								1: set transparent
//                  int pal_sel:    Palette selection (0~3)
//									0: Text Palette 0
//									1: Sprite Palette 0 
//   								2: Text Palette 1
//   								3: Sprite Palette 1
//	Return: 		none
//	Note:			The transparent setting will be updated to palette RAM directly.
//====================================================================================================
void	SetOneTransparentColor(int pal_index, int value, int pal_sel)
{
	int type;
	int *ptr;
	
	ptr = (int *)P_Palette_ADDR;
	type = P_Palette_Control_B -> B.Type;
	switch(type)
	{
		case 0:	//16-bit shared palette
				if (pal_sel<=1)
					P_Palette_Control_B -> B.Bank = 0;
				else 
					P_Palette_Control_B -> B.Bank = 2;
				*(ptr + pal_index) |= value << 15;
				P_Palette_Control_B -> B.Bank = 0;
				break;
		case 1:	//16-bit seperated palette 
				P_Palette_Control_B -> B.Bank = pal_sel;
				*(ptr + pal_index) |= value << 15;
				P_Palette_Control_B -> B.Bank = 0;
				break;
		case 2:	//25-bit shared palette
				P_Palette_Control_B -> B.Bank = 2;
				*(ptr + pal_index) |= value << 8;
				P_Palette_Control_B -> B.Bank = 0;
				break;
		case 3:	//25-bit seperated palette
				if ((pal_sel==0)||(pal_sel==2))
					P_Palette_Control_B -> B.Bank = 2;
				else 
					P_Palette_Control_B -> B.Bank = 3;
				*(ptr + pal_index) |= value << 8;
				P_Palette_Control_B -> B.Bank = 0;
				break;
	}
};	

//====================================================================================================
//	Description:	Set one block of palette colors to be transparent
//	Function:		SetTransparentColor()
//	Syntax:			void	SetTransparentColor(int col_st, int col_end, int value, int pal_sel);
//	Input Paramter:	int col_st:		palette start index address
//					int col_end:	palette end index address
//					int value:		0: clear transparent 
//									1: set transparent
//                  int pal_sel:    Palette selection (0~3)
//									0: Text Palette 0
//									1: Sprite Palette 0 
//   								2: Text Palette 1
//   								3: Sprite Palette 1		
//	Return: 		none
//  Note:			The transparent setting will be updated to palette RAM directly.
//====================================================================================================
void	SetTransparentColor(int col_st, int col_end, int value, int pal_sel)
{
	int	i;
	int type;
	int *ptr;
	
	ptr = (int *)P_Palette_ADDR;
	type = P_Palette_Control_B -> B.Type;
	switch(type)
	{
		case 0:	//16-bit shared palette
				if (pal_sel<=1)
					P_Palette_Control_B -> B.Bank = 0;
				else 
					P_Palette_Control_B -> B.Bank = 2;
				for (i=col_st; i<=col_end; i++)
					*(ptr + i) |= value << 15;
				P_Palette_Control_B -> B.Bank = 0;
				break;
		case 1:	//16-bit seperated palette 
				P_Palette_Control_B -> B.Bank = pal_sel;
				for (i=col_st; i<=col_end; i++)
					*(ptr + i) |= value << 15;
				P_Palette_Control_B -> B.Bank = 0;
				break;
		case 2:	//25-bit shared palette
				P_Palette_Control_B -> B.Bank = 2;
				for (i=col_st; i<=col_end; i++)
					*(ptr + i) |= value << 8;
				P_Palette_Control_B -> B.Bank = 0;
				break;
		case 3:	//25-bit seperated palette
				if ((pal_sel==0)||(pal_sel==2))
					P_Palette_Control_B -> B.Bank = 2;
				else 
					P_Palette_Control_B -> B.Bank = 3;
				for (i=col_st; i<=col_end; i++)
					*(ptr + i) |= value << 8;
				P_Palette_Control_B -> B.Bank = 0;
				break;
	}
};	

//====================================================================================================
//	Description:	Set all palette color to be transparent
//	Function:		SetAllTransparent()
//	Syntax:			void	SetAllTransparent(int value, int pal_sel);
//	Input Paramter:	int value:	0: clear transparent 
//								1: set transparent
//					int pal_sel:    Palette selection (0~3)
//									0: Text Palette 0
//									1: Sprite Palette 0 
//   								2: Text Palette 1
//   								3: Sprite Palette 1				
//	Return: 		none
//====================================================================================================
void	SetAllTransparent(int value, int pal_sel)
{
	SetTransparentColor(0, 255, value, pal_sel);
};

//====================================================================================================
//	Description:	Clear one sprite  
//	Function:		ClearOneSprite()
//	Syntax:			void	ClearOneSprite(int Spno);
//	Input Paramter:	int Spno:	Sprite number
//	Return: 		none
//====================================================================================================
void	ClearOneSprite(int Spno)
{	
	Sprite_Buff[Spno].sprcell		= 0;
	Sprite_Buff[Spno].Idx			= 0;
	Sprite_Buff[Spno].x				= 0;
	Sprite_Buff[Spno].y				= 0;
	Sprite_Buff[Spno].xSize			= 0;
	Sprite_Buff[Spno].ySize			= 0;
	Sprite_Buff[Spno].att0			= 0;
	Sprite_Buff[Spno].att1			= 0;
	Sprite_Buff[Spno].x1			= 0;
	Sprite_Buff[Spno].x2			= 0;							
	Sprite_Buff[Spno].x3			= 0;	
	Sprite_Buff[Spno].y1			= 0;
	Sprite_Buff[Spno].y2			= 0;
	Sprite_Buff[Spno].y3			= 0;
};

//====================================================================================================
//	Description:	Clear all sprite 
//	Function:		ClearAllSprite()
//	Syntax:			void	ClearAllSprite(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearAllSprite(void)
{
	int	i;	
	for (i=0; i<sp_number_max; i++)
		ClearOneSprite(i);
};

//====================================================================================================
//	Description:	Clear text register value
//	Function:		ClearTextRegister()
//	Syntax:			void	ClearTextRegister(int txn);
//	Input Paramter:	int txn: Text selection (0~2)
//							0: Text1
//							1: Text2
//							2: Text3
//	Return: 		none
//====================================================================================================
void	ClearTextRegister(int txn)
{
	int	i;
	int *ptr;
	
	if (txn == 0) {
		ptr = (int *)P_Tx1_X_Position_ADDR; 
		for(i = 0 ; i < 6 ; i++)
			*(ptr + i) = 0;
	}
	else if (txn == 1) {
		ptr = (int *)P_Tx2_X_Position_ADDR; 
		for(i = 0 ; i < 6 ; i++)
			*(ptr + i)= 0;	
	}
	else {
		ptr = (int *)P_Tx3_X_Position_ADDR; 
		for(i = 0 ; i < 8 ; i++)
			*(ptr + i)= 0;	
	}

};

//====================================================================================================
//	Description:	Clear all internal system RAM (10KW, 0 ~ 0x27FF)
//	Function:		ClearAllRam()
//	Syntax:			void	ClearAllRam(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearAllRam(void)
{
	MyMemSet(0, 0, 0x2800);
};

//====================================================================================================
//	Description:	Clear PPU's buffer and initialize variables
//	Function:		ClearSimple()
//	Syntax:			void	ClearSimple(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearSimple(void)
{
	ClearAllSprite();					    // Clear all sprite 

//	MyMemSet((U32)Text3CosSinBuff, 0, 480);	// Clear cos/sin Buffer
//	MyMemSet((U32)HoffsetBuff, 0, 240);		// Clear Hoffset Buffer
						
	MyMemSet((U32)Text1IndexTable, 0, text1_index_length);	// Clear Text1 index array
	MyMemSet((U32)Text2IndexTable, 0, text2_index_length);	// Clear Text2 index array
	MyMemSet((U32)Text3IndexTable, 0, text3_index_length);	// Clear Text3 index array
	MyMemSet((U32)Text1AttrTable, 0, text1_index_length>>1);	// Clear Text1 attribute array
	MyMemSet((U32)Text2AttrTable, 0, text2_index_length>>1);	// Clear Text2 attribute array
	MyMemSet((U32)Text3AttrTable, 0, text3_index_length>>1);	// Clear Text3 attribute array
	
	// clear variables for PPU driver 
	old_game_time = 0;
	game_time = 0;
	fb_switch = 0;
	tv_flag = 0;
	ppu_flag = 1;
	ppu_count = 0;
	spriteFlag 	= 0;						
	textScroll 	= 0;
	text1_x		= 0;
	text1_y		= 0;
	text2_x		= 0;
	text2_y		= 0;
	text3_x		= 0;
	text3_y		= 0;	
	TextModeFlag = 0;
	Text1Mode 	= 0;
	Text2Mode 	= 0;
	Text3Mode 	= 0;
	TxPaletteFlag0	= 0;
	SpPaletteFlag0	= 0;
	TxPaletteFlag1	= 0;
	SpPaletteFlag1	= 0;
	HoffsetFlag = 0;
	HCmpFlag 	= 0;
	VCmpFlag 	= 0;
	iHoffsetCount = 0;
	Text3RotateFlag = 0;
	Text25dFlag = 0;
	Text3CenterX = 0;
	Text3CenterY = 0;
	Text3OffsetX = 0;
	Text3OffsetY = 0;
    FadeInFlag = 0;
    FadeOutFlag = 0;
    FadePeriod = 0;
    cpu_done = 0;
    FadeCount = 0;
};

//====================================================================================================
//	Description:	Clear all PPU registers/RAM and API's variable values
//	Function:		ClearAllSetting()
//	Syntax:			void	ClearAllSetting(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearAllSetting(void)
{
  	ClearSimple();											// Clear PPU buffer and some API's variable value
	ClearTextRegister(TEXT1);								// Clear Text1 Register
	ClearTextRegister(TEXT2);								// Clear Text2 Register
	ClearTextRegister(TEXT3);								// Clear Text3 Register
	
	*P_PPU_RAM_Bank = 1;									// Clear Sprite RAM
	MyMemSet((U32)P_Sp_Num_ADDR, 0, 1024);
	*P_PPU_RAM_Bank = 0;
	MyMemSet((U32)P_Sp_Num_ADDR, 0, 1024);
		
	*P_Sp_Control = 0;										// Disable Sprite
	*P_PPU_IRQ_Control = 0;									// Disable all PPU interrupts 
	*P_PPU_IRQ_Status = 0x03ff;								// Clear all PPU interrupt flags 
  	*P_Blending = 0;
  	*P_Fade_Control = 0;
  	*P_Palette_Control = 0;
  	*P_PPU_Enable = 0;
  		  
	HCompressEffect(0, 0x80, 0);							// Initial horizontal compression value
	VCompressEffect(0x20, 0x00, 0x00);						// Initial vertical compression value
	HOffsetEffect(0, 0, 0);									// Initial horizontal movement value
};

//====================================================================================================
//	Description:	Enable V-Blanking interrupt
//	Function:		VblankIrqON()
//	Syntax:			void	VblankIrqON(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	VblankIrqON(void)
{
	P_PPU_IRQ_Control_B->B.BLK_IRQ_EN = 1;					// Set Vertical blanking IRQ on
	SetCpuIrqON();									   		// Set CPU IRQ on	
};

//====================================================================================================
//	Description:	Disable V-Blanking interrupt
//	Function:		VblankIrqOFF()
//	Syntax:			void	VblankIrqOFF(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	VblankIrqOFF(void)
{
	P_PPU_IRQ_Control_B->B.BLK_IRQ_EN = 0;					// Set Vertical blanking IRQ off
};

//====================================================================================================
//	Description:	Enable video timing interrupt
//	Function:		VideoTimingIrqON()
//	Syntax:			void	VideoTimingIrqON(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	VideoTimingIrqON(void)
{	
	P_PPU_IRQ_Control_B->B.VDO_IRQ_EN = 1;					// Set Video Timing IRQ on
	SetCpuIrqON();									   		// Set CPU IRQ on	
};

//====================================================================================================
//	Description:	Disable video timing interrupt
//	Function:		VideoTimingIrqOFF()
//	Syntax:			void	VideoTimingIrqOFF(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	VideoTimingIrqOFF(void)
{	
	P_PPU_IRQ_Control_B->B.VDO_IRQ_EN = 0;					// Set Video Timing IRQ off
};

//====================================================================================================
//	Description:	Enable Sprite DMA transfer end interrupt
//	Function:		SpDMAIrqON()
//	Syntax:			void	SpDMAIrqON(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	SpDMAIrqON(void)
{	
	P_PPU_IRQ_Control_B->B.DMA_IRQ_EN = 1;					// Set sprite DMA end IRQ on
	SetCpuIrqON();									   		// Set CPU IRQ on	
};

//====================================================================================================
//	Description:	Disable Sprite DMA transfer end interrupt
//	Function:		SpDMAIrqOFF()
//	Syntax:			void	SpDMAIrqOFF(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	SpDMAIrqOFF(void)
{	
	P_PPU_IRQ_Control_B->B.DMA_IRQ_EN = 0;					// Set sprite DMA end IRQ off	
};

//====================================================================================================
//	Description:	Enable palette write error interrupt
//	Function:		PaletteErrIrqON()
//	Syntax:			void	PaletteErrIrqON(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	PaletteErrIrqON(void)
{
	P_PPU_IRQ_Control_B->B.PALERR_IRQ_EN = 1;				// Set palette write error IRQ on
	SetCpuIrqON();									   		// Set CPU IRQ on	
};

//====================================================================================================
//	Description:	Disable palette write error interrupt
//	Function:		PaletteErrIrqOFF()
//	Syntax:			void	PaletteErrIrqOFF(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	PaletteErrIrqOFF(void)
{
	P_PPU_IRQ_Control_B->B.PALERR_IRQ_EN = 0;				// Set palette write error IRQ off	
};

//====================================================================================================
//	Description:	Enable text under run interrupt
//	Function:		TxUnderRunIrqON()
//	Syntax:			void	TxUnderRunIrqON(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	TxUnderRunIrqON(void)
{
	P_PPU_IRQ_Control_B->B.TXUR_IRQ_EN = 1;					// Set text under run IRQ on
	SetCpuIrqON();									   		// Set CPU IRQ on	
};

//====================================================================================================
//	Description:	Disable text under run interrupt
//	Function:		TxUnderRunIrqOFF()
//	Syntax:			void	TxUnderRunIrqOFF(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	TxUnderRunIrqOFF(void)
{
	P_PPU_IRQ_Control_B->B.TXUR_IRQ_EN = 0;					// Set text under run IRQ off
};

//====================================================================================================
//	Description:	Enable sprite under run interrupt
//	Function:		SpUnderRunIrqON()
//	Syntax:			void	SpUnderRunIrqON(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	SpUnderRunIrqON(void)
{
	P_PPU_IRQ_Control_B->B.SPUR_IRQ_EN = 1;					// Set sprite under run IRQ on
	SetCpuIrqON();									   		// Set CPU IRQ on	
};

//====================================================================================================
//	Description:	Disable sprite under run interrupt
//	Function:		SpUnderRunIrqOFF()
//	Syntax:			void	SpUnderRunIrqOFF(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	SpUnderRunIrqOFF(void)
{
	P_PPU_IRQ_Control_B->B.SPUR_IRQ_EN = 0;					// Set sprite under run IRQ off	
};

//====================================================================================================
//	Description:	Enable frame FIFO under run interrupt
//	Function:		FrameUnderRunIrqON()
//	Syntax:			void	FrameUnderRunIrqON(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	FrameUnderRunIrqON(void)
{
	P_PPU_IRQ_Control_B->B.FBUR_IRQ_EN = 1;					// Set frame under run IRQ on
	SetCpuIrqON();									   		// Set CPU IRQ on	
};

//====================================================================================================
//	Description:	Disable frame FIFO under run interrupt
//	Function:		FrameUnderRunIrqOFF()
//	Syntax:			void	FrameUnderRunIrqOFF(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	FrameUnderRunIrqOFF(void)
{
	P_PPU_IRQ_Control_B->B.FBUR_IRQ_EN = 0;					// Set frame under run IRQ off
};


//====================================================================================================
//	Description:	Clear V-Blanking interrupt status
//	Function:		ClearVblankIRQ()
//	Syntax:			void	ClearVblankIRQ(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearVblankIRQ(void)
{
	*P_PPU_IRQ_Status = 0x0001;		// clear V-Blank IRQ
};

//====================================================================================================
//	Description:	Clear Video Timing interrupt Status
//	Function:		ClearVideoTimingIRQ()
//	Syntax:			void	ClearVideoTimingIRQ(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearVideoTimingIRQ(void)
{
	*P_PPU_IRQ_Status = 0x0002;		// clear video timing IRQ
};

//====================================================================================================
//	Description:	Clear sprite DMA transfer end interrupt Status
//	Function:		ClearSpDMAIRQ()
//	Syntax:			void	ClearSpDMAIRQ(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearSpDMAIRQ(void)
{
	*P_PPU_IRQ_Status = 0x0004;		// clear sprite DMA transfer end IRQ
};

//====================================================================================================
//	Description:	Clear palette write error interrupt Status
//	Function:		ClearPaletteErrIRQ()
//	Syntax:			void	ClearPaletteErrIRQ(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearPaletteErrIRQ(void)
{
	*P_PPU_IRQ_Status = 0x0008;		// clear palette write error IRQ
};

//====================================================================================================
//	Description:	Clear text under run interrupt Status
//	Function:		ClearTxUnderRunIRQ()
//	Syntax:			void	ClearTxUnderRunIRQ(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearTxUnderRunIRQ(void)
{
	*P_PPU_IRQ_Status = 0x0010;		// clear text under run IRQ
};

//====================================================================================================
//	Description:	Clear sprite under run interrupt Status
//	Function:		ClearSpUnderRunIRQ()
//	Syntax:			void	ClearSpUnderRunIRQ(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearSpUnderRunIRQ(void)
{
	*P_PPU_IRQ_Status = 0x0020;		// clear text under run IRQ
};

//====================================================================================================
//	Description:	Clear frame buffer under run interrupt Status
//	Function:		ClearFrameUnderRunIRQ()
//	Syntax:			void	ClearFrameUnderRunIRQ(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearFrameUnderRunIRQ(void)
{
	*P_PPU_IRQ_Status = 0x0400;		// clear frame buffer under run IRQ
};

//====================================================================================================
//	Description:	Clear TV/TFT frame end interrupt Status
//	Function:		ClearTVFrameEndIRQ()
//	Syntax:			void	ClearTVFrameEndIRQ(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ClearTVFrameEndIRQ(void)
{
	*P_PPU_IRQ_Status = 0x0800;		// clear TV/TFT frame end IRQ
};

//====================================================================================================
//	Description:	Initial PPU system control
//	Function:		InitPPU()
//	Syntax:			void	InitPPU(int ppu_en, int tx_direct, int tx_botup, int vga_en, int vga_nonintl, int free, int fb_en, int fb_format, int sp_25d, int fb_mono);
//	Input Paramter:	int ppu_en:
//								0:PPU_DISABLE
//								1:PPU_ENABLE
//					int tx_direct:
//								0:TEXT_RELATED
//								1:TEXT_DIRECT
// 					int tx_botup:
//								0:TEXT_TOP2BOT
//								1:TEXT_BOT2TOP
//					int vga_en:
//								0:VGA_DISABLE		
//								1:VGA_ENABLE
//					int vga_nonintl:
//								0:VGA_INTERLACE
//								1:VGA_NON_INTERLACE
//					int free:
//								0:FREE_DISABLE (Max. 22-bit address mode)
//								1:FREE_ENABLE (Max. 27-bit address mode)
//					int fb_en:
//								0:LINE_BASE
//								1:FRAME_BASE
//					int fb_format:
//								0:RGB565
//								1:RGBG
//					int sp_25d:
//								0:SP2D_MODE
//								1:SP25D_MODE
//					int fb_mono:
//								0:16bpp
//								1:1bpp
//								2:2bpp
//								3:4bpp			
//	Return: 		none
//====================================================================================================
void	InitPPU(int ppu_en, int tx_direct, int tx_botup, int vga_en, int vga_nonintl, int free, int fb_en, int fb_format, int sp_25d, int fb_mono)
{
	P_PPU_Enable_B -> B.PPUen		= ppu_en;
	P_PPU_Enable_B -> B.TxDirect	= tx_direct;
	P_PPU_Enable_B -> B.TxBotUp		= tx_botup;
	P_PPU_Enable_B -> B.VGAen		= 0;
	P_PPU_Enable_B -> B.VGANonIntl	= vga_nonintl;
	P_PPU_Enable_B -> B.Free		= free;
	P_PPU_Enable_B -> B.FBen		= fb_en;
	P_PPU_Enable_B -> B.FBformat	= fb_format;
	P_PPU_Enable_B -> B.Sp25d		= 0;	
	P_PPU_Enable_B -> B.FBmono		= fb_mono;	
};

//====================================================================================================
//	Description:	Turn on PPU
//	Function:		ppu_on()
//	Syntax:			void	ppu_on(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ppu_on(void)
{
	P_PPU_Enable_B -> B.PPUen = 1;
}

//====================================================================================================
//	Description:	Turn off PPU
//	Function:		ppu_off()
//	Syntax:			void	ppu_off(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	ppu_off(void)
{
	P_PPU_Enable_B -> B.PPUen = 0;
}
		
//====================================================================================================
//	Description:	Wait Vertical blanking IRQ
//	Function:		WaitBlanking()
//	Syntax:			void	WaitBlanking(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	WaitBlanking(void)
{
	cpu_done = 1;
 	while(old_game_time == game_time);	//game_time++ in v-blanking IRQ
 	old_game_time = game_time;
};

//====================================================================================================
//	Description:	Wait Vertical blanking IRQ
//	Function:		WaitBlanking2()
//	Syntax:			void	WaitBlanking2(void);
//	Input Paramter:	none
//	Return: 		none
//====================================================================================================
void	WaitBlanking2(void)
{
	cpu_done = 1;
 	while(old_game_time == game_time);	//game_time++ in v-blanking IRQ
 	while(cpu_done == 1);
 	old_game_time = game_time;
};

//====================================================================================================
//	Description:	Set Text Position
//	Function:		SetTextPosition()
//	Syntax:			void	SetTextPosition(int text, int x, int y);
//	Input Paramter:	int text: 	TEXT selection (0~3)
//								0:Text1
//								1:Text2
//								2:Text3
//					int x:	x position
//					int y:	y position
//	Return: 		none
//	Note:			New Text position will be updated to register at v-blanking IRQ. 
//====================================================================================================
void	SetTextPosition( int text, int x, int y )
{
	if( text == TEXT1 )
	{
		text1_x += x;		// old x value add x value	
		text1_y += y;		// old y value add y value
	}			
	else if( text == TEXT2 )
	{
		text2_x += x;		// old x value add x value	
		text2_y += y;		// old y value add y value	
	}
	else
	{
		text3_x += x;		// old x value add x value	
		text3_y += y;		// old y value add y value	
	}
					
	textScroll = 1;			// set text scroll flag
};

//====================================================================================================
//	Description:	Screen fade out from original palette to black
//	Function:		Screen_Fade_Out()
//	Syntax:			int	Screen_Fade_Out(int n);
//	Input Paramter:	int n: Frame interval (n > 0)
//	Return: 		0:fade out process isn't completed
//					1:fade out process is completed 
//  Note:			Execute fade out once every n frame till the screen is become black.
//					Return "1" when the screen is faded out to black completely. 
//====================================================================================================
int		Screen_Fade_Out(int n)
{
	if((*P_Fade_Control&0xFF) != 0xFF)
	{	
		FadePeriod = n;
		FadeOutFlag = 1;
		return 0;
	}	
	else
	{
		FadePeriod = 0;
		FadeOutFlag = 0;
		return 1;
	}	
};		

//====================================================================================================
//	Description:	Screen fade in from black to original palette
//	Function:		Screen_Fade_In()
//	Syntax:			int	Screen_Fade_In(int n);
//	Input Paramter:	int n: Frame interval (n > 0)
//	Return: 		0:fade in process isn't completed
//					1:fade in process is completed 
//  Note:			Execute fade in once every n frame till the screen is recovered to original palette.
//					Return "1" when the screen is faded in to original palette completely. 
//====================================================================================================
int		Screen_Fade_In(int n)
{
	if((*P_Fade_Control&0xFF) != 0x00)
	{	
		FadePeriod = n;
		FadeInFlag = 1;
		return 0;
	}	
	else
	{
		FadePeriod = 0;
		FadeInFlag = 0;
		return 1;
	}	
};		
	
//====================================================================================================
//	Description:	Check Two Sprite x,y Position Hit
//	Function:		Sprite_Hit_Chk()
//	Syntax:			int		Sprite_Hit_Chk(int Main_Index, int Enemy_Index);
//	Input Paramter:	int Main_Index:		SpriteBuf Index 1 (0~255)
//					int Enemy_Index:	SpriteBuf Index 2 (0~255)
//	Return: 		0:					no hit
//					1:					hit
//====================================================================================================
int		Sprite_Hit_Chk(int Main_Index, int Enemy_Index)
{
	//Check Two Sprite if Availability
	if(Sprite_Buff[Main_Index].sprcell == 0 || Sprite_Buff[Enemy_Index].sprcell == 0)		
		return 0;
	
	//Check Two Sprite x,y Position
	if((Sprite_Buff[Main_Index].x > (Sprite_Buff[Enemy_Index].x - (Sprite_Buff[Main_Index].xSize&0x03ff))) &&
	   (Sprite_Buff[Main_Index].x < (Sprite_Buff[Enemy_Index].x + (Sprite_Buff[Enemy_Index].xSize&0x03ff) - 4)) &&
	   (Sprite_Buff[Main_Index].y >	(Sprite_Buff[Enemy_Index].y - (Sprite_Buff[Main_Index].ySize&0x03ff))) &&
	   (Sprite_Buff[Main_Index].y < (Sprite_Buff[Enemy_Index].y + (Sprite_Buff[Enemy_Index].ySize&0x03ff) - 4))) 
	{
		return 1;	
	}
};

//====================================================================================================
//	Description:	Text layer every scanline Horizontal Movement
//	Function:		HorizontalMovement()
//	Syntax:			void	HorizontalMovement(int StartScanline,int EndScanline,U32 lpScanline);
//	Input Paramter:	int StartScanline:	Start Scanline (0~239)
//					int EndScanline:	End Scanline (0~239)
//					U32 lpScanline:	Scanline Movement data table
//	Return: 		none
//  Note:			Horizontal movement value will be updated from buffer to register at v-blanking IRQ. 
//====================================================================================================
void	HorizontalMovement(int StartScanline, int EndScanline, U32 lpScanline)
{
//	if (EndScanline >= StartScanline)
//	{	
//		SetDMACopy0(lpScanline, (U32)HoffsetBuff+StartScanline, EndScanline-StartScanline+1); 
//		HoffsetFlag = 1;
//	}		
};

//====================================================================================================
//	Description:	Set text effect
//	Function:		SetTextEffect()
//	Syntax:			void	SetTextEffect(int nText,int nMode,int nEnable);
//	Input Paramter:	int nText: 	Text selection (0~2)
//								0:TEXT1		
//								1:TEXT2		
// 								2:TEXT3
//					int nMode:	Text effect selection (0~3)
//								0:WALLPAPER		
//								1:HOFFSET
//								2:BLEND
//								3:FLIP
//					nEnable:	Effect enable (0~3)
//								0:DISABLE
//								1:ENABLE
//					(Flip Mode):
//								0:NO_FLIP
//								1:H_FLIP
//								2:V_FLIP
//								3:HV_FLIP
//	Return: 		none
//====================================================================================================
void	SetTextEffect(int nText,int nMode,int nEnable)
{	
	if(nText == TEXT1)		//text1
	{
		switch(nMode)
		{
			case	WALLPAPER:
				P_Tx1_Control_B -> B.Wap		= nEnable;
			break;
			case	HOFFSET:
				P_Tx1_Control_B -> B.Mve 		= nEnable;
			break;
			case	BLEND:
				P_Tx1_Control_B -> B.Bld 		= nEnable;
			break;
			case	FLIP:
				P_Tx1_Attribute_B -> B.Flip 	= nEnable;
			break;	
		}
	}
	if(nText == TEXT2)		//text2
	{
		switch(nMode)
		{
			case	WALLPAPER:
				P_Tx2_Control_B -> B.Wap		= nEnable;
			break;
			case	HOFFSET:
				P_Tx2_Control_B -> B.Mve 		= nEnable;
			break;
			case	BLEND:
				P_Tx2_Control_B -> B.Bld 		= nEnable;
			break;
			case	FLIP:
				P_Tx2_Attribute_B -> B.Flip 	= nEnable;
			break;							
		}
	}
	if(nText == TEXT3)		//text3
	{
		switch(nMode)
		{
			case	WALLPAPER:
				P_Tx3_Control_B -> B.Wap		= nEnable;
			break;
			case	HOFFSET:
				P_Tx3_Control_B -> B.Mve 		= nEnable;
			break;
			case	BLEND:
				P_Tx3_Control_B -> B.Bld 		= nEnable;
			break;
			case	FLIP:
				P_Tx3_Attribute_B -> B.Flip 	= nEnable;
			break;							
		}
	}
};

//====================================================================================================
//	Description:	Set text blend mode 
//	Function:		SetTxBlendMode()
//	Syntax:			void	SetTxBlendMode(int nText, int mode);
//	Input Paramter:	int nText: 	Text selection (0~2)
//								0:TEXT1		
//								1:TEXT2		
// 								2:TEXT3
//					int	mode:	Mode selection (0~1) 
//								0:4-level blending mode
//								1:64-level blending mode
//	Return: 		none
//====================================================================================================
void	SetTxBlendMode(int nText, int mode)
{
	if (nText == TEXT1)
		P_Tx1_Control_B->B.Bldm = mode;
	else if (nText == TEXT2)
		P_Tx2_Control_B->B.Bldm = mode;
	else
		P_Tx3_Control_B->B.Bldm = mode;
};

//====================================================================================================
//	Description:	Set 4-level blending level 
//	Function:		SetBlendLevel4()
//	Syntax:			void	SetBlendLevel4(int nBlendLevel);
//	Input Paramter:	int	nBlendLevel: Blending level (0~3)
//	Return: 		none
//====================================================================================================
void	SetBlendLevel4(int nBlendLevel)
{
	*P_Blending = nBlendLevel;
};

//====================================================================================================
//	Description:	Set text 64-level blending level 
//	Function:		SetTxBlendLevel64()
//	Syntax:			void	SetTxBlendLevel64(int nText, int nBlendLevel);
//	Input Paramter:	int nText: 	Text selection (0~2)
//								0:TEXT1		
//								1:TEXT2		
// 								2:TEXT3
//					int	nBlendLevel: Blending level (0~63)	
//	Return: 		none
//====================================================================================================
void	SetTxBlendLevel64(int nText, int nBlendLevel)
{
	if(nText == TEXT1)			//text1
		P_Tx1_Control_B -> B.BldLev = nBlendLevel;	
	else if(nText == TEXT2)		//text2
		P_Tx2_Control_B -> B.BldLev = nBlendLevel;	
	else
		P_Tx3_Control_B -> B.BldLev = nBlendLevel;			
};

//====================================================================================================
//	Description:	Set Horizontal compression value
//	Function:		HCompressEffect()
//	Syntax:			void	HCompressEffect(int nMode,int nCompValue,U32 ptrCmpTable);
//	Input Paramter:	int	nMode: Mode selection (0~1)
//							   0:LINES_SAME
//							   1:LINES_DIFFERENT		
//					int nCompValue:	Horizontal compression value (1~128)
//					U32 ptrCmpTable: Horizontal compression value table address
//	Return: 		none
//	Notes:			If compress every line with the same value, just write value to nCompValue.
//					If compress every line with the different value, you need to set up one value table.
//					Horizontal compression effect is available only for Text1.
//====================================================================================================
void	HCompressEffect(int nMode, int nCompValue, U32 ptrCmpTable)
{
	LineMode = nMode;
	HCmpValue = nCompValue;
	ptrHCmpTable = ptrCmpTable;
	HCmpFlag = 1;
};

//====================================================================================================
//	Description:	Set vertical compression value
//	Function:		VCompressEffect()
//	Syntax:			void	VCompressEffect(int nCompValue,int nCompStep,int nCompOffset);
//	Input Paramter:	int nCompValue:   	vertical compression value
//					int nCompStep: 		vertical compression step value
//					int nCompOffset:	vertical compression offset value
//	Return: 		none
//====================================================================================================
void	VCompressEffect(int nCompValue,int nCompStep,int nCompOffset)
{
	VCmpValue = nCompValue;
	VCmpOffset = nCompOffset;
	VCmpStep = nCompStep;
	VCmpFlag = 1;
};

//====================================================================================================
//	Description:	Set horizontal movement value
//	Function:		HOffsetEffect()
//	Syntax:			void	HOffsetEffect(int nMode, int nMoveValue, U32 ptrMoveTable);
//	Input Paramter:	int	nMode: Mode selection (0~1)
//							   0:LINES_SAME
//							   1:LINES_DIFFERENT
//					int nMoveValue:	Horizontal movement value
//					U32 ptrMoveTable: Horizontal movement value table
//	Return: 		none
//	Notes:			If move every line with the same value,just write value to nMoveValue.
//					If move every line with the different value, you need to set up a value table.
//====================================================================================================
void	HOffsetEffect(int nMode, int nMoveValue, U32 ptrMoveTable)
{
//	if(nMode == LINES_SAME) 
//	{
//		MyMemSet((U32)HoffsetBuff, nMoveValue, 240);
//		HoffsetFlag = 1;
//	}		
//	else 
//	{
//		HorizontalMovement(0, 239, ptrMoveTable);
//	}	
};

//====================================================================================================
//	Description:	Horizontal movement effect 
//	Function:		Sea_Hoffset()
//	Syntax:			void	Sea_Hoffset(void);
//	Input Paramter:	none
//	Return: 		none
//	NOTES:			Horizontal movement as sea
//====================================================================================================
void	Sea_Hoffset(void)
{
	if(iHoffsetCount > 239)
		iHoffsetCount = 0;
	else
		iHoffsetCount++;						
	if(P_PPU_Enable_B -> B.VGAen == VGA_DISABLE) //QVGA
	{
		HorizontalMovement(0,239-iHoffsetCount,(U32)C_SeaHoffset+iHoffsetCount);
		HorizontalMovement(239-iHoffsetCount+1,239,(U32)C_SeaHoffset);
	}
	else
	{
		HorizontalMovement(0,239-iHoffsetCount,(U32)C_SeaHoffset_VGA+iHoffsetCount);
		HorizontalMovement(239-iHoffsetCount+1,239,(U32)C_SeaHoffset_VGA);
	}		
};

//====================================================================================================
//	Description:	Text TextAttribInRAM_Initial Effect
//	Function:		TextAttribInRAM_Initial()
//	Syntax:			int	TextAttribInRAM_Initial(int nText, int nBld, int nFlip, int nPalette, int *ptAttSrc)
//	Input Paramter:	int nText: Text selection (0~2)
//							   0:TEXT1			
//							   1:TEXT2
//							   2:TEXT3		
//					int nBld:  Blending mode
//							   0:Text_BlendDisable
//							   1:Text_BlendEnable	
//					int nFlip: Flip mode (0~3)
//									0:No Flip
//							   		1:H-Flip
//									2:V-Flip
//									3:HV-Flip
//					int nPalette: 4-bit palette selection (0~15)
//					int *ptAttSrc: attribute array pointer
//	Return: 		0:	Initial OK
//				   -1:  Initial Fail
//  Note:			Bitmap-mode text can't use this function.
//====================================================================================================
int TextAttribInRAM_Initial(int nText, int nBld, int nFlip, int nPalette, int *ptAttSrc)
{
	int *ptAtt;
	int attrib_length;
	U16 attrib_value = 0;

	if ( nText == TEXT1 )
	{
		P_Tx1_Control_B->B.Rgm 	 		= 	Text_AttInArray;
		ptAtt = Text1AttrTable;		
		attrib_length = text1_index_length >> 1;
	}
	//=================================================================
	else if ( nText == TEXT2 )
	{
		P_Tx2_Control_B->B.Rgm 	 		= 	Text_AttInArray;
		ptAtt = Text2AttrTable;		
		attrib_length = text2_index_length >> 1;
	}
	//=================================================================
	else
	{
		P_Tx3_Control_B->B.Rgm 	 		= 	Text_AttInArray;
		ptAtt = Text3AttrTable;		
		attrib_length = text3_index_length >> 1;
	}
	//=================================================================
	
	attrib_value |= (nBld << 6) & 0x40;
	attrib_value |= (nFlip << 4) & 0x30;
	attrib_value |= (nPalette) & 0xF;
	attrib_value |= attrib_value << 8;
	
	if (ptAtt == ptAttSrc)
	{
		MyMemSet((U32)ptAtt, attrib_value, attrib_length);
	}
	else
	{
		MyMemSet((U32)ptAttSrc, attrib_value, attrib_length);
		SetDMACopy0((U32)ptAttSrc, (U32)ptAtt, attrib_length);
	}
		
	return 0;
}

//====================================================================================================
//	Description:	Text Flip Effect
//	Function:		FlipEffect()
//	Syntax:			void	FlipEffect(int nText,int nFlipMode,int nSizeX,int nSizeY, int *FlipBuffer)
//	Input Paramter:	int nText: Text selection (0~2)
//							   0:TEXT1			
//							   1:TEXT2
//							   2:TEXT3		
//					int nFlipMode: Flip mode (0~3)
//									0:No Flip
//							   		1:H-Flip
//									2:V-Flip
//									3:HV-Flip
//					int nSizeX:	Real text size x
//					int nSizeY:	Real text size y
//	Return: 		none
//  Note:			Bitmap-mode text can't use this function.
//====================================================================================================
void	FlipEffect(int nText,int nFlipMode,int nSizeX,int nSizeY, int *FlipBuffer)
{
	int ix,iy;
	int NumX,NumY,NumX_Text,NumY_Text;
	int TextSize, nTextX, nTextY;
	int *ptIdx;
	int iCellX,iCellY;
	int index_length;
		
	switch(nText)
	{
		case TEXT1:
			TextSize = P_Tx1_Attribute_B->B.Size;
			P_Tx1_Attribute_B->B.Flip =	nFlipMode;
			iCellX = P_Tx1_Attribute_B->B.Hs;
			iCellY = P_Tx1_Attribute_B->B.Vs;
			ptIdx = Text1IndexTable;
			index_length = text1_index_length;
			break;
		case TEXT2:
			TextSize = P_Tx2_Attribute_B->B.Size;
			P_Tx2_Attribute_B->B.Flip =	nFlipMode;
			iCellX = P_Tx2_Attribute_B->B.Hs;
			iCellY = P_Tx2_Attribute_B->B.Vs;
			ptIdx = Text2IndexTable;
			index_length = text2_index_length;
			break;
	    case TEXT3:
			TextSize = P_Tx3_Attribute_B->B.Size;
			P_Tx3_Attribute_B->B.Flip =	nFlipMode;
			iCellX = P_Tx3_Attribute_B->B.Hs;
			iCellY = P_Tx3_Attribute_B->B.Vs; 
			ptIdx = Text3IndexTable;
			index_length = text3_index_length;
			break; 
	}  			 
	
	switch(TextSize)
	{
		case 0:
			nTextX = 512;
			nTextY = 256;
			break;
		case 1:	
			nTextX = 512;
			nTextY = 512;
			break;
		case 2:
			nTextX = 1024;
			nTextY = 512;
			break;
		case 3:
			nTextX = 1024;
			nTextY = 1024;
			break;		
	}	 
	
	NumX_Text = nTextX >> SHFBIT[iCellX]; //number of horizontal chcaracter in number array
	NumY_Text = nTextY >> SHFBIT[iCellY]; //number of vertical chcaracter in number array
	NumX = nSizeX >> SHFBIT[iCellX]; //number of horizontal chcaracter in real text
	NumY = nSizeY >> SHFBIT[iCellY]; //number of vertical chcaracter in real text	
	
	if (nFlipMode & 1) //Horizontal flip
	{ 
		//change text index memory and save the data to aTextIndex[]
		for(iy=0; iy<NumY_Text; iy++)				
		{
			for(ix=0; ix<NumX; ix++)							
			{
				FlipBuffer[ix + iy*NumX_Text] = *(ptIdx + (iy + 1)*NumX_Text - 1 - (NumX_Text - NumX) - ix);
			}
		}
		//update text index memory from aTextIndex[]
		SetDMACopy0((U32)FlipBuffer, (U32)ptIdx, index_length);
	}
	
	if (nFlipMode & 2) //Vertical flip
	{ 
		//change text index memory and save the data to aTextIndex[]
		for(iy=0; iy<NumY_Text; iy++)
		{
			for(ix=0; ix<NumX; ix++)
			{			
				FlipBuffer[ix + (NumY_Text-iy-1)*NumX_Text] = *(ptIdx + ix + iy*NumX_Text);
			}
		}
		//update text index memory from aTextIndex[]
		SetDMACopy0((U32)FlipBuffer, (U32)ptIdx, index_length);
	}	
};

//====================================================================================================
//	Description:	Initial character-mode text
//	Function:		InitCharacter()
//	Syntax:			void	InitCharacter(int nText, U32 IdxTab, U32 AttrTab, int nCellX, int nCellY, int nSizeX, int nSizeY, int nTextSize, int nColorMode, int nDepth, int nPalette);
//	Input Paramter:	int nText: Text selection (0~2)
//							   0:TEXT1			
//							   1:TEXT2
//							   2:TEXT3
//					U32 IdxTab: Character index data address
//					U32 AttrTab: Attribute data address
//					int nCellX: Horizontal character size (8/16/32/64)
//					int nCellY:	Vertical character size (8/16/32/64)
//					int nSizeX:	Real text size x
//					int nSizeY:	Real text size y
//					int nTextSize: The size of text layer (0~3)
//								   0:512x256
//								   1:512x512
//								   2:1024x512
//								   3:1024x1024
//					int nColorMode:	Color mode (0~5)
//									0:4 color		
//									1:16 color		
//									2:64 color		
//									3:256 color
//									4:32768 color
//									5:65536 color				
//					int nDepth: Depth layer (0~3)		
//								0:Text Depth 0
//								1:Text Depth 2
//								2:Text Depth 4
//							    3:Text Depth 6
//					int nPalette: 4-bit palette selection (0~15)
//	Return: 		none
//====================================================================================================
void	InitCharacter(int nText,U32 IdxTab,U32 AttrTab,int nCellX,int nCellY,int nSizeX,int nSizeY,int nTextSize,int nColorMode,int nDepth,int nPalette)
{
	int i;
	int nTextX, nTextY;
	int NumX, NumY;
	int	xsize,ysize;
	int *ptIdx, *ptAtt;
	int iCellX,iCellY;
	int rgb, color;
	
	switch(nCellX)
	{
		case	H_SIZE8:
			iCellX = 0;
			break;
		case	H_SIZE16:
			iCellX = 1;
			break;
		case	H_SIZE32:
			iCellX = 2;
			break;
		case	H_SIZE64:
			iCellX = 3;
			break;
	}
	switch(nCellY)
	{
		case	V_SIZE8:
			iCellY = 0;
			break;
		case	V_SIZE16:
			iCellY = 1;
			break;
		case	V_SIZE32:
			iCellY = 2;
			break;
		case	V_SIZE64:
			iCellY = 3;
			break;
	}
	
	switch(nTextSize)
	{
		case	0:
			nTextX = 512;
			nTextY = 256;
			break;
		case	1:
			nTextX = 512;
			nTextY = 512;
			break;
		case	2:
			nTextX = 1024;
			nTextY = 512;
			break;	
		case	3:
			nTextX = 1024;
			nTextY = 1024;
			break;	
	}			

	if (nColorMode < 4)	//4,16,64,256 colors
	{
		color = nColorMode;
		rgb = Text_RGBDisable;
	}
	else //32768,65536 colors
	{	
		color = nColorMode - 4;
		rgb = Text_RGBEnable;
	}		  	
			
	//-----------------------------------------------------------------
	NumX 		= nSizeX >> SHFBIT[iCellX];	//number of horizontal character in real text
	NumY 		= nSizeY >> SHFBIT[iCellY];	//number of vertical character in real text
	xsize 		= nTextX >> SHFBIT[iCellX];	//number of horizontal character in number array					 
	ysize 		= nTextY >> SHFBIT[iCellY];	//number of vertical character in number array
	//-----------------------------------------------------------------
//	*P_IOB_Mux = 0x00;
//	*P_IOB_Dir = 0x00ff;
//	*P_IOB_Attrib = 0x00ff;
//	*P_IOB_Buffer = 0x00;
//	while(1)
//	{
//	*P_IOB_Buffer += 0x0001;
//	cmd_delay(1);
//	}	
	
	if ( nText == TEXT1 )
	{
		P_Tx1_Attribute_B->B.Color 		= 	color;
		P_Tx1_Attribute_B->B.Hs 		= 	iCellX;
		P_Tx1_Attribute_B->B.Vs 		= 	iCellY;
		P_Tx1_Attribute_B->B.Palette 	= 	nPalette;
		P_Tx1_Attribute_B->B.Depth 		= 	nDepth;
		P_Tx1_Attribute_B->B.Size 		= 	nTextSize;
		P_Tx1_Control_B->W 		   	   &= 	0x08;
		P_Tx1_Control_B->B.Linr 	 	= 	Text_CharMode;
		P_Tx1_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
		P_Tx1_Control_B->B.RGB			= 	rgb;
		P_Tx1_N_Ptr_B->W 			 	= 	(U16)&Text1IndexTable;
		P_Tx1_A_Ptr_B->W 				= 	(U16)&Text1AttrTable;
		//------------------------------------------------------------
		ptIdx = Text1IndexTable;
		ptAtt = Text1AttrTable;		
	}
	//=================================================================
	else if ( nText == TEXT2 )
	{
		P_Tx2_Attribute_B->B.Color 		= 	color;
		P_Tx2_Attribute_B->B.Hs 		= 	iCellX;
		P_Tx2_Attribute_B->B.Vs 		= 	iCellY;
		P_Tx2_Attribute_B->B.Palette 	= 	nPalette;
		P_Tx2_Attribute_B->B.Depth 		= 	nDepth;
		P_Tx2_Attribute_B->B.Size 		= 	nTextSize;
		P_Tx2_Control_B->W 		   	   &= 	0x08;
		P_Tx2_Control_B->B.Linr 	 	= 	Text_CharMode;
		P_Tx2_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
		P_Tx2_Control_B->B.RGB			= 	rgb;
		P_Tx2_N_Ptr_B->W 				= 	(U16)&Text2IndexTable;
		P_Tx2_A_Ptr_B->W 				= 	(U16)&Text2AttrTable;
		//------------------------------------------------------------
		ptIdx = Text2IndexTable;
		ptAtt = Text2AttrTable;		
	}
	//=================================================================
	else
	{
		P_Tx3_Attribute_B->B.Color 		= 	color;
		P_Tx3_Attribute_B->B.Hs 		= 	iCellX;
		P_Tx3_Attribute_B->B.Vs 		= 	iCellY;
		P_Tx3_Attribute_B->B.Palette 	= 	nPalette;
		P_Tx3_Attribute_B->B.Depth 		= 	nDepth;
		P_Tx3_Attribute_B->B.Size 		= 	nTextSize;
		P_Tx3_Control_B->W 		   	   &= 	0x08;
		P_Tx3_Control_B->B.Linr 	 	= 	Text_CharMode;
		P_Tx3_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
		P_Tx3_Control_B->B.RGB			= 	rgb;
		P_Tx3_N_Ptr_B->W 				= 	(U16)&Text3IndexTable;
		P_Tx3_A_Ptr_B->W 				= 	(U16)&Text3AttrTable;
		//------------------------------------------------------------
		ptIdx = Text3IndexTable;
		ptAtt = Text3AttrTable;		
	}
	//=================================================================
	
	//=================================================================
	for(i=0; i<ysize; i++) 	//Update number array
		SetDMACopy0(IdxTab+NumX*i, (U32)(ptIdx+xsize*i), xsize);	
	if((P_PPU_Enable_B -> B.TxDirect == 1)||(nColorMode >= 4)) {
		for(i=0; i<ysize; i++) //Update attribute array
			SetDMACopy0(AttrTab+(NumX>>1)*i, (U32)(ptAtt+(xsize>>1)*i), xsize>>1);			
	}					
};

//====================================================================================================
//	Description:	Show character-mode text
//	Function:		fnShow_Chr()
//	Syntax:			void	fnShow_Chr(int nText,U32 IdxTab,U32 AttrTab,U32 CharData,int nCellX,int nCellY,int nSizeX,int nSizeY,int nTextSize,int nColor,int nDepth,int nPalette,int nPalBank);
//	Input Paramter:	int nText: Text selection (0~2)
//							   0:TEXT1			
//							   1:TEXT2
//							   2:TEXT3
//					U32 IdxTab: Character index data address
//					U32 AttrTab: Attribute data address
//					U32 CharData: Character data address
//					int nCellX: Horizontal character size (8/16/32/64)
//					int nCellY:	Vertical character size (8/16/32/64)
//					int nSizeX:	Real text size x
//					int nSizeY:	Real text size y
//					int nTextSize: The size of text layer (0~3)
//								   0:512x256
//								   1:512x512
//								   2:1024x512
//								   3:1024x1024
//					int nColor:	Color mode (0~5)
//								0:4 color		
//								1:16 color		
//								2:64 color		
//								3:256 color
//								4:32768 color
//								5:65536 color		
//					int nDepth: Depth layer (0~3)		
//								0:Text Depth 0
//								1:Text Depth 2
//								2:Text Depth 4
//							    3:Text Depth 6
//					int nPalette: 4-bit palette selection (0~15)
//					int nPalBank: Text palette RAM bank (0~1) 
//	Return: 		none
//====================================================================================================
void	fnShow_Chr(int nText,U32 IdxTab,U32 AttrTab,U32 CharData,int nCellX,int nCellY,int nSizeX,int nSizeY,int nTextSize,int nColor,int nDepth,int nPalette,int nPalBank)
{
	U16 i,j;
	
	if(nText == TEXT1)
		P_Tx1_Control_B->B.Txe= 0;
	else if(nText == TEXT2)
		P_Tx2_Control_B->B.Txe= 0;
	else if(nText == TEXT3)
		P_Tx3_Control_B->B.Txe= 0;
	else
		P_Tx4_Control_B->B.Txe= 0;
		
	InitCharacter(nText,IdxTab,AttrTab,nCellX,nCellY,nSizeX,nSizeY,nTextSize,nColor,nDepth,nPalette);
	
	if (P_PPU_Enable_B -> B.Free == 0) {
		i = nPalBank<<15;
		j = (CharData&0x003fffc0)>>6;
	}
	else {
		i = (CharData>>16) | (nPalBank<<15);
		j = CharData&0xffff;
	}
		
	if(nText == TEXT1)
	{
		text1_x = 0;
		text1_y = 0;
		Scrolling_H1 = 0;
		Scrolling_V1 = 0;
		*P_Segment_Tx1H = i;
		*P_Segment_Tx1 = j;
		*P_Tx1_X_Position = 0;
		*P_Tx1_Y_Position = 0;
		P_Tx1_Control_B->B.Txe= 1;
	}
	else if(nText == TEXT2)
	{
		text2_x = 0;
		text2_y = 0;
		Scrolling_H2 = 0;
		Scrolling_V2 = 0;
		*P_Segment_Tx2H = i;
		*P_Segment_Tx2 = j; 
		*P_Tx2_X_Position = 0;
		*P_Tx2_Y_Position = 0;
		P_Tx2_Control_B->B.Txe= 1;
	}
	else
	{
		text3_x = 0;
		text3_y = 0;
		Scrolling_H3 = 0;
		Scrolling_V3 = 0;
		*P_Segment_Tx3H = i;
		*P_Segment_Tx3 = j; 
		*P_Tx3_X_Position = 0;
		*P_Tx3_Y_Position = 0;
		P_Tx3_Control_B->B.Txe= 1;
	}
};

//====================================================================================================
//	Description:	Initial bitmap-mode text
//	Function:		InitBitmap()
//	Syntax:			void	InitBitmap(int nText,U32 bmpdata,int nSizeX,int nSizeY,int nTextSize,int nColorMode,int nDepth,int nPalette);
//	Input Paramter:	int nText: Text selection (0~2)
//							   0:TEXT1			
//							   1:TEXT2
//							   2:TEXT3
//					U32 bmpdata: bitmap data address
//					int nSizeX:	Real text size x
//					int nSizeY:	Real text size y
//					int nTextSize: The size of text layer (0~3)
//								   0:512x256
//								   1:512x512
//								   2:1024x512
//								   3:1024x1024
//					int nColorMode:	Color mode (0~5)
//									0:4 color		
//									1:16 color		
//									2:64 color		
//									3:256 color
//									4:32768 color
//									5:65536 color		
//					int nDepth: Depth layer (0~3)		
//								0:Text Depth 0
//								1:Text Depth 2
//								2:Text Depth 4
//							    3:Text Depth 6
//					int nPalette: 4-bit palette selection (0~15)
//	Return: 		none
//	Note:			The bitmap special mode is applied only when horizontal size is 320/640/512/1024.
//					The bitmap special mode means that PPU hardware computes start address of each line automatically. 		
//====================================================================================================
void	InitBitmap(int nText,U32 bmpdata,int nSizeX,int nSizeY,int nTextSize,int nColorMode,int nDepth,int nPalette)
{
	int i, iBitColor, sizeY;
	int *ptAttr,*ptIdx;
	int special = 0; //bitmap special mode
	U16 Bank;
	U32 Addr32;
	
	if (nSizeX == 320)
	{	
		sizeY = 0;
		special = 1;
	}	
	if (nSizeX == 640)
	{	
		sizeY = 1;
		special = 1;
	}	
	if (nSizeX == 512)
	{	
		sizeY = 2;
		special = 1;
	}	
	if (nSizeX == 1024)
	{	
		sizeY = 3;
		special = 1;
	}	
				
	if ( nText == TEXT1 )					//text1
	{
		if(nColorMode == COLOR32768)		//32768 color
		{
			P_Tx1_Attribute_B->B.Color 		= 	0;
			P_Tx1_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx1_Control_B->W 		   	   &= 	0x08;
			P_Tx1_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx1_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx1_Control_B->B.RGB			= 	Text_RGBEnable;
		}
		else if(nColorMode == COLOR65536)	//65536 color
		{
			P_Tx1_Attribute_B->B.Color 		= 	1;
			P_Tx1_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx1_Control_B->W 		   	   &= 	0x08;
			P_Tx1_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx1_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx1_Control_B->B.RGB			= 	Text_RGBEnable;
		}
		else	//4 or 16 or 64 or 256 color
		{		
			P_Tx1_Attribute_B->B.Color 		= 	nColorMode;
			P_Tx1_Attribute_B->B.Palette 	= 	nPalette;
			P_Tx1_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx1_Control_B->W 		  	   &= 	0x08;
			P_Tx1_Control_B->B.Linr 	 	= 	Text_LinerMode;
			P_Tx1_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx1_Control_B->B.RGB			= 	Text_RGBDisable;
		}
		P_Tx1_N_Ptr_B->W = (U16)&Text1IndexTable;
		P_Tx1_A_Ptr_B->W = (U16)&Text1AttrTable;
		ptAttr = Text1AttrTable;
		ptIdx = Text1IndexTable;
		if (special == 1) {
			P_Tx1_Attribute_B->B.Vs = sizeY;
			P_Tx1_Attribute_B->B.Hs = 3;		
		}					
	}
	//-----------------------------------------------------------------
	if ( nText == TEXT2 )					//text2
	{
		if(nColorMode == COLOR32768)		//32768 color
		{
			P_Tx2_Attribute_B->B.Color 		=	0;
			P_Tx2_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx2_Control_B->W 		   	   &= 	0x08;
			P_Tx2_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx2_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx2_Control_B->B.RGB			= 	Text_RGBEnable;			
		}
		else if(nColorMode == COLOR65536)	//65536 color
		{
			P_Tx2_Attribute_B->B.Color 		=	1;
			P_Tx2_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx2_Control_B->W 		   	   &= 	0x08;
			P_Tx2_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx2_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx2_Control_B->B.RGB			= 	Text_RGBEnable;			
		}
		else	//4 or 16 or 64 or 256 color
		{	
			P_Tx2_Attribute_B->B.Color 		= 	nColorMode;
			P_Tx2_Attribute_B->B.Palette 	= 	nPalette;
			P_Tx2_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx2_Control_B->W 		  	    &= 	0x08;
			P_Tx2_Control_B->B.Linr 	 	= 	Text_LinerMode;
			P_Tx2_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx2_Control_B->B.RGB			= 	Text_RGBDisable;
		}
		P_Tx2_N_Ptr_B->W = (U16)&Text2IndexTable;
		P_Tx2_A_Ptr_B->W = (U16)&Text2AttrTable;
		ptAttr = Text2AttrTable;
		ptIdx = Text2IndexTable;
		if (special == 1) {
			P_Tx2_Attribute_B->B.Vs = sizeY;
			P_Tx2_Attribute_B->B.Hs = 3;		
		}							
	}
	//-----------------------------------------------------------------
	if ( nText == TEXT3 )					//text3
	{
		if(nColorMode == COLOR32768)		//32768 color
		{
			P_Tx3_Attribute_B->B.Color 		= 	0;
			P_Tx3_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx3_Control_B->W 		  	   &= 	0x08;
			P_Tx3_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx3_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx3_Control_B->B.RGB			= 	Text_RGBEnable;
		}
		else if(nColorMode == COLOR65536)	//65536 color
		{
			P_Tx3_Attribute_B->B.Color 		= 	1;
			P_Tx3_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx3_Control_B->W 		  	   &= 	0x08;
			P_Tx3_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx3_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx3_Control_B->B.RGB			= 	Text_RGBEnable;
		}
		else	//4 or 16 or 64 or 256 color
		{	
			P_Tx3_Attribute_B->B.Color 		= 	nColorMode;
			P_Tx3_Attribute_B->B.Palette 	= 	nPalette;
			P_Tx3_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx3_Control_B->W 		   	   &= 	0x08;
			P_Tx3_Control_B->B.Linr 	 	= 	Text_LinerMode;
			P_Tx3_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx3_Control_B->B.RGB			= 	Text_RGBDisable;
		}
		P_Tx3_N_Ptr_B->W = (U16)&Text3IndexTable;
		P_Tx3_A_Ptr_B->W = (U16)&Text3AttrTable;
		ptAttr = Text3AttrTable;
		ptIdx = Text3IndexTable;
		if (special == 1) {
			P_Tx3_Attribute_B->B.Vs = sizeY;
			P_Tx3_Attribute_B->B.Hs = 3;	
		}							
	}
	//-----------------------------------------------------------------

	if (special == 0)
	{
		switch(nColorMode)
		{
			case	COLOR4:
				iBitColor = 2;
				break;
			case	COLOR16:
				iBitColor = 4;
				break;
			case	COLOR64:
				iBitColor = 6;
				break;
			case	COLOR256:
				iBitColor = 8;
				break;
			case	COLOR32768:
				iBitColor = 16;
				break;
			case	COLOR65536:
				iBitColor = 16;
				break;
		}
		
		switch(nTextSize)
		{
			case	0:	//512x256
				sizeY = 256;
				break;
			case	1:	//512x512
				sizeY = 512;
				break;
			case	2:	//1024x512
				sizeY = 512;
				break;
			case	3:	//1024x1024
				sizeY = 1024;
				break;
		}						
		
		if(nSizeY < sizeY)
			sizeY = nSizeY; 				
							
		if (P_PPU_Enable_B -> B.Free)
			bmpdata = 0;
				
		for(i=0;i<sizeY;i++)
		{
			Addr32 = bmpdata;
			Addr32 += ((unsigned long)i*(unsigned long)nSizeX*(unsigned long)iBitColor)>>4;
			*ptIdx = Addr32&0xffff;							// put offset value
			Bank = (Addr32>>16)&0x00ff;
			if(!(i%2))										// put segment value in low byte for even point
			{
				*ptAttr = Bank;
			}
			else											// put segment value in high byte for odd point
			{
				*ptAttr += (Bank<<8);
				ptAttr++; 
			}
			ptIdx++;
		} 
	}	
};

//====================================================================================================
//	Description:	Show bitmap-mode text
//	Function:		fnShow_Bmp()
//	Syntax:			void	fnShow_Bmp(int nText, U32 bmpdata, int nSizeX, int nSizeY, int nTextSize, int nColorMode, int nDepth, int nPalette, int nAuto, int nPalBank);
//	Input Paramter:	int nText: Text selection (0~2)
//							   0:TEXT1			
//							   1:TEXT2
//							   2:TEXT3
//					U32 bmpdata: bitmap data address
//					int nSizeX:	Real text size x
//					int nSizeY:	Real text size y
//					int nTextSize: The size of text layer (0~3)
//								   0:512x256
//								   1:512x512
//								   2:1024x512
//								   3:1024x1024
//					int nColorMode:	Color mode (0~5)
//									0:4 color		
//									1:16 color		
//									2:64 color		
//									3:256 color		
//									4:32768 color
//									5:65536 color		
//					int nDepth: Depth layer (0~3)		
//								0:Text Depth 0
//								1:Text Depth 2
//								2:Text Depth 4
//							    3:Text Depth 6
//					int nPalette: 4-bit palette selection (0~15)
//					int nPalBank: Text palette RAM bank (0~1) 
//	Return: 		none
//	Note:			The bitmap special mode is applied automatically only when horizontal size is 320/640/512/1024.
//					The bitmap special mode means that PPU hardware computes start address of each line automatically. 		
//====================================================================================================
void	fnShow_Bmp(int nText,U32 bmpdata,int nSizeX,int nSizeY,int nTextSize,int nColorMode,int nDepth,int nPalette,int nPalBank)
{
	U32 Addr32;
	
	Addr32 = bmpdata;
	if(nText == TEXT1)
		P_Tx1_Control_B->B.Txe = 0;
	else if(nText == TEXT2)
		P_Tx2_Control_B->B.Txe = 0;
	else
		P_Tx3_Control_B->B.Txe = 0;
				
	InitBitmap(nText,bmpdata,nSizeX,nSizeY,nTextSize,nColorMode,nDepth,nPalette);
	
	if(nText == TEXT1)
	{
		text1_x = 0;
		text1_y = 0;
		*P_Tx1_X_Position = 0;
		*P_Tx1_Y_Position = 0;
		*P_Segment_Tx1H = (Addr32>>16) | (nPalBank<<15);
		*P_Segment_Tx1 = Addr32&0xffff;
		P_Tx1_Attribute_B->B.Size = nTextSize;
		P_Tx1_Control_B->B.Txe = 1;
	}
	else if(nText == TEXT2)
	{
		text2_x = 0;
		text2_y = 0;
		*P_Tx2_X_Position = 0;
		*P_Tx2_Y_Position = 0;
		*P_Segment_Tx2H = (Addr32>>16) | (nPalBank<<15);
		*P_Segment_Tx2 = Addr32&0xffff;
		P_Tx2_Attribute_B->B.Size = nTextSize;
		P_Tx2_Control_B->B.Txe = 1;
	}
	else
	{
		text3_x = 0;
		text3_y = 0;
		*P_Tx3_X_Position = 0;
		*P_Tx3_Y_Position = 0;
		*P_Segment_Tx3H = (Addr32>>16) | (nPalBank<<15);
		*P_Segment_Tx3 = Addr32&0xffff;
		P_Tx3_Attribute_B->B.Size = nTextSize;
		P_Tx3_Control_B->B.Txe = 1;
	}
};

//====================================================================================================
//	Description:	Initial palette
//	Function:		PaletteInitial()
//	Syntax:			void	PaletteInitial(int nMode, int nPalette, U32 PaletteData);
//	Input Paramter:	int nMode: Mode selection (0~1)	
//							   0:PALETTE_RAM
//							   1:PALETTE_BUFF
//					int nPalette: Palette selection (0~3)
//								  0: Text Palette 0
//								  1: Sprite Palette 0
//								  2: Text Palette 1
//								  3: Sprite Palette 1	
//					U32 PaletteData: Palette data address
//	Return: 		none
//====================================================================================================
void	PaletteInitial(int nMode, int nPalette, U32 PaletteData)
{
	if(nMode == PALETTE_BUFF)
	{
		if (nPalette == 0)
		{					
			ptrTxPalette0 = PaletteData; 
			TxPaletteFlag0 = 1;
		}
		else if	(nPalette == 1) 
		{
			ptrSpPalette0 = PaletteData; 
			SpPaletteFlag0 = 1;
		}
		else if (nPalette == 2)
		{
			ptrTxPalette1 = PaletteData; 
			TxPaletteFlag1 = 1;
		}
		else
		{	
			ptrSpPalette1 = PaletteData; 
			SpPaletteFlag1 = 1;
		}		  			
	}
	//----------------------
	if(nMode == PALETTE_RAM)
	{	
		P_Palette_Control_B -> B.Bank = nPalette;
		SetDMACopy0(PaletteData, (U32)P_Palette_ADDR, 256);
		P_Palette_Control_B -> B.Bank = 0;		
	}		
};

//====================================================================================================
//	Description:	Scrolling text (character mode)
//	Function:		ScrollingEffect()
//	Syntax:			void	ScrollingEffect(int nText,U32 IdxTab,int nHValue,int nVValue,int nSizeX,int nSizeY);
//	Input Paramter:	int nText: Text selection (0~2)
//							   0:TEXT1			
//							   1:TEXT2
//							   2:TEXT3
//					U32 IdxTab: Character index table address
//					int nHValue: Horizontal movement value
//								 nHValue > 0 : scrolling left 
//								 nHValue < 0 : scrolling right
//					int nVValue: Vertical movement value
//								 nHValue > 0 : scrolling up 
//								 nHValue < 0 : scrolling down
//					int nSizeX:	Real text size x
//					int nSizeY: Real text size y
//	Return: 		none
//	Note:			Bitmap-mode text can't use this function. 
//====================================================================================================
void	ScrollingEffect(int nText,U32 IdxTab,int nHValue,int nVValue,unsigned int nSizeX,unsigned int nSizeY)
{
	int i,j,update;
	int NumX,NumY;
	int	xsize,ysize;
	int *ptIdx;
	int *ptX,*ptY;
	int TextSize;
	int Scrolling_H, Scrolling_V;
	int iCellX, iCellY;
	int nCellX, nCellY;
	
	if(nText == TEXT1)	
	{
		ptIdx = Text1IndexTable;
		ptX = (int*)P_Tx1_X_Position;
		ptY = (int*)P_Tx1_Y_Position;
		TextSize = P_Tx1_Attribute_B->B.Size;
		iCellX = P_Tx1_Attribute_B->B.Hs;
		iCellY = P_Tx1_Attribute_B->B.Vs;
		Scrolling_H = Scrolling_H1;
		Scrolling_V = Scrolling_V1;
	}
	if(nText == TEXT2)	
	{
		ptIdx = Text2IndexTable;
		ptX = (int*)P_Tx2_X_Position;
		ptY = (int*)P_Tx2_Y_Position;
		TextSize = P_Tx2_Attribute_B->B.Size;
		iCellX = P_Tx2_Attribute_B->B.Hs;
		iCellY = P_Tx2_Attribute_B->B.Vs;
		Scrolling_H = Scrolling_H2;
		Scrolling_V = Scrolling_V2;
	}
	if(nText == TEXT3)	
	{
		ptIdx = Text3IndexTable;
		ptX = (int*)P_Tx3_X_Position;
		ptY = (int*)P_Tx3_Y_Position;
		TextSize = P_Tx3_Attribute_B->B.Size;
		iCellX = P_Tx3_Attribute_B->B.Hs;
		iCellY = P_Tx3_Attribute_B->B.Vs;
		Scrolling_H = Scrolling_H3;
		Scrolling_V = Scrolling_V3;
	}
	
	//-----------------------------------------------------------------
	NumX = nSizeX >> SHFBIT[iCellX]; //Number of horizontal character in real text
	NumY = nSizeY >> SHFBIT[iCellY]; //Number of vertical character in real text 
	//-------------------------------
	
	if(TextSize == 0) 
	{
		xsize = 512 >> SHFBIT[iCellX];	//Number of horizontal character in number array						 
		ysize = 256 >> SHFBIT[iCellY];	//Number of vertical character in number array
	}			
	if(TextSize == 1) 
	{
		xsize = 512 >> SHFBIT[iCellX];	//Number of horizontal character in number array						 
		ysize = 512 >> SHFBIT[iCellY]; //Number of vertical character in number array	
	}	 
	if(TextSize == 2) 
	{
		xsize = 1024 >> SHFBIT[iCellX]; //Number of horizontal character in number array							 
		ysize = 512 >> SHFBIT[iCellY]; //Number of vertical character in number array	
	}
	if(TextSize == 3) 
	{
		xsize = 1024 >> SHFBIT[iCellX]; //Number of horizontal character in number array							 
		ysize = 1024 >> SHFBIT[iCellY]; //Number of vertical character in number array	
	}
	
	switch(iCellX)
	{
		case	0:
			nCellX = 8;
			break;
		case	1:
			nCellX = 16;
			break;
		case	2:
			nCellX = 32;
			break;
		case	3:
			nCellX = 64;
			break;
	}
	switch(iCellY)
	{
		case	0:
			nCellY = 8;
			break;
		case	1:
			nCellY = 16;
			break;
		case	2:
			nCellY = 32;
			break;
		case	3:
			nCellY = 64;
			break;
	}
	//-------------------------------
	update = 0;
	if (nHValue)
	{
		j = *ptX + nHValue;
		if (j >= nCellX) //left mov cell
		{	 
			Scrolling_H += j >> SHFBIT[iCellX];
			Scrolling_H %= NumX;
			update = 1;
			j %= nCellX;	 
		}
		*ptX = j;
		
		if (j < 0) //right mov cell
		{
			Scrolling_H -= (nCellX-j) >> SHFBIT[iCellX];
			Scrolling_H += NumX;
			Scrolling_H %= NumX; 				
			update = 1;
			*ptX = (nCellX+j)%nCellX;		
		}
	}			
				
	if (nVValue)
	{
		j = *ptY + nVValue;
		if (j >= nCellY) //up mov cell
		{	 
			Scrolling_V += j >> SHFBIT[iCellY];
			Scrolling_V %= NumY;
			update = 1;
			j %= nCellY;	 
		}
		*ptY = j;
		
		if (j < 0) //down mov cell
		{
			Scrolling_V -= (nCellY-j) >> SHFBIT[iCellY];
			Scrolling_V += NumY;
			Scrolling_V %= NumY; 				
			update = 1;
			*ptY = (nCellY+j)%nCellY;		
		}
	}			
	
	if (update)
	{	
		for(i=0; i<ysize; i++)				//update text index
		{
			if(Scrolling_H <= (NumX-xsize))
			{	 
				SetDMACopy0(IdxTab+Scrolling_H+NumX*((i+Scrolling_V)%NumY),(U32)(ptIdx + xsize*i),xsize);
			}
			else
			{
				SetDMACopy0(IdxTab+Scrolling_H+NumX*((i+Scrolling_V)%NumY),(U32)(ptIdx + xsize*i),NumX-Scrolling_H);
				SetDMACopy0(IdxTab+NumX*((i+Scrolling_V)%NumY),(U32)(ptIdx + xsize*i+(NumX-Scrolling_H)),xsize-(NumX-Scrolling_H));
			}	
		}
	}			
				
	if(nText == TEXT1)	
	{
		Scrolling_H1 = Scrolling_H;
		Scrolling_V1 = Scrolling_V;
	}
	if(nText == TEXT2)	
	{
		Scrolling_H2 = Scrolling_H;
		Scrolling_V2 = Scrolling_V;
	}
	if(nText == TEXT3)	
	{
		Scrolling_H3 = Scrolling_H;
		Scrolling_V3 = Scrolling_V;
	}		
};

//====================================================================================================
//	Description:	Set sprite control mode
//	Function:		SetSpriteCtrl()
//	Syntax:			void	SetSpriteCtrl(int spen, int coord, int round, int direct, int spnum);
//	Input Paramter:	int spen: Sprite layer enable (0~1)		
//							  0:Disable
//							  1:Enable
//					int coord: Sprite coordinate system (0~1) 
//							   0:Center Coordinate mode
//							   1:Left-top Coordinate mode
//					int round: Sprite round-robin mode enable (0~1)		
//							  0:Disable
//							  1:Enable
//					int direct: Sprite addressing mode (0~1)
//							  0:Related addressing mode
//							  1:Direct addressing mode
//					int spnum: Maximum available sprite number (1~256)		
//	Return: 		none
//====================================================================================================
void	SetSpriteCtrl(int spen, int coord, int round, int direct, int spnum)
{
	P_Sp_Control_B->B.Spen 		= spen;
	P_Sp_Control_B->B.Coor 		= coord;
	P_Sp_Control_B->B.Round		= round;
	P_Sp_Control_B->B.Dir 		= direct;
	if (spnum >= 256)
		P_Sp_Control_B->B.Spnum = 0;
	else
		P_Sp_Control_B->B.Spnum = spnum;	
};

//====================================================================================================
//	Description:	Set sprite effect
//	Function:		SetSpriteEffect()
//	Syntax:			void	SetSpriteEffect(int nMode, int nEnable);
//	Input Paramter:	int nMode: Sprite special effect selection (0~2)
//							   0:Mosaic effect
//							   1:Rotate effect
//							   2:Zoom effect
//					nEnable: Effect enable (0~1)
//							 0:Disable
//							 1:Enable
//	Return: 		none
//====================================================================================================
void	SetSpriteEffect(int nMode, int nEnable)
{
	switch(nMode)
	{
		case	SP_MOSAIC:
			P_Sp_Control_B->B.Mosen = nEnable;
			break;
		case	SP_ROTATE:
			P_Sp_Control_B->B.Roten	= nEnable;
			break;
		case	SP_ZOOM:
			P_Sp_Control_B->B.Zoomen = nEnable;
			break;
	}
};	

//====================================================================================================
//	Description:	Set sprite blend mode 
//	Function:		SetSpBlendMode()
//	Syntax:			void	SetSpBlendMode(int mode);
//	Input Paramter:	int	mode: Blending mode (0~1)
//							  0:4-level blending mode
//							  1:64-level blending mode
//	Return: 		none
//====================================================================================================
void	SetSpBlendMode(int mode)
{
	P_Sp_Control_B->B.Bldm 	= mode;
};

//====================================================================================================
//	Description:	Set palette type
//	Function:		SetPaletteType()
//	Syntax:			void	SetPaletteType(int type);
//	Input Paramter:	int type: Palette type (0~3)
//							  0:PALETTE16_SHARE (Text and Sprite share the same 16-bit palette)
//							  1:PALETTE16_SEPARATE (Text and Sprite have the different 16-bit palette)
//							  2:PALETTE24_SHARE (Text and Sprite share the same 25-bit palette)
//							  3:PALETTE24_SEPARATE (Text and Sprite have the different 25-bit palette)
//	Return: 		none
//====================================================================================================
void	SetPaletteType(int type)
{
	P_Palette_Control_B->B.Type = type;
};

//====================================================================================================
//	Description:	Set palette ram bank
//	Function:		SetPaletteRamBank()
//	Syntax:			void	SetPaletteRamBank(int bank);
//	Input Paramter:	int bank: Bank value (0~3)
//	Return: 		none
//====================================================================================================
void	SetPaletteRamBank(int bank)
{
	P_Palette_Control_B->B.Bank = bank;
};

//====================================================================================================
//	Description:	Set text layer working mode
//	Function:		SetTextMode()
//	Syntax:			void	SetTextMode(int nText, int mode);
//	Input Paramter:	int nText: Text selection (0~2)
//							   0:TEXT1
//							   1:TEXT2
//							   2:TEXT3
//					int mode: Woking mode (0~3)
//							  0: MODE_2D   			   (TEXT1/2/3/4)
//							  1: MODE_HCMP 			   (TEXT1)
//							  2: MODE_VCMP	   		   (TEXT1/TEXT2)
//							  3: MODE_HVCMP 		   (TEXT1)
//	Return: 		none
//====================================================================================================
void	SetTextMode(int nText, int mode)
{
	switch (nText)
	{
		case 0:
			Text1Mode = mode; 
			TextModeFlag = 1;
			break;
		case 1:
			Text2Mode = mode; 
			TextModeFlag = 1;
			break;
		case 2:
			Text3Mode = mode; 
			TextModeFlag = 1;
			break;
	}					
};

//====================================================================================================
//	Description:	Set Sprite Position
//	Function:		SetSpritePosition()
//	Syntax:			void	SetSpritePosition(int nSpIdx, int x, int y, int scroll);
//	Input Paramter:	int nSpIdx:	Sprite index (0~255)
//					int x: X position increasement
//					int y: Y position increasement
//					int scroll: Sprite scroll enable (0~1)
//								0:Disable
//								1:Enable (when the sprite exceeds screen boundary, it will appear in opposite direction.) 
//	Return: 		none
//  Note:			The original is on top-left conner of text screen.  
//====================================================================================================
void	SetSpritePosition(int nSpIdx, int x, int y, int scroll)
{
	int screen_width, screen_height;
	int xSize, ySize;
	int xmin, xmax, ymin, ymax;

	if( Sprite_Buff[nSpIdx].sprcell != 0 )	// check sprite exist/non-exist
	{
		if ((Sprite_Buff[nSpIdx].Idx & 0x8000) == 0)
		{
			Sprite_Buff[nSpIdx].x += x;
			Sprite_Buff[nSpIdx].y += y;
			if (scroll)
			{
					screen_width = QVGA_SCREENWIDTH;
					screen_height = QVGA_SCREENHEIGHT;
				xSize = Sprite_Buff[nSpIdx].xSize & 0x03ff;	// get x size
				ySize = Sprite_Buff[nSpIdx].ySize & 0x03ff;	// get y size
				xmin = 0 - xSize;
				xmax = screen_width + xSize;
				ymin = 0 - ySize;
				ymax = screen_height + ySize;		
				if (Sprite_Buff[nSpIdx].x > xmax)
					Sprite_Buff[nSpIdx].x = xmin;
				if (Sprite_Buff[nSpIdx].y > ymax)
					Sprite_Buff[nSpIdx].y = ymin;
				if (Sprite_Buff[nSpIdx].x < xmin)
					Sprite_Buff[nSpIdx].x = xmax;
				if (Sprite_Buff[nSpIdx].y < ymin)
					Sprite_Buff[nSpIdx].y = ymax;
			}
		}
	}			
};


//================================================================================
//	Description:	Sprite coordinate system conversion
//	Function:		SpCoordConvert()
//	Syntax:			void	SpCoordConvert(int nSpIdx, int *x, int *y);
//	Input Paramter:	nSpIdx: Sprite index (0~255)
//					*x: X position pointer
//					*y: Y position pointer
//	Return: 		none
//  Note:			Convert left-top coordinate to center coordinate.
//================================================================================	
void	SpCoordConvert(int nSpIdx, int *x, int *y)
{
	int xCell, yCell, cx, cy;	
	int screen_width, screen_height;

	if(P_Sp_Control_B->B.Coor == 0)										
	{	
			screen_width = QVGA_SCREENWIDTH;
			screen_height = QVGA_SCREENHEIGHT + 14;
		xCell = SPCell[(Sprite_Buff[nSpIdx].sprcell[10])>>4];	//get horizontal character size
		yCell = SPCell[(Sprite_Buff[nSpIdx].sprcell[9])>>6];	//get vertical character size
//		cx = *x - screen_width/2 + xCell/2 + 1;
//		cy = screen_height/2 - 1 - *y - yCell/2;
		cx = *x - screen_width/2 + 1;
		cy = screen_height/2 - 1 - *y;
		*x = cx & 0x03ff;
		*y = cy & 0x03ff;
	}
	else
	{
		*x = *x & 0x03ff;
		*y = *y & 0x03ff;
	}		
};	

//====================================================================================================
//	Description:	Initial sprite buffer and set sprite segment 
//	Function:		Init_Sprite()
//	Syntax:			void	Init_Sprite(U32 SpCharData);
//	Input Paramter:	U32 SpCharData: Sprite character data address
//	Return: 		none
//  Note:			After calling this function, please run "Paint_Sprite()" to show sprites.
//====================================================================================================
void	Init_Sprite(U32 SpCharData)
{
	int i, k, attribute;
		
	if (P_PPU_Enable_B -> B.Free == 0) {			
		*P_Segment_Sp = (SpCharData&0x003fffc0)>>6;
	}
	else {
		*P_Segment_SpH = SpCharData>>16;
		*P_Segment_Sp = SpCharData&0xffff;
	}	
			
	for(i=0; i<sp_number_max; i++)											// Process Sprite Attribute	
	{
		if( Sprite_Buff[i].sprcell != 0 )								// Check sprite exist/non-exist
		{									
			// Save Rotate Level / Y1[5:0]
			Sprite_Buff[i].xSize |= Sprite_Buff[i].sprcell[1];			
			
			// Save Zoom Level / Y2[5:0]
			Sprite_Buff[i].ySize |= Sprite_Buff[i].sprcell[3];			
			
			// Save Attribute 0
			attribute = 0;						
			for ( k=0; k<ATT_LENGTH; k++ )								
				attribute |= Sprite_Buff[i].sprcell[5+k];
			Sprite_Buff[i].att0 = attribute;	
			
			// Save Attribute 1
			attribute = 0;						
			attribute |= Sprite_Buff[i].sprcell[14];
			attribute |= Sprite_Buff[i].sprcell[15];	
			Sprite_Buff[i].att1 = attribute;
			// Save 2.5D flag
			if (P_PPU_Enable_B -> B.Sp25d)				
				Sprite_Buff[i].Idx |= 0x8000;
			else
				Sprite_Buff[i].Idx &= 0x7FFF;			
		}
	}				
};
//====================================================================================================
//	Description:	Update sprite buffer 
//	Function:		Update_Sprite()
//	Syntax:			void	Init_Sprite(int nSpIdx);
//	Input Paramter:	nSpIdx: Sprite index (0~255)
//	Return: 		none
//  Note:			After calling this function, please run "Paint_Sprite()" to show sprites.
//====================================================================================================
void Update_Sprite(int nSpIdx)
{
	int  k, attribute;
	if( Sprite_Buff[nSpIdx].sprcell != 0 )								// Check sprite exist/non-exist
	{									
		// Save Rotate Level / Y1[5:0]
		Sprite_Buff[nSpIdx].xSize |= Sprite_Buff[nSpIdx].sprcell[1];			
			
		// Save Zoom Level / Y2[5:0]
		Sprite_Buff[nSpIdx].ySize |= Sprite_Buff[nSpIdx].sprcell[3];			
			
		// Save Attribute 0
		attribute = 0;						
		for ( k=0; k<ATT_LENGTH; k++ )								
			attribute |= Sprite_Buff[nSpIdx].sprcell[5+k];
		Sprite_Buff[nSpIdx].att0 = attribute;	
			
		// Save Attribute 1
		attribute = 0;						
		attribute |= Sprite_Buff[nSpIdx].sprcell[14];
		attribute |= Sprite_Buff[nSpIdx].sprcell[15];	
		Sprite_Buff[nSpIdx].att1 = attribute;
		// Save 2.5D flag
		if (P_PPU_Enable_B -> B.Sp25d)				
			Sprite_Buff[nSpIdx].Idx |= 0x8000;
		else
			Sprite_Buff[nSpIdx].Idx &= 0x7FFF;			
	}
}

				   	
//====================================================================================================
//	Description:	Show sprites on screen
//	Function:		Paint_Sprite()
//	Syntax:			void	Paint_Sprite();
//	Input Paramter:	none
//	Return: 		none
//  Note:			Before calling this function, please run "Init_Sprite()" once.
//====================================================================================================
void	Paint_Sprite()
{
	int i, j, k, h, counter, counter2, id_carry;
	int cx, cy;
	int x, y, x1, y1, x2, y2, x3, y3;
	int screen_width, screen_height;
	int xtemp, ytemp;
	int xcell, ycell;
	
	if(spriteFlag == 0)
	{		
			screen_width = QVGA_SCREENWIDTH;
			screen_height = QVGA_SCREENHEIGHT + 14;
		
		MyMemSet((U32)SpriteBuf0, 0, (sp_number_max<<2));
		MyMemSet((U32)SpriteBuf1, 0, (sp_number_max<<2));
							
		counter = 0;
		counter2 = 0;
				
		for(i=0; i<sp_number_max; i++)	// Process Sprite Buffer Number	
		{
			if( Sprite_Buff[i].sprcell != 0 ) // Check sprite if exist?
			{	
				if (P_PPU_Enable_B -> B.Sp25d == 0)
					Sprite_Buff[i].Idx &= 0x7FFF;
				xcell = SPCell[(Sprite_Buff[i].sprcell[10])>>4]; // get x-cell size
				ycell = SPCell[(Sprite_Buff[i].sprcell[9])>>6];	 // get y-cell size				
				if (Sprite_Buff[i].Idx & 0x8000)
				{
					//Get Sprite Position 0 ~ 3
					x = Sprite_Buff[i].x; 
				   	y = Sprite_Buff[i].y;				    					    	
				   	x1 = Sprite_Buff[i].x1; 
				   	y1 = Sprite_Buff[i].y1;
				   	x2 = Sprite_Buff[i].x2; 
				   	y2 = Sprite_Buff[i].y2;
				   	x3 = Sprite_Buff[i].x3; 
				   	y3 = Sprite_Buff[i].y3;
				   	//Get Cell Number
				   	xtemp = (Sprite_Buff[i].xSize & 0x03ff); //x cell number
				   	if (xtemp%xcell)
				   		cx = xtemp/xcell+1;
				   	else
				   		cx = xtemp/xcell;	
				   	ytemp = (Sprite_Buff[i].ySize & 0x03ff); //y cell number
				   	if (ytemp%ycell)
				   		cy = ytemp/ycell+1;
				   	else
				   		cy = ytemp/ycell;			  				   							
				}		 
									
				for( j=0; j<SP_MAX_CHAR; j++ ) // MAX Sprite Characters Combination Mode
				{
					if( Sprite_Buff[i].sprcell[j*CELL_LENGTH] == 0xffff ) // Check Sprite Characters Combination Flag
					{
						counter += j*4;
						if (P_PPU_Enable_B -> B.Sp25d == 0)	
							counter2 += j*1;
						else
							counter2 += j*4;	
						break;
					}
					//Character Number Index [15:0]					
					SpriteBuf0[ 0+counter+j*4 ]	= (Sprite_Buff[i].Idx & 0x7FFF) + Sprite_Buff[i].sprcell[j*CELL_LENGTH];
					if (SpriteBuf0[ 0+counter+j*4 ] < Sprite_Buff[i].sprcell[j*CELL_LENGTH])
						id_carry = 1;
					else
						id_carry = 0;										
				    //Sprite Attribute 0			
				    SpriteBuf0[ 3+counter+j*4 ] = Sprite_Buff[i].att0;
				    			    	
				    if ((Sprite_Buff[i].Idx & 0x8000) == 0) 
				    {
				    	//Character Number Index [23:16] & Attribute 1
				    	if (P_PPU_Enable_B -> B.Sp25d == 0)	{				    		
				    		SpriteBuf1[ 0+counter2+j*1 ] = id_carry + Sprite_Buff[i].sprcell[ j*CELL_LENGTH+16 ]; 
				    		SpriteBuf1[ 0+counter2+j*1 ] |= Sprite_Buff[i].att1;
				    	}
				    	else {			
				    		SpriteBuf1[ 0+counter2+j*4 ] = id_carry + Sprite_Buff[i].sprcell[ j*CELL_LENGTH+16 ]; 
				    		SpriteBuf1[ 0+counter2+j*4 ] |= Sprite_Buff[i].att1;
				    	}				    			
				    	//Sprite Position 0
				    	xtemp = Sprite_Buff[i].sprcell[j*CELL_LENGTH+2]; // Cell x position
						ytemp = Sprite_Buff[i].sprcell[j*CELL_LENGTH+4]; // Cell y position
						if (P_PPU_Enable_B -> B.Sp25d == 0)
						{	
							cx = (Sprite_Buff[i].xSize & 0x03ff) - xcell; // get maximum x position
							cy = ycell - (Sprite_Buff[i].ySize & 0x03ff); // get minimum y position
							if((Sprite_Buff[i].att0 & 0x0004) != 0) // HFlip 						
								xtemp = cx - xtemp;					
							if((Sprite_Buff[i].att0 & 0x0008) != 0) // VFlip				
								ytemp = cy - ytemp;
						}																		
						if(P_Sp_Control_B->B.Coor == 0)										
						{
							// fix x, y the origin of the coordinates
							cx = Sprite_Buff[i].x + xtemp - screen_width/2 + xcell/2 + 1;
								if (cx>511)
								cx = 511;
							if (cx<-512)
								cx = -512;		
							cy = screen_height/2 - 1 - Sprite_Buff[i].y + ytemp - ycell/2;
								if (cy>511)
								cy = 511;
							if (cy<-512)
								cy = -512;	
						}
						else
						{
							// fix x, y the origin of the coordinates by hardware
							cx = Sprite_Buff[i].x + xtemp;
							cy = Sprite_Buff[i].y + ytemp;      // modify by sam for correct Top left mode
						}	
						k = Sprite_Buff[i].xSize & 0xfc00; 					// get rotate level
						SpriteBuf0[ 1+counter+j*4 ] = k | (cx & 0x03ff);	// sprite x position & rotate level
						k = Sprite_Buff[i].ySize & 0xfc00; 					// get zoom level
						SpriteBuf0[ 2+counter+j*4 ] = k | (cy & 0x03ff);	// sprite y position & zoom	level						
				    }
				   	else 
				    {
//				    	//Character Number Index [23:16] & Attribute 1
//				    	SpriteBuf1[ 0+counter2+j*4 ] = id_carry + Sprite_Buff[i].sprcell[ j*CELL_LENGTH+16 ]; 
//				    	SpriteBuf1[ 0+counter2+j*4 ] |= Sprite_Buff[i].att1;
//				    	//Compute Sprite Cell 2.5D Position
//				    	xtemp = Sprite_Buff[i].sprcell[j*CELL_LENGTH+2]; // Cell x position
//						ytemp = Sprite_Buff[i].sprcell[j*CELL_LENGTH+4]; // Cell y position
//						h = xtemp/xcell;
//						k = -ytemp/ycell;
//				    	x = HGridBuff[k][h];
//				    	x1 = HGridBuff[k][h+1];
//				    	x2 = HGridBuff[k+1][h+1];
//				    	x3 = HGridBuff[k+1][h];
//				    	y = VGridBuff[k][h];
//				    	y1 = VGridBuff[k][h+1];
//				    	y2 = VGridBuff[k+1][h+1];
//				    	y3 = VGridBuff[k+1][h];
//				    	//Coordinate Conversion
//				    	SpCoordConvert(i, &x, &y);
//				    	SpCoordConvert(i, &x1, &y1);
//				    	SpCoordConvert(i, &x2, &y2);
//				    	SpCoordConvert(i, &x3, &y3);				    					    	
//				    	//Write Position 0 ~ 3
//						SpriteBuf0[ 1+counter+j*4 ] = x | ((y1 & 0x003f) << 10);
//						SpriteBuf0[ 2+counter+j*4 ] = y | ((y2 & 0x003f) << 10);
//						SpriteBuf1[ 1+counter2+j*4 ] = x1 | ((y3 & 0x003f) << 10);
//						SpriteBuf1[ 2+counter2+j*4 ] = x2 | ((y3 & 0x00c0) << 8) | ((y1 & 0x03c0) << 4);
//						SpriteBuf1[ 3+counter2+j*4 ] = x3 | ((y3 & 0x0300) << 6) | ((y2 & 0x03c0) << 4);									
				    }			   					
				}
			}
		}
		spriteFlag = 1;                                     
	}
};

//================================================================================
//	Description:	Set Sprite rotate level
//	Function:		SetSpRotate()
//	Syntax:			void	SetSpRotate(int nSpIdx, int nRotate);
//	Input Paramter:	int nSpIdx:	Sprite index (0~255)
//					int nRotate: Rotate level (0~63)
//	Return: 		none
//================================================================================
void	SetSpRotate(int nSpIdx, int nRotate)
{
	int k;
	
	if( Sprite_Buff[nSpIdx].sprcell != 0 )	// check sprite exist/non-exist
	{
		if ((Sprite_Buff[nSpIdx].Idx & 0x8000) == 0)
		{	 
			k = Sprite_Buff[nSpIdx].xSize & 0x03ff;	
			Sprite_Buff[nSpIdx].xSize = k | (nRotate << 10);
		}	
	}	 	
};

//================================================================================
//	Description:	Set Sprite zoom level
//	Function:		SetSpZoom()
//	Syntax:			void	SetSpZoom(int nSpIdx, int nZoom);
//	Input Paramter:	int nSpIdx:	Sprite index (0~255)
//					int nZoom: Zoom level (0~63) 
//	Return: 		none
//================================================================================
void	SetSpZoom(int nSpIdx, int nZoom)
{
	int k;
	
	if( Sprite_Buff[nSpIdx].sprcell != 0 )	// check sprite exist/ non-exist
	{
		if ((Sprite_Buff[nSpIdx].Idx & 0x8000) == 0)
		{	 
			k = Sprite_Buff[nSpIdx].ySize & 0x03ff;	
			Sprite_Buff[nSpIdx].ySize = k | (nZoom << 10);
		}	
	}	 	
};

//================================================================================
//	Description:	Set Sprite Depth
//	Function:		SetSpDepth()
//	Syntax:			void	SetSpDepth(int nSpIdx, int nDepth);
//	Input Paramter:	int nSpIdx:	Sprite index (0~255)
//					int nDepth:	Depth (0~3)
//								0: Sprite depth 1
//								1: Sprite depth 3
//								2: Sprite depth 5
//								3: Sprite depth 7		 
//	Return: 		none
//================================================================================
void	SetSpDepth(int nSpIdx, int nDepth)
{
	int k;
	
	if( Sprite_Buff[nSpIdx].sprcell != 0 )	// check sprite exist/ non-exist
	{
		k = Sprite_Buff[nSpIdx].att0 & 0xcfff;	
		Sprite_Buff[nSpIdx].att0 = k | (nDepth << 12);
	}	 	
};

//================================================================================
//	Description:	Set Sprite Blending effect
//	Function:		SetSpBlend()
//	Syntax:			void	SetSpBlend(int nSpIdx, int nEnable);
//	Input Paramter:	int nSpIdx:	Sprite index (0~255)
//					int nEnable: Blend enable (0~1)
//								0:Disable
//								1:Enable
//	Return: 		none
//================================================================================
void	SetSpBlend(int nSpIdx, int nEnable)
{
	int k;
	
	if( Sprite_Buff[nSpIdx].sprcell != 0 )	// check sprite exist/ non-exist
	{
		k = Sprite_Buff[nSpIdx].att0 & 0xbfff;
		Sprite_Buff[nSpIdx].att0 = k | (nEnable << 14);
	}	 	
};

//================================================================================
//	Description:	Set Sprite Mosaic Level
//	Function:		SetSpMosaic()
//	Syntax:			void	SetSpMosaic(int nSpIdx, int nMosaic);
//	Input Paramter:	int nSpIdx:	Sprite index (0~255)
//					int nMosaic: Mosaic level (0~3)
//								 0: No mosaic
//								 1: 2x2 mosaic
//								 2: 4x4 mosaic
//								 3: 8x8 mosaic
//	Return: 		none
//================================================================================
void	SetSpMosaic(int nSpIdx, int nMosaic)
{
	int k;
	
	if( Sprite_Buff[nSpIdx].sprcell != 0 )	// check sprite exist/ non-exist
	{
		k = Sprite_Buff[nSpIdx].att1 & 0x3fff;
		Sprite_Buff[nSpIdx].att1 = k | (nMosaic << 14);
	}	 	
};

//================================================================================
//	Description:	Set Sprite 64-level Blending Level
//	Function:		SetSpBlend64()
//	Syntax:			void	SetSpBlend64(int nSpIdx, int nBlend);
//	Input Paramter:	int nSpIdx:	Sprite index (0~255)
//					int nBlend:	Blend level (0~63)
//	Return: 		none
//================================================================================
void	SetSpBlend64(int nSpIdx, int nBlend)
{
	int k;
	
	if( Sprite_Buff[nSpIdx].sprcell != 0 )	// check sprite exist/ non-exist
	{
		k = Sprite_Buff[nSpIdx].att1 & 0xc0ff;	
		Sprite_Buff[nSpIdx].att1 = k | (nBlend << 8);
	}	 	
};

//================================================================================
//	Description:	Set Sprite Flip effect
//	Function:		SetSpriteFlip()
//	Syntax:			void	SetSpriteFlip(int nSpIdx, int nFlip);
//	Input Paramter:	int nSpIdx: Sprite index (0~255)
//					int nFlip: Flip mode (0~3)
//							   0: NO_FLIP					
//							   1: H_FLIP
//							   2: V_FLIP
//							   3: HV_FLIP
//	Return: 		none
//================================================================================
void	SetSpriteFlip(int nSpIdx, int nFlip)
{
	int k;
	
	if( Sprite_Buff[nSpIdx].sprcell != 0 )	// check sprite exist/ non-exist
	{
		k = Sprite_Buff[nSpIdx].att0 & 0xfff3;	
		Sprite_Buff[nSpIdx].att0 = k | (nFlip << 2);
	}	 	
};

//================================================================================
//	Description:	Set Sprite 4-bit Palette selection
//	Function:		SetSpPaletteBank()
//	Syntax:			void	SetSpPaletteBank(int nSpIdx, int sel);
//	Input Paramter:	int nSpIdx: Sprite index (0~255)
//					int sel: Palette selection (0~15)						
//	Return: 		none
//================================================================================
void	SetSpPaletteBank(int nSpIdx, int sel)
{
	int k;
	
	if( Sprite_Buff[nSpIdx].sprcell != 0 )	// check sprite exist or non-exist
	{
		k = Sprite_Buff[nSpIdx].att0 & 0xf0ff;	
		Sprite_Buff[nSpIdx].att0 = k | (sel << 8);
	}	 	
};


//================================================================================
//	Description:	Clear CPU I-Cache
//	Function:		ClearICache()
//	Syntax:			void	ClearICache();
//	Input Paramter:	none		
//	Return: 		none
//================================================================================
void	ClearICache()
{
	int size;
	
	// Get Cache size
	size = *P_Cache_Ctrl & 0x000c;
	
	// Disable Cache
	*P_Cache_Ctrl = 0;
	while(*P_Cache_Ctrl);
		
	// Clear Cache
	*P_Cache_Ctrl = size | 0x0002;
	while(*P_Cache_Ctrl & 0x002);
};

//================================================================================
//	Description:	Set CPU Instruction Cache
//	Function:		SetICache()
//	Syntax:			void	SetICache();
//	Input Paramter:	int size: Cache size (0~3) 	
//							  0:8 words 
//							  1:1k bytes  
//							  2:2k bytes
//							  3:4k bytes		
//	Return: 		none
//================================================================================
void	SetICache(int size)
{	
	switch(size)
	{
		case 0: //8-words
			*P_Cache_Ctrl = 0x0001;
			break;
	    case 1: //1k bytes
			*P_Cache_Ctrl = 0x0005;					
			break;
		case 2: //2k bytes
			*P_Cache_Ctrl = 0x0009;						
			break;
		case 3: //4k bytes
			*P_Cache_Ctrl = 0x000d;
			break;								 					
	}
	while((*P_Cache_Ctrl & 0x0001) == 0);
};


//====================================================================================================
//	Description:	PPU Service function
//	Function:		PPU_Service()
//	Syntax:			void	PPU_Service(void);
//	Input Paramter:	none
//	Return: 		none
//	NOTE:			Update PPU registers and SRAM
//====================================================================================================
void	PPU_Service(void)
{
	U16 i;
	
	FadeCount++;
	WriteColorPalette();
	
	if(TextModeFlag==1)			// text working mode	
	{	
		P_Tx1_Control_B->B.Mode = Text1Mode;
		P_Tx2_Control_B->B.Mode = Text2Mode;
		P_Tx3_Control_B->B.Mode = Text3Mode;
		TextModeFlag = 0;
	}						
		
	if(textScroll==1)			// text scroll 
	{
		*P_Tx1_X_Position		= text1_x;
		*P_Tx1_Y_Position		= text1_y;
		*P_Tx2_X_Position		= text2_x;
		*P_Tx2_Y_Position		= text2_y;
		*P_Tx3_X_Position		= text3_x;
		*P_Tx3_Y_Position		= text3_y;
		textScroll 				= 0;
	}        
	
	if(HoffsetFlag==1)
	{
//		*P_PPU_RAM_Bank = 0; 
//		SetDMACopy0((U32)HoffsetBuff, (U32)P_Tx_HvOffset_ADDR, 240);
//		HoffsetFlag = 0;	
	}
	
	if(HCmpFlag==1) 
	{
		*P_PPU_RAM_Bank = 0;
		if(LineMode == LINES_SAME)
			MyMemSet((U32)P_HComp_Value_ADDR, HCmpValue, 240);		
		else	
			SetDMACopy0(ptrHCmpTable, (U32)P_HComp_Value_ADDR, 240);
		HCmpFlag = 0;
	}	
	
	if(VCmpFlag==1)
	{
		*P_VComp_Value 	= VCmpValue;
		*P_VComp_Offset = VCmpOffset;
		*P_VComp_Step  	= VCmpStep;
		VCmpFlag = 0;
	}
	
	
	if(FadeInFlag==1)
	{
		if (FadePeriod != 0)
		{	
			if (FadeCount%FadePeriod == 0)
			{	
				i = *P_Fade_Control&0x00FF;
				if (i != 0x00)
					*P_Fade_Control = i - 1;
				FadeInFlag = 0;
				FadePeriod = 0;
			}	
		}		
	}
	
	if(FadeOutFlag==1)
	{
		if (FadePeriod != 0)
		{	
			if (FadeCount%FadePeriod == 0)
			{	
				i = *P_Fade_Control&0x00FF;
				if (i != 0xFF)
					*P_Fade_Control = i + 1;
				FadeOutFlag = 0;
				FadePeriod = 0;
			}	
		}		
	}
							
	if(spriteFlag==1)
	{
		spriteFlag				= 0;
		// DMA tranfer data to 0x7400 - 77ff (bank 1)
		*P_PPU_RAM_Bank 		= 1;
		*P_SPDMA_Source			= (U16)SpriteBuf1;
		*P_SPDMA_Target			= P_Sp_Num_ADDR;
		if (P_PPU_Enable_B -> B.Sp25d == 0)
			*P_SPDMA_Number		= sp_number_max - 1;
		else
			*P_SPDMA_Number		= sp_number_max*4 - 1;		
		while (*P_SPDMA_Number);										
		// DMA tranfer data to 0x7400 - 77ff (bank 0)
		*P_PPU_RAM_Bank 		= 0;
		*P_SPDMA_Source			= (U16)SpriteBuf0;
		*P_SPDMA_Target			= P_Sp_Num_ADDR;
		*P_SPDMA_Number			= sp_number_max*4 - 1;			
		while (*P_SPDMA_Number);									
	}
};
			

//====================================================================================================
//	Description:	Initial HVGA bitmap-mode text
//	Function:		InitBitmapHVGA()
//	Syntax:			void	InitBitmapHVGA(int nText,U32 bmpdata,int nSizeX,int nSizeY,int nTextSize,int nColorMode,int nDepth,int nPalette);
//	Input Paramter:	int nText: Text selection (0~2)
//							   0:TEXT1			
//							   1:TEXT2
//							   2:TEXT3
//					U32 bmpdata: bitmap data address
//					int nSizeX:	Real text size x
//					int nSizeY:	Real text size y
//					int nTextSize: The size of text layer (0~3)
//								   0:512x256
//								   1:512x512
//								   2:1024x512
//								   3:1024x1024
//					int nColorMode:	Color mode (0~5)
//									0:4 color		
//									1:16 color		
//									2:64 color		
//									3:256 color
//									4:32768 color
//									5:65536 color		
//					int nDepth: Depth layer (0~3)		
//								0:Text Depth 0
//								1:Text Depth 2
//								2:Text Depth 4
//							    3:Text Depth 6
//					int nPalette: 4-bit palette selection (0~15)
//	Return: 		none
//====================================================================================================
void	InitBitmapHVGA(int nText,U32 bmpdata,int nSizeX,int nSizeY,int nTextSize,int nColorMode,int nDepth,int nPalette)
{
	int i, j, iBitColor, sizeY;
	int *ptAttr,*ptIdx;
	U16 Bank;
	U32 Addr32;
				
	if ( nText == TEXT1 )					//text1
	{
		if(nColorMode == COLOR32768)		//32768 color
		{
			P_Tx1_Attribute_B->B.Color 		= 	0;
			P_Tx1_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx1_Control_B->W 		   	   &= 	0x08;
			P_Tx1_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx1_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx1_Control_B->B.RGB			= 	Text_RGBEnable;
		}
		else if(nColorMode == COLOR65536)	//65536 color
		{
			P_Tx1_Attribute_B->B.Color 		= 	1;
			P_Tx1_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx1_Control_B->W 		   	   &= 	0x08;
			P_Tx1_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx1_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx1_Control_B->B.RGB			= 	Text_RGBEnable;
		}
		else	//4 or 16 or 64 or 256 color
		{		
			P_Tx1_Attribute_B->B.Color 		= 	nColorMode;
			P_Tx1_Attribute_B->B.Palette 	= 	nPalette;
			P_Tx1_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx1_Control_B->W 		  	   &= 	0x08;
			P_Tx1_Control_B->B.Linr 	 	= 	Text_LinerMode;
			P_Tx1_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx1_Control_B->B.RGB			= 	Text_RGBDisable;
		}
		P_Tx1_N_Ptr_B->W = (U16)&Text1IndexTable;
		P_Tx1_A_Ptr_B->W = (U16)&Text1AttrTable;
		ptAttr = Text1AttrTable;
		ptIdx = Text1IndexTable;
	}
	//-----------------------------------------------------------------
	if ( nText == TEXT2 )					//text2
	{
		if(nColorMode == COLOR32768)		//32768 color
		{
			P_Tx2_Attribute_B->B.Color 		=	0;
			P_Tx2_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx2_Control_B->W 		   	   &= 	0x08;
			P_Tx2_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx2_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx2_Control_B->B.RGB			= 	Text_RGBEnable;			
		}
		else if(nColorMode == COLOR65536)	//65536 color
		{
			P_Tx2_Attribute_B->B.Color 		=	1;
			P_Tx2_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx2_Control_B->W 		   	   &= 	0x08;
			P_Tx2_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx2_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx2_Control_B->B.RGB			= 	Text_RGBEnable;			
		}
		else	//4 or 16 or 64 or 256 color
		{	
			P_Tx2_Attribute_B->B.Color 		= 	nColorMode;
			P_Tx2_Attribute_B->B.Palette 	= 	nPalette;
			P_Tx2_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx2_Control_B->W 		  	    &= 	0x08;
			P_Tx2_Control_B->B.Linr 	 	= 	Text_LinerMode;
			P_Tx2_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx2_Control_B->B.RGB			= 	Text_RGBDisable;
		}
		P_Tx2_N_Ptr_B->W = (U16)&Text2IndexTable;
		P_Tx2_A_Ptr_B->W = (U16)&Text2AttrTable;
		ptAttr = Text2AttrTable;
		ptIdx = Text2IndexTable;
	}
	//-----------------------------------------------------------------
	if ( nText == TEXT3 )					//text3
	{
		if(nColorMode == COLOR32768)		//32768 color
		{
			P_Tx3_Attribute_B->B.Color 		= 	0;
			P_Tx3_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx3_Control_B->W 		  	   &= 	0x08;
			P_Tx3_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx3_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx3_Control_B->B.RGB			= 	Text_RGBEnable;
		}
		else if(nColorMode == COLOR65536)	//65536 color
		{
			P_Tx3_Attribute_B->B.Color 		= 	1;
			P_Tx3_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx3_Control_B->W 		  	   &= 	0x08;
			P_Tx3_Control_B->B.Linr  		= 	Text_LinerMode;
			P_Tx3_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx3_Control_B->B.RGB			= 	Text_RGBEnable;
		}
		else	//4 or 16 or 64 or 256 color
		{	
			P_Tx3_Attribute_B->B.Color 		= 	nColorMode;
			P_Tx3_Attribute_B->B.Palette 	= 	nPalette;
			P_Tx3_Attribute_B->B.Depth 		= 	nDepth;
			P_Tx3_Control_B->W 		   	   &= 	0x08;
			P_Tx3_Control_B->B.Linr 	 	= 	Text_LinerMode;
			P_Tx3_Control_B->B.Rgm 	 		= 	Text_AttInRegister;
			P_Tx3_Control_B->B.RGB			= 	Text_RGBDisable;
		}
		P_Tx3_N_Ptr_B->W = (U16)&Text3IndexTable;
		P_Tx3_A_Ptr_B->W = (U16)&Text3AttrTable;
		ptAttr = Text3AttrTable;
		ptIdx = Text3IndexTable;
	}
	
	switch(nColorMode)
	{
		case	COLOR4:
			iBitColor = 2;
			break;
		case	COLOR16:
			iBitColor = 4;
			break;
		case	COLOR64:
			iBitColor = 6;
			break;
		case	COLOR256:
			iBitColor = 8;
			break;
		case	COLOR32768:
			iBitColor = 16;
			break;
		case	COLOR65536:
			iBitColor = 16;
			break;
	}		
	
	switch(nTextSize)
	{
		case	0:	//512x256
			sizeY = 256;
			break;
		case	1:	//512x512
			sizeY = 512;
			break;
		case	2:	//1024x512
			sizeY = 512;
			break;
		case	3:	//1024x1024
			sizeY = 1024;
			break;
	}						
		
	if(nSizeY < sizeY)
		sizeY = nSizeY; 				
						
	if (P_PPU_Enable_B -> B.Free)
		bmpdata = 0;
			
	j = 0;
	for(i=0;i<sizeY;i++)
	{
		Addr32 = bmpdata;
		Addr32 += ((unsigned long)i*(unsigned long)nSizeX*(unsigned long)iBitColor)>>4;
		*ptIdx = Addr32&0xffff;							// put offset value
		Bank = (Addr32>>16)&0x00ff;
		if(!(j%2))										// put segment value in low byte for even point
		{
			*ptAttr = Bank;
		}
		else											// put segment value in high byte for odd point
		{
			*ptAttr += (Bank<<8);
			ptAttr++; 
		}
		ptIdx++;
		j++;
		if(!(j%2))										// put segment value in low byte for even point
		{
			*ptAttr = Bank;
		}
		else											// put segment value in high byte for odd point
		{
			*ptAttr += (Bank<<8);
			ptAttr++; 
		}
		ptIdx++;
		j++;
	} 
};

//====================================================================================================
//	Description:	Show HVGA bitmap-mode text 
//	Function:		fnShow_Bmp_HVGA()
//	Syntax:			void	fnShow_Bmp_HVGA(int nText, U32 bmpdata, int nSizeX, int nSizeY, int nTextSize, int nColorMode, int nDepth, int nPalette, int nAuto, int nPalBank);
//	Input Paramter:	int nText: Text selection (0~2)
//							   0:TEXT1			
//							   1:TEXT2
//							   2:TEXT3
//					U32 bmpdata: bitmap data address
//					int nSizeX:	Real text size x
//					int nSizeY:	Real text size y
//					int nTextSize: The size of text layer (0~3)
//								   0:512x256
//								   1:512x512
//								   2:1024x512
//								   3:1024x1024
//					int nColorMode:	Color mode (0~5)
//									0:4 color		
//									1:16 color		
//									2:64 color		
//									3:256 color		
//									4:32768 color
//									5:65536 color		
//					int nDepth: Depth layer (0~3)		
//								0:Text Depth 0
//								1:Text Depth 2
//								2:Text Depth 4
//							    3:Text Depth 6
//					int nPalette: 4-bit palette selection (0~15)
//					int nPalBank: Text palette RAM bank (0~1) 
//	Return: 		none
//	Note:			The bitmap special mode is applied automatically only when horizontal size is 320/640/512/1024.
//					The bitmap special mode means that PPU hardware computes start address of each line automatically. 		
//====================================================================================================
void	fnShow_Bmp_HVGA(int nText,U32 bmpdata,int nSizeX,int nSizeY,int nTextSize,int nColorMode,int nDepth,int nPalette,int nPalBank)
{
	U32 Addr32;
	
	Addr32 = bmpdata;
	if(nText == TEXT1)
		P_Tx1_Control_B->B.Txe = 0;
	else if(nText == TEXT2)
		P_Tx2_Control_B->B.Txe = 0;
	else if(nText == TEXT3)
		P_Tx3_Control_B->B.Txe = 0;
	else
		P_Tx4_Control_B->B.Txe = 0;
				
	InitBitmapHVGA(nText,bmpdata,nSizeX,nSizeY,nTextSize,nColorMode,nDepth,nPalette);
	
	if(nText == TEXT1)
	{
		text1_x = 0;
		text1_y = 0;
		*P_Tx1_X_Position = 0;
		*P_Tx1_Y_Position = 0;
		*P_Segment_Tx1H = (Addr32>>16) | (nPalBank<<15);
		*P_Segment_Tx1 = Addr32&0xffff;
		P_Tx1_Attribute_B->B.Size = nTextSize;
		P_Tx1_Control_B->B.Txe = 1;
	}
	else if(nText == TEXT2)
	{
		text2_x = 0;
		text2_y = 0;
		*P_Tx2_X_Position = 0;
		*P_Tx2_Y_Position = 0;
		*P_Segment_Tx2H = (Addr32>>16) | (nPalBank<<15);
		*P_Segment_Tx2 = Addr32&0xffff;
		P_Tx2_Attribute_B->B.Size = nTextSize;
		P_Tx2_Control_B->B.Txe = 1;
	}
	else
	{
		text3_x = 0;
		text3_y = 0;
		*P_Tx3_X_Position = 0;
		*P_Tx3_Y_Position = 0;
		*P_Segment_Tx3H = (Addr32>>16) | (nPalBank<<15);
		*P_Segment_Tx3 = Addr32&0xffff;
		P_Tx3_Attribute_B->B.Size = nTextSize;
		P_Tx3_Control_B->B.Txe = 1;
	}
};

//====================================================================================================
//	Description:	Get the address of resource file 
//	Function:		GetResAddress()
//	Syntax:			U32 GetResAddress(U16 *p);
//	Input Paramter:	U16 *p: The pointer of address table for resoure file 
//	Return: 		32-bit Long address 
//====================================================================================================
U32	GetResAddress(U16 *p)
{ 
	U32 addr0, addr1;
   
	
	addr0 = *p;		//Offet
	addr1 = *(p+1); //Seg16
	addr0 += addr1 << 16;
	return addr0;
}

//====================================================================================================
//	Description:	Init PPU Driver
//	Function:		InitPPUDrv()
//	Syntax:			S16 InitPPUDrv(U16 text1_index_length, U16 text2_index_length, U16 text3_index_length, U16 sp_number_max);
//	Input Paramter:	text1_index_length: Length of Number Array of Text1
//					text2_index_length: Length of Number Array of Text2
//					text3_index_length: Length of Number Array of Text3
//					sp_number_max: Max number of Sprite
//	Return: 		PPU Driver version: high byte: main verison, low byte: sub version
//====================================================================================================
S16 InitPPUDrv(U16 length1, U16 length2, U16 length3, U16 sp_no)
{
	text1_index_length = length1;
	text2_index_length = length2;
	text3_index_length = length2;
	sp_number_max = sp_no;
	
	return PPU_Driver_Version;
}
//====================================================================================================
//	Description:	Set TEXT Char 0 Auto Transparent Mode
//	Function:		SetTextChar0AutoTransparentMode
//	Syntax:			S16 SetTextChar0AutoTransparentMode(U16 auto_en);
//	Input Paramter:	auto_en: 
//							0:TextChar0AutoTransparent_Disable
//							1:TextChar0AutoTransparent_Enable
//	Return: 		16-bit int
//====================================================================================================
S16 SetTextChar0AutoTransparentMode(U16 auto_en)
{
	if (auto_en == TextChar0AutoTransparent_Enable)
		*P_PPU_Enable |= 0x2;
	else if (auto_en == TextChar0AutoTransparent_Disable)
		*P_PPU_Enable &= ~0x2;
	else
		return -1;
	return 0;
}
//================================================================================
//	Description:	PPU v-blanking IRQ service
//	Function:		VBLK_Service()
//	Syntax:			void	VBLK_Service();
//	Input Paramter:	none 	
//	Return: 		none
//  Note:			Call this function in IRQ5 	
//================================================================================
void	VBLK_Service(void)
{
	game_time++; //game_time++;
	ClearVblankIRQ(); //clear v-blanking IRQ status
	if(P_PPU_Enable_B -> B.VGAen == VGA_DISABLE) //QVGA
	{		
		PPU_Service(); //Run PPU Service
			cpu_done = 0;	
	}
	else //VGA
	{											
		//GPL951 not support VGA			    			
	}
};
	
																 															
																 															
																 													