End of memory layout (incomplete yet)


0x27C0000 : SNES RAM (128 ko)
0x27E0000 : ???? (0xD000 o)
0x27ED000 : ???? (0xF00 o)
0x27EDF00 : APU SPC infos (256o)

0x27EE000 : APU RAM (64ko)
0x27FE000 : APU SPC infos (256o)
0x27FE100 : ???  (0x900)
0x27FE200 : ....

0x27FF000 : IPC (???)

0x27FFFE0 : SNEmul/APU Debug (8o)
0x27FFFEC : SNEmul/APU CMD (4o)
0x27FFFF0 : SNEmul/APU ANS (4o)
0x27FFFF8 : APU->SNES ports
0x27FFFFC : SNES->APU ports
0x2800000 : ------------- End of RAM

#define ROM_PAGING_SIZE	(1*1024*1024)
#define	PAGE_SIZE		8192
#define PAGE_OFFSET		0
/*#define	PAGE_SIZE		65536
#define PAGE_OFFSET		3*/

uchar	*ROM_paging = NULL;
uint16	*ROM_paging_offs = NULL;
int		ROM_paging_cur = 0;

void	mem_clear_paging()
{
	if (ROM_paging)
	{
		free(ROM_paging);
		free(ROM_paging_offs);
		ROM_paging = NULL;
		ROM_paging_offs = NULL;
	}
}

void	mem_init_paging()
{
	if (ROM_paging)
		mem_clear_paging();
		
	ROM_paging = malloc(ROM_PAGING_SIZE);
	if (!ROM_paging)
	{
		iprintf("Not enough memory for ROM paging.\n");
		while(1);
	}	
	ROM_paging_offs = malloc(ROM_PAGING_SIZE/PAGE_SIZE);
	if (!ROM_paging_offs)
	{
		iprintf("Not enough memory for ROM paging (2).\n");
		while(1);
	}	
	memset(ROM_paging_offs, 0xFF, ROM_PAGING_SIZE/PAGE_SIZE);
	ROM_paging_cur = 0;
}

void	mem_setCacheBlock(int block)
{
	block <<= PAGE_OFFSET;
	for (i = 0; i < PAGE_SIZE/8192; i++, block++)
	{

		if ((block & 7) >= 4)
		{
			MAP[block] = MAP_RELOAD;
			MAP[block+0x400] = MAP_RELOAD;		
		}
		if (SNES.BlockIsROM[block+0x200])	
			MAP[block+0x200] = MAP_RELOAD;
		MAP[block+0x600] = MAP_RELOAD;
	}	
}

void	mem_removeCacheBlock(int block)
{
	block <<= PAGE_OFFSET;
	for (i = 0; i < PAGE_SIZE/8192; i++, block++)
	{

		if ((block & 7) >= 4)
		{
			MAP[block] = MAP_RELOAD;
			MAP[block+0x400] = MAP_RELOAD;	
			i++:	
		}
		if (SNES.BlockIsROM[block+0x200])	
			MAP[block+0x200] = MAP_RELOAD;
		MAP[block+0x600] = MAP_RELOAD;
	}	
}

uint8 *mem_checkReload(int block)
{
	int i;
	uchar *ptr;
	int	ret;
	
	FS_flog("==> %d\n", block); 
	
	if (!CFG.LargeROM)
		return NULL;
			
	i = (block & 0x1FF) >> PAGE_OFFSET; 
//	LOG("checkReload %x %x\r\n", block, i);
	
	if (ROM_paging_offs[ROM_paging_cur] != 0xFFFF)
	{
//		LOG("remove %d\r\n", ROM_paging_offs[ROM_paging_cur]);
		mem_removeCacheBlock(ROM_paging_offs[ROM_paging_cur]);
	}
	
	ROM_paging_offs[ROM_paging_cur] = i;
	ptr = ROM_paging+(ROM_paging_cur*PAGE_SIZE);
	
//	LOG("@%d(%d) => blk %d\n", i*PAGE_SIZE, SNES.ROMHeader+i*PAGE_SIZE, ROM_paging_cur);
	ret = FS_loadROMPage(ptr, SNES.ROMHeader+i*PAGE_SIZE, PAGE_SIZE);
//	LOG("ret = %d %x %x %x %x\n", ret, ptr[0], ptr[1], ptr[2], ptr[3]);
	
	
	mem_setCacheBlock(i, ptr);
	
	ROM_paging_cur++;
	if (ROM_paging_cur >= ROM_PAGING_SIZE/PAGE_SIZE)
		ROM_paging_cur = 0;
				
	ptr += (block & ((1 << PAGE_OFFSET)-1)) * 8192; 
	FS_flog("%d %p\n", block, ptr-(block << 13)); 
	return ptr-(block << 13);
}


#define ROM_PAGING_SIZE	(1*1024*1024)
#define	PAGE_SIZE		8192

uchar	*ROM_paging = NULL;
uint16	*ROM_paging_offs = NULL;
int		ROM_paging_cur = 0;

void	mem_clear_paging()
{
	if (ROM_paging)
	{
		free(ROM_paging);
		free(ROM_paging_offs);
		ROM_paging = NULL;
		ROM_paging_offs = NULL;
	}
}

void	mem_init_paging()
{
	if (ROM_paging)
		mem_clear_paging();
		
	ROM_paging = malloc(ROM_PAGING_SIZE);
	if (!ROM_paging)
	{
		iprintf("Not enough memory for ROM paging.\n");
		while(1);
	}	
	ROM_paging_offs = malloc((ROM_PAGING_SIZE/PAGE_SIZE)*2);
	if (!ROM_paging_offs)
	{
		iprintf("Not enough memory for ROM paging (2).\n");
		while(1);
	}	
	memset(ROM_paging_offs, 0xFF, (ROM_PAGING_SIZE/PAGE_SIZE)*2);
	ROM_paging_cur = 0;
}

void	mem_setCacheBlock(int block, int nb, char *ptr)
{
	int	i;
	for (i = 0; i < nb; block++, i++)
	{
		if ((block & 7) >= 4)
		{
			MAP[block] = ptr;
			MAP[block+0x400] = ptr;		
		}
		if (SNES.BlockIsROM[block+0x200])	
			MAP[block+0x200] = ptr;
		MAP[block+0x600] = ptr;
	}
}

void	mem_removeCacheBlock(int block)
{
	if ((block & 7) >= 4)
	{
		MAP[block] = MAP_RELOAD;
		MAP[block+0x400] = MAP_RELOAD;	
	}
	if (SNES.BlockIsROM[block+0x200])	
		MAP[block+0x200] = MAP_RELOAD;
	MAP[block+0x600] = MAP_RELOAD;	
}

uint8 *mem_checkReload(int block)
{
	int i;
	uchar *ptr;
	int	ret;
	
	FS_flog("==> %d\n", block); 
	
#if 0	
	if (/*!CFG.LargeROM && */MAP[block] != NULL)
		return NULL;
#endif
			
	i = block & 0x1FF; 
//	LOG("checkReload %x %x\r\n", block, i);
	
	if (ROM_paging_offs[ROM_paging_cur] != 0xFFFF)
	{
		// FIXME : should check if the block
		// is used by some part of CPU (MemCache, PCptr...)
//		LOG("remove %d\r\n", ROM_paging_offs[ROM_paging_cur]);
		mem_removeCacheBlock(ROM_paging_offs[ROM_paging_cur]);
	}
	
	ROM_paging_offs[ROM_paging_cur] = i;
	ptr = ROM_paging+(ROM_paging_cur*PAGE_SIZE);
	
//	LOG("@%d(%d) => blk %d\n", i*PAGE_SIZE, SNES.ROMHeader+i*PAGE_SIZE, ROM_paging_cur);
	ret = FS_loadROMPage(ptr, SNES.ROMHeader+i*PAGE_SIZE, PAGE_SIZE);
//	LOG("ret = %d %x %x %x %x\n", ret, ptr[0], ptr[1], ptr[2], ptr[3]);
	
	
	mem_setCacheBlock(i, 1, ptr-(block << 13));
	
	ROM_paging_cur += 1;
	if (ROM_paging_cur >= ROM_PAGING_SIZE/PAGE_SIZE)
		ROM_paging_cur = 0;
				 
	FS_flog("%d %p\n", block, ptr-(block << 13)); 
	return ptr-(block << 13);
}

uint8 *mem_checkReloadPC(int block)
{
	uchar *ptr;
	
	// Allocate 3 contiguos block (24kb) between new PC
	// So there should be less problem with code execution
	 
#if 0	
	for (i = 0; i < ROM_PAGING_SIZE/PAGE_SIZE: i++)
	{
		if (ROM_paging_offs[i] == block ||
			ROM_paging_offs[i] == block-1 ||
			ROM_paging_offs[i] == block+1)))
			ROM_paging_offs[i] = 0xFFFF;
	}
#endif	
	
	mem_checkReload(block-1);
	ptr = mem_checkReload(block);
	mem_checkReload(block+1);

	return ptr;
}
#else

