

#include "extmem.h"
#include "ui_temp.h"
#include "hiscore.h"
#include "driver.h"
#include "fileio.h"

#define DEBUG 0

//static int flagmode;

/* helper macros */
#define HANDLER_IS_RAM(h)		((FPTR)(h) == STATIC_RAM)
#define HANDLER_IS_ROM(h)		((FPTR)(h) == STATIC_ROM)
#define HANDLER_IS_RAMROM(h)	((FPTR)(h) == STATIC_RAMROM)
#define HANDLER_IS_NOP(h)		((FPTR)(h) == STATIC_NOP)
#define HANDLER_IS_BANK(h)		((FPTR)(h) >= STATIC_BANK1 && (FPTR)(h) <= STATIC_BANKMAX)
#define HANDLER_IS_STATIC(h)	((FPTR)(h) < STATIC_COUNT)

#define HANDLER_TO_BANK(h)		((FPTR)(h))
#define BANK_TO_HANDLER(b)		((void *)(b))


static struct ExtMemory	GameRam_KailleraStateSave[MAX_CPU][MAX_EXT_MEMORY];
static struct ExtMemory	GameRam_SyncCheck[MAX_CPU][MAX_EXT_MEMORY];

static unsigned int nTotalGameRamSize_KailleraStateSave;
static unsigned int nTotalGameRamSize_SyncCheck;
static BOOL			bGameRamSearch_KailleraStateSave = FALSE;
static BOOL			bGameRamSearch_SyncCheck = FALSE;

//static unsigned int GameRamOverSize = 0;


#include "zlib.h" /*//kt */

static void reset_table(struct ExtMemory * table)
{
	struct ExtMemory	* ext;

	for(ext = table; ext->data; ext++)
		ext->data = 0;

	memset(table, 0, sizeof(struct ExtMemory) * MAX_EXT_MEMORY);
}

void init_game_ram_serch(struct ExtMemory *GameRam, unsigned int nGameRamOffset, unsigned int *pTotalGameRamSize, int use)
{
	int	count = 0;
	int i;
	int cpu;

#if DEBUG
	{
		FILE *fp;
		
		
		fp = fopen("a.txt", "w");
		fprintf(fp,"%s\n", Machine->gamedrv->name);
		fclose(fp);
	}
#endif

	(*pTotalGameRamSize) = 0;

	for (i=0; i<MAX_CPU; i++)
		reset_table((struct ExtMemory*)((int)GameRam + i*nGameRamOffset));

	for (cpu=0; cpu<cpu_gettotalcpu(); cpu++)
	{
	const struct Memory_WriteAddress	* mwa = (struct Memory_WriteAddress *)Machine->drv->cpu[cpu].memory_write;
	struct ExtMemory					* ext_gr = (struct ExtMemory*)((int)GameRam + cpu*nGameRamOffset);
	int									region = REGION_CPU1 + cpu;

	if ( Machine->drv->cpu[cpu].cpu_type &&
		!(Machine->drv->cpu[cpu].cpu_type & CPU_AUDIO_CPU))
	while(!IS_MEMPORT_END(mwa))
	{
		if(!IS_MEMPORT_MARKER(mwa))
		{
			mem_write_handler	handler = mwa->handler;
			//UINT32			handlerAddress = (UINT32)handler;
			//const int			handlerStatic = (const int)handler;
			char				source[MAX_PATH];
			int					enable;

			strcpy( source, Machine->gamedrv->source_file);
			StrCharReplacement( source, '\\', '/');

			enable = 1;
			if (HANDLER_IS_ROM(handler) || HANDLER_IS_NOP(handler) || !HANDLER_IS_STATIC(handler))
				enable = 0;

			if (cpu == 1)	enable = 0;

			if (!strcmp(source, "src/drivers/twin16.c"))
			{
				if (cpu != 1)	enable = 0; else enable = 1;
				if (mwa->start < 0x060000 || mwa->start > 0x063fff)	enable = 0;
				//use = 1;
			}

			if (!strcmp(source, "src/drivers/taito_f3.c"))
			{
				if (mwa->start < 0x400000 || mwa->start > 0x43ffff)	enable = 0;
				//use = 1;
			}

			if (!strcmp(source, "src/drivers/cps1.c"))
			{
				//if (cpu != 0)	enable = 0;
				if (mwa->start < 0xff0000 || mwa->start > 0xffffff)	enable = 0;
				//use = 1;
			}
			if (!strcmp(source, "src/drivers/cps2.c"))
			{
				if (cpu != 0)	enable = 0;
				if (mwa->start < 0xff0000 || mwa->start > 0xff0000)	enable = 0;
				//use = 1;
			}
			if (!strcmp(source, "src/drivers/cps3.c"))
			{
				if (mwa->start < 0x02000000 || mwa->start > 0x0207ffff)	enable = 0;
			}

			if (!strcmp(source, "src/drivers/cave.c") ||
				!strcmp(source, "src/drivers/cave_fix.c"))
			{
				//use = 1;
			}

			if (!strcmp(source, "src/drivers/neogeo.c") ||
				!strcmp(source, "src/drivers/neogeo_new.c"))
			{	//		{ 0x100000, 0x10ffff, MWA16_BANK1 },	// WORK RAM
				//if (mwa->start < 0x100000 || mwa->start > 0x10ffff)	enable = 0;
				//use = 1;
			}

			if (!strcmp(source, "src/drivers/gradius3.c"))
			{
				use = 1;
			}
#if DEBUG
			{
				FILE *fp;
				
				fp = fopen("a.txt", "a");
				fprintf(fp,"{%08X,%08X}%d,%08X,%08X,%d,%d\n", mwa->start, mwa->end, region, (mwa->end - mwa->start) + 1,mwa->handler,enable,use);
				fclose(fp);
			}
#endif

			if (enable && use)
			{
				unsigned int size = (mwa->end - mwa->start) + 1;

				{
				ext_gr->data = (UINT8 *)1;	// used
				if(HANDLER_IS_BANK(handler))
				{
					ext_gr->data = (UINT8 *)2;	//bank
					//usrintf_showmessage( "use BankRAM" );	// debug message
				}

				ext_gr->start =		mwa->start;
				ext_gr->end =		mwa->end;
				ext_gr->region =	region;
				ext_gr++;

				(*pTotalGameRamSize) += size;
				}
			}

			count++;
		}

		mwa++;
	}
	}
}

void end_game_ram_serch(void)
{
	int i;
	if(bGameRamSearch_KailleraStateSave == TRUE)
	{
		for (i=0; i<MAX_CPU; i++)
			reset_table(&GameRam_KailleraStateSave[i][0]);
	}
	if(bGameRamSearch_SyncCheck == TRUE)
	{
		for (i=0; i<MAX_CPU; i++)
			reset_table(&GameRam_SyncCheck[i][0]);
	}

	bGameRamSearch_SyncCheck			= FALSE;
	bGameRamSearch_KailleraStateSave	= FALSE;
	nTotalGameRamSize_SyncCheck			= 0;
	nTotalGameRamSize_KailleraStateSave	= 0;


	memset (GameRam_SyncCheck, 0, sizeof(GameRam_SyncCheck));
	memset (GameRam_KailleraStateSave, 0, sizeof(GameRam_KailleraStateSave));
}

unsigned long game_ram_serch_crc32_(unsigned long crc)
{
	int cpu;
	//unsigned int pos = 0;
	if (bGameRamSearch_SyncCheck == FALSE)
		init_game_ram_serch(&GameRam_SyncCheck[0][0], (unsigned int)&GameRam_SyncCheck[1][0] - (unsigned int)&GameRam_SyncCheck[0][0],&nTotalGameRamSize_SyncCheck, 1);
	bGameRamSearch_SyncCheck = TRUE;

	if (nTotalGameRamSize_SyncCheck == 0) return crc;

	for (cpu=0; cpu<cpu_gettotalcpu(); cpu++)
	{
		if ( Machine->drv->cpu[cpu].cpu_type &&
			!(Machine->drv->cpu[cpu].cpu_type & CPU_AUDIO_CPU))
		{
			struct ExtMemory	* ext;
			for(ext = &GameRam_SyncCheck[cpu][0]; ext->data; ext++)
			{
				const unsigned int len = ext->end - ext->start + 1;
				unsigned char *p;
				//int i;
				if ((int)ext->data == 2)	//bank
				{
					p = dynamic_bank_find_base(cpu, ext->start);
					if (p)
						crc = crc32(crc, p, len);
				} else
				{
					p = memory_find_base(cpu, ext->start);
					if (p)
						crc = crc32(crc, p, len);
				}
			}
		}
	}
	return crc;
}

unsigned long game_ram_serch_crc32_kaillera_state_save(unsigned long crc)
{
	int cpu;
	//unsigned int pos = 0;
	if (bGameRamSearch_KailleraStateSave == FALSE)
		init_game_ram_serch(&GameRam_KailleraStateSave[0][0], (unsigned int)&GameRam_KailleraStateSave[1][0] - (unsigned int)&GameRam_KailleraStateSave[0][0], &nTotalGameRamSize_KailleraStateSave, 0);
	bGameRamSearch_KailleraStateSave = TRUE;

	if (nTotalGameRamSize_KailleraStateSave == 0) return crc;

	for (cpu=0; cpu<cpu_gettotalcpu(); cpu++)
	{
		if ( Machine->drv->cpu[cpu].cpu_type &&
			!(Machine->drv->cpu[cpu].cpu_type & CPU_AUDIO_CPU))
		{
			struct ExtMemory	* ext;
			for(ext = &GameRam_KailleraStateSave[cpu][0]; ext->data; ext++)
			{
				unsigned char *p = memory_find_base(cpu, ext->start);
				const unsigned int len = ext->end - ext->start + 1;
				crc = crc32(crc, p, len);
			}
		}
	}
	return crc;
}
