GB MBC: Initial HuC-3 save format

This commit is contained in:
Vicki Pfau 2022-02-04 23:48:03 -08:00
parent c829cd2e70
commit 26aea8544f
4 changed files with 71 additions and 11 deletions

View File

@ -7,7 +7,7 @@ Features:
- Cheat code support in homebrew ports - Cheat code support in homebrew ports
- Acclerometer and gyro support for controllers on PC - Acclerometer and gyro support for controllers on PC
- Support for combo "Super Game Boy Color" SGB + GBC ROM hacks - Support for combo "Super Game Boy Color" SGB + GBC ROM hacks
- Improved support for HuC-3 mapper - Improved support for HuC-3 mapper, including RTC
- Support for 64 kiB SRAM saves used in some bootlegs - Support for 64 kiB SRAM saves used in some bootlegs
- Discord Rich Presence now supports time elapsed - Discord Rich Presence now supports time elapsed
- Additional scaling shaders - Additional scaling shaders

View File

@ -42,9 +42,18 @@ struct GBMBCRTCSaveBuffer {
uint32_t latchedDaysHi; uint32_t latchedDaysHi;
uint64_t unixTime; uint64_t unixTime;
}; };
struct GBMBCHuC3SaveBuffer {
uint8_t regs[0x80];
uint64_t latchedUnix;
};
void GBMBCRTCRead(struct GB* gb); void GBMBCRTCRead(struct GB* gb);
void GBMBCRTCWrite(struct GB* gb); void GBMBCRTCWrite(struct GB* gb);
void GBMBCHuC3Read(struct GB* gb);
void GBMBCHuC3Write(struct GB* gb);
CXX_GUARD_END CXX_GUARD_END
#endif #endif

View File

@ -143,8 +143,12 @@ void GBYankROM(struct GB* gb) {
static void GBSramDeinit(struct GB* gb) { static void GBSramDeinit(struct GB* gb) {
if (gb->sramVf) { if (gb->sramVf) {
gb->sramVf->unmap(gb->sramVf, gb->memory.sram, gb->sramSize); gb->sramVf->unmap(gb->sramVf, gb->memory.sram, gb->sramSize);
if (gb->memory.mbcType == GB_MBC3_RTC && gb->sramVf == gb->sramRealVf) { if (gb->sramVf == gb->sramRealVf) {
if (gb->memory.mbcType == GB_MBC3_RTC) {
GBMBCRTCWrite(gb); GBMBCRTCWrite(gb);
} else if (gb->memory.mbcType == GB_HuC3) {
GBMBCHuC3Write(gb);
}
} }
gb->sramVf = NULL; gb->sramVf = NULL;
} else if (gb->memory.sram) { } else if (gb->memory.sram) {
@ -163,6 +167,8 @@ bool GBLoadSave(struct GB* gb, struct VFile* vf) {
if (gb->memory.mbcType == GB_MBC3_RTC) { if (gb->memory.mbcType == GB_MBC3_RTC) {
GBMBCRTCRead(gb); GBMBCRTCRead(gb);
} else if (gb->memory.mbcType == GB_HuC3) {
GBMBCHuC3Read(gb);
} }
} }
return vf; return vf;
@ -246,6 +252,8 @@ void GBSramClean(struct GB* gb, uint32_t frameCount) {
} }
if (gb->memory.mbcType == GB_MBC3_RTC) { if (gb->memory.mbcType == GB_MBC3_RTC) {
GBMBCRTCWrite(gb); GBMBCRTCWrite(gb);
} else if (gb->memory.mbcType == GB_HuC3) {
GBMBCHuC3Write(gb);
} }
if (gb->sramVf == gb->sramRealVf) { if (gb->sramVf == gb->sramRealVf) {
if (gb->memory.sram && gb->sramVf->sync(gb->sramVf, gb->memory.sram, gb->sramSize)) { if (gb->memory.sram && gb->sramVf->sync(gb->sramVf, gb->memory.sram, gb->sramSize)) {

View File

@ -440,6 +440,8 @@ void GBMBCInit(struct GB* gb) {
if (gb->memory.mbcType == GB_MBC3_RTC) { if (gb->memory.mbcType == GB_MBC3_RTC) {
GBMBCRTCRead(gb); GBMBCRTCRead(gb);
} else if (gb->memory.mbcType == GB_HuC3) {
GBMBCHuC3Read(gb);
} }
} }
@ -1692,6 +1694,21 @@ uint8_t _GBHitekRead(struct GBMemory* memory, uint16_t address) {
} }
} }
static void _appendSaveSuffix(struct GB* gb, const void* buffer, size_t size) {
struct VFile* vf = gb->sramVf;
if ((size_t) vf->size(vf) < gb->sramSize + size) {
// Writing past the end of the file can invalidate the file mapping
vf->unmap(vf, gb->memory.sram, gb->sramSize);
gb->memory.sram = NULL;
}
vf->seek(vf, gb->sramSize, SEEK_SET);
vf->write(vf, buffer, size);
if (!gb->memory.sram) {
gb->memory.sram = vf->map(vf, gb->sramSize, MAP_WRITE);
GBMBCSwitchSramBank(gb, gb->memory.sramCurrentBank);
}
}
void GBMBCRTCRead(struct GB* gb) { void GBMBCRTCRead(struct GB* gb) {
struct GBMBCRTCSaveBuffer rtcBuffer; struct GBMBCRTCSaveBuffer rtcBuffer;
struct VFile* vf = gb->sramVf; struct VFile* vf = gb->sramVf;
@ -1735,15 +1752,41 @@ void GBMBCRTCWrite(struct GB* gb) {
STORE_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi); STORE_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi);
STORE_64LE(gb->memory.rtcLastLatch, 0, &rtcBuffer.unixTime); STORE_64LE(gb->memory.rtcLastLatch, 0, &rtcBuffer.unixTime);
if ((size_t) vf->size(vf) < gb->sramSize + sizeof(rtcBuffer)) { _appendSaveSuffix(gb, &rtcBuffer, sizeof(rtcBuffer));
// Writing past the end of the file can invalidate the file mapping }
vf->unmap(vf, gb->memory.sram, gb->sramSize);
gb->memory.sram = NULL; void GBMBCHuC3Read(struct GB* gb) {
struct GBMBCHuC3SaveBuffer buffer;
struct VFile* vf = gb->sramVf;
if (!vf) {
return;
} }
vf->seek(vf, gb->sramSize, SEEK_SET); vf->seek(vf, gb->sramSize, SEEK_SET);
vf->write(vf, &rtcBuffer, sizeof(rtcBuffer)); if (vf->read(vf, &buffer, sizeof(buffer)) < (ssize_t) sizeof(buffer)) {
if (!gb->memory.sram) { return;
gb->memory.sram = vf->map(vf, gb->sramSize, MAP_WRITE);
GBMBCSwitchSramBank(gb, gb->memory.sramCurrentBank);
} }
size_t i;
for (i = 0; i < 0x80; ++i) {
gb->memory.mbcState.huc3.registers[i * 2] = buffer.regs[i] & 0xF;
gb->memory.mbcState.huc3.registers[i * 2 + 1] = buffer.regs[i] >> 4;
}
LOAD_64LE(gb->memory.rtcLastLatch, 0, &buffer.latchedUnix);
}
void GBMBCHuC3Write(struct GB* gb) {
struct VFile* vf = gb->sramVf;
if (!vf) {
return;
}
struct GBMBCHuC3SaveBuffer buffer;
size_t i;
for (i = 0; i < 0x80; ++i) {
buffer.regs[i] = gb->memory.mbcState.huc3.registers[i * 2] & 0xF;
buffer.regs[i] |= gb->memory.mbcState.huc3.registers[i * 2 + 1] << 4;
}
STORE_64LE(gb->memory.rtcLastLatch, 0, &buffer.latchedUnix);
_appendSaveSuffix(gb, &buffer, sizeof(buffer));
} }