Support for RTC latching. Fixes #4.
This commit is contained in:
parent
92c2b22735
commit
ee4907949b
@ -369,7 +369,7 @@ int GB_save_battery(GB_gameboy_t *gb, const char *path)
|
|||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
if (gb->cartridge_type->has_rtc) {
|
if (gb->cartridge_type->has_rtc) {
|
||||||
if (fwrite(gb->rtc_data, 1, sizeof(gb->rtc_data), f) != sizeof(gb->rtc_data)) {
|
if (fwrite(&gb->rtc_real, 1, sizeof(gb->rtc_real), f) != sizeof(gb->rtc_real)) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
@ -397,7 +397,7 @@ void GB_load_battery(GB_gameboy_t *gb, const char *path)
|
|||||||
goto reset_rtc;
|
goto reset_rtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fread(gb->rtc_data, 1, sizeof(gb->rtc_data), f) != sizeof(gb->rtc_data)) {
|
if (fread(&gb->rtc_real, 1, sizeof(gb->rtc_real), f) != sizeof(gb->rtc_real)) {
|
||||||
goto reset_rtc;
|
goto reset_rtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,7 +418,7 @@ void GB_load_battery(GB_gameboy_t *gb, const char *path)
|
|||||||
goto exit;
|
goto exit;
|
||||||
reset_rtc:
|
reset_rtc:
|
||||||
gb->last_rtc_second = time(NULL);
|
gb->last_rtc_second = time(NULL);
|
||||||
gb->rtc_high |= 0x80; /* This gives the game a hint that the clock should be reset. */
|
gb->rtc_real.high |= 0x80; /* This gives the game a hint that the clock should be reset. */
|
||||||
exit:
|
exit:
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return;
|
return;
|
||||||
|
15
Core/gb.h
15
Core/gb.h
@ -306,15 +306,16 @@ typedef struct GB_gameboy_s {
|
|||||||
GB_SECTION(rtc,
|
GB_SECTION(rtc,
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint8_t rtc_seconds;
|
uint8_t seconds;
|
||||||
uint8_t rtc_minutes;
|
uint8_t minutes;
|
||||||
uint8_t rtc_hours;
|
uint8_t hours;
|
||||||
uint8_t rtc_days;
|
uint8_t days;
|
||||||
uint8_t rtc_high;
|
uint8_t high;
|
||||||
};
|
};
|
||||||
uint8_t rtc_data[5];
|
uint8_t data[5];
|
||||||
};
|
} rtc_real, rtc_latched;
|
||||||
time_t last_rtc_second;
|
time_t last_rtc_second;
|
||||||
|
bool rtc_latch;
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Video Display */
|
/* Video Display */
|
||||||
|
@ -78,8 +78,8 @@ static uint8_t read_mbc_ram(GB_gameboy_t *gb, uint16_t addr)
|
|||||||
|
|
||||||
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
||||||
/* RTC read */
|
/* RTC read */
|
||||||
gb->rtc_high |= ~0xC1; /* Not all bytes in RTC high are used. */
|
gb->rtc_latched.high |= ~0xC1; /* Not all bytes in RTC high are used. */
|
||||||
return gb->rtc_data[gb->mbc_ram_bank - 8];
|
return gb->rtc_latched.data[gb->mbc_ram_bank - 8];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gb->mbc_ram) {
|
if (!gb->mbc_ram) {
|
||||||
@ -284,7 +284,12 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break;
|
case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break;
|
||||||
case 0x2000: case 0x3000: gb->mbc3.rom_bank = value; break;
|
case 0x2000: case 0x3000: gb->mbc3.rom_bank = value; break;
|
||||||
case 0x4000: case 0x5000: gb->mbc3.ram_bank = value; break;
|
case 0x4000: case 0x5000: gb->mbc3.ram_bank = value; break;
|
||||||
case 0x6000: case 0x7000: /* Todo: Clock latching support */ break;
|
case 0x6000: case 0x7000:
|
||||||
|
if (!gb->rtc_latch && (value & 1)) { /* Todo: verify condition is correct*/
|
||||||
|
memcpy(&gb->rtc_latched, &gb->rtc_real, sizeof(gb->rtc_real));
|
||||||
|
}
|
||||||
|
gb->rtc_latch = value & 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GB_MBC5:
|
case GB_MBC5:
|
||||||
@ -314,8 +319,7 @@ static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
|
|
||||||
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
||||||
/* RTC read */
|
/* RTC read */
|
||||||
gb->rtc_data[gb->mbc_ram_bank - 8] = value;
|
gb->rtc_latched.data[gb->mbc_ram_bank - 8] = gb->rtc_real.data[gb->mbc_ram_bank - 8] = value; /* Todo: does it really write both? */
|
||||||
gb->rtc_high |= ~0xC1; /* Not all bytes in RTC high are used. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb->cartridge_type->mbc_type == GB_MBC2) {
|
if (gb->cartridge_type->mbc_type == GB_MBC2) {
|
||||||
|
@ -114,26 +114,26 @@ void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac)
|
|||||||
|
|
||||||
void GB_rtc_run(GB_gameboy_t *gb)
|
void GB_rtc_run(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
if ((gb->rtc_high & 0x40) == 0) { /* is timer running? */
|
if ((gb->rtc_real.high & 0x40) == 0) { /* is timer running? */
|
||||||
time_t current_time = time(NULL);
|
time_t current_time = time(NULL);
|
||||||
while (gb->last_rtc_second < current_time) {
|
while (gb->last_rtc_second < current_time) {
|
||||||
gb->last_rtc_second++;
|
gb->last_rtc_second++;
|
||||||
if (++gb->rtc_seconds == 60)
|
if (++gb->rtc_real.seconds == 60)
|
||||||
{
|
{
|
||||||
gb->rtc_seconds = 0;
|
gb->rtc_real.seconds = 0;
|
||||||
if (++gb->rtc_minutes == 60)
|
if (++gb->rtc_real.minutes == 60)
|
||||||
{
|
{
|
||||||
gb->rtc_minutes = 0;
|
gb->rtc_real.minutes = 0;
|
||||||
if (++gb->rtc_hours == 24)
|
if (++gb->rtc_real.hours == 24)
|
||||||
{
|
{
|
||||||
gb->rtc_hours = 0;
|
gb->rtc_real.hours = 0;
|
||||||
if (++gb->rtc_days == 0)
|
if (++gb->rtc_real.days == 0)
|
||||||
{
|
{
|
||||||
if (gb->rtc_high & 1) /* Bit 8 of days*/
|
if (gb->rtc_real.high & 1) /* Bit 8 of days*/
|
||||||
{
|
{
|
||||||
gb->rtc_high |= 0x80; /* Overflow bit */
|
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
||||||
}
|
}
|
||||||
gb->rtc_high ^= 1;
|
gb->rtc_real.high ^= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user