Add quick reset API (Closes #506)

This commit is contained in:
Lior Halphon 2022-10-17 18:52:02 +03:00
parent 9b202c670e
commit 5d5ff1702e
5 changed files with 83 additions and 20 deletions

View File

@ -53,6 +53,8 @@ enum model {
MODEL_AGB,
MODEL_SGB,
MODEL_MGB,
MODEL_QUICK_RESET = -1,
};
@interface Document ()
@ -253,6 +255,7 @@ static void infraredStateChanged(GB_gameboy_t *gb, bool on)
return (GB_model_t)[[NSUserDefaults standardUserDefaults] integerForKey:@"GBDMGModel"];
case MODEL_NONE:
case MODEL_QUICK_RESET:
case MODEL_CGB:
return (GB_model_t)[[NSUserDefaults standardUserDefaults] integerForKey:@"GBCGBModel"];
@ -623,7 +626,12 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
current_model = (enum model)[sender tag];
}
GB_switch_model_and_reset(&gb, [self internalModel]);
if ([sender tag] == MODEL_QUICK_RESET) {
GB_quick_reset(&gb);
}
else {
GB_switch_model_and_reset(&gb, [self internalModel]);
}
if (old_width != GB_get_screen_width(&gb)) {
[self.view screenSizeChanged];
@ -631,7 +639,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
[self updateMinSize];
if ([sender tag] != 0) {
if ([sender tag] > MODEL_NONE) {
/* User explictly selected a model, save the preference */
[[NSUserDefaults standardUserDefaults] setBool:current_model == MODEL_DMG forKey:@"EmulateDMG"];
[[NSUserDefaults standardUserDefaults] setBool:current_model == MODEL_SGB forKey:@"EmulateSGB"];
@ -1176,7 +1184,7 @@ static bool is_path_writeable(const char *path)
[(NSMenuItem *)anItem setState:self.isPaused];
return !GB_debugger_is_stopped(&gb);
}
else if ([anItem action] == @selector(reset:) && anItem.tag != MODEL_NONE) {
else if ([anItem action] == @selector(reset:) && anItem.tag != MODEL_NONE && anItem.tag != MODEL_QUICK_RESET) {
[(NSMenuItem *)anItem setState:anItem.tag == current_model];
}
else if ([anItem action] == @selector(interrupt:)) {

View File

@ -202,6 +202,12 @@
<action selector="reset:" target="-1" id="DKW-Bd-h3v"/>
</connections>
</menuItem>
<menuItem title="Quick Reset" tag="-1" alternate="YES" keyEquivalent="r" id="uPG-01-49E">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="reset:" target="-1" id="VV1-VP-L7g"/>
</connections>
</menuItem>
<menuItem title="Pause" keyEquivalent="p" id="4K4-hw-R7Q">
<connections>
<action selector="togglePause:" target="-1" id="osW-wt-QAa"/>

View File

@ -1604,6 +1604,10 @@ static void reset_ram(GB_gameboy_t *gb)
GB_palette_changed(gb, false, i * 2);
}
}
if (!gb->cartridge_type->has_battery) {
memset(gb->mbc_ram, 0xFF, gb->mbc_ram_size);
}
}
static void request_boot_rom(GB_gameboy_t *gb)
@ -1646,8 +1650,29 @@ static void request_boot_rom(GB_gameboy_t *gb)
}
}
void GB_reset(GB_gameboy_t *gb)
static void GB_reset_internal(GB_gameboy_t *gb, bool quick)
{
struct {
uint8_t hram[sizeof(gb->hram)];
uint8_t background_palettes_data[sizeof(gb->background_palettes_data)];
uint8_t object_palettes_data[sizeof(gb->object_palettes_data)];
uint8_t oam[sizeof(gb->oam)];
uint8_t extra_oam[sizeof(gb->extra_oam)];
uint8_t dma, obp0, obp1;
} *preserved_state = NULL;
if (quick) {
preserved_state = alloca(sizeof(*preserved_state));
memcpy(preserved_state->hram, gb->hram, sizeof(gb->hram));
memcpy(preserved_state->background_palettes_data, gb->background_palettes_data, sizeof(gb->background_palettes_data));
memcpy(preserved_state->object_palettes_data, gb->object_palettes_data, sizeof(gb->object_palettes_data));
memcpy(preserved_state->oam, gb->oam, sizeof(gb->oam));
memcpy(preserved_state->extra_oam, gb->extra_oam, sizeof(gb->extra_oam));
preserved_state->dma = gb->io_registers[GB_IO_DMA];
preserved_state->obp0 = gb->io_registers[GB_IO_OBP0];
preserved_state->obp1 = gb->io_registers[GB_IO_OBP1];
}
uint32_t mbc_ram_size = gb->mbc_ram_size;
GB_model_t model = gb->model;
GB_update_clock_rate(gb);
@ -1679,14 +1704,9 @@ void GB_reset(GB_gameboy_t *gb)
update_dmg_palette(gb);
}
reset_ram(gb);
gb->serial_mask = 0x80;
gb->io_registers[GB_IO_SC] = 0x7E;
/* These are not deterministic, but 00 (CGB) and FF (DMG) are the most common initial values by far */
gb->io_registers[GB_IO_DMA] = gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = GB_is_cgb(gb)? 0x00 : 0xFF;
gb->accessed_oam_row = -1;
gb->dma_current_dest = 0xA1;
@ -1718,10 +1738,37 @@ void GB_reset(GB_gameboy_t *gb)
gb->nontrivial_jump_state = NULL;
}
if (!quick) {
reset_ram(gb);
/* These are not deterministic, but 00 (CGB) and FF (DMG) are the most common initial values by far.
The retain their previous values on quick resets */
gb->io_registers[GB_IO_DMA] = gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = GB_is_cgb(gb)? 0x00 : 0xFF;
}
else {
memcpy(gb->hram, preserved_state->hram, sizeof(gb->hram));
memcpy(gb->background_palettes_data, preserved_state->background_palettes_data, sizeof(gb->background_palettes_data));
memcpy(gb->object_palettes_data, preserved_state->object_palettes_data, sizeof(gb->object_palettes_data));
memcpy(gb->oam, preserved_state->oam, sizeof(gb->oam));
memcpy(gb->extra_oam, preserved_state->extra_oam, sizeof(gb->extra_oam));
gb->io_registers[GB_IO_DMA] = preserved_state->dma;
gb->io_registers[GB_IO_OBP0] = preserved_state->obp0;
gb->io_registers[GB_IO_OBP1] = preserved_state->obp1;
}
gb->magic = state_magic();
request_boot_rom(gb);
}
void GB_reset(GB_gameboy_t *gb)
{
GB_reset_internal(gb, false);
}
void GB_quick_reset(GB_gameboy_t *gb)
{
GB_reset_internal(gb, true);
}
void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model)
{
gb->model = model;

View File

@ -881,6 +881,7 @@ bool GB_is_sgb(GB_gameboy_t *gb); // Returns true if the model is SGB or SGB2
bool GB_is_hle_sgb(GB_gameboy_t *gb); // Returns true if the model is SGB or SGB2 and the SFC/SNES side is HLE'd
GB_model_t GB_get_model(GB_gameboy_t *gb);
void GB_reset(GB_gameboy_t *gb);
void GB_quick_reset(GB_gameboy_t *gb); // Similar to the cart reset line
void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model);
/* Returns the time passed, in 8MHz ticks. */

View File

@ -196,12 +196,9 @@ void GB_configure_cart(GB_gameboy_t *gb)
}
}
if (gb->mbc_ram) {
free(gb->mbc_ram);
gb->mbc_ram = NULL;
gb->mbc_ram_size = 0;
}
size_t old_mbc_ram_size = gb->mbc_ram_size;
gb->mbc_ram_size = 0;
if (gb->cartridge_type->has_ram) {
if (gb->cartridge_type->mbc_type == GB_MBC2) {
gb->mbc_ram_size = 0x200;
@ -224,12 +221,16 @@ void GB_configure_cart(GB_gameboy_t *gb)
}
}
if (gb->mbc_ram_size) {
gb->mbc_ram = malloc(gb->mbc_ram_size);
if (gb->mbc_ram && old_mbc_ram_size != gb->mbc_ram_size) {
free(gb->mbc_ram);
gb->mbc_ram = NULL;
}
if (gb->mbc_ram_size && !gb->mbc_ram) {
gb->mbc_ram = malloc(gb->mbc_ram_size);
/* Todo: Some games assume unintialized MBC RAM is 0xFF. It this true for all cartridge types? */
memset(gb->mbc_ram, 0xFF, gb->mbc_ram_size);
}
/* Todo: Some games assume unintialized MBC RAM is 0xFF. It this true for all cartridge types? */
memset(gb->mbc_ram, 0xFF, gb->mbc_ram_size);
}
/* MBC1 has at least 3 types of wiring (We currently support two (Standard and 4bit-MBC1M) of these).