Libretro: Add GB/GBC core

Gb,gbc and sgb enhanced version of roms and savestates working. Bios loading for gb/gbc works too. No save ram / battery handling yet.

Fix offset and pitch issues with vba rendering and when borders are enabled.
This commit is contained in:
retro-wertz 2018-07-17 01:55:19 +08:00
parent f05a05e622
commit bf447bf89a
12 changed files with 685 additions and 64 deletions

View File

@ -2852,6 +2852,7 @@ void gbReset()
gbCheatWrite(true); // Emulates GS codes.
}
#ifndef __LIBRETRO__
void gbWriteSaveMBC1(const char* name)
{
if (gbRam) {
@ -3335,6 +3336,7 @@ bool gbReadSaveMMM01(const char* name)
} else
return false;
}
#endif // !__LIBRETRO__
void gbInit()
{
@ -3343,11 +3345,16 @@ void gbInit()
gbMemory = (uint8_t*)malloc(65536);
#ifdef __LIBRETRO__
pix = (uint8_t*)calloc(1, 4 * 256 * 224);
#else
pix = (uint8_t*)calloc(1, 4 * 257 * 226);
#endif
gbLineBuffer = (uint16_t*)malloc(160 * sizeof(uint16_t));
}
#ifndef __LIBRETRO__
bool gbWriteBatteryFile(const char* file, bool extendedSave)
{
if (gbBattery) {
@ -3480,6 +3487,7 @@ bool gbReadBatteryFile(const char* file)
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
return res;
}
#endif // !__LIBRETRO__
bool gbReadGSASnapshot(const char* fileName)
{
@ -3617,6 +3625,7 @@ variable_desc gbSaveGameStruct[] = {
{ NULL, 0 }
};
#ifndef __LIBRETRO__
static bool gbWriteSaveState(gzFile gzFile)
{
@ -4091,6 +4100,7 @@ bool gbReadSaveState(const char* name)
return res;
}
#endif // !__LIBRETRO__
bool gbWritePNGFile(const char* fileName)
{
@ -4457,8 +4467,13 @@ void gbDrawLine()
{
switch (systemColorDepth) {
case 16: {
#ifdef __LIBRETRO__
uint16_t* dest = (uint16_t*)pix + gbBorderLineSkip * (register_LY + gbBorderRowSkip)
+ gbBorderColumnSkip;
#else
uint16_t* dest = (uint16_t*)pix + (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1)
+ gbBorderColumnSkip;
#endif
for (int x = 0; x < 160;) {
*dest++ = systemColorMap16[gbLineMix[x++]];
*dest++ = systemColorMap16[gbLineMix[x++]];
@ -4482,7 +4497,9 @@ void gbDrawLine()
}
if (gbBorderOn)
dest += gbBorderColumnSkip;
#ifndef __LIBRETRO__
*dest++ = 0; // for filters that read one pixel more
#endif
} break;
case 24: {
@ -4527,8 +4544,13 @@ void gbDrawLine()
} break;
case 32: {
#ifdef __LIBRETRO__
uint32_t* dest = (uint32_t*)pix + gbBorderLineSkip * (register_LY + gbBorderRowSkip)
+ gbBorderColumnSkip;
#else
uint32_t* dest = (uint32_t*)pix + (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1)
+ gbBorderColumnSkip;
#endif
for (int x = 0; x < 160;) {
*dest++ = systemColorMap32[gbLineMix[x++]];
*dest++ = systemColorMap32[gbLineMix[x++]];
@ -5418,6 +5440,361 @@ void gbEmulate(int ticksToStop)
}
}
bool gbLoadRomData(const char* data, unsigned size)
{
gbRomSize = size;
if (gbRom != NULL) {
gbCleanUp();
}
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
gbRom = (uint8_t*)calloc(1, gbRomSize);
if (gbRom == NULL) {
return 0;
}
memcpy(gbRom, data, gbRomSize);
gbBatteryError = false;
if (bios != NULL) {
free(bios);
bios = NULL;
}
bios = (uint8_t*)calloc(1, 0x900);
return gbUpdateSizes();
}
#ifdef __LIBRETRO__
#include <stddef.h>
unsigned int gbWriteSaveState(uint8_t* data, unsigned)
{
uint8_t* orig = data;
utilWriteIntMem(data, GBSAVE_GAME_VERSION);
utilWriteMem(data, &gbRom[0x134], 15);
utilWriteIntMem(data, useBios);
utilWriteIntMem(data, inBios);
utilWriteDataMem(data, gbSaveGameStruct);
utilWriteMem(data, &IFF, 2);
if (gbSgbMode) {
gbSgbSaveGame(data);
}
utilWriteMem(data, &gbDataMBC1, sizeof(gbDataMBC1));
utilWriteMem(data, &gbDataMBC2, sizeof(gbDataMBC2));
utilWriteMem(data, &gbDataMBC3, sizeof(gbDataMBC3));
utilWriteMem(data, &gbDataMBC5, sizeof(gbDataMBC5));
utilWriteMem(data, &gbDataHuC1, sizeof(gbDataHuC1));
utilWriteMem(data, &gbDataHuC3, sizeof(gbDataHuC3));
utilWriteMem(data, &gbDataTAMA5, sizeof(gbDataTAMA5));
if (gbTAMA5ram != NULL)
utilWriteMem(data, gbTAMA5ram, gbTAMA5ramSize);
utilWriteMem(data, &gbDataMMM01, sizeof(gbDataMMM01));
utilWriteMem(data, gbPalette, 128 * sizeof(uint16_t));
utilWriteMem(data, &gbMemory[0x8000], 0x8000);
if (gbRamSize && gbRam) {
utilWriteIntMem(data, gbRamSize);
utilWriteMem(data, gbRam, gbRamSize);
}
if (gbCgbMode) {
utilWriteMem(data, gbVram, 0x4000);
utilWriteMem(data, gbWram, 0x8000);
}
gbSoundSaveGame(data);
// We dont care about cheat saves
// gbCheatsSaveGame(data);
utilWriteIntMem(data, gbLcdModeDelayed);
utilWriteIntMem(data, gbLcdTicksDelayed);
utilWriteIntMem(data, gbLcdLYIncrementTicksDelayed);
utilWriteIntMem(data, gbSpritesTicks[299]);
utilWriteIntMem(data, gbTimerModeChange);
utilWriteIntMem(data, gbTimerOnChange);
utilWriteIntMem(data, gbHardware);
utilWriteIntMem(data, gbBlackScreen);
utilWriteIntMem(data, oldRegister_WY);
utilWriteIntMem(data, gbWindowLine);
utilWriteIntMem(data, inUseRegister_WY);
utilWriteIntMem(data, gbScreenOn);
utilWriteIntMem(data, 0x12345678); // end marker
return (ptrdiff_t)data - (ptrdiff_t)orig;
}
bool gbReadSaveState(const uint8_t* data, unsigned)
{
int version = utilReadIntMem(data);
if (version != GBSAVE_GAME_VERSION) {
systemMessage(MSG_UNSUPPORTED_VB_SGM,
N_("Unsupported VBA-M save game version %d"), version);
return false;
}
uint8_t romname[20];
utilReadMem(romname, data, 15);
if (memcmp(&gbRom[0x134], romname, 15) != 0) {
systemMessage(MSG_CANNOT_LOAD_SGM_FOR,
N_("Cannot load save game for %s. Playing %s"),
romname, &gbRom[0x134]);
return false;
}
bool ub = false;
bool ib = false;
ub = utilReadIntMem(data) ? true : false;
ib = utilReadIntMem(data) ? true : false;
if ((ub != useBios) && (ib)) {
if (useBios)
systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS,
N_("Save game is not using the BIOS files"));
else
systemMessage(MSG_SAVE_GAME_USING_BIOS,
N_("Save game is using the BIOS file"));
return false;
}
gbReset();
inBios = ib;
utilReadDataMem(data, gbSaveGameStruct);
// Correct crash when loading color gameboy save in regular gameboy type.
if (!gbCgbMode) {
if (gbVram != NULL) {
free(gbVram);
gbVram = NULL;
}
if (gbWram != NULL) {
free(gbWram);
gbWram = NULL;
}
} else {
if (gbVram == NULL)
gbVram = (uint8_t*)malloc(0x4000);
if (gbWram == NULL)
gbWram = (uint8_t*)malloc(0x8000);
memset(gbVram, 0, 0x4000);
memset(gbPalette, 0, 2 * 128);
}
utilReadMem(&IFF, data, 2);
if (gbSgbMode) {
gbSgbReadGame(data, version);
} else {
gbSgbMask = 0; // loading a game at the wrong time causes no display
}
utilReadMem(&gbDataMBC1, data, sizeof(gbDataMBC1));
utilReadMem(&gbDataMBC2, data, sizeof(gbDataMBC2));
utilReadMem(&gbDataMBC3, data, sizeof(gbDataMBC3));
utilReadMem(&gbDataMBC5, data, sizeof(gbDataMBC5));
utilReadMem(&gbDataHuC1, data, sizeof(gbDataHuC1));
utilReadMem(&gbDataHuC3, data, sizeof(gbDataHuC3));
utilReadMem(&gbDataTAMA5, data, sizeof(gbDataTAMA5));
if (gbTAMA5ram != NULL) {
utilReadMem(gbTAMA5ram, data, gbTAMA5ramSize);
}
utilReadMem(&gbDataMMM01, data, sizeof(gbDataMMM01));
utilReadMem(gbPalette, data, 128 * sizeof(uint16_t));
utilReadMem(&gbMemory[0x8000], data, 0x8000);
if (gbRamSize && gbRam) {
int ramSize = utilReadIntMem(data);
utilReadMem(gbRam, data, (gbRamSize > ramSize) ? ramSize : gbRamSize); //read
/*if (ramSize > gbRamSize)
utilGzSeek(gzFile, ramSize - gbRamSize, SEEK_CUR);*/ // Libretro Note: ????
}
memset(gbSCYLine, register_SCY, sizeof(gbSCYLine));
memset(gbSCXLine, register_SCX, sizeof(gbSCXLine));
memset(gbBgpLine, (gbBgp[0] | (gbBgp[1] << 2) | (gbBgp[2] << 4) | (gbBgp[3] << 6)), sizeof(gbBgpLine));
memset(gbObp0Line, (gbObp0[0] | (gbObp0[1] << 2) | (gbObp0[2] << 4) | (gbObp0[3] << 6)), sizeof(gbObp0Line));
memset(gbObp1Line, (gbObp1[0] | (gbObp1[1] << 2) | (gbObp1[2] << 4) | (gbObp1[3] << 6)), sizeof(gbObp1Line));
memset(gbSpritesTicks, 0x0, sizeof(gbSpritesTicks));
if (inBios) {
gbMemoryMap[0x00] = &gbMemory[0x0000];
if (gbHardware & 5) {
memcpy((uint8_t*)(gbMemory), (uint8_t*)(gbRom), 0x1000);
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x100);
} else if (gbHardware & 2) {
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x900);
memcpy((uint8_t*)(gbMemory + 0x100), (uint8_t*)(gbRom + 0x100), 0x100);
}
} else {
gbMemoryMap[0x00] = &gbRom[0x0000];
}
gbMemoryMap[0x01] = &gbRom[0x1000];
gbMemoryMap[0x02] = &gbRom[0x2000];
gbMemoryMap[0x03] = &gbRom[0x3000];
gbMemoryMap[0x04] = &gbRom[0x4000];
gbMemoryMap[0x05] = &gbRom[0x5000];
gbMemoryMap[0x06] = &gbRom[0x6000];
gbMemoryMap[0x07] = &gbRom[0x7000];
gbMemoryMap[0x08] = &gbMemory[0x8000];
gbMemoryMap[0x09] = &gbMemory[0x9000];
gbMemoryMap[0x0a] = &gbMemory[0xa000];
gbMemoryMap[0x0b] = &gbMemory[0xb000];
gbMemoryMap[0x0c] = &gbMemory[0xc000];
gbMemoryMap[0x0d] = &gbMemory[0xd000];
gbMemoryMap[0x0e] = &gbMemory[0xe000];
gbMemoryMap[0x0f] = &gbMemory[0xf000];
switch (gbRomType) {
case 0x00:
case 0x01:
case 0x02:
case 0x03:
// MBC 1
memoryUpdateMapMBC1();
break;
case 0x05:
case 0x06:
// MBC2
memoryUpdateMapMBC2();
break;
case 0x0b:
case 0x0c:
case 0x0d:
// MMM01
memoryUpdateMapMMM01();
break;
case 0x0f:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
// MBC 3
memoryUpdateMapMBC3();
break;
case 0x19:
case 0x1a:
case 0x1b:
// MBC5
memoryUpdateMapMBC5();
break;
case 0x1c:
case 0x1d:
case 0x1e:
// MBC 5 Rumble
memoryUpdateMapMBC5();
break;
case 0x22:
// MBC 7
memoryUpdateMapMBC7();
break;
case 0x56:
// GS3
memoryUpdateMapGS3();
break;
case 0xfd:
// TAMA5
memoryUpdateMapTAMA5();
break;
case 0xfe:
// HuC3
memoryUpdateMapHuC3();
break;
case 0xff:
// HuC1
memoryUpdateMapHuC1();
break;
}
if (gbCgbMode) {
utilReadMem(gbVram, data, 0x4000);
utilReadMem(gbWram, data, 0x8000);
int value = register_SVBK;
if (value == 0)
value = 1;
gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000];
gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000];
gbMemoryMap[0x0d] = &gbWram[value * 0x1000];
}
gbSoundReadGame(data, version);
if (gbCgbMode && gbSgbMode) {
gbSgbMode = 0;
}
if (gbBorderOn && !gbSgbMask) {
gbSgbRenderBorder();
}
gbLcdModeDelayed = utilReadIntMem(data);
gbLcdTicksDelayed = utilReadIntMem(data);
gbLcdLYIncrementTicksDelayed = utilReadIntMem(data);
gbSpritesTicks[299] = utilReadIntMem(data) & 0xff;
gbTimerModeChange = (utilReadIntMem(data) ? true : false);
gbTimerOnChange = (utilReadIntMem(data) ? true : false);
gbHardware = utilReadIntMem(data);
gbBlackScreen = (utilReadIntMem(data) ? true : false);
oldRegister_WY = utilReadIntMem(data);
gbWindowLine = utilReadIntMem(data);
inUseRegister_WY = utilReadIntMem(data);
gbScreenOn = (utilReadIntMem(data) ? true : false);
if (gbSpeed)
gbLine99Ticks *= 2;
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
if (version >= 12 && utilReadIntMem(data) != 0x12345678)
assert(false); // fails if something read too much/little from file
return true;
}
bool gbWriteMemSaveState(char*, int, long&)
{
return false;
}
bool gbReadMemSaveState(char*, int)
{
return false;
}
bool gbReadBatteryFile(const char*)
{
return false;
}
bool gbWriteBatteryFile(const char*)
{
return false;
}
#endif
struct EmulatedSystem GBSystem = {
// emuMain
gbEmulate,
@ -5445,7 +5822,7 @@ struct EmulatedSystem GBSystem = {
NULL,
// emuHasDebugger
false,
// emuCount
// emuCount
#ifdef FINAL_VERSION
70000 / 4,
#else

View File

@ -31,18 +31,25 @@ void gbGetHardwareType();
void gbReset();
void gbCleanUp();
void gbCPUInit(const char*, bool);
#ifdef __LIBRETRO__
unsigned int gbWriteSaveState(uint8_t*, unsigned);
bool gbReadSaveState(const uint8_t*, unsigned);
#else
bool gbWriteSaveState(const char*);
bool gbReadSaveState(const char*);
#endif
bool gbWriteBatteryFile(const char*);
bool gbWriteBatteryFile(const char*, bool);
bool gbReadBatteryFile(const char*);
bool gbWriteSaveState(const char*);
bool gbWriteMemSaveState(char*, int, long&);
bool gbReadSaveState(const char*);
bool gbReadMemSaveState(char*, int);
void gbSgbRenderBorder();
bool gbWritePNGFile(const char*);
bool gbWriteBMPFile(const char*);
bool gbReadGSASnapshot(const char*);
bool gbLoadRomData(const char* data, unsigned size);
extern int gbHardware;
extern struct EmulatedSystem GBSystem;

View File

@ -30,6 +30,7 @@ void gbCheatUpdateMap()
}
}
#ifndef __LIBRETRO__
void gbCheatsSaveGame(gzFile gzFile)
{
utilWriteInt(gzFile, gbCheatNumber);
@ -98,6 +99,7 @@ void gbCheatsReadGameSkip(gzFile gzFile, int version)
}
}
}
#endif
void gbCheatsSaveCheatList(const char* file)
{

View File

@ -19,9 +19,11 @@ struct gbCheat {
bool enabled;
};
#ifndef __LIBRETRO__
void gbCheatsSaveGame(gzFile);
void gbCheatsReadGame(gzFile, int);
void gbCheatsReadGameSkip(gzFile, int);
#endif
void gbCheatsSaveCheatList(const char*);
bool gbCheatsLoadCheatList(const char*);
bool gbCheatReadGSCodeFile(const char*);

View File

@ -113,7 +113,11 @@ void gbSgbFillScreen(uint16_t color)
switch (systemColorDepth) {
case 16: {
for (int y = 0; y < 144; y++) {
#ifdef __LIBRETRO__
int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip + gbBorderColumnSkip;
#else
int yLine = (y + gbBorderRowSkip + 1) * (gbBorderLineSkip + 2) + gbBorderColumnSkip;
#endif
uint16_t* dest = (uint16_t*)pix + yLine;
for (register int x = 0; x < 160; x++)
gbSgbDraw16Bit(dest++, color);
@ -131,7 +135,11 @@ void gbSgbFillScreen(uint16_t color)
} break;
case 32: {
for (int y = 0; y < 144; y++) {
#ifdef __LIBRETRO__
int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip + gbBorderColumnSkip;
#else
int yLine = (y + gbBorderRowSkip + 1) * (gbBorderLineSkip + 1) + gbBorderColumnSkip;
#endif
uint32_t* dest = (uint32_t*)pix + yLine;
for (register int x = 0; x < 160; x++) {
gbSgbDraw32Bit(dest++, color);
@ -181,9 +189,14 @@ void gbSgbRenderScreenToBuffer()
void gbSgbDrawBorderTile(int x, int y, int tile, int attr)
{
#ifdef __LIBRETRO__
uint16_t* dest = (uint16_t*)pix + (y * 256) + x;
uint32_t* dest32 = (uint32_t*)pix + (y * 256) + x;
#else
uint16_t* dest = (uint16_t*)pix + ((y + 1) * (256 + 2)) + x;
uint32_t* dest32 = (uint32_t*)pix + ((y + 1) * 256 + 1) + x;
#endif
uint8_t* dest8 = (uint8_t*)pix + ((y * 256) + x) * 3;
uint32_t* dest32 = (uint32_t*)pix + ((y + 1) * 257) + x;
uint8_t* tileAddress = &gbSgbBorderChar[tile * 32];
uint8_t* tileAddress2 = &gbSgbBorderChar[tile * 32 + 16];
@ -245,13 +258,21 @@ void gbSgbDrawBorderTile(int x, int y, int tile, int attr)
switch (systemColorDepth) {
case 16:
#ifdef __LIBRETRO__
gbSgbDraw16Bit(dest + yyy * 256 + xxx, cc);
#else
gbSgbDraw16Bit(dest + yyy * (256 + 2) + xxx, cc);
#endif
break;
case 24:
gbSgbDraw24Bit(dest8 + (yyy * 256 + xxx) * 3, cc);
break;
case 32:
#ifdef __LIBRETRO__
gbSgbDraw32Bit(dest32 + yyy * 256 + xxx, cc);
#else
gbSgbDraw32Bit(dest32 + yyy * (256 + 1) + xxx, cc);
#endif
break;
}
}
@ -860,6 +881,36 @@ variable_desc gbSgbSaveStructV3[] = {
{ NULL, 0 }
};
#ifdef __LIBRETRO__
void gbSgbSaveGame(uint8_t*& data)
{
utilWriteDataMem(data, gbSgbSaveStructV3);
utilWriteMem(data, gbSgbBorder, 2048);
utilWriteMem(data, gbSgbBorderChar, 32 * 256);
utilWriteMem(data, gbSgbPacket, 16 * 7);
utilWriteMem(data, gbSgbSCPPalette, 4 * 512 * sizeof(uint16_t));
utilWriteMem(data, gbSgbATF, 20 * 18);
utilWriteMem(data, gbSgbATFList, 45 * 20 * 18);
}
void gbSgbReadGame(const uint8_t*& data, int version)
{
utilReadDataMem(data, gbSgbSaveStructV3);
utilReadMem(gbSgbBorder, data, 2048);
utilReadMem(gbSgbBorderChar, data, 32 * 256);
utilReadMem(gbSgbPacket, data, 16 * 7);
utilReadMem(gbSgbSCPPalette, data, 4 * 512 * sizeof(uint16_t));
utilReadMem(gbSgbATF, data, 20 * 18);
utilReadMem(gbSgbATFList, data, 45 * 20 * 18);
}
#else // !__LIBRETRO__
void gbSgbSaveGame(gzFile gzFile)
{
utilWriteData(gzFile, gbSgbSaveStructV3);
@ -894,3 +945,4 @@ void gbSgbReadGame(gzFile gzFile, int version)
utilGzRead(gzFile, gbSgbATF, 20 * 18);
utilGzRead(gzFile, gbSgbATFList, 45 * 20 * 18);
}
#endif // !__LIBRETRO__

View File

@ -7,9 +7,14 @@ void gbSgbCommand();
void gbSgbResetPacketState();
void gbSgbReset();
void gbSgbDoBitTransfer(uint8_t);
void gbSgbRenderBorder();
#ifdef __LIBRETRO__
void gbSgbSaveGame(uint8_t*&);
void gbSgbReadGame(const uint8_t*&, int);
#else
void gbSgbSaveGame(gzFile);
void gbSgbReadGame(gzFile, int version);
void gbSgbRenderBorder();
#endif
extern uint8_t gbSgbATF[20 * 18];
extern int gbSgbMode;

View File

@ -358,6 +358,7 @@ enum {
nr52
};
#ifndef __LIBRETRO__
static void gbSoundReadGameOld(int version, gzFile gzFile)
{
if (version == 11) {
@ -395,6 +396,7 @@ static void gbSoundReadGameOld(int version, gzFile gzFile)
memcpy(&s.regs[0x20], &gbMemory[0xFF30], 0x10); // wave
}
#endif
// New state format
@ -430,7 +432,11 @@ static variable_desc gb_state[] = {
{ NULL, 0 }
};
#ifdef __LIBRETRO__
void gbSoundSaveGame(uint8_t*& out)
#else
void gbSoundSaveGame(gzFile out)
#endif
{
gb_apu->save_state(&state.apu);
@ -438,19 +444,31 @@ void gbSoundSaveGame(gzFile out)
memset(dummy_state, 0, sizeof dummy_state);
state.version = 1;
#ifdef __LIBRETRO__
utilWriteDataMem(out, gb_state);
#else
utilWriteData(out, gb_state);
#endif
}
#ifdef __LIBRETRO__
void gbSoundReadGame(const uint8_t*& in, int version)
#else
void gbSoundReadGame(int version, gzFile in)
#endif
{
// Prepare APU and default state
reset_apu();
gb_apu->save_state(&state.apu);
if (version > 11)
#ifdef __LIBRETRO__
utilReadDataMem(in, gb_state);
#else
utilReadData(in, gb_state);
else
gbSoundReadGameOld(version, in);
#endif
gb_apu->load_state(state.apu);
}

View File

@ -68,7 +68,12 @@ extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to gbSo
extern int soundTicks; // Number of 16.8 MHz clocks until gbSoundTick() will be called
// Saves/loads emulator state
#ifdef __LIBRETRO__
void gbSoundSaveGame(uint8_t*&);
void gbSoundReadGame(const uint8_t*&, int);
#else
void gbSoundSaveGame(gzFile out);
void gbSoundReadGame(int version, gzFile in);
#endif
#endif // GBSOUND_H

View File

@ -1,6 +1,6 @@
TILED_RENDERING=0
STATIC_LINKING=0
FRONTEND_SUPPORTS_RGB565=0
FRONTEND_SUPPORTS_RGB565=1
SPACE :=
SPACE := $(SPACE) $(SPACE)

View File

@ -1,6 +1,22 @@
INCFLAGS := -I$(CORE_DIR)
SOURCES_CXX :=
SOURCES_CXX := $(CORE_DIR)/gba/GBA-thumb.cpp \
SOURCES_CXX += \
$(CORE_DIR)/libretro/libretro.cpp \
$(CORE_DIR)/libretro/UtilRetro.cpp \
$(CORE_DIR)/libretro/SoundRetro.cpp \
$(CORE_DIR)/libretro/scrc32.cpp
SOURCES_CXX += \
$(CORE_DIR)/apu/Gb_Oscs.cpp \
$(CORE_DIR)/apu/Gb_Apu_State.cpp \
$(CORE_DIR)/apu/Blip_Buffer.cpp \
$(CORE_DIR)/apu/Multi_Buffer.cpp \
$(CORE_DIR)/apu/Effects_Buffer.cpp \
$(CORE_DIR)/apu/Gb_Apu.cpp
SOURCES_CXX += \
$(CORE_DIR)/gba/GBA-thumb.cpp \
$(CORE_DIR)/gba/Sound.cpp \
$(CORE_DIR)/gba/Mode1.cpp \
$(CORE_DIR)/gba/CheatSearch.cpp \
@ -20,13 +36,13 @@ SOURCES_CXX := $(CORE_DIR)/gba/GBA-thumb.cpp \
$(CORE_DIR)/gba/GBA.cpp \
$(CORE_DIR)/gba/EEprom.cpp \
$(CORE_DIR)/gba/RTC.cpp \
$(CORE_DIR)/gba/Sram.cpp \
$(CORE_DIR)/apu/Gb_Oscs.cpp \
$(CORE_DIR)/apu/Gb_Apu_State.cpp \
$(CORE_DIR)/apu/Blip_Buffer.cpp \
$(CORE_DIR)/apu/Multi_Buffer.cpp \
$(CORE_DIR)/apu/Gb_Apu.cpp \
$(CORE_DIR)/libretro/libretro.cpp \
$(CORE_DIR)/libretro/UtilRetro.cpp \
$(CORE_DIR)/libretro/SoundRetro.cpp \
$(CORE_DIR)/libretro/scrc32.cpp
$(CORE_DIR)/gba/Sram.cpp
SOURCES_CXX += \
$(CORE_DIR)/gb/gbCheats.cpp \
$(CORE_DIR)/gb/GB.cpp \
$(CORE_DIR)/gb/gbGfx.cpp \
$(CORE_DIR)/gb/gbGlobals.cpp \
$(CORE_DIR)/gb/gbMemory.cpp \
$(CORE_DIR)/gb/gbSGB.cpp \
$(CORE_DIR)/gb/gbSound.cpp

View File

@ -108,6 +108,7 @@ bool utilIsGBAImage(const char* file)
bool utilIsGBImage(const char* file)
{
/*
FILE *fp;
bool ret = false;
char buffer[47];
@ -121,6 +122,20 @@ bool utilIsGBImage(const char* file)
}
fclose (fp);
return ret;
*/
if (strlen(file) > 4) {
const char *p = strrchr(file, '.');
if (p != NULL) {
if ((_stricmp(p, ".dmg") == 0) || (_stricmp(p, ".gb") == 0)
|| (_stricmp(p, ".gbc") == 0) || (_stricmp(p, ".cgb") == 0)
|| (_stricmp(p, ".sgb") == 0)) {
return true;
}
}
}
return false;
}
// strip .gz or .z off end

View File

@ -25,6 +25,13 @@
#include "../gba/Sound.h"
#include "../gba/bios.h"
#include "../gb/gb.h"
#include "../gb/gbCheats.h"
#include "../gb/gbGlobals.h"
#include "../gb/gbMemory.h"
#include "../gb/gbSGB.h"
#include "../gb/gbSound.h"
#define RETRO_DEVICE_GBA RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0)
#define RETRO_DEVICE_GBA_ALT1 RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1)
#define RETRO_DEVICE_GBA_ALT2 RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 2)
@ -44,18 +51,23 @@ static float sndFiltering = 0.5f;
static bool sndInterpolation = true;
static bool can_dupe = false;
static bool usebios = false;
static unsigned retropad_layout =1;
static unsigned retropad_layout = 1;
static EmulatedSystem* core = NULL;
static IMAGE_TYPE type = IMAGE_UNKNOWN;
static const double FramesPerSecond = (16777216.0 / 280896.0); // 59.73
static const long SampleRate = 32768;
static const int GBWidth = 160;
static const int GBHeight = 144;
static const int SGBWidth = 256;
static const int SGBHeight = 224;
static const int GBAWidth = 240;
static const int GBAHeight = 160;
static unsigned width = 240;
static unsigned height = 160;
static EmulatedSystem* core = NULL;
static IMAGE_TYPE type = IMAGE_UNKNOWN;
uint16_t systemColorMap16[0x10000];
uint32_t systemColorMap32[0x10000];
uint16_t systemGbPalette[24];
int RGB_LOW_BITS_MASK = 0;
int systemRedShift = 0;
int systemBlueShift = 0;
@ -71,14 +83,29 @@ int emulating = 0;
void (*dbgOutput)(const char* s, uint32_t addr);
void (*dbgSignal)(int sig, int number);
#define GS555(x) (x | (x << 5) | (x << 10))
uint16_t systemGbPalette[24] = {
GS555(0x1f), GS555(0x15), GS555(0x0c), 0,
GS555(0x1f), GS555(0x15), GS555(0x0c), 0,
GS555(0x1f), GS555(0x15), GS555(0x0c), 0,
GS555(0x1f), GS555(0x15), GS555(0x0c), 0,
GS555(0x1f), GS555(0x15), GS555(0x0c), 0,
GS555(0x1f), GS555(0x15), GS555(0x0c), 0
};
void* retro_get_memory_data(unsigned id)
{
if (id == RETRO_MEMORY_SAVE_RAM)
{
if ((saveType == 1) | (saveType == 4))
return eepromData;
if ((saveType == 2) | (saveType == 3))
return flashSaveMemory;
if (type == IMAGE_GBA)
{
if ((saveType == 1) | (saveType == 4))
return eepromData;
if ((saveType == 2) | (saveType == 3))
return flashSaveMemory;
} else {
// TODO: GB / GBC saves here
}
}
if (id == RETRO_MEMORY_SYSTEM_RAM)
return workRAM;
@ -92,10 +119,15 @@ size_t retro_get_memory_size(unsigned id)
{
if (id == RETRO_MEMORY_SAVE_RAM)
{
if ((saveType == 1) | (saveType == 4))
return eepromSize;
if ((saveType == 2) | (saveType == 3))
return flashSize;
if (type == IMAGE_GBA)
{
if ((saveType == 1) | (saveType == 4))
return eepromSize;
if ((saveType == 2) | (saveType == 3))
return flashSize;
} else {
// TODO: GB / GBC saves here
}
}
if (id == RETRO_MEMORY_SYSTEM_RAM)
return 0x40000;
@ -207,7 +239,7 @@ void retro_set_environment(retro_environment_t cb)
void retro_get_system_info(struct retro_system_info *info)
{
info->need_fullpath = false;
info->valid_extensions = "gba";
info->valid_extensions = "dmg|gb|gbc|cgb|sgb|gba";
#ifdef GIT_VERSION
info->library_version = "2.1.0" GIT_VERSION;
#else
@ -220,6 +252,9 @@ void retro_get_system_info(struct retro_system_info *info)
void retro_get_system_av_info(struct retro_system_av_info *info)
{
float aspect = (3.0f / 2.0f);
if (type == IMAGE_GB)
aspect = !gbBorderOn ? (10.0 / 9.0) : (8.0 / 7.0);
info->geometry.base_width = width;
info->geometry.base_height = height;
info->geometry.max_width = width;
@ -342,13 +377,7 @@ static void load_image_preferences(void)
}
}
#ifdef _WIN32
static const char SLASH = '\\';
#else
static const char SLASH = '/';
#endif
static void gba_init(void)
static void update_colormaps(void)
{
#ifdef FRONTEND_SUPPORTS_RGB565
systemColorDepth = 16;
@ -364,8 +393,21 @@ static void gba_init(void)
utilUpdateSystemColorMaps(false);
log("Loading VBA-M Core (GBA)...\n");
log("Color Depth = %d\n", systemColorDepth);
}
#ifdef _WIN32
static const char SLASH = '\\';
#else
static const char SLASH = '/';
#endif
static void gba_init(void)
{
log("Loading VBA-M Core (GBA)...\n");
update_colormaps();
load_image_preferences();
@ -397,8 +439,45 @@ static void gba_init(void)
core = &GBASystem;
width = 240;
height = 160;
width = GBAWidth;
height = GBAHeight;
}
static void gb_init(void)
{
const char *biosname[] = {"gb_bios.bin", "gbc_bios.bin"};
log("Loading VBA-M Core (GB/GBC)...\n");
update_colormaps();
soundInit();
gbSoundSetSampleRate(SampleRate);
gbGetHardwareType();
if (usebios)
{
snprintf(biosfile, sizeof(biosfile), "%s%c%s",
retro_system_directory, SLASH, biosname[gbCgbMode]);
log("Loading bios: %s\n", biosfile);
}
gbCPUInit(biosfile, usebios);
gbReset();
if (gbBorderOn) {
width = gbBorderLineSkip = SGBWidth;
height = SGBHeight;
gbBorderColumnSkip = (SGBWidth - GBWidth) >> 1;
gbBorderRowSkip = (SGBHeight - GBHeight) >> 1;
} else {
width = gbBorderLineSkip = GBWidth;
height = GBHeight;
gbBorderColumnSkip = gbBorderRowSkip = 0;
}
core = &GBSystem;
}
static void gba_soundchanged(void)
@ -618,8 +697,11 @@ bool retro_unserialize(const void* data, size_t size)
void retro_cheat_reset(void)
{
cheatsEnabled = 1;
cheatsDeleteAll(false);
if (type == IMAGE_GBA)
{
cheatsEnabled = 1;
cheatsDeleteAll(false);
}
}
void retro_cheat_set(unsigned index, bool enabled, const char* code)
@ -664,6 +746,11 @@ void retro_cheat_set(unsigned index, bool enabled, const char* code)
} while (*c++);
*/
// TODO: Add cheat code support for GB/GBC
if (type != IMAGE_GBA)
return;
std::string codeLine=code;
std::string name="cheat_"+index;
int matchLength=0;
@ -785,36 +872,58 @@ bool retro_load_game(const struct retro_game_info *game)
update_variables();
update_input_descriptors();
romSize = CPULoadRomData((const char*)game->data, game->size);
if (!romSize)
return false;
type = utilFindType((const char *)game->path);
gba_init();
switch (type)
{
case IMAGE_UNKNOWN:
log("Unsupported image %s!\n", game->path);
return 0;
struct retro_memory_descriptor desc[11];
memset(desc, 0, sizeof(desc));
case IMAGE_GBA:
{
romSize = CPULoadRomData((const char*)game->data, game->size);
desc[0].start=0x03000000; desc[0].select=0xFF000000; desc[0].len=0x8000; desc[0].ptr=internalRAM;//fast WRAM
desc[1].start=0x02000000; desc[1].select=0xFF000000; desc[1].len=0x40000; desc[1].ptr=workRAM;//slow WRAM
/* TODO: if SRAM is flash, use start=0 addrspace="S" instead */
desc[2].start=0x0E000000; desc[2].select=0; desc[2].len=flashSize; desc[2].ptr=flashSaveMemory;//SRAM
desc[3].start=0x08000000; desc[3].select=0; desc[3].len=romSize; desc[3].ptr=rom;//ROM
if (!romSize)
return false;
gba_init();
struct retro_memory_descriptor desc[11];
memset(desc, 0, sizeof(desc));
desc[0].start=0x03000000; desc[0].select=0xFF000000; desc[0].len=0x8000; desc[0].ptr=internalRAM;//fast WRAM
desc[1].start=0x02000000; desc[1].select=0xFF000000; desc[1].len=0x40000; desc[1].ptr=workRAM;//slow WRAM
/* TODO: if SRAM is flash, use start=0 addrspace="S" instead */
desc[2].start=0x0E000000; desc[2].select=0; desc[2].len=flashSize; desc[2].ptr=flashSaveMemory;//SRAM
desc[3].start=0x08000000; desc[3].select=0; desc[3].len=romSize; desc[3].ptr=rom;//ROM
desc[3].flags=RETRO_MEMDESC_CONST;
desc[4].start=0x0A000000; desc[4].select=0; desc[4].len=romSize; desc[4].ptr=rom;//ROM mirror 1
desc[4].start=0x0A000000; desc[4].select=0; desc[4].len=romSize; desc[4].ptr=rom;//ROM mirror 1
desc[4].flags=RETRO_MEMDESC_CONST;
desc[5].start=0x0C000000; desc[5].select=0; desc[5].len=romSize; desc[5].ptr=rom;//ROM mirror 2
desc[5].start=0x0C000000; desc[5].select=0; desc[5].len=romSize; desc[5].ptr=rom;//ROM mirror 2
desc[5].flags=RETRO_MEMDESC_CONST;
desc[6].start=0x00000000; desc[6].select=0; desc[6].len=0x4000; desc[6].ptr=bios;//BIOS
desc[6].start=0x00000000; desc[6].select=0; desc[6].len=0x4000; desc[6].ptr=bios;//BIOS
desc[6].flags=RETRO_MEMDESC_CONST;
desc[7].start=0x06000000; desc[7].select=0xFF000000; desc[7].len=0x18000; desc[7].ptr=vram;//VRAM
desc[8].start=0x05000000; desc[8].select=0xFF000000; desc[8].len=0x400; desc[8].ptr=paletteRAM;//palettes
desc[9].start=0x07000000; desc[9].select=0xFF000000; desc[9].len=0x400; desc[9].ptr=oam;//OAM
desc[10].start=0x04000000;desc[10].select=0; desc[10].len=0x400; desc[10].ptr=ioMem;//bunch of registers
struct retro_memory_map retromap={ desc, sizeof(desc)/sizeof(*desc) };
environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &retromap);
desc[7].start=0x06000000; desc[7].select=0xFF000000; desc[7].len=0x18000; desc[7].ptr=vram;//VRAM
desc[8].start=0x05000000; desc[8].select=0xFF000000; desc[8].len=0x400; desc[8].ptr=paletteRAM;//palettes
desc[9].start=0x07000000; desc[9].select=0xFF000000; desc[9].len=0x400; desc[9].ptr=oam;//OAM
desc[10].start=0x04000000;desc[10].select=0; desc[10].len=0x400; desc[10].ptr=ioMem;//bunch of registers
struct retro_memory_map retromap={ desc, sizeof(desc)/sizeof(*desc) };
environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &retromap);
bool yes = true;
environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, &yes);
bool yes = true;
environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, &yes);
}
break;
case IMAGE_GB:
if (!gbLoadRomData((const char *)game->data, game->size))
return false;
gb_init();
break;
}
uint8_t* state_buf = (uint8_t*)malloc(2000000);
serialize_size = core->emuWriteState(state_buf, 2000000);
@ -863,6 +972,19 @@ void systemFrame(void)
has_frame = 1;
}
void systemGbBorderOn()
{
width = gbBorderLineSkip = SGBWidth;
height = SGBHeight;
gbBorderColumnSkip = (SGBWidth - GBWidth) >> 1;
gbBorderRowSkip = (SGBHeight - GBHeight) >> 1;
struct retro_system_av_info avinfo;
retro_get_system_av_info(&avinfo);
//environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &avinfo);
environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avinfo);
}
void systemMessage(const char* fmt, ...)
{
char buffer[256];