Fix reset() issue with dynarec flushing

On a reset bios_swi_entrypoint can end up pointing to code over the
watermark, due to block_lookup_address_arm looking up the function
instead of translating it.
Fix it by making flush and init different functions (albeit similar).

Tested by running and resetting games automatically, causing ~10% of
games to crash.
This commit is contained in:
David Guillen Fandos 2023-06-09 20:21:35 +02:00
parent 84c347edad
commit 34eb7a3bf3
6 changed files with 27 additions and 7 deletions

View File

@ -60,7 +60,7 @@ static void update_hook_codebreaker(cheat_type *cheat)
u32 pcaddr = 0x08000000 | (address & 0x1ffffff);
#ifdef HAVE_DYNAREC
if (cheat_master_hook != pcaddr)
init_caches(); /* Flush caches to install hook */
flush_dynarec_caches(); /* Flush caches to install hook */
#endif
cheat_master_hook = pcaddr;
return; /* Only support for one hook */

3
cpu.h
View File

@ -164,7 +164,8 @@ extern u32 rom_branch_hash[ROM_BRANCH_HASH_SIZE];
void flush_translation_cache_rom(void);
void flush_translation_cache_ram(void);
void dump_translation_cache(void);
void init_caches(void);
void init_dynarec_caches(void);
void flush_dynarec_caches(void);
void init_emitter(bool);
void init_bios_hooks(void);

View File

@ -3343,6 +3343,7 @@ void init_bios_hooks(void)
void flush_translation_cache_ram(void)
{
/* Flushes RAM caches avoiding doing too much work (ie. wiping unused memory) */
flush_ram_count++;
/*printf("ram flush %d (pc %x), %x to %x, %x to %x\n",
flush_ram_count, reg[REG_PC], iwram_code_min, iwram_code_max,
@ -3380,15 +3381,32 @@ void flush_translation_cache_ram(void)
void flush_translation_cache_rom(void)
{
/* We flush the generated code except for everything below the watermark. */
last_rom_translation_ptr = &rom_translation_cache[rom_cache_watermark];
rom_translation_ptr = &rom_translation_cache[rom_cache_watermark];
memset(rom_branch_hash, 0, sizeof(rom_branch_hash));
}
void init_caches(void)
void init_dynarec_caches(void)
{
/* Ensure we wipe everything including the SMC mirrors */
/* Initialize caches so that we can start initalizing the emitter. */
rom_translation_ptr = last_rom_translation_ptr = &rom_translation_cache[0];
memset(rom_branch_hash, 0, sizeof(rom_branch_hash));
ram_translation_ptr = last_ram_translation_ptr = &ram_translation_cache[0];
memset(iwram, 0, 0x8000);
memset(&ewram[0x40000], 0, 0x40000);
ewram_code_min = 0;
ewram_code_max = 0x40000;
iwram_code_min = 0;
iwram_code_max = 0x8000;
}
void flush_dynarec_caches(void)
{
/* Flush ROM and RAM caches. */
flush_translation_cache_rom();
ewram_code_min = 0;
ewram_code_max = 0x40000;

View File

@ -803,8 +803,9 @@ static void check_variables(int started_from_load)
else if (strcmp(var.value, "enabled") == 0)
dynarec_enable = 1;
/* Flush dynarec cache to ensure we do not execute old code */
if (dynarec_enable != prevvalue)
init_caches();
flush_dynarec_caches();
}
else
dynarec_enable = 1;

2
main.c
View File

@ -100,8 +100,8 @@ void init_main(void)
video_count = 960;
#ifdef HAVE_DYNAREC
init_dynarec_caches();
init_emitter(gamepak_must_swap());
init_caches();
#endif
}

View File

@ -103,7 +103,7 @@ bool gba_load_state(const void* src)
// Reset most of the frame state and dynarec state
#ifdef HAVE_DYNAREC
if (dynarec_enable)
init_caches();
flush_dynarec_caches();
#endif
instruction_count = 0;