vbagx/source/vmmem.cpp

443 lines
8.7 KiB
C++
Raw Permalink Normal View History

2008-09-14 22:40:26 +02:00
/****************************************************************************
2008-09-17 04:27:55 +02:00
* Visual Boy Advance GX
*
* Tantric September 2008
*
* vmmem.cpp
*
* GameBoy Advance Virtual Memory Paging
***************************************************************************/
2008-09-14 22:40:26 +02:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <fat.h>
#include <sys/dir.h>
2010-03-22 00:49:59 +01:00
#include "vbagx.h"
2008-09-26 08:23:00 +02:00
#include "fileop.h"
2009-04-08 09:08:12 +02:00
#include "menu.h"
#include "filebrowser.h"
#include "gcunzip.h"
2010-03-22 00:49:59 +01:00
#include "vba/gba/GBA.h"
#include "vba/gba/Globals.h"
#include "vba/Util.h"
#include "vba/common/Port.h"
2008-09-14 22:40:26 +02:00
#define MEM_BAD 0xff
#define MEM_VM 0x01
#define MEM_UN 0x80
2008-10-27 05:31:59 +01:00
int GBAROMSize = 0;
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
#ifdef USE_VM
/** Setup VM to use small 16kb windows **/
#define VMSHIFTBITS 14
#define VMSHIFTMASK 0x3FFF
#define MAXGBAROM ( 32 * 1024 * 1024 )
#define MAXROM (4 * 1024 * 1024)
#define MAXVMPAGE ( MAXGBAROM >> VMSHIFTBITS )
#define MAXVMMASK ( ( MAXROM >> VMSHIFTBITS ) - 1 )
typedef struct
{
char *pageptr;
int pagetype;
int pageno;
}
VMPAGE;
static VMPAGE vmpage[MAXVMPAGE];
static int vmpageno = 0;
static FILE* romfile = NULL;
static char *rombase = NULL;
#endif
2008-09-14 22:40:26 +02:00
extern void CPUUpdateRenderBuffers(bool force);
2008-09-14 22:40:26 +02:00
/****************************************************************************
2008-10-18 21:27:43 +02:00
* VMClose
2008-09-14 22:40:26 +02:00
****************************************************************************/
2008-10-18 21:27:43 +02:00
void VMClose()
2008-09-14 22:40:26 +02:00
{
2008-10-18 21:27:43 +02:00
if(vram != NULL)
{
free(vram);
vram = NULL;
}
if(paletteRAM != NULL)
{
free(paletteRAM);
paletteRAM = NULL;
}
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
if(internalRAM != NULL)
{
free(internalRAM);
internalRAM = NULL;
}
if(workRAM != NULL)
{
free(workRAM);
workRAM = NULL;
}
if(bios != NULL)
{
free(bios);
bios = NULL;
}
if(pix != NULL)
{
free(pix);
pix = NULL;
}
if(oam != NULL)
{
free(oam);
oam = NULL;
}
if(ioMem != NULL)
{
free(ioMem);
ioMem = NULL;
}
#ifdef USE_VM
if (rombase != NULL)
{
2008-10-18 21:27:43 +02:00
free(rombase);
rombase = NULL;
}
2008-10-18 21:27:43 +02:00
#endif
}
2008-09-14 22:40:26 +02:00
/****************************************************************************
2008-10-18 21:27:43 +02:00
* VMAllocGBA
*
* Allocate the memory required for GBA.
2008-09-14 22:40:26 +02:00
****************************************************************************/
2008-10-18 21:27:43 +02:00
static void VMAllocGBA( void )
2008-09-14 22:40:26 +02:00
{
2008-10-18 21:27:43 +02:00
workRAM = (u8 *)calloc(1, 0x40000);
bios = (u8 *)calloc(1,0x4000);
internalRAM = (u8 *)calloc(1,0x8000);
paletteRAM = (u8 *)calloc(1,0x400);
vram = (u8 *)calloc(1, 0x20000);
oam = (u8 *)calloc(1, 0x400);
pix = (u8 *)calloc(1, 4 * 241 * 162);
ioMem = (u8 *)calloc(1, 0x400);
if(workRAM == NULL || bios == NULL || internalRAM == NULL ||
paletteRAM == NULL || vram == NULL || oam == NULL ||
pix == NULL || ioMem == NULL)
{
2009-04-08 09:08:12 +02:00
ErrorPrompt("Out of memory!");
2008-10-18 21:27:43 +02:00
VMClose();
}
2008-09-14 22:40:26 +02:00
}
2008-10-18 21:27:43 +02:00
#ifndef USE_VM
2008-09-14 22:40:26 +02:00
/****************************************************************************
* VMCPULoadROM
*
* MEM2 version of GBA CPULoadROM
****************************************************************************/
2009-10-02 00:42:02 +02:00
bool VMCPULoadROM()
2008-09-26 08:23:00 +02:00
{
VMClose();
VMAllocGBA();
GBAROMSize = 0;
2008-11-12 08:53:25 +01:00
if(!inSz)
2008-09-26 08:23:00 +02:00
{
2008-11-12 08:53:25 +01:00
char filepath[1024];
2009-10-02 00:42:02 +02:00
if(!MakeFilePath(filepath, FILE_ROM))
2008-11-12 08:53:25 +01:00
return false;
2008-09-14 22:40:26 +02:00
2009-10-02 00:42:02 +02:00
GBAROMSize = LoadFile ((char *)rom, filepath, browserList[browser.selIndex].length, NOTSILENT);
2008-11-12 08:53:25 +01:00
}
else
{
GBAROMSize = LoadSzFile(szpath, (unsigned char *)rom);
2008-09-26 08:23:00 +02:00
}
2008-09-14 22:40:26 +02:00
2008-09-26 10:10:36 +02:00
if(GBAROMSize)
{
2008-10-18 21:27:43 +02:00
flashInit();
eepromInit();
2008-09-26 08:23:00 +02:00
CPUUpdateRenderBuffers( true );
return true;
}
2008-09-26 08:23:00 +02:00
else
{
2008-09-26 08:23:00 +02:00
VMClose();
return false;
}
2008-09-14 22:40:26 +02:00
}
#else
2008-09-17 04:27:55 +02:00
2008-09-14 22:40:26 +02:00
/****************************************************************************
* VMFindFree
*
* Look for a free page in the VM block. If none found, do a round-robin
****************************************************************************/
static void VMFindFree( void )
{
2010-01-25 08:36:48 +01:00
++vmpageno;
2008-10-18 21:27:43 +02:00
vmpageno &= MAXVMMASK;
2010-01-25 08:36:48 +01:00
if ( vmpageno == 0 ) ++vmpageno;
2008-10-18 21:27:43 +02:00
2010-01-25 08:36:48 +01:00
for (unsigned i = 1; i < MAXVMPAGE; ++i )
2008-10-18 21:27:43 +02:00
{
/** Remove any other pointer to this vmpage **/
if ( vmpage[i].pageno == vmpageno )
{
vmpage[i].pageptr = NULL;
vmpage[i].pagetype = MEM_UN;
vmpage[i].pageno = -1;
break;
}
}
2008-09-14 22:40:26 +02:00
}
/****************************************************************************
* VMAllocate
*
* Allocate a VM page
****************************************************************************/
static void VMAllocate( int pageid )
{
2008-10-18 21:27:43 +02:00
VMFindFree();
vmpage[pageid].pageptr = rombase + ( vmpageno << VMSHIFTBITS );
vmpage[pageid].pagetype = MEM_VM;
vmpage[pageid].pageno = vmpageno;
2008-09-14 22:40:26 +02:00
}
/****************************************************************************
* VMInit
*
* Set everything to default
****************************************************************************/
static void VMInit( void )
{
2008-10-18 21:27:43 +02:00
/** Clear down pointers **/
memset(&vmpage, 0, sizeof(VMPAGE) * MAXVMPAGE);
2010-01-25 08:36:48 +01:00
if(MAXVMPAGE % 4 == 0)
2008-10-18 21:27:43 +02:00
{
2010-01-25 08:36:48 +01:00
for (unsigned i =0 ; i < MAXVMPAGE; i+=4 )
{
vmpage[i ].pageno = -1;
vmpage[i ].pagetype = MEM_UN;
vmpage[i+1].pageno = -1;
vmpage[i+1].pagetype = MEM_UN;
vmpage[i+2].pageno = -1;
vmpage[i+2].pagetype = MEM_UN;
vmpage[i+3].pageno = -1;
vmpage[i+3].pagetype = MEM_UN;
}
}
else
{
for (unsigned i =0 ; i < MAXVMPAGE; ++i )
{
vmpage[i].pageno = -1;
vmpage[i].pagetype = MEM_UN;
}
2008-10-18 21:27:43 +02:00
}
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
/** Allocate physical **/
if ( rombase == NULL )
rombase = (char *)memalign(32, MAXROM);
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
vmpageno = 0;
rom = (u8 *)rombase;
2008-09-14 22:40:26 +02:00
}
/****************************************************************************
* VMCPULoadROM
*
* VM version of GBA CPULoadROM
****************************************************************************/
2009-10-02 00:42:02 +02:00
int VMCPULoadROM()
2008-09-14 22:40:26 +02:00
{
int res;
char filepath[MAXPATHLEN];
2008-09-14 22:40:26 +02:00
2009-10-02 00:42:02 +02:00
if(!MakeFilePath(filepath, FILE_ROM))
2009-10-07 20:04:26 +02:00
return 0;
2008-12-28 22:58:07 +01:00
// loading compressed files via VM is not supported
if(!utilIsGBAImage(filepath))
{
2010-03-18 00:20:17 +01:00
ErrorPrompt("Compressed GBA files are not supported!");
return 0;
}
if (romfile != NULL)
fclose(romfile);
2009-10-02 00:42:02 +02:00
romfile = fopen(filepath, "rb");
2008-12-28 22:58:07 +01:00
if (romfile == NULL)
{
2010-03-18 00:20:17 +01:00
ErrorPrompt("Error opening file!");
return 0;
}
2008-09-14 22:40:26 +02:00
/** Fix VM **/
VMClose();
VMInit();
VMAllocGBA();
GBAROMSize = 0;
2008-10-03 09:02:25 +02:00
res = fread(rom, 1, (1 << VMSHIFTBITS), romfile);
if ( res != (1 << VMSHIFTBITS ) )
{
2010-03-18 00:20:17 +01:00
ErrorPrompt("Error reading file!");
VMClose();
return 0;
}
2008-09-14 22:40:26 +02:00
2009-10-07 20:04:26 +02:00
fseeko(romfile,0,SEEK_END);
GBAROMSize = ftello(romfile);
2008-12-18 19:58:30 +01:00
vmpageno = 0;
vmpage[0].pageptr = rombase;
vmpage[0].pageno = 0;
vmpage[0].pagetype = MEM_VM;
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
flashInit();
eepromInit();
CPUUpdateRenderBuffers( true );
2008-09-14 22:40:26 +02:00
return 1;
2008-09-14 22:40:26 +02:00
}
/****************************************************************************
* GBA Memory Read Routines
****************************************************************************/
/****************************************************************************
* VMNewPage
****************************************************************************/
static void VMNewPage( int pageid )
{
2010-01-25 08:36:48 +01:00
int res = fseek( romfile, pageid << VMSHIFTBITS, SEEK_SET );
2008-09-14 22:40:26 +02:00
if (res) // fseek returns non-zero on a failure
2008-10-18 21:27:43 +02:00
{
2010-03-18 00:20:17 +01:00
ErrorPrompt("Seek error!");
2008-10-18 21:27:43 +02:00
VMClose();
2009-04-08 09:08:12 +02:00
ExitApp();
2008-10-18 21:27:43 +02:00
}
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
VMAllocate( pageid );
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
res = fread( vmpage[pageid].pageptr, 1, 1 << VMSHIFTBITS, romfile );
2008-09-14 22:40:26 +02:00
}
/****************************************************************************
2008-10-18 21:27:43 +02:00
* VMRead32
*
* Return a 32bit value
****************************************************************************/
2008-09-14 22:40:26 +02:00
u32 VMRead32( u32 address )
{
2008-10-29 07:34:15 +01:00
if ( address >= (u32)GBAROMSize )
2008-10-18 21:27:43 +02:00
{
2010-01-25 08:36:48 +01:00
return u32(( ( ( address >> 1 ) & 0xffff ) << 16 ) | ( ( ( address + 2 ) >> 1 ) & 0xffff ));
2008-10-18 21:27:43 +02:00
}
2008-09-14 22:40:26 +02:00
2010-01-25 08:36:48 +01:00
int pageid = address >> VMSHIFTBITS;
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
switch( vmpage[pageid].pagetype )
{
case MEM_UN:
2008-09-14 22:40:26 +02:00
VMNewPage(pageid);
2008-10-18 21:27:43 +02:00
case MEM_VM:
2008-09-14 22:40:26 +02:00
return READ32LE( vmpage[pageid].pageptr + ( address & VMSHIFTMASK ) );
2008-10-18 21:27:43 +02:00
default:
2010-03-18 00:20:17 +01:00
ErrorPrompt("VM32: Unknown page type!");
2008-09-23 01:00:10 +02:00
VMClose();
2009-04-08 09:08:12 +02:00
ExitApp();
2008-10-18 21:27:43 +02:00
return 0;
}
2008-09-14 22:40:26 +02:00
}
/****************************************************************************
2008-10-18 21:27:43 +02:00
* VMRead16
*
* Return a 16bit value
****************************************************************************/
2008-09-14 22:40:26 +02:00
u16 VMRead16( u32 address )
{
2008-10-29 07:34:15 +01:00
if ( address >= (u32)GBAROMSize )
2008-10-18 21:27:43 +02:00
{
return ( address >> 1 ) & 0xffff;
}
2008-09-14 22:40:26 +02:00
2010-01-25 08:36:48 +01:00
int pageid = address >> VMSHIFTBITS;
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
switch( vmpage[pageid].pagetype )
{
case MEM_UN:
2008-09-14 22:40:26 +02:00
VMNewPage(pageid);
2008-10-18 21:27:43 +02:00
case MEM_VM:
2008-09-14 22:40:26 +02:00
return READ16LE( vmpage[pageid].pageptr + ( address & VMSHIFTMASK ) );
2008-10-18 21:27:43 +02:00
default:
2010-03-18 00:20:17 +01:00
ErrorPrompt("VM16: Unknown page type!");
2008-10-18 21:27:43 +02:00
VMClose();
2009-04-08 09:08:12 +02:00
ExitApp();
2008-10-18 21:27:43 +02:00
return 0;
}
2008-09-14 22:40:26 +02:00
}
/****************************************************************************
2008-10-18 21:27:43 +02:00
* VMRead8
*
* Return 8bit value
****************************************************************************/
2008-09-14 22:40:26 +02:00
u8 VMRead8( u32 address )
{
2008-10-29 07:34:15 +01:00
if ( address >= (u32)GBAROMSize )
2008-10-18 21:27:43 +02:00
{
return ( address >> 1 ) & 0xff;
}
2008-09-14 22:40:26 +02:00
2010-01-25 08:36:48 +01:00
int pageid = address >> VMSHIFTBITS;
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
switch( vmpage[pageid].pagetype )
{
case MEM_UN:
2008-09-14 22:40:26 +02:00
VMNewPage(pageid);
2008-10-18 21:27:43 +02:00
case MEM_VM:
return (u8)vmpage[pageid].pageptr[ (address & VMSHIFTMASK) ];
2008-09-14 22:40:26 +02:00
2008-10-18 21:27:43 +02:00
default:
2010-03-18 00:20:17 +01:00
ErrorPrompt("VM8: Unknown page type!");
2008-10-18 21:27:43 +02:00
VMClose();
2009-04-08 09:08:12 +02:00
ExitApp();
2008-10-18 21:27:43 +02:00
return 0;
}
2008-09-14 22:40:26 +02:00
}
#endif