From f6f3a910397afb769f84d1332014c4eda1fedebe Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Mon, 22 Mar 2021 21:45:52 +0100 Subject: [PATCH] Adding Normmatt's BIOS as a built-in BIOS Add options to select whether to boot from BIOS (default is no, as it is now) and whether to use the original bios or the builtin one (default is auto, which tries to use the official but falls back to the builtin if not found). --- Makefile.common | 2 +- bios/README.md | 7 +++ bios/open_gba_bios.bin | Bin 0 -> 16384 bytes bios_data.S | 7 +++ cpu.c | 18 ++++++-- gba_memory.h | 1 + libretro.c | 100 ++++++++++++++++++++++++++++++++-------- libretro_core_options.h | 23 +++++++++ main.h | 14 ++++++ 9 files changed, 147 insertions(+), 25 deletions(-) create mode 100644 bios/README.md create mode 100644 bios/open_gba_bios.bin create mode 100644 bios_data.S diff --git a/Makefile.common b/Makefile.common index 7e70627..0dcbedc 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1,6 +1,6 @@ INCFLAGS := -I$(CORE_DIR)/libretro -I$(CORE_DIR)/src -SOURCES_ASM := +SOURCES_ASM := $(CORE_DIR)/bios_data.S ifeq ($(HAVE_GRIFFIN), 1) SOURCES_C := $(CORE_DIR)/gpsp_griffin.c diff --git a/bios/README.md b/bios/README.md new file mode 100644 index 0000000..64d6679 --- /dev/null +++ b/bios/README.md @@ -0,0 +1,7 @@ + +This BIOS is an open source replacement for Nintendo's official BIOS. +It was written originally by Normmatt and the VBA/VBA-M team, and its source +code can be found at https://github.com/Nebuleon/ReGBA/tree/master/bios + +It is distributed under the GPL2 license (see repo) + diff --git a/bios/open_gba_bios.bin b/bios/open_gba_bios.bin new file mode 100644 index 0000000000000000000000000000000000000000..802982e4336f04eebc08148ffaf904d19ecd0ba4 GIT binary patch literal 16384 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 literal 0 HcmV?d00001 diff --git a/bios_data.S b/bios_data.S new file mode 100644 index 0000000..9de9d8a --- /dev/null +++ b/bios_data.S @@ -0,0 +1,7 @@ + +.globl open_gba_bios_rom + +.data +open_gba_bios_rom: + .incbin "bios/open_gba_bios.bin" + diff --git a/cpu.c b/cpu.c index 2c93f38..11c947f 100644 --- a/cpu.c +++ b/cpu.c @@ -4297,13 +4297,23 @@ void init_cpu(void) for(i = 0; i < 16; i++) reg[i] = 0; - reg[REG_SP] = 0x03007F00; - reg[REG_PC] = 0x08000000; - reg[REG_CPSR] = 0x0000001F; reg[CPU_HALT_STATE] = CPU_ACTIVE; - reg[CPU_MODE] = MODE_USER; reg[CHANGED_PC_STATUS] = 0; + if (selected_boot_mode == boot_game) { + reg[REG_SP] = 0x03007F00; + reg[REG_PC] = 0x08000000; + reg[REG_CPSR] = 0x0000001F; // system mode + reg[CPU_MODE] = MODE_USER; + } else { + reg[REG_SP] = 0x03007F00; + reg[REG_PC] = 0x00000000; + reg[REG_CPSR] = 0x00000013 | 0xC0; // supervisor + reg[CPU_MODE] = MODE_SUPERVISOR; + } + + // Stack pointers are set by BIOS, we set them + // nevertheless, should we not boot from BIOS reg_mode[MODE_USER][5] = 0x03007F00; reg_mode[MODE_IRQ][5] = 0x03007FA0; reg_mode[MODE_FIQ][5] = 0x03007FA0; diff --git a/gba_memory.h b/gba_memory.h index 9352e88..eaa5bab 100644 --- a/gba_memory.h +++ b/gba_memory.h @@ -201,6 +201,7 @@ extern u32 gbc_sound_update; extern u32 gbc_sound_wave_update; extern dma_transfer_type dma[4]; +extern u8 open_gba_bios_rom[1024*16]; extern u32 bios_read_protect; extern u16 palette_ram[512]; extern u16 oam_ram[512]; diff --git a/libretro.c b/libretro.c index bc61977..334864c 100644 --- a/libretro.c +++ b/libretro.c @@ -65,6 +65,7 @@ static unsigned audio_buff_occupancy = 0; static bool audio_buff_underrun = false; static unsigned audio_latency = 0; static bool update_audio_latency = false; +static bios_type selected_bios = auto_detect; static retro_log_printf_t log_cb; static retro_video_refresh_t video_cb; @@ -75,6 +76,7 @@ struct retro_perf_callback perf_cb; int dynarec_enable; int use_libretro_save_method = 0; +boot_mode selected_boot_mode = boot_game; u32 idle_loop_target_pc = 0xFFFFFFFF; u32 iwram_stack_optimize = 1; @@ -114,6 +116,25 @@ static void info_msg(const char* text) log_cb(RETRO_LOG_INFO, "[gpSP]: %s\n", text); } +static void show_warning_message(const char* text, unsigned durationms) { + unsigned ifversion = 0; + if (!environ_cb(RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION, &ifversion) || ifversion >= 1) { + /* Use the new API to display messages */ + struct retro_message_ext msg = { + .msg = text, .duration = durationms, + .priority = 2, .level = RETRO_LOG_WARN, + .target = RETRO_MESSAGE_TARGET_ALL, + .type = RETRO_MESSAGE_TYPE_NOTIFICATION, + .progress = -1, + }; + environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE_EXT, &msg); + } + else { + struct retro_message msg = {.msg = text, .frames = durationms / 17}; + environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg); + } +} + /* Frameskip START */ static void audio_buff_status_cb( @@ -348,8 +369,8 @@ static void video_run(void) sceGuTexMode(GU_PSM_5650, 0, 0, GU_FALSE); sceGuCopyImage(GU_PSM_5650, 0, 0, GBA_SCREEN_WIDTH, GBA_SCREEN_HEIGHT, GBA_SCREEN_WIDTH, gba_screen_pixels_buf, 0, 0, GBA_SCREEN_WIDTH, texture_vram_p); - sceGuTexImage(0, next_pow2(GBA_SCREEN_WIDTH), next_pow2(GBA_SCREEN_HEIGHT), GBA_SCREEN_WIDTH, texture_vram_p); - sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB); + sceGuTexImage(0, next_pow2(GBA_SCREEN_WIDTH), next_pow2(GBA_SCREEN_HEIGHT), GBA_SCREEN_WIDTH, texture_vram_p); + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB); sceGuDisable(GU_BLEND); sceGuFinish(); @@ -484,6 +505,8 @@ void retro_init(void) audio_buff_underrun = false; audio_latency = 0; update_audio_latency = false; + selected_bios = auto_detect; + selected_boot_mode = boot_game; } void retro_deinit(void) @@ -660,6 +683,32 @@ static void check_variables(int started_from_load) dynarec_enable = 0; #endif + if (started_from_load) { + var.key = "gpsp_bios"; + var.value = 0; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "auto")) + selected_bios = auto_detect; + else if (!strcmp(var.value, "builtin")) + selected_bios = builtin_bios; + else if (!strcmp(var.value, "official")) + selected_bios = official_bios; + } + + var.key = "gpsp_boot_mode"; + var.value = 0; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "game")) + selected_boot_mode = boot_game; + else if (!strcmp(var.value, "bios")) + selected_boot_mode = boot_bios; + } + } + var.key = "gpsp_frameskip"; var.value = 0; frameskip_type_prev = current_frameskip_type; @@ -795,30 +844,41 @@ bool retro_load_game(const struct retro_game_info* info) extract_directory(main_path, info->path, sizeof(main_path)); - if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir) - strcpy(filename_bios, dir); - else - strcpy(filename_bios, main_path); - - strcat(filename_bios, "/gba_bios.bin"); - - if (environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &dir) && dir) strcpy(save_path, dir); else strcpy(save_path, main_path); - if (load_bios(filename_bios) != 0) + if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir) + strcpy(filename_bios, dir); + else + strcpy(filename_bios, main_path); + + bool bios_loaded = false; + printf("USE %d\n", (int)selected_bios); + if (selected_bios == auto_detect || selected_bios == official_bios) { - error_msg("Could not load BIOS image file."); - return false; + bios_loaded = true; + strcat(filename_bios, "/gba_bios.bin"); + + if (load_bios(filename_bios) != 0) + { + if (selected_bios == official_bios) + show_warning_message("Could not load BIOS image file, using built-in BIOS", 2500); + bios_loaded = false; + } + + if (bios_loaded && bios_rom[0] != 0x18) + { + if (selected_bios == official_bios) + show_warning_message("BIOS image seems incorrect, using built-in BIOS", 2500); + bios_loaded = false; + } } - if (bios_rom[0] != 0x18) - { - info_msg("You have an incorrect BIOS image."); - info_msg("While many games will work fine, some will not."); - info_msg("It is strongly recommended that you obtain the correct BIOS file."); + if (!bios_loaded) { + /* Load the built-in BIOS */ + memcpy(bios_rom, open_gba_bios_rom, sizeof(bios_rom)); } memset(gamepak_backup, -1, sizeof(gamepak_backup)); @@ -921,8 +981,8 @@ void retro_run(void) input_poll_cb(); - /* Check whether current frame should - * be skipped */ + /* Check whether current frame should + * be skipped */ skip_next_frame = 0; if (current_frameskip_type != no_frameskip) diff --git a/libretro_core_options.h b/libretro_core_options.h index b5b138d..d2b95fa 100644 --- a/libretro_core_options.h +++ b/libretro_core_options.h @@ -53,6 +53,29 @@ extern "C" { * frontend language definition */ struct retro_core_option_definition option_defs_us[] = { + { + "gpsp_bios", + "BIOS", + "Choose the BIOS image to use. The official BIOS must be provided by the user. Using a non-official (or builtin) BIOS might result in incompatibility problems with some games. Best results are to be achieved with the official Nintendo BIOS.", + { + { "auto", "Auto select" }, + { "builtin", "Builtin BIOS" }, + { "official", "Original BIOS" }, + { NULL, NULL }, + }, + "auto" + }, + { + "gpsp_boot_mode", + "Boot mode", + "Choose whether to boot the BIOS before the game or not. There's not much difference in either modes.", + { + { "game", "Boot to game" }, + { "bios", "Boot to BIOS" }, + { NULL, NULL }, + }, + "game" + }, { "gpsp_frameskip", "Frameskip", diff --git a/main.h b/main.h index dbb839f..bdb29e3 100644 --- a/main.h +++ b/main.h @@ -64,6 +64,19 @@ typedef enum fixed_interval_frameskip } frameskip_type; +typedef enum +{ + auto_detect = 0, + builtin_bios, + official_bios +} bios_type; + +typedef enum +{ + boot_game = 0, + boot_bios +} boot_mode; + extern u32 cpu_ticks; extern u32 execute_cycles; extern u32 global_cycles_per_instruction; @@ -98,6 +111,7 @@ u32 file_length(FILE *fp); extern u32 num_skipped_frames; extern int dynarec_enable; +extern boot_mode selected_boot_mode; void change_ext(const char *src, char *buffer, const char *extension);