mirror of https://github.com/bsnes-emu/bsnes.git
Redo TPP1 saving, fix RTC and HUC3 in BESS
This commit is contained in:
parent
f0a6488546
commit
87a2d48675
84
Core/gb.c
84
Core/gb.c
|
@ -572,6 +572,15 @@ typedef struct {
|
||||||
uint8_t padding5[3];
|
uint8_t padding5[3];
|
||||||
} GB_vba_rtc_time_t;
|
} GB_vba_rtc_time_t;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) {
|
||||||
|
uint32_t magic;
|
||||||
|
uint16_t version;
|
||||||
|
uint8_t mr4;
|
||||||
|
uint8_t reserved;
|
||||||
|
uint64_t last_rtc_second;
|
||||||
|
uint8_t rtc_data[4];
|
||||||
|
} GB_tpp1_rtc_save_t;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
struct __attribute__((packed)) {
|
struct __attribute__((packed)) {
|
||||||
GB_rtc_time_t rtc_real;
|
GB_rtc_time_t rtc_real;
|
||||||
|
@ -589,6 +598,18 @@ typedef union {
|
||||||
} vba64;
|
} vba64;
|
||||||
} GB_rtc_save_t;
|
} GB_rtc_save_t;
|
||||||
|
|
||||||
|
static void GB_fill_tpp1_save_data(GB_gameboy_t *gb, GB_tpp1_rtc_save_t *data)
|
||||||
|
{
|
||||||
|
data->magic = BE32('TPP1');
|
||||||
|
data->version = BE16(0x100);
|
||||||
|
data->mr4 = gb->tpp1_mr4;
|
||||||
|
data->reserved = 0;
|
||||||
|
data->last_rtc_second = LE64(time(NULL));
|
||||||
|
unrolled for (unsigned i = 4; i--;) {
|
||||||
|
data->rtc_data[i] = gb->rtc_real.data[i ^ 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int GB_save_battery_size(GB_gameboy_t *gb)
|
int GB_save_battery_size(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
if (!gb->cartridge_type->has_battery) return 0; // Nothing to save.
|
if (!gb->cartridge_type->has_battery) return 0; // Nothing to save.
|
||||||
|
@ -599,6 +620,11 @@ int GB_save_battery_size(GB_gameboy_t *gb)
|
||||||
if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
||||||
return gb->mbc_ram_size + sizeof(GB_huc3_rtc_time_t);
|
return gb->mbc_ram_size + sizeof(GB_huc3_rtc_time_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
||||||
|
return gb->mbc_ram_size + sizeof(GB_tpp1_rtc_save_t);
|
||||||
|
}
|
||||||
|
|
||||||
GB_rtc_save_t rtc_save_size;
|
GB_rtc_save_t rtc_save_size;
|
||||||
return gb->mbc_ram_size + (gb->cartridge_type->has_rtc ? sizeof(rtc_save_size.vba64) : 0);
|
return gb->mbc_ram_size + (gb->cartridge_type->has_rtc ? sizeof(rtc_save_size.vba64) : 0);
|
||||||
}
|
}
|
||||||
|
@ -613,7 +639,13 @@ int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size)
|
||||||
|
|
||||||
memcpy(buffer, gb->mbc_ram, gb->mbc_ram_size);
|
memcpy(buffer, gb->mbc_ram, gb->mbc_ram_size);
|
||||||
|
|
||||||
if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
||||||
|
buffer += gb->mbc_ram_size;
|
||||||
|
GB_tpp1_rtc_save_t rtc_save;
|
||||||
|
GB_fill_tpp1_save_data(gb, &rtc_save);
|
||||||
|
memcpy(buffer, &rtc_save, sizeof(rtc_save));
|
||||||
|
}
|
||||||
|
else if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
||||||
buffer += gb->mbc_ram_size;
|
buffer += gb->mbc_ram_size;
|
||||||
|
|
||||||
#ifdef GB_BIG_ENDIAN
|
#ifdef GB_BIG_ENDIAN
|
||||||
|
@ -676,7 +708,16 @@ int GB_save_battery(GB_gameboy_t *gb, const char *path)
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
||||||
|
GB_tpp1_rtc_save_t rtc_save;
|
||||||
|
GB_fill_tpp1_save_data(gb, &rtc_save);
|
||||||
|
|
||||||
|
if (fwrite(&rtc_save, sizeof(rtc_save), 1, f) != 1) {
|
||||||
|
fclose(f);
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
||||||
#ifdef GB_BIG_ENDIAN
|
#ifdef GB_BIG_ENDIAN
|
||||||
GB_huc3_rtc_time_t rtc_save = {
|
GB_huc3_rtc_time_t rtc_save = {
|
||||||
__builtin_bswap64(gb->last_rtc_second),
|
__builtin_bswap64(gb->last_rtc_second),
|
||||||
|
@ -731,6 +772,14 @@ int GB_save_battery(GB_gameboy_t *gb, const char *path)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void GB_load_tpp1_save_data(GB_gameboy_t *gb, const GB_tpp1_rtc_save_t *data)
|
||||||
|
{
|
||||||
|
gb->last_rtc_second = LE64(data->last_rtc_second);
|
||||||
|
unrolled for (unsigned i = 4; i--;) {
|
||||||
|
gb->rtc_real.data[i ^ 3] = data->rtc_data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size)
|
void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size)
|
||||||
{
|
{
|
||||||
memcpy(gb->mbc_ram, buffer, MIN(gb->mbc_ram_size, size));
|
memcpy(gb->mbc_ram, buffer, MIN(gb->mbc_ram_size, size));
|
||||||
|
@ -738,6 +787,22 @@ void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t
|
||||||
goto reset_rtc;
|
goto reset_rtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
||||||
|
GB_tpp1_rtc_save_t rtc_save;
|
||||||
|
if (size - gb->mbc_ram_size < sizeof(rtc_save)) {
|
||||||
|
goto reset_rtc;
|
||||||
|
}
|
||||||
|
memcpy(&rtc_save, buffer + gb->mbc_ram_size, sizeof(rtc_save));
|
||||||
|
|
||||||
|
GB_load_tpp1_save_data(gb, &rtc_save);
|
||||||
|
|
||||||
|
if (gb->last_rtc_second > time(NULL)) {
|
||||||
|
/* We must reset RTC here, or it will not advance. */
|
||||||
|
goto reset_rtc;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
||||||
GB_huc3_rtc_time_t rtc_save;
|
GB_huc3_rtc_time_t rtc_save;
|
||||||
if (size - gb->mbc_ram_size < sizeof(rtc_save)) {
|
if (size - gb->mbc_ram_size < sizeof(rtc_save)) {
|
||||||
|
@ -847,6 +912,21 @@ void GB_load_battery(GB_gameboy_t *gb, const char *path)
|
||||||
goto reset_rtc;
|
goto reset_rtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
||||||
|
GB_tpp1_rtc_save_t rtc_save;
|
||||||
|
if (fread(&rtc_save, sizeof(rtc_save), 1, f) != 1) {
|
||||||
|
goto reset_rtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_load_tpp1_save_data(gb, &rtc_save);
|
||||||
|
|
||||||
|
if (gb->last_rtc_second > time(NULL)) {
|
||||||
|
/* We must reset RTC here, or it will not advance. */
|
||||||
|
goto reset_rtc;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
||||||
GB_huc3_rtc_time_t rtc_save;
|
GB_huc3_rtc_time_t rtc_save;
|
||||||
if (fread(&rtc_save, sizeof(rtc_save), 1, f) != 1) {
|
if (fread(&rtc_save, sizeof(rtc_save), 1, f) != 1) {
|
||||||
|
|
12
Core/gb.h
12
Core/gb.h
|
@ -98,6 +98,13 @@ typedef union {
|
||||||
uint8_t days;
|
uint8_t days;
|
||||||
uint8_t high;
|
uint8_t high;
|
||||||
};
|
};
|
||||||
|
struct {
|
||||||
|
uint8_t seconds;
|
||||||
|
uint8_t minutes;
|
||||||
|
uint8_t hours:5;
|
||||||
|
uint8_t weekday:3;
|
||||||
|
uint8_t weeks;
|
||||||
|
} tpp1;
|
||||||
uint8_t data[5];
|
uint8_t data[5];
|
||||||
} GB_rtc_time_t;
|
} GB_rtc_time_t;
|
||||||
|
|
||||||
|
@ -515,6 +522,7 @@ struct GB_gameboy_internal_s {
|
||||||
uint64_t last_rtc_second;
|
uint64_t last_rtc_second;
|
||||||
bool rtc_latch;
|
bool rtc_latch;
|
||||||
uint32_t rtc_cycles;
|
uint32_t rtc_cycles;
|
||||||
|
uint8_t tpp1_mr4;
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Video Display */
|
/* Video Display */
|
||||||
|
@ -781,8 +789,6 @@ void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *
|
||||||
void *GB_get_user_data(GB_gameboy_t *gb);
|
void *GB_get_user_data(GB_gameboy_t *gb);
|
||||||
void GB_set_user_data(GB_gameboy_t *gb, void *data);
|
void GB_set_user_data(GB_gameboy_t *gb, void *data);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int GB_load_boot_rom(GB_gameboy_t *gb, const char *path);
|
int GB_load_boot_rom(GB_gameboy_t *gb, const char *path);
|
||||||
void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size);
|
void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size);
|
||||||
int GB_load_rom(GB_gameboy_t *gb, const char *path);
|
int GB_load_rom(GB_gameboy_t *gb, const char *path);
|
||||||
|
@ -850,5 +856,5 @@ unsigned GB_get_screen_width(GB_gameboy_t *gb);
|
||||||
unsigned GB_get_screen_height(GB_gameboy_t *gb);
|
unsigned GB_get_screen_height(GB_gameboy_t *gb);
|
||||||
double GB_get_usual_frame_rate(GB_gameboy_t *gb);
|
double GB_get_usual_frame_rate(GB_gameboy_t *gb);
|
||||||
unsigned GB_get_player_count(GB_gameboy_t *gb);
|
unsigned GB_get_player_count(GB_gameboy_t *gb);
|
||||||
|
|
||||||
#endif /* GB_h */
|
#endif /* GB_h */
|
||||||
|
|
|
@ -185,30 +185,13 @@ static uint8_t read_mbc_ram(GB_gameboy_t *gb, uint16_t addr)
|
||||||
case 0: return gb->tpp1_rom_bank;
|
case 0: return gb->tpp1_rom_bank;
|
||||||
case 1: return gb->tpp1_rom_bank >> 8;
|
case 1: return gb->tpp1_rom_bank >> 8;
|
||||||
case 2: return gb->tpp1_ram_bank;
|
case 2: return gb->tpp1_ram_bank;
|
||||||
case 3: return gb->rumble_strength | (((gb->rtc_real.high & 0xC0) ^ 0x40) >> 4);
|
case 3: return gb->rumble_strength | gb->tpp1_mr4;
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
break; // Read RAM
|
break; // Read RAM
|
||||||
case 5:
|
case 5:
|
||||||
switch (addr & 3) {
|
return gb->rtc_latched.data[(addr & 3) ^ 3];
|
||||||
case 0: { // Week count
|
|
||||||
unsigned total_days = (((gb->rtc_latched.high & 7) << 8) + gb->rtc_latched.days);
|
|
||||||
if (gb->rtc_latched.high & 0x20) {
|
|
||||||
return total_days / 7 - 1;
|
|
||||||
}
|
|
||||||
return total_days / 7;
|
|
||||||
}
|
|
||||||
case 1: { // Week count
|
|
||||||
unsigned total_days = (((gb->rtc_latched.high & 7) << 8) + gb->rtc_latched.days);
|
|
||||||
if (gb->rtc_latched.high & 0x20) {
|
|
||||||
return gb->rtc_latched.hours | 0xe0; // Hours and weekday
|
|
||||||
}
|
|
||||||
return gb->rtc_latched.hours | ((total_days % 7) << 5); // Hours and weekday
|
|
||||||
}
|
|
||||||
case 2: return gb->rtc_latched.minutes;
|
|
||||||
case 3: return gb->rtc_latched.seconds;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
|
@ -625,20 +608,17 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||||
memcpy(&gb->rtc_latched, &gb->rtc_real, sizeof(gb->rtc_real));
|
memcpy(&gb->rtc_latched, &gb->rtc_real, sizeof(gb->rtc_real));
|
||||||
break;
|
break;
|
||||||
case 0x11: {
|
case 0x11: {
|
||||||
uint8_t flags = gb->rtc_real.high & 0xc0;
|
|
||||||
memcpy(&gb->rtc_real, &gb->rtc_latched, sizeof(gb->rtc_real));
|
memcpy(&gb->rtc_real, &gb->rtc_latched, sizeof(gb->rtc_real));
|
||||||
gb->rtc_real.high &= ~0xe0;
|
|
||||||
gb->rtc_real.high |= flags;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x14:
|
case 0x14:
|
||||||
gb->rtc_real.high &= ~0x80;
|
gb->tpp1_mr4 &= ~0x8;
|
||||||
break;
|
break;
|
||||||
case 0x18:
|
case 0x18:
|
||||||
gb->rtc_real.high |= 0x40;
|
gb->tpp1_mr4 &= ~0x4;
|
||||||
break;
|
break;
|
||||||
case 0x19:
|
case 0x19:
|
||||||
gb->rtc_real.high &= ~0x40;
|
gb->tpp1_mr4 |= 0x4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x20:
|
case 0x20:
|
||||||
|
@ -776,32 +756,7 @@ static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||||
case 3:
|
case 3:
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
switch (addr & 3) {
|
gb->rtc_latched.data[(addr & 3) ^ 3] = value;
|
||||||
case 0: {
|
|
||||||
unsigned total_days = (((gb->rtc_latched.high & 7) << 8) + gb->rtc_latched.days);
|
|
||||||
total_days = total_days % 7 + value * 7;
|
|
||||||
bool had_illegal_weekday = gb->rtc_latched.high & 0x20;
|
|
||||||
gb->rtc_latched.days = total_days;
|
|
||||||
gb->rtc_latched.high = total_days >> 8;
|
|
||||||
if (had_illegal_weekday) {
|
|
||||||
gb->rtc_latched.high |= 0x20;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
unsigned total_days = (((gb->rtc_latched.high & 7) << 8) + gb->rtc_latched.days);
|
|
||||||
total_days = total_days / 7 * 7 + (value >> 5);
|
|
||||||
gb->rtc_latched.hours = value & 0x1F;
|
|
||||||
gb->rtc_latched.days = total_days;
|
|
||||||
gb->rtc_latched.high = total_days >> 8;
|
|
||||||
if ((value & 0xE0) == 0xE0) { // Illegal weekday
|
|
||||||
gb->rtc_latched.high |= 0x20;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case 2: gb->rtc_latched.minutes = value; return;
|
|
||||||
case 3: gb->rtc_latched.seconds = value; return;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -112,6 +112,14 @@ typedef struct __attribute__((packed)){
|
||||||
GB_huc3_rtc_time_t data;
|
GB_huc3_rtc_time_t data;
|
||||||
} BESS_HUC3_t;
|
} BESS_HUC3_t;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)){
|
||||||
|
BESS_block_t header;
|
||||||
|
uint64_t last_rtc_second;
|
||||||
|
uint8_t real_rtc_data[4];
|
||||||
|
uint8_t latched_rtc_data[4];
|
||||||
|
uint8_t mr4;
|
||||||
|
} BESS_TPP1_t;
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
uint16_t address;
|
uint16_t address;
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
|
@ -222,7 +230,7 @@ static size_t bess_size_for_cartridge(const GB_cartridge_t *cart)
|
||||||
case GB_HUC3:
|
case GB_HUC3:
|
||||||
return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_HUC3_t);
|
return sizeof(BESS_block_t) + 3 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_HUC3_t);
|
||||||
case GB_TPP1:
|
case GB_TPP1:
|
||||||
return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_RTC_t);
|
return sizeof(BESS_block_t) + 4 * sizeof(BESS_MBC_pair_t) + sizeof(BESS_TPP1_t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +261,7 @@ size_t GB_get_save_state_size(GB_gameboy_t *gb)
|
||||||
+ sizeof(BESS_CORE_t)
|
+ sizeof(BESS_CORE_t)
|
||||||
+ sizeof(BESS_XOAM_t)
|
+ sizeof(BESS_XOAM_t)
|
||||||
+ (gb->sgb? sizeof(BESS_SGB_t) : 0)
|
+ (gb->sgb? sizeof(BESS_SGB_t) : 0)
|
||||||
+ bess_size_for_cartridge(gb->cartridge_type) // MBC & RTC/HUC3 block
|
+ bess_size_for_cartridge(gb->cartridge_type) // MBC & RTC/HUC3/TPP1 block
|
||||||
+ sizeof(BESS_block_t) // END block
|
+ sizeof(BESS_block_t) // END block
|
||||||
+ sizeof(BESS_footer_t);
|
+ sizeof(BESS_footer_t);
|
||||||
}
|
}
|
||||||
|
@ -630,7 +638,22 @@ static int save_state_internal(GB_gameboy_t *gb, virtual_file_t *file, bool appe
|
||||||
|
|
||||||
save_bess_mbc_block(gb, file);
|
save_bess_mbc_block(gb, file);
|
||||||
if (gb->cartridge_type->has_rtc) {
|
if (gb->cartridge_type->has_rtc) {
|
||||||
if (gb->cartridge_type ->mbc_type != GB_HUC3) {
|
if (gb->cartridge_type ->mbc_type == GB_TPP1) {
|
||||||
|
BESS_TPP1_t bess_tpp1 = {0,};
|
||||||
|
bess_tpp1.header = (BESS_block_t){BE32('TPP1'), LE32(sizeof(bess_tpp1) - sizeof(bess_tpp1.header))};
|
||||||
|
|
||||||
|
bess_tpp1.last_rtc_second = LE64(gb->last_rtc_second);
|
||||||
|
unrolled for (unsigned i = 4; i--;) {
|
||||||
|
bess_tpp1.real_rtc_data[i] = gb->rtc_real.data[i ^ 3];
|
||||||
|
bess_tpp1.latched_rtc_data[i] = gb->rtc_latched.data[i ^ 3];
|
||||||
|
}
|
||||||
|
bess_tpp1.mr4 = gb->tpp1_mr4;
|
||||||
|
|
||||||
|
if (file->write(file, &bess_tpp1, sizeof(bess_tpp1)) != sizeof(bess_tpp1)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (gb->cartridge_type ->mbc_type != GB_HUC3) {
|
||||||
BESS_RTC_t bess_rtc = {0,};
|
BESS_RTC_t bess_rtc = {0,};
|
||||||
bess_rtc.header = (BESS_block_t){BE32('RTC '), LE32(sizeof(bess_rtc) - sizeof(bess_rtc.header))};
|
bess_rtc.header = (BESS_block_t){BE32('RTC '), LE32(sizeof(bess_rtc) - sizeof(bess_rtc.header))};
|
||||||
bess_rtc.real.seconds = gb->rtc_real.seconds;
|
bess_rtc.real.seconds = gb->rtc_real.seconds;
|
||||||
|
@ -997,33 +1020,51 @@ static int load_bess_save(GB_gameboy_t *gb, virtual_file_t *file, bool is_samebo
|
||||||
BESS_RTC_t bess_rtc;
|
BESS_RTC_t bess_rtc;
|
||||||
if (LE32(block.size) != sizeof(bess_rtc) - sizeof(block)) goto parse_error;
|
if (LE32(block.size) != sizeof(bess_rtc) - sizeof(block)) goto parse_error;
|
||||||
if (file->read(file, &bess_rtc.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
|
if (file->read(file, &bess_rtc.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
|
||||||
if (gb->cartridge_type->has_rtc && gb->cartridge_type->mbc_type != GB_HUC3) {
|
if (!gb->cartridge_type->has_rtc || gb->cartridge_type->mbc_type != GB_MBC3) break;
|
||||||
gb->rtc_real.seconds = bess_rtc.real.seconds;
|
save.rtc_real.seconds = bess_rtc.real.seconds;
|
||||||
gb->rtc_real.minutes = bess_rtc.real.minutes;
|
save.rtc_real.minutes = bess_rtc.real.minutes;
|
||||||
gb->rtc_real.hours = bess_rtc.real.hours;
|
save.rtc_real.hours = bess_rtc.real.hours;
|
||||||
gb->rtc_real.days = bess_rtc.real.days;
|
save.rtc_real.days = bess_rtc.real.days;
|
||||||
gb->rtc_real.high = bess_rtc.real.high;
|
save.rtc_real.high = bess_rtc.real.high;
|
||||||
gb->rtc_latched.seconds = bess_rtc.latched.seconds;
|
save.rtc_latched.seconds = bess_rtc.latched.seconds;
|
||||||
gb->rtc_latched.minutes = bess_rtc.latched.minutes;
|
save.rtc_latched.minutes = bess_rtc.latched.minutes;
|
||||||
gb->rtc_latched.hours = bess_rtc.latched.hours;
|
save.rtc_latched.hours = bess_rtc.latched.hours;
|
||||||
gb->rtc_latched.days = bess_rtc.latched.days;
|
save.rtc_latched.days = bess_rtc.latched.days;
|
||||||
gb->rtc_latched.high = bess_rtc.latched.high;
|
save.rtc_latched.high = bess_rtc.latched.high;
|
||||||
gb->last_rtc_second = LE64(bess_rtc.last_rtc_second);
|
if (gb->rtc_mode == GB_RTC_MODE_SYNC_TO_HOST) {
|
||||||
|
save.last_rtc_second = MIN(LE64(bess_rtc.last_rtc_second), time(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case BE32('HUC3'):
|
case BE32('HUC3'):
|
||||||
if (!found_core) goto parse_error;
|
if (!found_core) goto parse_error;
|
||||||
BESS_HUC3_t bess_huc3;
|
BESS_HUC3_t bess_huc3;
|
||||||
if (LE32(block.size) != sizeof(bess_huc3) - sizeof(block)) goto parse_error;
|
if (LE32(block.size) != sizeof(bess_huc3) - sizeof(block)) goto parse_error;
|
||||||
if (file->read(file, &bess_huc3.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
|
if (file->read(file, &bess_huc3.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
|
||||||
if (gb->cartridge_type->mbc_type == GB_HUC3) {
|
if (gb->cartridge_type->mbc_type != GB_HUC3) break;
|
||||||
gb->last_rtc_second = LE64(bess_huc3.data.last_rtc_second);
|
if (gb->rtc_mode == GB_RTC_MODE_SYNC_TO_HOST) {
|
||||||
gb->huc3_minutes = LE16(bess_huc3.data.minutes);
|
save.last_rtc_second = MIN(LE64(bess_huc3.data.last_rtc_second), time(NULL));
|
||||||
gb->huc3_days = LE16(bess_huc3.data.days);
|
|
||||||
gb->huc3_alarm_minutes = LE16(bess_huc3.data.alarm_minutes);
|
|
||||||
gb->huc3_alarm_days = LE16(bess_huc3.data.alarm_days);
|
|
||||||
gb->huc3_alarm_enabled = bess_huc3.data.alarm_enabled;
|
|
||||||
}
|
}
|
||||||
|
save.huc3_minutes = LE16(bess_huc3.data.minutes);
|
||||||
|
save.huc3_days = LE16(bess_huc3.data.days);
|
||||||
|
save.huc3_alarm_minutes = LE16(bess_huc3.data.alarm_minutes);
|
||||||
|
save.huc3_alarm_days = LE16(bess_huc3.data.alarm_days);
|
||||||
|
save.huc3_alarm_enabled = bess_huc3.data.alarm_enabled;
|
||||||
|
break;
|
||||||
|
case BE32('TPP1'):
|
||||||
|
if (!found_core) goto parse_error;
|
||||||
|
BESS_TPP1_t bess_tpp1;
|
||||||
|
if (LE32(block.size) != sizeof(bess_tpp1) - sizeof(block)) goto parse_error;
|
||||||
|
if (file->read(file, &bess_tpp1.header + 1, LE32(block.size)) != LE32(block.size)) goto error;
|
||||||
|
if (gb->cartridge_type->mbc_type != GB_TPP1) break;
|
||||||
|
if (gb->rtc_mode == GB_RTC_MODE_SYNC_TO_HOST) {
|
||||||
|
save.last_rtc_second = MIN(LE64(bess_tpp1.last_rtc_second), time(NULL));
|
||||||
|
}
|
||||||
|
unrolled for (unsigned i = 4; i--;) {
|
||||||
|
save.rtc_real.data[i ^ 3] = bess_tpp1.real_rtc_data[i];
|
||||||
|
save.rtc_latched.data[i ^ 3] = bess_tpp1.latched_rtc_data[i];
|
||||||
|
}
|
||||||
|
save.tpp1_mr4 = bess_tpp1.mr4;
|
||||||
break;
|
break;
|
||||||
case BE32('SGB '):
|
case BE32('SGB '):
|
||||||
if (!found_core) goto parse_error;
|
if (!found_core) goto parse_error;
|
||||||
|
|
|
@ -283,27 +283,31 @@ static void GB_rtc_run(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
bool running = false;
|
||||||
|
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
||||||
|
running = gb->tpp1_mr4 & 0x4;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
running = (gb->rtc_real.high & 0x40) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((gb->rtc_real.high & 0x40) == 0) { /* is timer running? */
|
if (running) { /* is timer running? */
|
||||||
while (gb->last_rtc_second + 60 * 60 * 24 < current_time) {
|
while (gb->last_rtc_second + 60 * 60 * 24 < current_time) {
|
||||||
gb->last_rtc_second += 60 * 60 * 24;
|
gb->last_rtc_second += 60 * 60 * 24;
|
||||||
if (++gb->rtc_real.days == 0) {
|
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
||||||
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
if (++gb->rtc_real.tpp1.weekday == 7) {
|
||||||
if ((gb->rtc_real.high & 7) >= 6) { /* Bit 8 of days*/
|
gb->rtc_real.tpp1.weekday = 0;
|
||||||
gb->rtc_real.high &= 0x40;
|
if (++gb->rtc_real.tpp1.weeks == 0) {
|
||||||
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
gb->tpp1_mr4 |= 8; /* Overflow bit */
|
||||||
}
|
|
||||||
else {
|
|
||||||
gb->rtc_real.high++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
|
else if (++gb->rtc_real.days == 0) {
|
||||||
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
|
||||||
}
|
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
||||||
|
|
||||||
gb->rtc_real.high ^= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb->rtc_real.high ^= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,21 +319,21 @@ static void GB_rtc_run(GB_gameboy_t *gb, uint8_t cycles)
|
||||||
if (++gb->rtc_real.minutes != 60) continue;
|
if (++gb->rtc_real.minutes != 60) continue;
|
||||||
gb->rtc_real.minutes = 0;
|
gb->rtc_real.minutes = 0;
|
||||||
|
|
||||||
if (++gb->rtc_real.hours != 24) continue;
|
|
||||||
gb->rtc_real.hours = 0;
|
|
||||||
|
|
||||||
if (++gb->rtc_real.days != 0) continue;
|
|
||||||
|
|
||||||
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
if (gb->cartridge_type->mbc_type == GB_TPP1) {
|
||||||
if ((gb->rtc_real.high & 7) >= 6) { /* Bit 8 of days*/
|
if (++gb->rtc_real.tpp1.hours != 24) continue;
|
||||||
gb->rtc_real.high &= 0x40;
|
gb->rtc_real.tpp1.hours = 0;
|
||||||
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
if (++gb->rtc_real.tpp1.weekday != 7) continue;
|
||||||
}
|
gb->rtc_real.tpp1.weekday = 0;
|
||||||
else {
|
if (++gb->rtc_real.tpp1.weeks == 0) {
|
||||||
gb->rtc_real.high++;
|
gb->tpp1_mr4 |= 8; /* Overflow bit */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (++gb->rtc_real.hours != 24) continue;
|
||||||
|
gb->rtc_real.hours = 0;
|
||||||
|
|
||||||
|
if (++gb->rtc_real.days != 0) continue;
|
||||||
|
|
||||||
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
|
if (gb->rtc_real.high & 1) { /* Bit 8 of days*/
|
||||||
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
gb->rtc_real.high |= 0x80; /* Overflow bit */
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue