/********************
	pcgraph.c
 ********************/

#include	"ot_header.h"
#include	"ot_sub.h"
//#include	<libnos.h>
#include	<os_internal.h>

#include	"kn_def.h"
#include	"kn_dynamic.h"
#include	"kn_main.h"
#include	"kn_stage.h"
#include	"kn_backup.h"


#if SW_KN_3DLX
#else
extern long long int	gspFast3DQ_fifoTextStart[], gspFast3DQ_fifoTextEnd[];
extern long long int	gspFast3DQ_fifoDataStart[], gspFast3DQ_fifoDataEnd[];
#endif
/*******************************************************
	SYSTEM BUFFER
*******************************************************/
extern u64	datYieldBuffer[DAT_YIELD_SIZE64] ;		/* 0x900 */
extern u64	dram_stack[SP_DRAM_STACK_SIZE64] ;		/* 0x400 */
#if RSP_DRAM_SW
#if (SW_KN_LANGUAGE == KN_EU)
#define	SP_OUT_DRAM_SIZE	0x2c000
#else

#if SW_KN_6M 
#define	SP_OUT_DRAM_SIZE	0x20000
#else
#define	SP_OUT_DRAM_SIZE	0x30000
#endif

#endif
uwlong			rsp_dram_buff[(SP_OUT_DRAM_SIZE>>3)+2] ;
#endif

/*******************************************************
	SINGLE BUFFER
*******************************************************/
Automatic		automatic_BF ;

/*******************************************************
	DOUBLE BUFFER
*******************************************************/
int			double_index ;
Dynamic			dynamic_BF[2], *dynamic_p ;
OSTask			task_BF[2], *task_p ;
Gfx			*glist_p ;

static int		glistNum = 0, glistMaxNum = 0;
/*******************************************************
	TRIPLE BUFFER
*******************************************************/
int			triple_index, old_triple_index, next_triple_index ;
/*******************************************************
	DOUBBLE BUFFER
*******************************************************/
int			indexHi = 0;
ushort		*pFBufferHi[2] = {
	(ushort *)( FRAME_BUFFER_H0 ), 
	(ushort *)( FRAME_BUFFER_H1 ), 
};
/*******************************************************
	GRAPHIC LIST
*******************************************************/
extern Gfx 		init_rcp_GL[] ;
extern Gfx 		init_rcp_full_GL[] ;

/*******************************************************
	MESSAGE WORK
*******************************************************/
OSMesg			MesgB_dummy[1] ;
static OSMesg		MesgB_FRM_dummy[1] ;
static OSMesg		MesgB_RSP_dummy[1] ;
static OSMesg		MesgB_RDP_dummy[1] ;

/*******************************************************
	VARIABLE
*******************************************************/
uint			main_count ;

#if SYS_TIME_SW
int			process_meter_fg = 0 ;
int			sm_cpu_min, sm_cpu_max ;
int			sm_rsp_min, sm_rsp_max ;
int			sm_all_min, sm_all_max ;
#endif

/*******************************************************
	SEGMENT ADDRESS
*******************************************************/
uint			_codeSEGSegmentPhyStart, _codeSEGSegmentPhyEnd ;
uint			_loadCodeSEGSegmentPhyStart, _loadCodeSEGSegmentPhyEnd ;
uint			_zbufferSEGSegmentPhyStart, _zbufferSEGSegmentPhyEnd ;
uint			_fbufferSEGSegmentPhyStart, _fbufferSEGSegmentPhyEnd ;
uint			_staticSEGSegmentPhyStart, _staticSEGSegmentPhyEnd ;
uint			_staticGameSEGSegmentPhyStart, _staticGameSEGSegmentPhyEnd ;
uint			_staticLangSEGSegmentPhyStart, _staticLangSEGSegmentPhyEnd ;
uint			_autoSEGSegmentPhyStart, _autoSEGSegmentPhyEnd ;
uint			_dynamicSEGSegmentPhyStart, _dynamicSEGSegmentPhyEnd ;
uint			_BuffersSegmentPhyStart, _BuffersSegmentPhyEnd ;
uint			_screenSEGSegmentPhyStart, _screenSEGSegmentPhyEnd ;

uint			_bankBufferSEGSegmentPhyStart, _bankBufferSEGSegmentPhyEnd ;
uint			_courseBufferSEGSegmentPhyStart, _courseBufferSEGSegmentPhyEnd ;
uint			_courseDTSEGSegmentPhyStart, _courseDTSEGSegmentPhyEnd ;
uint			_progBankSEGSegmentPhyStart, _progBankSEGSegmentPhyEnd ;


/* Segment Base Addr */
uint courseSegmentBase = COURSE_BUFFER;
uint courseComSegmentBase = 0;
uint courseDTSegmentBase = COURSE_BUFFER + COURSE_DT_OFFSET;
uint bankSegmentBase = BANK_BUFFER;

/* Segment Base Addr */
int	DRAMFreeSize;
#if (SW_KN_LANGUAGE == KN_EU)
int	DRAMFreeSize2;
#endif
/*******************************************************************************
	DISPLAY PROCESS TIME
*******************************************************************************/
#if SYS_TIME_SW
Gfx *make_process_time_glist( Gfx *gp )
{
	#define SM_X1		(DISPLAY_X1 + 20)		/* x pos */
	#define SM_X2		(DISPLAY_X2)
	#define SM_WX		(SM_X2 - SM_X1 + 1)
	#define SM_WY		(2)				/* y width */
	#define SM_SY		(1)				/* y space */
	#define	SM_Y_LOOP	(DISPLAY_Y2 - SM_WY - SM_SY - 1)/* y pos */
	#define	SM_Y_GRDP	(SM_Y_LOOP - SM_WY - SM_SY)
	#define	SM_Y_GRSP	(SM_Y_GRDP - SM_WY - SM_SY)
	#define	SM_Y_GCPU	(SM_Y_GRSP - SM_WY - SM_SY)
	#define	SM_Y_ARSP	(SM_Y_GRSP)
	#define	SM_Y_ACPU	(SM_Y_GCPU)
	#define	SM_FRAMES	(8)
	#define	SM_SCALES	(4)
	#define SM_CONV(x)	(CYCLE2FRAME(x) * SM_WX / SM_FRAMES)
	#define	SM_CONV_A	(4)				/* audio sclae */
	#define	SM_C_ACPU	RGBA16(31,31,31,1)
	#define	SM_C_ARSP	RGBA16(31,31,31,1)
	#define	SM_C_GCPU	RGBA16(31,13,13,1)
	#define	SM_C_GRSP	RGBA16(17,17,31,1)
	#define	SM_C_GRDP	RGBA16( 0,31, 0,1)
	#define	SM_C_LOOP	RGBA16(21,21, 0,1)
	#define	SM_C_GCPU0	RGBA16(12, 0, 0,1)
	#define	SM_C_GRSP0	RGBA16( 0, 0,31,1)
	#define	SM_C_LOOP0	RGBA16( 0, 6, 0,1)
	#define	SM_C_SC1	RGBA16( 0, 0, 0,1)
	#define	SM_C_SC2	RGBA16( 8, 8, 8,1)

	int		i, x1, x2 ;
	ProcessTime	*tp ;

	/***********************************************************************
		INITIATE
	***********************************************************************/
	gSPClearGeometryMode( gp++, 0xFFFFFFFF ) ;
	gSPSetGeometryMode( gp++, G_SHADE ) ;
	gSPTexture( gp++, 0x8000, 0x8000, 0, G_TX_RENDERTILE, G_OFF ) ;
	gDPPipeSync( gp++ ) ;
	gDPSetCycleType( gp++, G_CYC_FILL ) ;
	gDPSetRenderMode( gp++, G_RM_NOOP, G_RM_NOOP2 ) ;
	gDPSetCombineMode( gp++, G_CC_SHADE, G_CC_SHADE ) ;
	gDPSetAlphaCompare( gp++, G_AC_NONE ) ;
	gDPSetCombineKey( gp++, G_CK_NONE ) ;
	gDPSetBlendMask( gp++, 0xFFFF ) ;

	/**********************************************************************
		SCALE
	**********************************************************************/
	x2 = SM_X1 ;
	for ( i = 0 ; i < SM_SCALES ; ++i ) {
		x1 = x2 ;
		x2 = SM_X1 + (i+1) * SM_WX / SM_FRAMES ;
		gDPPipeSync( gp++ ) ;
		if ( (i & 1) == 0 ) {
			gDPSetFillColor( gp++, SM_C_SC1 << 16 | SM_C_SC1 ) ;
		} else {
			gDPSetFillColor( gp++, SM_C_SC2 << 16 | SM_C_SC2 ) ;
		}
		gDPFillRectangle( gp++, x1, SM_Y_GCPU-SM_SY, x2, SM_Y_LOOP+SM_WY+SM_SY-1 ) ;
	}

	/***********************************************************************
		GRAPH CPU METER
	***********************************************************************/
	if ( ( i = GcpuTsel - 1 ) == -1 )  i = 2 ;
	tp = & GcpuTime[i] ;
	if ( ( i = SM_CONV( tp->end - tp->start ) ) != 0 ) {
		if ( ( x2 = SM_X1 + i ) > SM_X2 )  x2 = SM_X2 ;
		gDPPipeSync( gp++ ) ;
		gDPSetFillColor( gp++, SM_C_GCPU << 16 | SM_C_GCPU ) ;
		gDPFillRectangle( gp++, SM_X1, SM_Y_GCPU, x2, SM_Y_GCPU+SM_WY-1 ) ;
	}

	if ( x2 < sm_cpu_min )  sm_cpu_min = x2 ;
	else if ( x2 > sm_cpu_max )  sm_cpu_max = x2 ;
	if ( sm_cpu_max < SM_X2 ) gDPFillRectangle( gp++, sm_cpu_max, SM_Y_GCPU, sm_cpu_max+1, SM_Y_GCPU+SM_WY-1 ) ;
	if ( sm_cpu_min > SM_X1 ) {
		gDPPipeSync( gp++ ) ;
		gDPSetFillColor( gp++, SM_C_GCPU0 << 16 | SM_C_GCPU0 ) ;
		gDPFillRectangle( gp++, sm_cpu_min, SM_Y_GCPU, sm_cpu_min+1, SM_Y_GCPU+SM_WY-1 ) ;
	}

	/**********************************************************************
		AUDIO CPU METER
	**********************************************************************/
	if ( ( i = AcpuTsel - 1 ) == -1 )  i = 2 ;
	tp = & AcpuTime[i] ;
	if ( ( i = SM_CONV_A * SM_CONV( tp->end - tp->start ) ) != 0 ) {
		if ( ( x2 = SM_X1 + i ) > SM_X2 )  x2 = SM_X2 ;
		gDPPipeSync( gp++ ) ;
		gDPSetFillColor( gp++, SM_C_ACPU << 16 | SM_C_ACPU ) ;
		gDPFillRectangle( gp++, SM_X1, SM_Y_ACPU, x2, SM_Y_ACPU+SM_WY-1 ) ;
	}

	/***********************************************************************
		GRAPH RSP METER
	***********************************************************************/
	if ( ( i = GrspTsel - 1 ) == -1 )  i = 2 ;
	tp = & GrspTime[i] ;
	if ( ( i = SM_CONV( tp->end - tp->start ) ) != 0 ) {
		if ( ( x2 = SM_X1 + i ) > SM_X2 )  x2 = SM_X2 ;
		gDPPipeSync( gp++ ) ;
		gDPSetFillColor( gp++, SM_C_GRSP << 16 | SM_C_GRSP ) ;
		gDPFillRectangle( gp++, SM_X1, SM_Y_GRSP, x2, SM_Y_GRSP+SM_WY-1 ) ;
	}

	if ( x2 < sm_rsp_min )  sm_rsp_min = x2 ;
	else if ( x2 > sm_rsp_max )  sm_rsp_max = x2 ;
	if ( sm_rsp_max < SM_X2 ) gDPFillRectangle( gp++, sm_rsp_max, SM_Y_GRSP, sm_rsp_max+1, SM_Y_GRSP+SM_WY-1 ) ;
	if ( sm_rsp_min > SM_X1 ) {
		gDPPipeSync( gp++ ) ;
		gDPSetFillColor( gp++, SM_C_GRSP0 << 16 | SM_C_GRSP0 ) ;
		gDPFillRectangle( gp++, sm_rsp_min, SM_Y_GRSP, sm_rsp_min+1, SM_Y_GRSP+SM_WY-1 ) ;
	}

	/**********************************************************************
		AUDIO RSP METER
	**********************************************************************/
	if ( ( i = ArspTsel - 1 ) == -1 )  i = 2 ;
	tp = & ArspTime[i] ;
	if ( ( i = SM_CONV_A * SM_CONV( tp->end - tp->start ) ) != 0 ) {
		if ( ( x2 = SM_X1 + i ) > SM_X2 )  x2 = SM_X2 ;
		gDPPipeSync( gp++ ) ;
		gDPSetFillColor( gp++, SM_C_ARSP << 16 | SM_C_ARSP ) ;
		gDPFillRectangle( gp++, SM_X1, SM_Y_ARSP, x2, SM_Y_ARSP+SM_WY-1 ) ;
	}

	/***********************************************************************
		GRAPH RDP METER
	***********************************************************************/
	if ( ( i = GrdpTsel - 1 ) == -1 )  i = 2 ;
	tp = & GrdpTime[i] ;
	if ( ( i = SM_CONV( tp->end - tp->start ) ) != 0 ) {
		if ( ( x2 = SM_X1 + i ) > SM_X2 )  x2 = SM_X2 ;
		gDPPipeSync( gp++ ) ;
		gDPSetFillColor( gp++, SM_C_GRDP << 16 | SM_C_GRDP ) ;
		gDPFillRectangle( gp++, SM_X1, SM_Y_GRDP, x2, SM_Y_GRDP+SM_WY-1 ) ;
	}

	/***********************************************************************
		LOOP METER
	***********************************************************************/
	if ( ( i = LoopTsel - 1 ) == -1 )  i = 2 ;
	tp = & LoopTime[i] ;
	if ( ( i = SM_CONV( tp->end - tp->start ) ) != 0 ) {
		if ( ( x2 = SM_X1 + i ) > SM_X2 )  x2 = SM_X2 ;
		gDPPipeSync( gp++ ) ;
		gDPSetFillColor( gp++, SM_C_LOOP << 16 | SM_C_LOOP ) ;
		gDPFillRectangle( gp++, SM_X1, SM_Y_LOOP, x2, SM_Y_LOOP+SM_WY-1 ) ;
	}

	if ( x2 < sm_all_min )  sm_all_min = x2 ;
	else if ( x2 > sm_all_max )  sm_all_max = x2 ;
	if ( sm_all_max < SM_X2 ) gDPFillRectangle( gp++, sm_all_max, SM_Y_LOOP, sm_all_max+1, SM_Y_LOOP+SM_WY-1 ) ;
	if ( sm_all_min > SM_X1 ) {
		gDPPipeSync( gp++ ) ;
		gDPSetFillColor( gp++, SM_C_LOOP0 << 16 | SM_C_LOOP0 ) ;
		gDPFillRectangle( gp++, sm_all_min, SM_Y_LOOP, sm_all_min+1, SM_Y_LOOP+SM_WY-1 ) ;
	}

	return ( gp ) ;
}
#endif


/*******************************************************************************
	INCREASE TRIPLE_INDEX
*******************************************************************************/
void inc_triple_index( void )
{
	int	tmp_index ;

	tmp_index	  = old_triple_index ;
	old_triple_index  = triple_index ;
	triple_index	  = next_triple_index ;
	next_triple_index = tmp_index ;

	if( vram_mode == VM_HI ) indexHi ^= 1;
}


/*******************************************************************************
	DECREASE TRIPLE_INDEX
*******************************************************************************/
void dec_triple_index( void )
{
	int	tmp_index ;


	tmp_index	  = next_triple_index ;
	next_triple_index = triple_index ;
	triple_index	  = old_triple_index ;
	old_triple_index  = tmp_index ;
}


/*******************************************************************************
	START GRAPHIC LIST
*******************************************************************************/
void start_graphic_list( void )
{
	gSPSegment( glist_p++, 0, 0x00 ) ;
	gSPSegment( glist_p++, STATIC_SEGMENT, _staticSEGSegmentPhyStart ) ;
	gSPSegment( glist_p++, AUTO_SEGMENT,    osVirtualToPhysical( & automatic_BF ) ) ;
	gSPSegment( glist_p++, DYNAMIC_SEGMENT, osVirtualToPhysical( dynamic_p ) ) ;
	gSPSegment( glist_p++, KN_DYNAMIC_SEGMENT, osVirtualToPhysical( pKnDynamic ) ) ;
	gSPSegment( glist_p++, BANK_SEGMENT, bankSegmentBase );
	gSPSegment( glist_p++, COURSE_SEGMENT, courseSegmentBase );
	gSPSegment( glist_p++, COURSE_COM_SEGMENT, courseComSegmentBase );

	if ( players == 2 ) {
		gSPDisplayList( glist_p++, init_rcp_full_GL ) ;
	} else {
		gSPDisplayList( glist_p++, init_rcp_GL ) ;
	}


	switch ( vram_mode ) {
		case VM_NORMAL:
			gDPPipeSync( glist_p++ ) ;
			gDPSetColorImage( glist_p++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WD, OS_K0_TO_PHYSICAL( fbuffer_t[triple_index] ) ) ;
			break ;
		case VM_SCREEN:
		case VM_SMOKE:
			gSPSegment( glist_p++, SCREEN_SEGMENT,  OS_K0_TO_PHYSICAL( fbuffer_t[3] ) ) ;
			gDPPipeSync( glist_p++ ) ;
			gDPSetColorImage( glist_p++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WD, OS_K0_TO_PHYSICAL( fbuffer_t[3] ) ) ;
			break ;
		case VM_HI:
			gDPPipeSync( glist_p++ ) ;
			gDPSetColorImage( glist_p++, G_IM_FMT_RGBA, G_IM_SIZ_16b, SCREEN_WD_HI, OS_K0_TO_PHYSICAL( pFBufferHi[indexHi] ) ) ;
			break;
	}
}


/*******************************************************************************
	END GRAPHIC LIST
*******************************************************************************/
void end_graphic_list( void )
{
	#if SYS_TIME_SW
	if ( process_meter_fg )  glist_p = make_process_time_glist( glist_p ) ;
	#endif

	gDPFullSync( glist_p++ ) ;
	gSPEndDisplayList( glist_p++ ) ;
}


/*******************************************************************************
	SET TASK LIST
*******************************************************************************/
void SetTaskList( OSTask *tp )
{
	#if RSP_DRAM_SW

	tp->t.type		= M_GFXTASK ;
	tp->t.flags		= 0 ;
	tp->t.ucode_boot	= (u64 *) rspbootTextStart ;
	tp->t.ucode_boot_size	= (u32)rspbootTextEnd - (u32)rspbootTextStart ;
#if SW_KN_3DLX
	tp->t.ucode		= (u64 *) gspF3DLX_fifoTextStart ;
#else
	tp->t.ucode		= (u64 *) gspF3DEX_fifoTextStart ;
#endif
  	tp->t.ucode_size	= SP_UCODE_SIZE ;
#if SW_KN_3DLX
	tp->t.ucode_data	= (u64 *) gspF3DLX_fifoDataStart ;
#else
	tp->t.ucode_data	= (u64 *) gspF3DEX_fifoDataStart ;
#endif
  	tp->t.ucode_data_size	= SP_UCODE_DATA_SIZE ;
  	tp->t.dram_stack	= (u64 *) &dram_stack[0] ;
  	tp->t.dram_stack_size	= SP_DRAM_STACK_SIZE8 ;
	tp->t.output_buff	= (u64 *)( ALIGN16( (u32)rsp_dram_buff ) );
 	tp->t.output_buff_size	= (u64 *)( ALIGN16( (u32)rsp_dram_buff ) ) + (SP_OUT_DRAM_SIZE>>3);
 	tp->t.data_ptr		= (u64 *) dynamic_p->glist ;
  	tp->t.data_size		= (int)( glist_p - dynamic_p->glist ) * sizeof(Gfx) ;
 	tp->t.yield_data_ptr	= datYieldBuffer ;
	tp->t.yield_data_size	= OS_YIELD_DATA_SIZE ;

	#else

	tp->t.type		= M_GFXTASK ;
	tp->t.flags		= 0 ; /*OS_TASK_DP_WAIT*/
	tp->t.ucode_boot	= (u64 *) rspbootTextStart ;
	tp->t.ucode_boot_size	= (u32)rspbootTextEnd - (u32)rspbootTextStart ;
	tp->t.ucode		= (u64 *) gspFast3DTextStart ;
  	tp->t.ucode_size	= SP_UCODE_SIZE ;
	tp->t.ucode_data	= (u64 *) gspFast3DDataStart ;
  	tp->t.ucode_data_size	= SP_UCODE_DATA_SIZE ;
  	tp->t.dram_stack	= (u64 *) &dram_stack[0] ;
  	tp->t.dram_stack_size	= SP_DRAM_STACK_SIZE8 ;
	tp->t.output_buff	= (u64 *) 0x00 ;
	tp->t.output_buff_size	= (u64 *) 0x00 ;
  	tp->t.data_ptr		= (u64 *) dynamic_p->glist ;
  	tp->t.data_size		= (int)( glist_p - dynamic_p->glist ) * sizeof(Gfx) ;
  	tp->t.yield_data_ptr	= datYieldBuffer ;
	tp->t.yield_data_size	= OS_YIELD_DATA_SIZE ;

	#endif
}


/*******************************************************************************
	SET TASK LIST
*******************************************************************************/
void StartTask( OSTask *tp )
{
	Gtask_p = tp ;
	osSendMesg( &MesgQ_X2T_etc, MESG_X2T_GTASKREQ, OS_MESG_NOBLOCK ) ;
}


/*******************************************************************************
	CHANGE DOUBLE BUFFER
*******************************************************************************/
void change_double_buffer( void )
{
	double_index ^= 1 ;
	task_p    = & task_BF[ double_index ];
	dynamic_p = & dynamic_BF[ double_index ] ;
	glist_p   = & (dynamic_p->glist)[0] ;
}


/*******************************************************************************
	GRAPHIC PROCESS
*******************************************************************************/
void GraphProcess( void *arg )
{
	register uint			trans_size;
	Mtxf mtxf_dummy;
	
	#if SYS_TIME_SW
	OSTime		os_time ;
	#endif
	ulong		*vp1, *vp2 ;
	#if  WINDOW_PRINT_SW
	Gfx		*gp1, *gp2 ;
	#endif

//	u32 stat;

//	stat = __osGetFpcCsr();
//	__osSetFpcCsr( stat | FPCSR_EI );
	/***********************************************************************
		SEGMENT COPY
	***********************************************************************/
	_codeSEGSegmentPhyStart    = osVirtualToPhysical(_codeSEGSegmentStart) ;
	_codeSEGSegmentPhyEnd      = osVirtualToPhysical(_codeSEGSegmentEnd) ;
	_loadCodeSEGSegmentPhyStart    = _codeSEGSegmentPhyEnd;
	_loadCodeSEGSegmentPhyEnd      = _loadCodeSEGSegmentPhyStart + (_loadCodeSEGSegmentEnd - _loadCodeSEGSegmentStart);

	_zbufferSEGSegmentPhyStart = osVirtualToPhysical(_zbufferSEGSegmentStart) ;
	_zbufferSEGSegmentPhyEnd   = osVirtualToPhysical(_zbufferSEGSegmentEnd) ;

	_fbufferSEGSegmentPhyStart = osVirtualToPhysical(_fbufferSEGSegmentStart) ;
	_fbufferSEGSegmentPhyEnd   = osVirtualToPhysical(_fbufferSEGSegmentEnd) ;

	_BuffersSegmentPhyStart    = osVirtualToPhysical(_BuffersSegmentStart) ;
	_BuffersSegmentPhyEnd      = osVirtualToPhysical(_BuffersSegmentEnd) ;

#if SW_KN_6M
	_staticSEGSegmentPhyStart  = osVirtualToPhysical((char *)STATIC_ADDR);
#else
	_staticSEGSegmentPhyStart  = ALIGN16(_loadCodeSEGSegmentPhyEnd);
#endif
	_staticSEGSegmentPhyEnd    = _staticSEGSegmentPhyStart + ALIGN16(_staticSEGSegmentEnd-_staticSEGSegmentStart) ;

	_staticGameSEGSegmentPhyStart = _staticSEGSegmentPhyEnd;
	_staticGameSEGSegmentPhyEnd = _staticGameSEGSegmentPhyStart + ALIGN16(_staticGameSEGSegmentEnd-_staticGameSEGSegmentStart);
	_staticLangSEGSegmentPhyStart = _staticGameSEGSegmentPhyEnd;
#if (SW_KN_LANGUAGE == KN_EU)
	if( euLanguage == EL_ENGLISH ) {
		_staticLangSEGSegmentPhyEnd = _staticLangSEGSegmentPhyStart + ALIGN16(_staticEngSEGSegmentEnd-_staticEngSEGSegmentStart);
	}
	else {
		_staticLangSEGSegmentPhyEnd = _staticLangSEGSegmentPhyStart + ALIGN16(_staticGerSEGSegmentEnd-_staticGerSEGSegmentStart);
	}
#else
	_staticLangSEGSegmentPhyEnd = _staticLangSEGSegmentPhyStart;
#endif
	_progBankSEGSegmentPhyStart = osVirtualToPhysical((char *)PROG_BANK);
	_progBankSEGSegmentPhyEnd   = _progBankSEGSegmentPhyStart + (uint)PROG_BANK_SIZE;

	_courseBufferSEGSegmentPhyStart = osVirtualToPhysical((char *)COURSE_BUFFER);
	_courseBufferSEGSegmentPhyEnd   = _courseBufferSEGSegmentPhyStart + (uint)COURSE_BUF_SIZE;

	_courseDTSEGSegmentPhyStart = osVirtualToPhysical((char *)COURSE_BUFFER) + COURSE_DT_OFFSET;
	_courseDTSEGSegmentPhyEnd   = _courseDTSEGSegmentPhyStart + (uint)COURSE_DT_SIZE;

	_bankBufferSEGSegmentPhyStart    = osVirtualToPhysical((char *)BANK_BUFFER);
	_bankBufferSEGSegmentPhyEnd      = _bankBufferSEGSegmentPhyStart + (uint)BANK_BUF_SIZE;

	_autoSEGSegmentPhyStart    = osVirtualToPhysical( &automatic_BF ) ; 
	_autoSEGSegmentPhyEnd      = osVirtualToPhysical( &automatic_BF + 1 ) ; 

	_dynamicSEGSegmentPhyStart = osVirtualToPhysical( dynamic_BF ) ; 
	_dynamicSEGSegmentPhyEnd   = osVirtualToPhysical( dynamic_BF + 2 ) ; 

	_screenSEGSegmentPhyStart = _fbufferSEGSegmentPhyStart ;
	_screenSEGSegmentPhyEnd   = _fbufferSEGSegmentPhyEnd ;

#if (SW_KN_LANGUAGE == KN_EU)
	DRAMFreeSize = (int)( osVirtualToPhysical( (void *)START_GATE_ADDR )
				  - ( _loadCodeSEGSegmentPhyEnd+ALIGN16(_staticSEGSegmentEnd-_staticSEGSegmentStart)
				 + ALIGN16(_staticGameSEGSegmentEnd-_staticGameSEGSegmentStart)
				 + ALIGN16(_staticEngSEGSegmentEnd-_staticEngSEGSegmentStart)));
	DRAMFreeSize2 = (int)( osVirtualToPhysical( (void *)START_GATE_ADDR )
				  - ( _loadCodeSEGSegmentPhyEnd+ALIGN16(_staticSEGSegmentEnd-_staticSEGSegmentStart)
				 + ALIGN16(_staticGameSEGSegmentEnd-_staticGameSEGSegmentStart)
				 + ALIGN16(_staticGerSEGSegmentEnd-_staticGerSEGSegmentStart) ) );
#else
	DRAMFreeSize = (int)( osVirtualToPhysical( (void *)START_GATE_ADDR )
				  - ( _loadCodeSEGSegmentPhyEnd+ALIGN16(_staticSEGSegmentEnd-_staticSEGSegmentStart)
			 + ALIGN16(_staticGameSEGSegmentEnd-_staticGameSEGSegmentStart) ) );
#endif
	#if  WINDOW_PRINT_SW
	WINDOW_PRINT("----------------------------------------------------------------------------\n") ;
	WINDOW_PRINT("             ROM                   CPU                   DRAM\n") ;
	WINDOW_PRINT("[audio    ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)_BuffersSegmentRomStart ,(long)_BuffersSegmentRomEnd
		,(long)_BuffersSegmentStart ,(long)_BuffersSegmentEnd
		,(long)_BuffersSegmentPhyStart ,(long)_BuffersSegmentPhyEnd
	) ;
  	WINDOW_PRINT("[code     ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)_codeSEGSegmentRomStart ,(long)_codeSEGSegmentRomEnd
		,(long)_codeSEGSegmentStart ,(long)_codeSEGSegmentEnd
		,(long)_codeSEGSegmentPhyStart ,(long)_codeSEGSegmentPhyEnd
	) ;
	WINDOW_PRINT("[zbuffer  ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)_zbufferSEGSegmentRomStart ,(long)_zbufferSEGSegmentRomEnd
		,(long)_zbufferSEGSegmentStart ,(long)_zbufferSEGSegmentEnd
		,(long)_zbufferSEGSegmentPhyStart ,(long)_zbufferSEGSegmentPhyEnd
	) ;
	WINDOW_PRINT("[prog     ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)0,(long)0
		,(long)osPhysicalToVirtual(_progBankSEGSegmentPhyStart)
		,(long)osPhysicalToVirtual(_progBankSEGSegmentPhyEnd)
		,(long)_progBankSEGSegmentPhyStart ,(long)_progBankSEGSegmentPhyEnd
	) ;
	WINDOW_PRINT("[course   ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)0,(long)0
		,(long)osPhysicalToVirtual(_courseBufferSEGSegmentPhyStart)
		,(long)osPhysicalToVirtual(_courseBufferSEGSegmentPhyEnd)
		,(long)_courseBufferSEGSegmentPhyStart ,(long)_courseBufferSEGSegmentPhyEnd
	) ;
	WINDOW_PRINT("[bank     ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)0,(long)0
		,(long)osPhysicalToVirtual(_bankBufferSEGSegmentPhyStart)
		,(long)osPhysicalToVirtual(_bankBufferSEGSegmentPhyEnd)
		,(long)_bankBufferSEGSegmentPhyStart ,(long)_bankBufferSEGSegmentPhyEnd
	) ;
	WINDOW_PRINT("[fbuffer  ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)_fbufferSEGSegmentRomStart ,(long)_fbufferSEGSegmentRomEnd
		,(long)_fbufferSEGSegmentStart ,(long)_fbufferSEGSegmentEnd
		,(long)_fbufferSEGSegmentPhyStart ,(long)_fbufferSEGSegmentPhyEnd
	) ;

	WINDOW_PRINT("             ROM                   RCP                   DRAM\n") ;
	WINDOW_PRINT("[static   ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)_staticSEGSegmentRomStart ,(long)_staticSEGSegmentRomEnd
		,(long)_staticSEGSegmentStart ,(long)_staticSEGSegmentEnd
		,(long)_staticSEGSegmentPhyStart ,(long)_staticSEGSegmentPhyEnd
	) ;
	WINDOW_PRINT("[static2  ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)_staticGameSEGSegmentRomStart ,(long)_staticGameSEGSegmentRomEnd
		,(long)_staticGameSEGSegmentStart ,(long)_staticGameSEGSegmentEnd
		,(long)_staticGameSEGSegmentPhyStart ,(long)_staticGameSEGSegmentPhyEnd
	) ;
	WINDOW_PRINT("[automatic]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)_autoSEGSegmentRomStart ,(long)_autoSEGSegmentRomEnd
		,(long)_autoSEGSegmentStart ,(long)_autoSEGSegmentEnd
		,(long)_autoSEGSegmentPhyStart ,(long)_autoSEGSegmentPhyEnd
	) ;
	WINDOW_PRINT("[dynamic  ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)_dynamicSEGSegmentRomStart ,(long)_dynamicSEGSegmentRomEnd
		,(long)_dynamicSEGSegmentStart ,(long)_dynamicSEGSegmentEnd
		,(long)_dynamicSEGSegmentPhyStart ,(long)_dynamicSEGSegmentPhyEnd
	) ;
	WINDOW_PRINT("[screen   ]  %8X - %8X , %8X - %8X , %8X - %8X\n"
		,(long)_screenSEGSegmentRomStart ,(long)_screenSEGSegmentRomEnd
		,(long)_screenSEGSegmentStart ,(long)_screenSEGSegmentEnd
		,(long)_screenSEGSegmentPhyStart ,(long)_screenSEGSegmentPhyEnd
	) ;
	WINDOW_PRINT("----------------------------------------------------------------------------\n") ;
	osSyncPrintf( "--- 6[MB] --------------------\n" );
	osSyncPrintf( "DRAM Free Size ( after code ) = 0x%X ( %d[KB] )\n",
				  ( osVirtualToPhysical( (void *)START_GATE_ADDR ) - _loadCodeSEGSegmentPhyEnd ),
				  (int)( osVirtualToPhysical( (void *)START_GATE_ADDR )
						 - _loadCodeSEGSegmentPhyEnd ) / 1024 );
	osSyncPrintf( "DRAM Free Size ( after static ) = 0x%X ( %d[KB] )\n",
				  ( osVirtualToPhysical( (void *)CAMERA_BUFFER ) - _staticLangSEGSegmentPhyEnd ),
				  (int)( osVirtualToPhysical( (void *)CAMERA_BUFFER ) - _staticLangSEGSegmentPhyEnd ) / 1024 );

	osSyncPrintf( "--- 4[MB] --------------------\n" );
	osSyncPrintf( "DRAM Free Size ( ROM ) = 0x%X ( %d[KB] )\n",
				  DRAMFreeSize + DRAM_SIZE_DIFFERENCE, (DRAMFreeSize + DRAM_SIZE_DIFFERENCE) / 1024 );
#if (SW_KN_LANGUAGE == KN_EU)
	osSyncPrintf( "DRAM Free Size2( ROM ) = 0x%X ( %d[KB] )\n",
				  DRAMFreeSize2 + DRAM_SIZE_DIFFERENCE, (DRAMFreeSize2 + DRAM_SIZE_DIFFERENCE) / 1024 );
#endif

	WINDOW_PRINT("%X - %X\n",(u32)rsp_dram_buff,(u32)&rsp_dram_buff[SP_OUT_DRAM_SIZE>>3]);
	#endif

	/* Load Code */
	transCodeSeg();
	
	/* STATIC COMMON */
	knRomCopy( (uchar *)_staticSEGSegmentRomStart, (uchar *)_staticSEGSegmentPhyStart,
			   (uint)ALIGN16(_staticSEGSegmentRomEnd - _staticSEGSegmentRomStart) );
	knRomCopy( (uchar *)_staticGameSEGSegmentRomStart, (uchar *)_staticGameSEGSegmentPhyStart,
			   (uint)ALIGN16(_staticGameSEGSegmentRomEnd - _staticGameSEGSegmentRomStart) );
#if (SW_KN_LANGUAGE == KN_EU)
//	knRomCopy( (uchar *)_staticLangSEGSegmentRomStart, (uchar *)_staticLangSEGSegmentPhyStart,
//			   (uint)ALIGN16(_staticLangSEGSegmentRomEnd - _staticLangSEGSegmentRomStart) );
#endif

	/***********************************************************************
		INITIATE MAIN PROCESS
	***********************************************************************/
	double_index =	0 ;				/* ZERO VARIABLE */

	old_triple_index  = 2 ;		/* TRIPLE INDEX */
	triple_index	  = 0 ;
	next_triple_index = 1 ;

	init_sin_table() ;		/* SIN TABLE */

	make_ROTmatrix( &automatic_BF.e_MT, &mtxf_dummy,
			0.0f, 0.0f, 1.0f,
			0.0f, 1.0f, 0.0f,
			0.0f, 0.0f, 0.0f ) ;

	init_rand( osGetTime() ) ;	/* RANDOM */
	osSetTime( 0 ) ;

	osViSwapBuffer( fbuffer_t[ triple_index ] ) ;

	change_double_buffer() ;	/* FIRST RSP TASK */
	inc_triple_index() ;
	start_graphic_list() ;
	end_graphic_list() ;
	SetTaskList( task_p ) ;
	StartTask( task_p ) ;

	/***********************************************************************
		LOOP
	***********************************************************************/
	while (1) {

	init_main_process() ;


	/***********************************************************************
		LOOP MAIN
	***********************************************************************/
	for ( main_count = 0 ; ; ++main_count ) {

		/***************************************************************
			WAIT FRAME
		***************************************************************/
		(void)osRecvMesg( &MesgQ_T2G_timing, MesgB_FRM_dummy, OS_MESG_BLOCK ) ;

		#if SYS_TIME_SW
		if ( main_count < 3 ) {
			sm_cpu_min = sm_rsp_min = sm_all_min = DISPLAY_X2 ;
			sm_cpu_max = sm_rsp_max = sm_all_max = DISPLAY_X1 ;
		}
		os_time = osGetTime() ;
		LoopTime_p->end = os_time ;
		if ( ++ LoopTsel == 3 )  LoopTsel = 0 ;
		LoopTime_p = & LoopTime[ LoopTsel ] ;
		LoopTime_p->start = os_time ;
		#endif


		/***************************************************************
			START CPU WORK
		***************************************************************/
		#if SYS_TIME_SW
		if ( ++ GcpuTsel == 3 )  GcpuTsel = 0 ;
		GcpuTime_p = & GcpuTime[ GcpuTsel ] ;
		GcpuTime_p->start = os_time ;
		#endif

		#if SOUND_SW
		StartSound() ;
		#endif


		/***************************************************************
			MAIN WORKING
		***************************************************************/
		change_double_buffer() ;

		move_main_process() ;


		/***************************************************************
			MAKE GRAPHIC LIST
		***************************************************************/
		#if  WINDOW_PRINT_SW
		gp1 = glist_p ;
		#endif

		inc_triple_index() ;
		start_graphic_list() ;

		glist_p = make_main_process_glist( glist_p ) ;

		end_graphic_list() ;

		#if  WINDOW_PRINT_SW
		gp2 = glist_p ;
		glistNum = (int)(gp2-gp1);
		if( glistNum >= glistMaxNum ) {
			glistMaxNum = glistNum;
//			WINDOW_PRINT("DisplayList Max Number = %d\n", glistMaxNum );
		}
//		WINDOW_PRINT("glist number = %d \r", glistNum );
		
		if( (uint)(gp2-gp1) >= (uint)GFX_MAX ) {
			WINDOW_PRINT( "glist buffer over!! ( %d / %d )\n", glistNum, GFX_MAX );
		}
		#endif

		/***************************************************************
			END CPU WORK
		***************************************************************/
		#if SYS_TIME_SW
		GcpuTime_p->end = osGetTime() ;
		#endif


		/***************************************************************
			END OLD RCP WORK
		***************************************************************/
		#if SYS_TIME_SW
		if ( ++ GrdpTsel == 3 )  GrdpTsel = 0 ;
		GrdpTime_p = & GrdpTime[ GrdpTsel ] ;
		GrdpTime_p->start = osGetTime() ;
		#endif

		(void)osRecvMesg( &MesgQ_T2G_rspdone, MesgB_RSP_dummy, OS_MESG_BLOCK ) ;
		(void)osRecvMesg( &MesgQ_T2G_rdpdone, MesgB_RDP_dummy, OS_MESG_BLOCK ) ;
		while ( ( osDpGetStatus() & (DPC_STATUS_TMEM_BUSY|DPC_STATUS_PIPE_BUSY|DPC_STATUS_CMD_BUSY|DPC_STATUS_DMA_BUSY) ) != 0 ) ;

		/* --- £Ä£Í£ÁÅ¾Á÷ --- */
		if( gameModeOld == GM_CPACK2NEXT && gameModeChangeFlag ) 	{
			knRomCopy( (uchar *)_staticGameSEGSegmentRomStart, (uchar *)_staticGameSEGSegmentPhyStart,
			   (uint)ALIGN16(_staticGameSEGSegmentRomEnd - _staticGameSEGSegmentRomStart) );
		}
		#if (SW_KN_LANGUAGE == KN_EU)
		if( gameModeOld == GM_TITLE2NEXT && gameModeChangeFlag && euLanguageMenuOn ) {
			if( euLanguage == EL_ENGLISH ) {
				knRomCopy( (uchar *)_staticEngSEGSegmentRomStart, (uchar *)_staticLangSEGSegmentPhyStart,
				   (uint)ALIGN16(_staticEngSEGSegmentRomEnd - _staticEngSEGSegmentRomStart) );
			}
			else {
				knRomCopy( (uchar *)_staticGerSEGSegmentRomStart, (uchar *)_staticLangSEGSegmentPhyStart,
				   (uint)ALIGN16(_staticGerSEGSegmentRomEnd - _staticGerSEGSegmentRomStart) );
			}
		}
		#endif
		if( gameModeChangeFlag ) transBankSegData();
		if( gameModeChangeFlag ) transProgram();
		autoTransData();

		SetTaskList( task_p ) ;		

		#if SYS_TIME_SW
		GrdpTime_p->end = osGetTime() ;
		#endif


		if ( vram_mode == VM_SMOKE ) {
			vp1 = (u32 *)fbuffer_t[old_triple_index] + SCREEN_WD * SCREEN_HT / 2 - 1 ;
			for (
			vp2 = (u32 *)fbuffer_t[3] + SCREEN_WD * SCREEN_HT / 2 - 1 ;
			(u32)vp2 >= (u32)fbuffer_t[3] ;
			-- vp2, --vp1
			) {
				*vp2 = *vp1 ;
			}
		}

		/***************************************************************
			START NEW RCP WORK
		***************************************************************/
		StartTask( task_p ) ;


		/***************************************************************
			SWAP FRAME BUFFER
		***************************************************************/
//		changeViMode();
		if( vram_mode == VM_HI ) {
			if( game_mode == GM_CPACK && gameModeChangeFlag ) {
#if (SW_KN_LANGUAGE == KN_JP)
			    osViSetMode( &osViModeTable[OS_VI_NTSC_HPF1] );
#elif (SW_KN_LANGUAGE == KN_US || SW_KN_LANGAGE == ZH)
				if( osTvType == 1 ) osViSetMode( &osViModeTable[OS_VI_NTSC_HPF1] );
			    else osViSetMode( &osViModeTable[OS_VI_PAL_HPF1] );	/* Í×£Í£Ð£Á£Ì¥Ñ¥Ã¥Á */
#elif (SW_KN_LANGUAGE == KN_EU)
				setOriginalViMode( 1 );
#endif
				osViSetSpecialFeatures(	OS_VI_GAMMA_OFF | OS_VI_GAMMA_DITHER_ON );
			}
			osViSwapBuffer( pFBufferHi[indexHi] ) ;
		}
		else {
		    if( gameModeOld == GM_CPACK2NEXT && gameModeChangeFlag ) {
#if (SW_KN_LANGUAGE == KN_JP)
				osViSetMode( &osViModeTable[OS_VI_NTSC_LAN1] );
#elif (SW_KN_LANGUAGE == KN_US || SW_KN_LANGAGE == ZH)
				if( osTvType == 1 ) osViSetMode( &osViModeTable[OS_VI_NTSC_LAN1] );
			    else osViSetMode( &osViModeTable[OS_VI_PAL_LAN1] );	/* Í×£Í£Ð£Á£Ì¥Ñ¥Ã¥Á */
#elif (SW_KN_LANGUAGE == KN_EU)
				setOriginalViMode( 0 );
#endif
				osViSetSpecialFeatures(
					OS_VI_GAMMA_OFF |
					OS_VI_GAMMA_DITHER_ON |
					OS_VI_DIVOT_OFF |
					OS_VI_DITHER_FILTER_ON
				);
			}
			osViSwapBuffer( fbuffer_t[ old_triple_index ] ) ;
		}

	}
	}
}

