From d8225bb313a19bc3b65e257401d3cf5f3eaa32e3 Mon Sep 17 00:00:00 2001 From: negativeExponent Date: Sat, 5 Sep 2020 20:40:15 +0800 Subject: Add optional battery save using libretro save api - Adds core option to allow battery saves using the libretro api (retro_get_memory_data/size) - Initial save size set at 128KB and actual size is automatically determined internally by gba. - This will always assume that a save file is supported since save size or type cannot be determined until gba tries to write to backup memory. - A 128KB block of memory is used as buffer, similar method to VBA Next/Beetle GBA workarounds. Fix https://github.com/libretro/gpsp/issues/72 --- gba_memory.c | 54 +++---------------------------- gba_memory.h | 57 +++++++++++++++++++++++++++++++++ libretro.c | 102 +++++++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 132 insertions(+), 81 deletions(-) diff --git a/gba_memory.c b/gba_memory.c index a2d2a93..567010b 100644 --- a/gba_memory.c +++ b/gba_memory.c @@ -367,40 +367,11 @@ u32 gbc_sound_update = 0; // If the GBC audio waveform is modified: u32 gbc_sound_wave_update = 0; -typedef enum -{ - BACKUP_SRAM, - BACKUP_FLASH, - BACKUP_EEPROM, - BACKUP_NONE -} backup_type_type; - -typedef enum -{ - SRAM_SIZE_32KB, - SRAM_SIZE_64KB -} sram_size_type; - // Keep it 32KB until the upper 64KB is accessed, then make it 64KB. backup_type_type backup_type = BACKUP_NONE; sram_size_type sram_size = SRAM_SIZE_32KB; -typedef enum -{ - FLASH_BASE_MODE, - FLASH_ERASE_MODE, - FLASH_ID_MODE, - FLASH_WRITE_MODE, - FLASH_BANKSWITCH_MODE -} flash_mode_type; - -typedef enum -{ - FLASH_SIZE_64KB, - FLASH_SIZE_128KB -} flash_size_type; - flash_mode_type flash_mode = FLASH_BASE_MODE; u32 flash_command_position = 0; u8 *flash_bank_ptr = gamepak_backup; @@ -459,25 +430,6 @@ u8 read_backup(u32 address) // EEPROM is 512 bytes by default; it is autodetecte as 8KB if // 14bit address DMAs are made (this is done in the DMA handler). -typedef enum -{ - EEPROM_512_BYTE, - EEPROM_8_KBYTE -} eeprom_size_type; - -typedef enum -{ - EEPROM_BASE_MODE, - EEPROM_READ_MODE, - EEPROM_READ_HEADER_MODE, - EEPROM_ADDRESS_MODE, - EEPROM_WRITE_MODE, - EEPROM_WRITE_ADDRESS_MODE, - EEPROM_ADDRESS_FOOTER_MODE, - EEPROM_WRITE_FOOTER_MODE -} eeprom_mode_type; - - eeprom_size_type eeprom_size = EEPROM_512_BYTE; eeprom_mode_type eeprom_mode = EEPROM_BASE_MODE; u32 eeprom_address_length; @@ -2197,7 +2149,8 @@ u32 save_backup(char *name) void update_backup(void) { - save_backup(backup_filename); + if (!use_libretro_save_method) + save_backup(backup_filename); } #define CONFIG_FILENAME "game_config.txt" @@ -2480,7 +2433,8 @@ u32 load_gamepak(const struct retro_game_info* info, const char *name) if (p) strcpy(p, ".sav"); - load_backup(backup_filename); + if (!use_libretro_save_method) + load_backup(backup_filename); memcpy(gamepak_title, gamepak_rom + 0xA0, 12); memcpy(gamepak_code, gamepak_rom + 0xAC, 4); diff --git a/gba_memory.h b/gba_memory.h index 630c622..f1243b5 100644 --- a/gba_memory.h +++ b/gba_memory.h @@ -21,6 +21,7 @@ #define MEMORY_H #include "libretro.h" +extern int use_libretro_save_method; typedef enum { @@ -215,6 +216,62 @@ extern flash_device_id_type flash_device_id; extern const u8 *state_mem_read_ptr; extern u8 *state_mem_write_ptr; +typedef enum +{ + BACKUP_SRAM, + BACKUP_FLASH, + BACKUP_EEPROM, + BACKUP_NONE +} backup_type_type; + +typedef enum +{ + SRAM_SIZE_32KB, + SRAM_SIZE_64KB +} sram_size_type; + +typedef enum +{ + FLASH_BASE_MODE, + FLASH_ERASE_MODE, + FLASH_ID_MODE, + FLASH_WRITE_MODE, + FLASH_BANKSWITCH_MODE +} flash_mode_type; + +typedef enum +{ + FLASH_SIZE_64KB, + FLASH_SIZE_128KB +} flash_size_type; + + +extern backup_type_type backup_type; +extern sram_size_type sram_size; +extern flash_size_type flash_size; + +typedef enum +{ + EEPROM_512_BYTE, + EEPROM_8_KBYTE +} eeprom_size_type; + +typedef enum +{ + EEPROM_BASE_MODE, + EEPROM_READ_MODE, + EEPROM_READ_HEADER_MODE, + EEPROM_ADDRESS_MODE, + EEPROM_WRITE_MODE, + EEPROM_WRITE_ADDRESS_MODE, + EEPROM_ADDRESS_FOOTER_MODE, + EEPROM_WRITE_FOOTER_MODE +} eeprom_mode_type; + +extern eeprom_size_type eeprom_size; + +extern u8 gamepak_backup[1024 * 128]; + static inline void state_mem_write(const void* src, size_t size) { memcpy(state_mem_write_ptr, src, size); diff --git a/libretro.c b/libretro.c index 3aacfec..b37a94e 100644 --- a/libretro.c +++ b/libretro.c @@ -8,6 +8,7 @@ #include "libretro.h" #include "memmap.h" +#include "gba_memory.h" #if defined(VITA) && defined(HAVE_DYNAREC) #include @@ -73,6 +74,7 @@ struct retro_perf_callback perf_cb; static cothread_t main_thread; static cothread_t cpu_thread; int dynarec_enable; +int use_libretro_save_method = 0; u32 idle_loop_target_pc = 0xFFFFFFFF; u32 iwram_stack_optimize = 1; @@ -332,6 +334,7 @@ void retro_set_environment(retro_environment_t cb) { "gpsp_frameskip_type", "Frameskip type; off|manual|automatic" }, { "gpsp_frameskip_value", "Frameskip value; 1|2|3|4|5|6|7|8|9" }, { "gpsp_frameskip_variation", "Frameskip variation; uniform|random" }, + { "gpsp_save_method", "Backup Save Method (Restart); gpSP|libretro" }, { NULL, NULL }, }; @@ -488,6 +491,19 @@ static void check_variables(int started_from_load) else if (!strcmp(var.value, "random")) random_skip = 1; } + + if (started_from_load) + { + var.key = "gpsp_save_method"; + var.value = NULL; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "libretro")) + use_libretro_save_method = 1; + else + use_libretro_save_method = 0; + } + } } static void set_input_descriptors() @@ -540,6 +556,7 @@ bool retro_load_game(const struct retro_game_info* info) if (!info) return false; + use_libretro_save_method = 0; check_variables(1); set_input_descriptors(); @@ -614,6 +631,7 @@ bool retro_load_game(const struct retro_game_info* info) info_msg("It is strongly recommended that you obtain the correct BIOS file."); } + memset(gamepak_backup, -1, sizeof(gamepak_backup)); gamepak_filename[0] = 0; if (load_gamepak(info, info->path) != 0) { @@ -630,7 +648,6 @@ bool retro_load_game(const struct retro_game_info* info) return true; } - bool retro_load_game_special(unsigned game_type, const struct retro_game_info* info, size_t num_info) { @@ -650,43 +667,66 @@ unsigned retro_get_region(void) void* retro_get_memory_data(unsigned id) { - if ( id == RETRO_MEMORY_SYSTEM_RAM ) - return ewram ; - // switch (id) - // { - // case RETRO_MEMORY_SAVE_RAM: - // return gamepak_backup; - // } + switch (id) + { + case RETRO_MEMORY_SYSTEM_RAM: + return ewram; + case RETRO_MEMORY_SAVE_RAM: + if (use_libretro_save_method) + return gamepak_backup; + break; + default: + break; + } return 0; } size_t retro_get_memory_size(unsigned id) { + switch (id) + { + case RETRO_MEMORY_SYSTEM_RAM: + return 1024 * 256 * 2; - if ( id == RETRO_MEMORY_SYSTEM_RAM ) - return 1024 * 256 * 2 ; - // switch (id) - // { - // case RETRO_MEMORY_SAVE_RAM: - // switch(backup_type) - // { - // case BACKUP_SRAM: - // return sram_size; - - // case BACKUP_FLASH: - // return flash_size; - - // case BACKUP_EEPROM: - // return eeprom_size; - - // case BACKUP_NONE: - // return 0x0; - - // default: - // return 0x8000; - // } - // } + case RETRO_MEMORY_SAVE_RAM: + if (use_libretro_save_method) + { + switch(backup_type) + { + case BACKUP_SRAM: + if(sram_size == SRAM_SIZE_32KB) + return 0x8000; + else + return 0x10000; + break; + + case BACKUP_FLASH: + if(flash_size == FLASH_SIZE_64KB) + return 0x10000; + else + return 0x20000; + break; + + case BACKUP_EEPROM: + if(eeprom_size == EEPROM_512_BYTE) + return 0x200; + else + return 0x2000; + break; + // assume 128KB save, regardless if rom supports battery saves + // this is needed because gba cannot provide initially the backup save size + // until a few cycles has passed (unless provided by a database) + case BACKUP_NONE: + default: + return (1024 * 128); + break; + } + } + break; + default: + break; + } return 0; } -- cgit v1.2.3