mirror of https://github.com/mgba-emu/mgba.git
GB MBC: Partial TAMA5 RTC
This commit is contained in:
parent
2a9f32a840
commit
bac42c9027
1
CHANGES
1
CHANGES
|
@ -78,6 +78,7 @@ Misc:
|
|||
- FFmpeg: Support dynamic audio sample rate
|
||||
- GB Audio: Increase sample rate
|
||||
- GB MBC: Filter out MBC errors when cartridge is yanked (fixes mgba.io/i/2488)
|
||||
- GB MBC: Partially implement TAMA5 RTC
|
||||
- GB Video: Add default SGB border
|
||||
- GBA: Automatically skip BIOS if ROM has invalid logo
|
||||
- GBA: Refine multiboot detection (fixes mgba.io/i/2192)
|
||||
|
|
|
@ -65,7 +65,7 @@ The following mappers are partially supported:
|
|||
- MBC6 (missing flash memory write support)
|
||||
- MMM01
|
||||
- Pocket Cam
|
||||
- TAMA5 (missing RTC support)
|
||||
- TAMA5 (incomplete RTC support)
|
||||
- HuC-1 (missing IR support)
|
||||
- HuC-3 (missing IR support)
|
||||
- Sachen MMC2 (missing alternate wiring support)
|
||||
|
|
|
@ -50,12 +50,23 @@ struct GBMBCHuC3SaveBuffer {
|
|||
uint64_t latchedUnix;
|
||||
};
|
||||
|
||||
struct GBMBCTAMA5SaveBuffer {
|
||||
uint8_t rtcTimerPage[0x8];
|
||||
uint8_t rtcAlarmPage[0x8];
|
||||
uint8_t rtcFreePage0[0x8];
|
||||
uint8_t rtcFreePage1[0x8];
|
||||
uint64_t latchedUnix;
|
||||
};
|
||||
|
||||
void GBMBCRTCRead(struct GB* gb);
|
||||
void GBMBCRTCWrite(struct GB* gb);
|
||||
|
||||
void GBMBCHuC3Read(struct GB* gb);
|
||||
void GBMBCHuC3Write(struct GB* gb);
|
||||
|
||||
void GBMBCTAMA5Read(struct GB* gb);
|
||||
void GBMBCTAMA5Write(struct GB* gb);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -94,7 +94,7 @@ enum GBTAMA5Register {
|
|||
GBTAMA5_BANK_HI = 0x1,
|
||||
GBTAMA5_WRITE_LO = 0x4,
|
||||
GBTAMA5_WRITE_HI = 0x5,
|
||||
GBTAMA5_CS = 0x6,
|
||||
GBTAMA5_ADDR_HI = 0x6,
|
||||
GBTAMA5_ADDR_LO = 0x7,
|
||||
GBTAMA5_MAX = 0x8,
|
||||
GBTAMA5_ACTIVE = 0xA,
|
||||
|
@ -102,6 +102,33 @@ enum GBTAMA5Register {
|
|||
GBTAMA5_READ_HI = 0xD,
|
||||
};
|
||||
|
||||
enum GBTAMA6RTCRegister {
|
||||
GBTAMA6_RTC_PA0_SECOND_1 = 0x0,
|
||||
GBTAMA6_RTC_PA0_SECOND_10 = 0x1,
|
||||
GBTAMA6_RTC_PA0_MINUTE_1 = 0x2,
|
||||
GBTAMA6_RTC_PA0_MINUTE_10 = 0x3,
|
||||
GBTAMA6_RTC_PA0_HOUR_1 = 0x4,
|
||||
GBTAMA6_RTC_PA0_HOUR_10 = 0x5,
|
||||
GBTAMA6_RTC_PA0_WEEK = 0x6,
|
||||
GBTAMA6_RTC_PA0_DAY_1 = 0x7,
|
||||
GBTAMA6_RTC_PA0_DAY_10 = 0x8,
|
||||
GBTAMA6_RTC_PA0_MONTH_1 = 0x9,
|
||||
GBTAMA6_RTC_PA0_MONTH_10 = 0xA,
|
||||
GBTAMA6_RTC_PA0_YEAR_1 = 0xB,
|
||||
GBTAMA6_RTC_PA0_YEAR_10 = 0xC,
|
||||
GBTAMA6_RTC_PAGE = 0xD,
|
||||
GBTAMA6_RTC_TEST = 0xE,
|
||||
GBTAMA6_RTC_RESET = 0xF,
|
||||
GBTAMA6_RTC_MAX
|
||||
};
|
||||
|
||||
enum GBTAMA6Command {
|
||||
GBTAMA6_MINUTE_WRITE = 0x4,
|
||||
GBTAMA6_HOUR_WRITE = 0x5,
|
||||
GBTAMA6_MINUTE_READ = 0x6,
|
||||
GBTAMA6_HOUR_READ = 0x7,
|
||||
};
|
||||
|
||||
enum GBHuC3Register {
|
||||
GBHUC3_RTC_MINUTES_LO = 0x10,
|
||||
GBHUC3_RTC_MINUTES_MI = 0x11,
|
||||
|
@ -180,6 +207,7 @@ struct GBPocketCamState {
|
|||
struct GBTAMA5State {
|
||||
uint8_t reg;
|
||||
uint8_t registers[GBTAMA5_MAX];
|
||||
uint8_t rtcTimerPage[GBTAMA6_RTC_MAX];
|
||||
};
|
||||
|
||||
struct GBHuC3State {
|
||||
|
|
|
@ -406,6 +406,10 @@ struct GBSerializedState {
|
|||
uint8_t locked;
|
||||
uint8_t bank0;
|
||||
} mmm01;
|
||||
struct {
|
||||
uint64_t lastLatch;
|
||||
uint8_t reg;
|
||||
} tama5;
|
||||
struct {
|
||||
uint64_t lastLatch;
|
||||
uint8_t index;
|
||||
|
@ -456,7 +460,13 @@ struct GBSerializedState {
|
|||
|
||||
uint32_t reserved2[0xA4];
|
||||
|
||||
union {
|
||||
uint8_t huc3Registers[0x80];
|
||||
struct {
|
||||
uint8_t registers[8];
|
||||
uint8_t rtcTimerPage[8];
|
||||
} tama5Registers;
|
||||
};
|
||||
|
||||
struct {
|
||||
uint8_t attributes[90];
|
||||
|
|
|
@ -220,6 +220,8 @@ static void GBSramDeinit(struct GB* gb) {
|
|||
GBMBCRTCWrite(gb);
|
||||
} else if (gb->memory.mbcType == GB_HuC3) {
|
||||
GBMBCHuC3Write(gb);
|
||||
} else if (gb->memory.mbcType == GB_TAMA5) {
|
||||
GBMBCTAMA5Write(gb);
|
||||
}
|
||||
}
|
||||
gb->sramVf = NULL;
|
||||
|
@ -244,6 +246,8 @@ bool GBLoadSave(struct GB* gb, struct VFile* vf) {
|
|||
GBMBCRTCRead(gb);
|
||||
} else if (gb->memory.mbcType == GB_HuC3) {
|
||||
GBMBCHuC3Read(gb);
|
||||
} else if (gb->memory.mbcType == GB_TAMA5) {
|
||||
GBMBCTAMA5Read(gb);
|
||||
}
|
||||
}
|
||||
return vf;
|
||||
|
@ -329,6 +333,8 @@ void GBSramClean(struct GB* gb, uint32_t frameCount) {
|
|||
GBMBCRTCWrite(gb);
|
||||
} else if (gb->memory.mbcType == GB_HuC3) {
|
||||
GBMBCHuC3Write(gb);
|
||||
} else if (gb->memory.mbcType == GB_TAMA5) {
|
||||
GBMBCTAMA5Write(gb);
|
||||
}
|
||||
if (gb->sramVf == gb->sramRealVf) {
|
||||
if (gb->memory.sram && gb->sramVf->sync(gb->sramVf, gb->memory.sram, gb->sramSize)) {
|
||||
|
|
245
src/gb/mbc.c
245
src/gb/mbc.c
|
@ -453,8 +453,6 @@ void GBMBCInit(struct GB* gb) {
|
|||
gb->memory.mbcRead = _GBHuC3Read;
|
||||
break;
|
||||
case GB_TAMA5:
|
||||
mLOG(GB_MBC, WARN, "unimplemented MBC: TAMA5");
|
||||
memset(gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
|
||||
gb->memory.mbcWrite = _GBTAMA5;
|
||||
gb->memory.mbcRead = _GBTAMA5Read;
|
||||
gb->sramSize = 0x20;
|
||||
|
@ -540,6 +538,8 @@ void GBMBCInit(struct GB* gb) {
|
|||
GBMBCRTCRead(gb);
|
||||
} else if (gb->memory.mbcType == GB_HuC3) {
|
||||
GBMBCHuC3Read(gb);
|
||||
} else if (gb->memory.mbcType == GB_TAMA5) {
|
||||
GBMBCTAMA5Read(gb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1514,6 +1514,150 @@ void _GBPocketCamCapture(struct GBMemory* memory) {
|
|||
}
|
||||
}
|
||||
|
||||
static const int _daysToMonth[] = {
|
||||
[ 1] = 0,
|
||||
[ 2] = 31,
|
||||
[ 3] = 31 + 28,
|
||||
[ 4] = 31 + 28 + 31,
|
||||
[ 5] = 31 + 28 + 31 + 30,
|
||||
[ 6] = 31 + 28 + 31 + 30 + 31,
|
||||
[ 7] = 31 + 28 + 31 + 30 + 31 + 30,
|
||||
[ 8] = 31 + 28 + 31 + 30 + 31 + 30 + 31,
|
||||
[ 9] = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
|
||||
[10] = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
|
||||
[11] = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
|
||||
[12] = 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
|
||||
};
|
||||
|
||||
static int _tama6DMYToDayOfYear(int day, int month, int year) {
|
||||
if (month < 1 || month > 12) {
|
||||
return -1;
|
||||
}
|
||||
day += _daysToMonth[month];
|
||||
if (month > 2 && (year % 4) == 0) {
|
||||
++day;
|
||||
}
|
||||
return day;
|
||||
}
|
||||
|
||||
static int _tama6DayOfYearToMonth(int day, int year) {
|
||||
int month;
|
||||
for (month = 1; month < 12; ++month) {
|
||||
if (day <= _daysToMonth[month + 1]) {
|
||||
return month;
|
||||
}
|
||||
if (month == 2 && year % 4 == 0) {
|
||||
if (day == 60) {
|
||||
return 2;
|
||||
}
|
||||
--day;
|
||||
}
|
||||
}
|
||||
return 12;
|
||||
}
|
||||
|
||||
static int _tama6DayOfYearToDayOfMonth(int day, int year) {
|
||||
int month;
|
||||
for (month = 1; month < 12; ++month) {
|
||||
if (day <= _daysToMonth[month + 1]) {
|
||||
return day - _daysToMonth[month];
|
||||
}
|
||||
if (month == 2 && year % 4 == 0) {
|
||||
if (day == 60) {
|
||||
return 29;
|
||||
}
|
||||
--day;
|
||||
}
|
||||
}
|
||||
return day - _daysToMonth[12];
|
||||
}
|
||||
|
||||
static void _latchTAMA6Rtc(struct mRTCSource* rtc, uint8_t* timerRegs, time_t* rtcLastLatch) {
|
||||
time_t t;
|
||||
if (rtc) {
|
||||
if (rtc->sample) {
|
||||
rtc->sample(rtc);
|
||||
}
|
||||
t = rtc->unixTime(rtc);
|
||||
} else {
|
||||
t = time(0);
|
||||
}
|
||||
time_t currentLatch = t;
|
||||
t -= *rtcLastLatch;
|
||||
*rtcLastLatch = currentLatch;
|
||||
if (!t) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t diff;
|
||||
diff = timerRegs[GBTAMA6_RTC_PA0_SECOND_1] + timerRegs[GBTAMA6_RTC_PA0_SECOND_10] * 10 + t % 60;
|
||||
if (diff < 0) {
|
||||
diff += 60;
|
||||
t -= 60;
|
||||
}
|
||||
timerRegs[GBTAMA6_RTC_PA0_SECOND_1] = diff % 10;
|
||||
timerRegs[GBTAMA6_RTC_PA0_SECOND_10] = (diff % 60) / 10;
|
||||
t /= 60;
|
||||
t += diff / 60;
|
||||
|
||||
diff = timerRegs[GBTAMA6_RTC_PA0_MINUTE_1] + timerRegs[GBTAMA6_RTC_PA0_MINUTE_10] * 10 + t % 60;
|
||||
if (diff < 0) {
|
||||
diff += 60;
|
||||
t -= 60;
|
||||
}
|
||||
timerRegs[GBTAMA6_RTC_PA0_MINUTE_1] = diff % 10;
|
||||
timerRegs[GBTAMA6_RTC_PA0_MINUTE_10] = (diff % 60) / 10;
|
||||
t /= 60;
|
||||
t += diff / 60;
|
||||
|
||||
diff = timerRegs[GBTAMA6_RTC_PA0_HOUR_1] + timerRegs[GBTAMA6_RTC_PA0_HOUR_10] * 10 + t % 24;
|
||||
if (diff < 0) {
|
||||
diff += 24;
|
||||
t -= 24;
|
||||
}
|
||||
timerRegs[GBTAMA6_RTC_PA0_HOUR_1] = (diff % 24) % 10;
|
||||
timerRegs[GBTAMA6_RTC_PA0_HOUR_10] = (diff % 24) / 10;
|
||||
t /= 24;
|
||||
t += diff / 24;
|
||||
|
||||
int day = timerRegs[GBTAMA6_RTC_PA0_DAY_1] + timerRegs[GBTAMA6_RTC_PA0_DAY_10] * 10;
|
||||
int month = timerRegs[GBTAMA6_RTC_PA0_MONTH_1] + timerRegs[GBTAMA6_RTC_PA0_MONTH_10] * 10;
|
||||
int year = timerRegs[GBTAMA6_RTC_PA0_YEAR_1] + timerRegs[GBTAMA6_RTC_PA0_YEAR_10] * 10;
|
||||
int dayInYear = _tama6DMYToDayOfYear(day, month, year);
|
||||
diff = dayInYear + t;
|
||||
while (diff <= 0) {
|
||||
// Previous year
|
||||
if (year % 4) {
|
||||
diff += 365;
|
||||
} else {
|
||||
diff += 366;
|
||||
}
|
||||
--year;
|
||||
}
|
||||
while (diff > (year % 4 ? 365 : 366)) {
|
||||
// Future year
|
||||
if (year % 4) {
|
||||
diff -= 365;
|
||||
} else {
|
||||
diff -= 366;
|
||||
}
|
||||
++year;
|
||||
}
|
||||
year %= 100;
|
||||
|
||||
day = _tama6DayOfYearToDayOfMonth(diff, year);
|
||||
month = _tama6DayOfYearToMonth(diff, year);
|
||||
|
||||
timerRegs[GBTAMA6_RTC_PA0_DAY_1] = day % 10;
|
||||
timerRegs[GBTAMA6_RTC_PA0_DAY_10] = day / 10;
|
||||
|
||||
timerRegs[GBTAMA6_RTC_PA0_MONTH_1] = month % 10;
|
||||
timerRegs[GBTAMA6_RTC_PA0_MONTH_10] = month / 10;
|
||||
|
||||
timerRegs[GBTAMA6_RTC_PA0_YEAR_1] = year % 10;
|
||||
timerRegs[GBTAMA6_RTC_PA0_YEAR_10] = year / 10;
|
||||
}
|
||||
|
||||
void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value) {
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
struct GBTAMA5State* tama5 = &memory->mbcState.tama5;
|
||||
|
@ -1524,8 +1668,9 @@ void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value) {
|
|||
} else {
|
||||
value &= 0xF;
|
||||
if (tama5->reg < GBTAMA5_MAX) {
|
||||
mLOG(GB_MBC, DEBUG, "TAMA5 write: %02X:%X", tama5->reg, value);
|
||||
tama5->registers[tama5->reg] = value;
|
||||
uint8_t address = ((tama5->registers[GBTAMA5_CS] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO];
|
||||
uint8_t address = ((tama5->registers[GBTAMA5_ADDR_HI] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO];
|
||||
uint8_t out = (tama5->registers[GBTAMA5_WRITE_HI] << 4) | tama5->registers[GBTAMA5_WRITE_LO];
|
||||
switch (tama5->reg) {
|
||||
case GBTAMA5_BANK_LO:
|
||||
|
@ -1534,18 +1679,36 @@ void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value) {
|
|||
break;
|
||||
case GBTAMA5_WRITE_LO:
|
||||
case GBTAMA5_WRITE_HI:
|
||||
case GBTAMA5_CS:
|
||||
case GBTAMA5_ADDR_HI:
|
||||
break;
|
||||
case GBTAMA5_ADDR_LO:
|
||||
switch (tama5->registers[GBTAMA5_CS] >> 1) {
|
||||
switch (tama5->registers[GBTAMA5_ADDR_HI] >> 1) {
|
||||
case 0x0: // RAM write
|
||||
memory->sram[address] = out;
|
||||
gb->sramDirty |= mSAVEDATA_DIRT_NEW;
|
||||
break;
|
||||
case 0x1: // RAM read
|
||||
break;
|
||||
case 0x2: // Other commands
|
||||
switch (address) {
|
||||
case GBTAMA6_MINUTE_WRITE:
|
||||
tama5->rtcTimerPage[GBTAMA6_RTC_PA0_MINUTE_1] = out & 0xF;
|
||||
tama5->rtcTimerPage[GBTAMA6_RTC_PA0_MINUTE_10] = out >> 4;
|
||||
break;
|
||||
case GBTAMA6_HOUR_WRITE:
|
||||
tama5->rtcTimerPage[GBTAMA6_RTC_PA0_HOUR_1] = out & 0xF;
|
||||
tama5->rtcTimerPage[GBTAMA6_RTC_PA0_HOUR_10] = out >> 4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x4: // RTC access
|
||||
if (!(address & 1)) {
|
||||
tama5->rtcTimerPage[out & 0xF] = out >> 4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mLOG(GB_MBC, STUB, "TAMA5 unknown address: %X-%02X:%02X", tama5->registers[GBTAMA5_CS] >> 1, address, out);
|
||||
mLOG(GB_MBC, STUB, "TAMA5 unknown address: %02X:%02X", address, out);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1571,18 +1734,41 @@ uint8_t _GBTAMA5Read(struct GBMemory* memory, uint16_t address) {
|
|||
return 0xFF;
|
||||
} else {
|
||||
uint8_t value = 0xF0;
|
||||
uint8_t address = ((tama5->registers[GBTAMA5_CS] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO];
|
||||
uint8_t address = ((tama5->registers[GBTAMA5_ADDR_HI] << 4) & 0x10) | tama5->registers[GBTAMA5_ADDR_LO];
|
||||
switch (tama5->reg) {
|
||||
case GBTAMA5_ACTIVE:
|
||||
return 0xF1;
|
||||
case GBTAMA5_READ_LO:
|
||||
case GBTAMA5_READ_HI:
|
||||
switch (tama5->registers[GBTAMA5_CS] >> 1) {
|
||||
case 1:
|
||||
switch (tama5->registers[GBTAMA5_ADDR_HI] >> 1) {
|
||||
case 0x1:
|
||||
value = memory->sram[address];
|
||||
break;
|
||||
case 0x2:
|
||||
mLOG(GB_MBC, STUB, "TAMA5 unknown read %s: %02X", tama5->reg == GBTAMA5_READ_HI ? "hi" : "lo", address);
|
||||
_latchTAMA6Rtc(memory->rtc, tama5->rtcTimerPage, &memory->rtcLastLatch);
|
||||
switch (address) {
|
||||
case GBTAMA6_MINUTE_READ:
|
||||
value = (tama5->rtcTimerPage[GBTAMA6_RTC_PA0_MINUTE_10] << 4) | tama5->rtcTimerPage[GBTAMA6_RTC_PA0_MINUTE_1];
|
||||
break;
|
||||
case GBTAMA6_HOUR_READ:
|
||||
value = (tama5->rtcTimerPage[GBTAMA6_RTC_PA0_HOUR_10] << 4) | tama5->rtcTimerPage[GBTAMA6_RTC_PA0_HOUR_1];
|
||||
break;
|
||||
default:
|
||||
mLOG(GB_MBC, STUB, "TAMA5 unknown read: %02X", tama5->reg);
|
||||
value = address;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x4:
|
||||
if (tama5->reg == GBTAMA5_READ_HI) {
|
||||
mLOG(GB_MBC, GAME_ERROR, "TAMA5 reading RTC incorrectly");
|
||||
break;
|
||||
}
|
||||
_latchTAMA6Rtc(memory->rtc, tama5->rtcTimerPage, &memory->rtcLastLatch);
|
||||
value = tama5->rtcTimerPage[tama5->registers[GBTAMA5_WRITE_LO]];
|
||||
break;
|
||||
default:
|
||||
mLOG(GB_MBC, STUB, "TAMA5 unknown read %s: %02X", tama5->reg == GBTAMA5_READ_HI ? "hi" : "lo", address);
|
||||
break;
|
||||
}
|
||||
if (tama5->reg == GBTAMA5_READ_HI) {
|
||||
|
@ -2015,3 +2201,42 @@ void GBMBCHuC3Write(struct GB* gb) {
|
|||
|
||||
_appendSaveSuffix(gb, &buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
void GBMBCTAMA5Read(struct GB* gb) {
|
||||
struct GBMBCTAMA5SaveBuffer buffer;
|
||||
struct VFile* vf = gb->sramVf;
|
||||
if (!vf) {
|
||||
return;
|
||||
}
|
||||
vf->seek(vf, gb->sramSize, SEEK_SET);
|
||||
if (vf->read(vf, &buffer, sizeof(buffer)) < (ssize_t) sizeof(buffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < 0x8; ++i) {
|
||||
gb->memory.mbcState.tama5.rtcTimerPage[i * 2] = buffer.rtcTimerPage[i] & 0xF;
|
||||
gb->memory.mbcState.tama5.rtcTimerPage[i * 2 + 1] = buffer.rtcTimerPage[i] >> 4;
|
||||
}
|
||||
LOAD_64LE(gb->memory.rtcLastLatch, 0, &buffer.latchedUnix);
|
||||
}
|
||||
|
||||
void GBMBCTAMA5Write(struct GB* gb) {
|
||||
struct VFile* vf = gb->sramVf;
|
||||
if (!vf) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct GBMBCTAMA5SaveBuffer buffer;
|
||||
size_t i;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
buffer.rtcTimerPage[i] = gb->memory.mbcState.tama5.rtcTimerPage[i * 2] & 0xF;
|
||||
buffer.rtcTimerPage[i] |= gb->memory.mbcState.tama5.rtcTimerPage[i * 2 + 1] << 4;
|
||||
buffer.rtcAlarmPage[i] = 0;
|
||||
buffer.rtcFreePage0[i] = 0;
|
||||
buffer.rtcFreePage1[i] = 0;
|
||||
}
|
||||
STORE_64LE(gb->memory.rtcLastLatch, 0, &buffer.latchedUnix);
|
||||
|
||||
_appendSaveSuffix(gb, &buffer, sizeof(buffer));
|
||||
}
|
||||
|
|
|
@ -765,6 +765,16 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) {
|
|||
STORE_16LE(memory->mbcState.mbc7.sr, 0, &state->memory.mbc7.sr);
|
||||
STORE_32LE(memory->mbcState.mbc7.writable, 0, &state->memory.mbc7.writable);
|
||||
break;
|
||||
case GB_TAMA5:
|
||||
STORE_64LE(memory->rtcLastLatch, 0, &state->memory.tama5.lastLatch);
|
||||
state->memory.tama5.reg = memory->mbcState.tama5.reg;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
state->tama5Registers.registers[i] = memory->mbcState.tama5.registers[i * 2] & 0xF;
|
||||
state->tama5Registers.registers[i] |= memory->mbcState.tama5.registers[i * 2 + 1] << 4;
|
||||
state->tama5Registers.rtcTimerPage[i] = memory->mbcState.tama5.rtcTimerPage[i * 2] & 0xF;
|
||||
state->tama5Registers.rtcTimerPage[i] |= memory->mbcState.tama5.rtcTimerPage[i * 2 + 1] << 4;
|
||||
}
|
||||
break;
|
||||
case GB_HuC3:
|
||||
STORE_64LE(memory->rtcLastLatch, 0, &state->memory.huc3.lastLatch);
|
||||
state->memory.huc3.index = memory->mbcState.huc3.index;
|
||||
|
@ -874,6 +884,16 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
|||
LOAD_16LE(memory->mbcState.mbc7.sr, 0, &state->memory.mbc7.sr);
|
||||
LOAD_32LE(memory->mbcState.mbc7.writable, 0, &state->memory.mbc7.writable);
|
||||
break;
|
||||
case GB_TAMA5:
|
||||
LOAD_64LE(memory->rtcLastLatch, 0, &state->memory.tama5.lastLatch);
|
||||
memory->mbcState.tama5.reg = state->memory.tama5.reg;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
memory->mbcState.tama5.registers[i * 2] = state->tama5Registers.registers[i] & 0xF;
|
||||
memory->mbcState.tama5.registers[i * 2 + 1] = state->tama5Registers.registers[i] >> 4;
|
||||
memory->mbcState.tama5.rtcTimerPage[i * 2] = state->tama5Registers.rtcTimerPage[i] & 0xF;
|
||||
memory->mbcState.tama5.rtcTimerPage[i * 2 + 1] = state->tama5Registers.rtcTimerPage[i] >> 4;
|
||||
}
|
||||
break;
|
||||
case GB_HuC3:
|
||||
LOAD_64LE(memory->rtcLastLatch, 0, &state->memory.huc3.lastLatch);
|
||||
memory->mbcState.huc3.index = state->memory.huc3.index;
|
||||
|
|
Loading…
Reference in New Issue