mirror of https://github.com/mgba-emu/mgba.git
GB MBC: Initial HuC-3 save format
This commit is contained in:
parent
c829cd2e70
commit
26aea8544f
2
CHANGES
2
CHANGES
|
@ -7,7 +7,7 @@ Features:
|
|||
- Cheat code support in homebrew ports
|
||||
- Acclerometer and gyro support for controllers on PC
|
||||
- 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
|
||||
- Discord Rich Presence now supports time elapsed
|
||||
- Additional scaling shaders
|
||||
|
|
|
@ -42,9 +42,18 @@ struct GBMBCRTCSaveBuffer {
|
|||
uint32_t latchedDaysHi;
|
||||
uint64_t unixTime;
|
||||
};
|
||||
|
||||
struct GBMBCHuC3SaveBuffer {
|
||||
uint8_t regs[0x80];
|
||||
uint64_t latchedUnix;
|
||||
};
|
||||
|
||||
void GBMBCRTCRead(struct GB* gb);
|
||||
void GBMBCRTCWrite(struct GB* gb);
|
||||
|
||||
void GBMBCHuC3Read(struct GB* gb);
|
||||
void GBMBCHuC3Write(struct GB* gb);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
||||
|
|
12
src/gb/gb.c
12
src/gb/gb.c
|
@ -143,8 +143,12 @@ void GBYankROM(struct GB* gb) {
|
|||
static void GBSramDeinit(struct GB* gb) {
|
||||
if (gb->sramVf) {
|
||||
gb->sramVf->unmap(gb->sramVf, gb->memory.sram, gb->sramSize);
|
||||
if (gb->memory.mbcType == GB_MBC3_RTC && gb->sramVf == gb->sramRealVf) {
|
||||
GBMBCRTCWrite(gb);
|
||||
if (gb->sramVf == gb->sramRealVf) {
|
||||
if (gb->memory.mbcType == GB_MBC3_RTC) {
|
||||
GBMBCRTCWrite(gb);
|
||||
} else if (gb->memory.mbcType == GB_HuC3) {
|
||||
GBMBCHuC3Write(gb);
|
||||
}
|
||||
}
|
||||
gb->sramVf = NULL;
|
||||
} else if (gb->memory.sram) {
|
||||
|
@ -163,6 +167,8 @@ bool GBLoadSave(struct GB* gb, struct VFile* vf) {
|
|||
|
||||
if (gb->memory.mbcType == GB_MBC3_RTC) {
|
||||
GBMBCRTCRead(gb);
|
||||
} else if (gb->memory.mbcType == GB_HuC3) {
|
||||
GBMBCHuC3Read(gb);
|
||||
}
|
||||
}
|
||||
return vf;
|
||||
|
@ -246,6 +252,8 @@ void GBSramClean(struct GB* gb, uint32_t frameCount) {
|
|||
}
|
||||
if (gb->memory.mbcType == GB_MBC3_RTC) {
|
||||
GBMBCRTCWrite(gb);
|
||||
} else if (gb->memory.mbcType == GB_HuC3) {
|
||||
GBMBCHuC3Write(gb);
|
||||
}
|
||||
if (gb->sramVf == gb->sramRealVf) {
|
||||
if (gb->memory.sram && gb->sramVf->sync(gb->sramVf, gb->memory.sram, gb->sramSize)) {
|
||||
|
|
59
src/gb/mbc.c
59
src/gb/mbc.c
|
@ -440,6 +440,8 @@ void GBMBCInit(struct GB* gb) {
|
|||
|
||||
if (gb->memory.mbcType == GB_MBC3_RTC) {
|
||||
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) {
|
||||
struct GBMBCRTCSaveBuffer rtcBuffer;
|
||||
struct VFile* vf = gb->sramVf;
|
||||
|
@ -1735,15 +1752,41 @@ void GBMBCRTCWrite(struct GB* gb) {
|
|||
STORE_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi);
|
||||
STORE_64LE(gb->memory.rtcLastLatch, 0, &rtcBuffer.unixTime);
|
||||
|
||||
if ((size_t) vf->size(vf) < gb->sramSize + 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;
|
||||
_appendSaveSuffix(gb, &rtcBuffer, sizeof(rtcBuffer));
|
||||
}
|
||||
|
||||
void GBMBCHuC3Read(struct GB* gb) {
|
||||
struct GBMBCHuC3SaveBuffer buffer;
|
||||
struct VFile* vf = gb->sramVf;
|
||||
if (!vf) {
|
||||
return;
|
||||
}
|
||||
vf->seek(vf, gb->sramSize, SEEK_SET);
|
||||
vf->write(vf, &rtcBuffer, sizeof(rtcBuffer));
|
||||
if (!gb->memory.sram) {
|
||||
gb->memory.sram = vf->map(vf, gb->sramSize, MAP_WRITE);
|
||||
GBMBCSwitchSramBank(gb, gb->memory.sramCurrentBank);
|
||||
if (vf->read(vf, &buffer, sizeof(buffer)) < (ssize_t) sizeof(buffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue