diff --git a/file.c b/file.c index 0f4b684026..bf06e89d6f 100644 --- a/file.c +++ b/file.c @@ -168,11 +168,11 @@ void save_file(const char* path, int type) static bool load_sgb_rom(void) { - void *rom_buf; + void *rom_buf = NULL; ssize_t rom_len = 0; - FILE *extra_rom; - void *extra_rom_buf; + FILE *extra_rom = NULL; + void *extra_rom_buf = NULL; ssize_t extra_rom_len = 0; if ((rom_len = read_file(g_extern.rom_file, &rom_buf)) == -1) @@ -220,9 +220,147 @@ error: return false; } +static bool load_bsx_rom(bool slotted) +{ + void *rom_buf = NULL; + ssize_t rom_len = 0; + + FILE *extra_rom = NULL; + void *extra_rom_buf = NULL; + ssize_t extra_rom_len = 0; + + if ((rom_len = read_file(g_extern.rom_file, &rom_buf)) == -1) + { + SSNES_ERR("Could not read ROM file.\n"); + goto error; + } + + extra_rom = fopen(g_extern.bsx_rom_path, "rb"); + if (!extra_rom) + { + SSNES_ERR("Couldn't open BSX game rom!\n"); + goto error; + } + + if ((extra_rom_len = read_file(extra_rom, &extra_rom_buf)) == -1) + { + SSNES_ERR("Cannot read BSX game rom.\n"); + goto error; + } + + if (slotted) + { + if (!psnes_load_cartridge_bsx_slotted( + NULL, rom_buf, rom_len, + NULL, extra_rom_buf, extra_rom_len)) + { + SSNES_ERR("Cannot load BSX slotted rom.\n"); + goto error; + } + + } + else + { + if (!psnes_load_cartridge_bsx( + NULL, rom_buf, rom_len, + NULL, extra_rom_buf, extra_rom_len)) + { + SSNES_ERR("Cannot load BSX rom.\n"); + goto error; + } + } + + if (g_extern.rom_file) + fclose(g_extern.rom_file); + if (extra_rom) + fclose(extra_rom); + free(rom_buf); + free(extra_rom_buf); + return true; + +error: + if (g_extern.rom_file) + fclose(g_extern.rom_file); + if (extra_rom) + fclose(extra_rom); + free(rom_buf); + free(extra_rom_buf); + return false; +} + +static bool load_sufami_rom(void) +{ + void *rom_buf = NULL; + ssize_t rom_len = 0; + + FILE *extra_rom[2] = {NULL}; + void *extra_rom_buf[2] = {NULL}; + ssize_t extra_rom_len[2] = {0}; + + if ((rom_len = read_file(g_extern.rom_file, &rom_buf)) == -1) + { + SSNES_ERR("Could not read ROM file.\n"); + goto error; + } + + const char *roms[2] = { g_extern.sufami_rom_path[0], g_extern.sufami_rom_path[1] }; + + for (int i = 0; i < 2; i++) + { + if (strlen(roms[i]) > 0) + { + extra_rom[i] = fopen(roms[i], "rb"); + if (!extra_rom[i]) + { + SSNES_ERR("Couldn't open BSX game rom!\n"); + goto error; + } + + if ((extra_rom_len[i] = read_file(extra_rom[i], &extra_rom_buf[i])) == -1) + { + SSNES_ERR("Cannot read BSX game rom.\n"); + goto error; + } + } + } + + if (!psnes_load_cartridge_sufami_turbo( + NULL, rom_buf, rom_len, + NULL, extra_rom_buf[0], extra_rom_len[0], + NULL, extra_rom_buf[1], extra_rom_len[1])) + { + SSNES_ERR("Cannot load Sufami Turbo rom.\n"); + goto error; + } + + + if (g_extern.rom_file) + fclose(g_extern.rom_file); + for (int i = 0; i < 2; i++) + { + if (extra_rom[i]) + fclose(extra_rom[i]); + free(extra_rom_buf[i]); + } + free(rom_buf); + return true; + +error: + if (g_extern.rom_file) + fclose(g_extern.rom_file); + for (int i = 0; i < 2; i++) + { + if (extra_rom[i]) + fclose(extra_rom[i]); + free(extra_rom_buf[i]); + } + free(rom_buf); + return false; +} + static bool load_normal_rom(void) { - void *rom_buf; + void *rom_buf = NULL; ssize_t rom_len = 0; if ((rom_len = read_file(g_extern.rom_file, &rom_buf)) == -1) @@ -247,9 +385,10 @@ static bool load_normal_rom(void) return true; } -bool init_rom_file(void) + +bool init_rom_file(enum ssnes_game_type type) { - switch (g_extern.game_type) + switch (type) { case SSNES_CART_SGB: if (!load_sgb_rom()) @@ -260,6 +399,21 @@ bool init_rom_file(void) if (!load_normal_rom()) return false; break; + + case SSNES_CART_BSX: + if (!load_bsx_rom(false)) + return false; + break; + + case SSNES_CART_BSX_SLOTTED: + if (!load_bsx_rom(true)) + return false; + break; + + case SSNES_CART_SUFAMI: + if (!load_sufami_rom()) + return false; + break; default: SSNES_ERR("Invalid ROM type!\n"); diff --git a/file.h b/file.h index aa6b78cf5c..d55e1c377e 100644 --- a/file.h +++ b/file.h @@ -24,6 +24,7 @@ #include #include #include +#include "general.h" ssize_t read_file(FILE *file, void **buf); @@ -32,6 +33,6 @@ void write_file(const char* path, uint8_t* data, size_t size); void load_save_file(const char* path, int type); void save_file(const char* path, int type); -bool init_rom_file(void); +bool init_rom_file(enum ssnes_game_type type); #endif diff --git a/general.h b/general.h index a40996159b..e835948c1a 100644 --- a/general.h +++ b/general.h @@ -81,7 +81,10 @@ struct settings enum ssnes_game_type { SSNES_CART_NORMAL = 0, - SSNES_CART_SGB + SSNES_CART_SGB, + SSNES_CART_BSX, + SSNES_CART_BSX_SLOTTED, + SSNES_CART_SUFAMI, }; struct global @@ -101,12 +104,17 @@ struct global enum ssnes_game_type game_type; char gb_rom_path[256]; + char bsx_rom_path[256]; + char sufami_rom_path[2][256]; char config_path[256]; char basename[256]; char savefile_name_srm[256]; - char savefile_name_rtc[260]; // Make sure that fill_pathname has space. + char savefile_name_rtc[512]; // Make sure that fill_pathname has space. + char savefile_name_psrm[512]; + char savefile_name_asrm[512]; + char savefile_name_bsrm[512]; char savestate_name[256]; #ifdef HAVE_FFMPEG diff --git a/ssnes.c b/ssnes.c index 6a3a539d3c..979a789b6d 100644 --- a/ssnes.c +++ b/ssnes.c @@ -240,12 +240,16 @@ static void print_help(void) puts("================================================="); puts("ssnes: Simple Super Nintendo Emulator (libsnes)"); puts("================================================="); - puts("Usage: ssnes [rom file] [-h/--help | -c/--config | -v/--verbose | -4/--multitap | -j/--justifier | -J/--justifiers | -S/--savestate | -m/--mouse | -g/--gameboy | -p/--scope | -s/--save" FFMPEG_HELP_QUARK "]"); + puts("Usage: ssnes [rom file] [-h/--help | -c/--config | -v/--verbose | -4/--multitap | -j/--justifier | -J/--justifiers | -S/--savestate | -m/--mouse | -g/--gameboy | -b/--bsx | -B/--bsxslot | --sufamiA | --sufamiB | -p/--scope | -s/--save" FFMPEG_HELP_QUARK "]"); puts("\t-h/--help: Show this help message"); puts("\t-s/--save: Path for save file (*.srm). Required when rom is input from stdin"); puts("\t-S/--savestate: Path to use for save states. If not selected, *.state will be assumed."); puts("\t-c/--config: Path for config file." SSNES_DEFAULT_CONF_PATH_STR); puts("\t-g/--gameboy: Path to Gameboy ROM. Load SuperGameBoy as the regular rom."); + puts("\t-b/--bsx: Path to BSX rom. Load BSX BIOS as the regular rom."); + puts("\t-B/--bsxslot: Path to BSX slotted rom. Load BSX BIOS as the regular rom."); + puts("\t--sufamiA: Path to A slot of Sufami Turbo. Load Sufami base cart as regular rom."); + puts("\t--sufamiB: Path to B slot of Sufami Turbo."); puts("\t-m/--mouse: Connect a virtual mouse into designated port of the SNES (1 or 2)."); puts("\t\tThis argument can be specified several times to connect more mice."); puts("\t-p/--scope: Connect a virtual SuperScope into port 2 of the SNES."); @@ -279,9 +283,13 @@ static void parse_input(int argc, char *argv[]) { "mouse", 1, NULL, 'm' }, { "scope", 0, NULL, 'p' }, { "savestate", 1, NULL, 'S' }, + { "bsx", 1, NULL, 'b' }, + { "bsxslot", 1, NULL, 'B' }, { "justifier", 0, NULL, 'j' }, { "justifiers", 0, NULL, 'J' }, { "multitap", 0, NULL, '4' }, + { "sufamiA", 1, NULL, 'Y' }, + { "sufamiB", 1, NULL, 'Z' }, { NULL, 0, NULL, 0 } }; @@ -293,7 +301,7 @@ static void parse_input(int argc, char *argv[]) #define FFMPEG_RECORD_ARG #endif - char optstring[] = "hs:vc:t:m:p4jkg:" FFMPEG_RECORD_ARG; + char optstring[] = "hs:vc:S:m:p4jJg:b:B:Y:Z:" FFMPEG_RECORD_ARG; for(;;) { int c = getopt_long(argc, argv, optstring, opts, &option_index); @@ -329,6 +337,26 @@ static void parse_input(int argc, char *argv[]) g_extern.game_type = SSNES_CART_SGB; break; + case 'b': + strncpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path) - 1); + g_extern.game_type = SSNES_CART_BSX; + break; + + case 'B': + strncpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path) - 1); + g_extern.game_type = SSNES_CART_BSX_SLOTTED; + break; + + case 'Y': + strncpy(g_extern.sufami_rom_path[0], optarg, sizeof(g_extern.sufami_rom_path[0]) - 1); + g_extern.game_type = SSNES_CART_SUFAMI; + break; + + case 'Z': + strncpy(g_extern.sufami_rom_path[1], optarg, sizeof(g_extern.sufami_rom_path[1]) - 1); + g_extern.game_type = SSNES_CART_SUFAMI; + break; + case 'S': strncpy(g_extern.savestate_name, optarg, sizeof(g_extern.savestate_name) - 1); break; @@ -453,48 +481,59 @@ static void init_controllers(void) } } -static int get_sram_type(enum ssnes_game_type type) -{ - switch (type) - { - case SSNES_CART_SGB: - return SNES_MEMORY_GAME_BOY_RAM; - case SSNES_CART_NORMAL: - return SNES_MEMORY_CARTRIDGE_RAM; - } - return 0; -} - -static int get_rtc_type(enum ssnes_game_type type) -{ - switch (type) - { - case SSNES_CART_SGB: - return SNES_MEMORY_GAME_BOY_RTC; - case SSNES_CART_NORMAL: - return SNES_MEMORY_CARTRIDGE_RTC; - } - return 0; -} - static inline void load_save_files(void) { - int ram_type = get_sram_type(g_extern.game_type); - int rtc_type = get_rtc_type(g_extern.game_type); + switch (g_extern.game_type) + { + case SSNES_CART_NORMAL: + case SSNES_CART_SGB: + load_save_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM); + load_save_file(g_extern.savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC); + break; - load_save_file(g_extern.savefile_name_srm, ram_type); - load_save_file(g_extern.savefile_name_rtc, rtc_type); + case SSNES_CART_BSX: + case SSNES_CART_BSX_SLOTTED: + load_save_file(g_extern.savefile_name_srm, SNES_MEMORY_BSX_RAM); + load_save_file(g_extern.savefile_name_psrm, SNES_MEMORY_BSX_PRAM); + break; + + case SSNES_CART_SUFAMI: + load_save_file(g_extern.savefile_name_asrm, SNES_MEMORY_SUFAMI_TURBO_A_RAM); + load_save_file(g_extern.savefile_name_bsrm, SNES_MEMORY_SUFAMI_TURBO_B_RAM); + break; + + default: + break; + } } static inline void save_files(void) { - int ram_type = get_sram_type(g_extern.game_type); - int rtc_type = get_rtc_type(g_extern.game_type); + switch (g_extern.game_type) + { + case SSNES_CART_NORMAL: + case SSNES_CART_SGB: + save_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM); + save_file(g_extern.savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC); + break; - save_file(g_extern.savefile_name_srm, ram_type); - save_file(g_extern.savefile_name_rtc, rtc_type); + case SSNES_CART_BSX: + case SSNES_CART_BSX_SLOTTED: + save_file(g_extern.savefile_name_srm, SNES_MEMORY_BSX_RAM); + save_file(g_extern.savefile_name_psrm, SNES_MEMORY_BSX_PRAM); + break; + + case SSNES_CART_SUFAMI: + save_file(g_extern.savefile_name_asrm, SNES_MEMORY_SUFAMI_TURBO_A_RAM); + save_file(g_extern.savefile_name_bsrm, SNES_MEMORY_SUFAMI_TURBO_B_RAM); + break; + + default: + break; + } } + #ifdef HAVE_FFMPEG static void init_recording(void) { @@ -535,6 +574,29 @@ static void deinit_recording(void) } #endif +static void fill_pathnames(void) +{ + switch (g_extern.game_type) + { + case SSNES_CART_BSX: + case SSNES_CART_BSX_SLOTTED: + // BSX PSRM + fill_pathname(g_extern.savefile_name_psrm, g_extern.savefile_name_srm, ".psrm"); + break; + + case SSNES_CART_SUFAMI: + // SUFAMI ARAM + fill_pathname(g_extern.savefile_name_asrm, g_extern.savefile_name_srm, ".asrm"); + // SUFAMI BRAM + fill_pathname(g_extern.savefile_name_bsrm, g_extern.savefile_name_srm, ".bsrm"); + break; + + default: + // Infer .rtc save path from save ram path. + fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc"); + } +} + int main(int argc, char *argv[]) { @@ -548,10 +610,9 @@ int main(int argc, char *argv[]) SSNES_LOG("Version of libsnes API: %u.%u\n", psnes_library_revision_major(), psnes_library_revision_minor()); - // Infer .rtc save path from save ram path. - fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc"); + fill_pathnames(); - if (!init_rom_file()) + if (!init_rom_file(g_extern.game_type)) goto error; init_drivers();