X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=frontend%2Flibretro.c;h=94d649e01439fb950f127bd2499a95e1ce36e4e8;hp=82e6f658d9eaa8d5cdd590308fdcb1b21ed42ce2;hb=a9579f3bc3d60571252172b17195bca246d1a1be;hpb=79f216e32563acc81517729fe56a6f11f110b0a4 diff --git a/frontend/libretro.c b/frontend/libretro.c index 82e6f658..94d649e0 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -5,16 +5,22 @@ * See the COPYING file in the top-level directory. */ +#define _GNU_SOURCE 1 // strcasestr #include #include #include +#include #include "../libpcsxcore/misc.h" #include "../libpcsxcore/psxcounters.h" +#include "../libpcsxcore/psxmem_map.h" #include "../libpcsxcore/new_dynarec/new_dynarec.h" +#include "../libpcsxcore/cdrom.h" +#include "../libpcsxcore/cdriso.h" +#include "../libpcsxcore/cheat.h" #include "../plugins/dfsound/out.h" -#include "../plugins/gpulib/cspace.h" -#include "linux/plat_mmap.h" +#include "../plugins/dfinput/externals.h" +#include "cspace.h" #include "main.h" #include "plugin.h" #include "plugin_lib.h" @@ -28,9 +34,18 @@ static retro_environment_t environ_cb; static retro_audio_sample_batch_t audio_batch_cb; static void *vout_buf; +static int vout_width, vout_height; +static int vout_doffs_old, vout_fb_dirty; +static bool vout_can_dupe; +static bool duping_enable; + static int samples_sent, samples_to_send; static int plugins_opened; -static int native_rgb565; +static int is_pal_mode; + +/* memory card data */ +extern char Mcd1Data[MCD_SIZE]; +extern char McdDisable[2]; /* PCSX ReARMed core calls and stuff */ int in_type1, in_type2; @@ -38,15 +53,55 @@ int in_a1[2] = { 127, 127 }, in_a2[2] = { 127, 127 }; int in_keystate; int in_enable_vibration; +/* PSX max resolution is 640x512, but with enhancement it's 1024x512 */ +#define VOUT_MAX_WIDTH 1024 +#define VOUT_MAX_HEIGHT 512 + +static void init_memcard(char *mcd_data) +{ + unsigned off = 0; + unsigned i; + + memset(mcd_data, 0, MCD_SIZE); + + mcd_data[off++] = 'M'; + mcd_data[off++] = 'C'; + off += 0x7d; + mcd_data[off++] = 0x0e; + + for (i = 0; i < 15; i++) { + mcd_data[off++] = 0xa0; + off += 0x07; + mcd_data[off++] = 0xff; + mcd_data[off++] = 0xff; + off += 0x75; + mcd_data[off++] = 0xa0; + } + + for (i = 0; i < 20; i++) { + mcd_data[off++] = 0xff; + mcd_data[off++] = 0xff; + mcd_data[off++] = 0xff; + mcd_data[off++] = 0xff; + off += 0x04; + mcd_data[off++] = 0xff; + mcd_data[off++] = 0xff; + off += 0x76; + } +} + static int vout_open(void) { return 0; } -static void vout_set_mode(int w, int h, int bpp) +static void vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp) { + vout_width = w; + vout_height = h; } +#ifndef FRONTEND_SUPPORTS_RGB565 static void convert(void *buf, size_t bytes) { unsigned int i, v, *p = buf; @@ -56,12 +111,14 @@ static void convert(void *buf, size_t bytes) p[i] = (v & 0x001f001f) | ((v >> 1) & 0x7fe07fe0); } } +#endif static void vout_flip(const void *vram, int stride, int bgr24, int w, int h) { unsigned short *dest = vout_buf; const unsigned short *src = vram; - int dstride = w, h1 = h; + int dstride = vout_width, h1 = h; + int doffs; if (vram == NULL) { // blanking @@ -69,6 +126,15 @@ static void vout_flip(const void *vram, int stride, int bgr24, int w, int h) goto out; } + doffs = (vout_height - h) * dstride; + doffs += (dstride - w) / 2 & ~1; + if (doffs != vout_doffs_old) { + // clear borders + memset(vout_buf, 0, dstride * h * 2); + vout_doffs_old = doffs; + } + dest += doffs; + if (bgr24) { // XXX: could we switch to RETRO_PIXEL_FORMAT_XRGB8888 here? @@ -86,9 +152,10 @@ static void vout_flip(const void *vram, int stride, int bgr24, int w, int h) } out: - if (!native_rgb565) - convert(vout_buf, w * h * 2); - video_cb(vout_buf, w, h, w * 2); +#ifndef FRONTEND_SUPPORTS_RGB565 + convert(vout_buf, vout_width * vout_height * 2); +#endif + vout_fb_dirty = 1; pl_rearmed_cbs.flip_cnt++; } @@ -98,12 +165,12 @@ static void vout_close(void) static void *pl_mmap(unsigned int size) { - return plat_mmap(0, size, 0, 0); + return psxMap(0, size, 0, MAP_TAG_VRAM); } static void pl_munmap(void *ptr, unsigned int size) { - plat_munmap(ptr, size); + psxUnmap(ptr, size, MAP_TAG_VRAM); } struct rearmed_cbs pl_rearmed_cbs = { @@ -126,13 +193,14 @@ void pl_frame_limit(void) void pl_timing_prepare(int is_pal) { + is_pal_mode = is_pal; } void plat_trigger_vibrate(int is_strong) { } -void pl_update_gun(int *xn, int *xres, int *y, int *in) +void pl_update_gun(int *xn, int *yn, int *xres, int *yres, int *in) { } @@ -170,7 +238,29 @@ void out_register_libretro(struct out_driver *drv) } /* libretro */ -void retro_set_environment(retro_environment_t cb) { environ_cb = cb; } +void retro_set_environment(retro_environment_t cb) +{ + static const struct retro_variable vars[] = { + { "frameskip", "Frameskip; 0|1|2|3" }, + { "region", "Region; Auto|NTSC|PAL" }, + { "pad1type", "Pad 1 Type; standard|analog" }, +#ifndef DRC_DISABLE + { "rearmed_drc", "Dynamic recompiler; enabled|disabled" }, +#endif +#ifdef __ARM_NEON__ + { "neon_interlace_enable", "Enable interlacing mode(s); disabled|enabled" }, + { "neon_enhancement_enable", "Enhanced resolution (slow); disabled|enabled" }, + { "neon_enhancement_no_main", "Enhanced resolution speed hack; disabled|enabled" }, +#endif + { "pcsx_rearmed_duping_enable", "Frame duping; on|off" }, + { NULL, NULL }, + }; + + environ_cb = cb; + + cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars); +} + void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; } void retro_set_audio_sample(retro_audio_sample_t cb) { (void)cb; } void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; } @@ -190,53 +280,366 @@ void retro_get_system_info(struct retro_system_info *info) { memset(info, 0, sizeof(*info)); info->library_name = "PCSX-ReARMed"; - info->library_version = REV; - info->valid_extensions = "bin|cue|img|mdf|pbp|cbn"; + info->library_version = "r19"; + info->valid_extensions = "bin|cue|img|mdf|pbp|toc|cbn|m3u"; info->need_fullpath = true; } void retro_get_system_av_info(struct retro_system_av_info *info) { memset(info, 0, sizeof(*info)); - info->timing.fps = 60; + info->timing.fps = is_pal_mode ? 50 : 60; info->timing.sample_rate = 44100; info->geometry.base_width = 320; info->geometry.base_height = 240; - info->geometry.max_width = 640; - info->geometry.max_height = 512; + info->geometry.max_width = VOUT_MAX_WIDTH; + info->geometry.max_height = VOUT_MAX_HEIGHT; info->geometry.aspect_ratio = 4.0 / 3.0; } -/* TODO */ +/* savestates */ size_t retro_serialize_size(void) { - return 0; + // it's currently 4380651 bytes, but have some reserved for future + return 0x430000; +} + +struct save_fp { + char *buf; + size_t pos; + int is_write; +}; + +static void *save_open(const char *name, const char *mode) +{ + struct save_fp *fp; + + if (name == NULL || mode == NULL) + return NULL; + + fp = malloc(sizeof(*fp)); + if (fp == NULL) + return NULL; + + fp->buf = (char *)name; + fp->pos = 0; + fp->is_write = (mode[0] == 'w' || mode[1] == 'w'); + + return fp; +} + +static int save_read(void *file, void *buf, u32 len) +{ + struct save_fp *fp = file; + if (fp == NULL || buf == NULL) + return -1; + + memcpy(buf, fp->buf + fp->pos, len); + fp->pos += len; + return len; +} + +static int save_write(void *file, const void *buf, u32 len) +{ + struct save_fp *fp = file; + if (fp == NULL || buf == NULL) + return -1; + + memcpy(fp->buf + fp->pos, buf, len); + fp->pos += len; + return len; +} + +static long save_seek(void *file, long offs, int whence) +{ + struct save_fp *fp = file; + if (fp == NULL) + return -1; + + switch (whence) { + case SEEK_CUR: + fp->pos += offs; + return fp->pos; + case SEEK_SET: + fp->pos = offs; + return fp->pos; + default: + return -1; + } +} + +static void save_close(void *file) +{ + struct save_fp *fp = file; + size_t r_size = retro_serialize_size(); + if (fp == NULL) + return; + + if (fp->pos > r_size) + SysPrintf("ERROR: save buffer overflow detected\n"); + else if (fp->is_write && fp->pos < r_size) + // make sure we don't save trash in leftover space + memset(fp->buf + fp->pos, 0, r_size - fp->pos); + free(fp); } bool retro_serialize(void *data, size_t size) { - return false; + int ret = SaveState(data); + return ret == 0 ? true : false; } bool retro_unserialize(const void *data, size_t size) { - return false; + int ret = LoadState(data); + return ret == 0 ? true : false; } +/* cheats */ void retro_cheat_reset(void) { + ClearAllCheats(); } void retro_cheat_set(unsigned index, bool enabled, const char *code) { + char buf[256]; + int ret; + + // cheat funcs are destructive, need a copy.. + strncpy(buf, code, sizeof(buf)); + buf[sizeof(buf) - 1] = 0; + + if (index < NumCheats) + ret = EditCheat(index, "", buf); + else + ret = AddCheat("", buf); + + if (ret != 0) + SysPrintf("Failed to set cheat %#u\n", index); + else if (index < NumCheats) + Cheats[index].Enabled = enabled; +} + +/* multidisk support */ +static bool disk_ejected; +static unsigned int disk_current_index; +static unsigned int disk_count; +static struct disks_state { + char *fname; + int internal_index; // for multidisk eboots +} disks[8]; + +static bool disk_set_eject_state(bool ejected) +{ + // weird PCSX API.. + SetCdOpenCaseTime(ejected ? -1 : (time(NULL) + 2)); + LidInterrupt(); + + disk_ejected = ejected; + return true; +} + +static bool disk_get_eject_state(void) +{ + /* can't be controlled by emulated software */ + return disk_ejected; +} + +static unsigned int disk_get_image_index(void) +{ + return disk_current_index; +} + +static bool disk_set_image_index(unsigned int index) +{ + if (index >= sizeof(disks) / sizeof(disks[0])) + return false; + + CdromId[0] = '\0'; + CdromLabel[0] = '\0'; + + if (disks[index].fname == NULL) { + SysPrintf("missing disk #%u\n", index); + CDR_shutdown(); + + // RetroArch specifies "no disk" with index == count, + // so don't fail here.. + disk_current_index = index; + return true; + } + + SysPrintf("switching to disk %u: \"%s\" #%d\n", index, + disks[index].fname, disks[index].internal_index); + + cdrIsoMultidiskSelect = disks[index].internal_index; + set_cd_image(disks[index].fname); + if (ReloadCdromPlugin() < 0) { + SysPrintf("failed to load cdr plugin\n"); + return false; + } + if (CDR_open() < 0) { + SysPrintf("failed to open cdr plugin\n"); + return false; + } + + if (!disk_ejected) { + SetCdOpenCaseTime(time(NULL) + 2); + LidInterrupt(); + } + + disk_current_index = index; + return true; +} + +static unsigned int disk_get_num_images(void) +{ + return disk_count; +} + +static bool disk_replace_image_index(unsigned index, + const struct retro_game_info *info) +{ + char *old_fname; + bool ret = true; + + if (index >= sizeof(disks) / sizeof(disks[0])) + return false; + + old_fname = disks[index].fname; + disks[index].fname = NULL; + disks[index].internal_index = 0; + + if (info != NULL) { + disks[index].fname = strdup(info->path); + if (index == disk_current_index) + ret = disk_set_image_index(index); + } + + if (old_fname != NULL) + free(old_fname); + + return ret; +} + +static bool disk_add_image_index(void) +{ + if (disk_count >= 8) + return false; + + disk_count++; + return true; } +static struct retro_disk_control_callback disk_control = { + .set_eject_state = disk_set_eject_state, + .get_eject_state = disk_get_eject_state, + .get_image_index = disk_get_image_index, + .set_image_index = disk_set_image_index, + .get_num_images = disk_get_num_images, + .replace_image_index = disk_replace_image_index, + .add_image_index = disk_add_image_index, +}; + +// just in case, maybe a win-rt port in the future? +#ifdef _WIN32 +#define SLASH '\\' +#else +#define SLASH '/' +#endif + +static char base_dir[PATH_MAX]; + +static bool read_m3u(const char *file) +{ + char line[PATH_MAX]; + char name[PATH_MAX]; + FILE *f = fopen(file, "r"); + if (!f) + return false; + + while (fgets(line, sizeof(line), f) && disk_count < sizeof(disks) / sizeof(disks[0])) { + if (line[0] == '#') + continue; + char *carrige_return = strchr(line, '\r'); + if (carrige_return) + *carrige_return = '\0'; + char *newline = strchr(line, '\n'); + if (newline) + *newline = '\0'; + + if (line[0] != '\0') + { + snprintf(name, sizeof(name), "%s%c%s", base_dir, SLASH, line); + disks[disk_count++].fname = strdup(name); + } + } + + fclose(f); + return (disk_count != 0); +} + +static void extract_directory(char *buf, const char *path, size_t size) +{ + char *base; + strncpy(buf, path, size - 1); + buf[size - 1] = '\0'; + + base = strrchr(buf, '/'); + if (!base) + base = strrchr(buf, '\\'); + + if (base) + *base = '\0'; + else + { + buf[0] = '.'; + buf[1] = '\0'; + } +} + +#ifdef __QNX__ +/* Blackberry QNX doesn't have strcasestr */ + +/* + * Find the first occurrence of find in s, ignore case. + */ +char * +strcasestr(const char *s, const char*find) +{ + char c, sc; + size_t len; + + if ((c = *find++) != 0) { + c = tolower((unsigned char)c); + len = strlen(find); + do { + do { + if ((sc = *s++) == 0) + return (NULL); + } while ((char)tolower((unsigned char)sc) != c); + } while (strncasecmp(s, find, len) != 0); + s--; + } + return ((char *)s); +} +#endif + bool retro_load_game(const struct retro_game_info *info) { + size_t i; + bool is_m3u = (strcasestr(info->path, ".m3u") != NULL); + +#ifdef FRONTEND_SUPPORTS_RGB565 enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565; if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) { - native_rgb565 = 1; - fprintf(stderr, "RGB565 supported, using it\n"); + SysPrintf("RGB565 supported, using it\n"); + } +#endif + + if (info == NULL || info->path == NULL) { + SysPrintf("info->path required\n"); + return false; } if (plugins_opened) { @@ -244,11 +647,32 @@ bool retro_load_game(const struct retro_game_info *info) plugins_opened = 0; } - set_cd_image(info->path); + for (i = 0; i < sizeof(disks) / sizeof(disks[0]); i++) { + if (disks[i].fname != NULL) { + free(disks[i].fname); + disks[i].fname = NULL; + } + disks[i].internal_index = 0; + } + + disk_current_index = 0; + extract_directory(base_dir, info->path, sizeof(base_dir)); + + if (is_m3u) { + if (!read_m3u(info->path)) { + SysPrintf("failed to read m3u file\n"); + return false; + } + } else { + disk_count = 1; + disks[0].fname = strdup(info->path); + } + + set_cd_image(disks[0].fname); /* have to reload after set_cd_image for correct cdr plugin */ if (LoadPlugins() == -1) { - printf("faled to load plugins\n"); + SysPrintf("failed to load plugins\n"); return false; } @@ -256,26 +680,36 @@ bool retro_load_game(const struct retro_game_info *info) NetOpened = 0; if (OpenPlugins() == -1) { - printf("faled to open plugins\n"); + SysPrintf("failed to open plugins\n"); return false; } plugin_call_rearmed_cbs(); + dfinput_activate(); Config.PsxAuto = 1; if (CheckCdrom() == -1) { - printf("unsupported/invalid CD image: %s\n", info->path); + SysPrintf("unsupported/invalid CD image: %s\n", info->path); return false; } SysReset(); if (LoadCdrom() == -1) { - printf("could not load CD-ROM!\n"); + SysPrintf("could not load CD-ROM!\n"); return false; } emu_on_new_cd(0); + // multidisk images + if (!is_m3u) { + disk_count = cdrIsoMultidiskCount < 8 ? cdrIsoMultidiskCount : 8; + for (i = 1; i < sizeof(disks) / sizeof(disks[0]) && i < cdrIsoMultidiskCount; i++) { + disks[i].fname = strdup(info->path); + disks[i].internal_index = i; + } + } + return true; } @@ -290,17 +724,23 @@ void retro_unload_game(void) unsigned retro_get_region(void) { - return RETRO_REGION_NTSC; + return is_pal_mode ? RETRO_REGION_PAL : RETRO_REGION_NTSC; } void *retro_get_memory_data(unsigned id) { - return NULL; + if (id == RETRO_MEMORY_SAVE_RAM) + return Mcd1Data; + else + return NULL; } size_t retro_get_memory_size(unsigned id) { - return 0; + if (id == RETRO_MEMORY_SAVE_RAM) + return MCD_SIZE; + else + return 0; } void retro_reset(void) @@ -328,11 +768,131 @@ static const unsigned short retro_psx_map[] = { }; #define RETRO_PSX_MAP_LEN (sizeof(retro_psx_map) / sizeof(retro_psx_map[0])) +static void update_variables(bool in_flight) +{ + struct retro_variable var; + + var.value = NULL; + var.key = "frameskip"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value) + pl_rearmed_cbs.frameskip = atoi(var.value); + + var.value = NULL; + var.key = "region"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value) + { + Config.PsxAuto = 0; + if (strcmp(var.value, "Automatic") == 0) + Config.PsxAuto = 1; + else if (strcmp(var.value, "NTSC") == 0) + Config.PsxType = 0; + else if (strcmp(var.value, "PAL") == 0) + Config.PsxType = 1; + } + + var.value = NULL; + var.key = "pad1type"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value) + { + in_type1 = PSE_PAD_TYPE_STANDARD; + if (strcmp(var.value, "analog") == 0) + in_type1 = PSE_PAD_TYPE_ANALOGPAD; + } + +#ifdef __ARM_NEON__ + var.value = "NULL"; + var.key = "neon_interlace_enable"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value) + { + if (strcmp(var.value, "disabled") == 0) + pl_rearmed_cbs.gpu_neon.allow_interlace = 0; + else if (strcmp(var.value, "enabled") == 0) + pl_rearmed_cbs.gpu_neon.allow_interlace = 1; + } + + var.value = NULL; + var.key = "neon_enhancement_enable"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value) + { + if (strcmp(var.value, "disabled") == 0) + pl_rearmed_cbs.gpu_neon.enhancement_enable = 0; + else if (strcmp(var.value, "enabled") == 0) + pl_rearmed_cbs.gpu_neon.enhancement_enable = 1; + } + + var.value = NULL; + var.key = "neon_enhancement_no_main"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value) + { + if (strcmp(var.value, "disabled") == 0) + pl_rearmed_cbs.gpu_neon.enhancement_no_main = 0; + else if (strcmp(var.value, "enabled") == 0) + pl_rearmed_cbs.gpu_neon.enhancement_no_main = 1; + } +#endif + + var.value = "NULL"; + var.key = "pcsx_rearmed_duping_enable"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value) + { + if (strcmp(var.value, "off") == 0) + duping_enable = false; + else if (strcmp(var.value, "on") == 0) + duping_enable = true; + } + +#ifndef DRC_DISABLE + var.value = NULL; + var.key = "rearmed_drc"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value) + { + R3000Acpu *prev_cpu = psxCpu; + + if (strcmp(var.value, "disabled") == 0) + Config.Cpu = CPU_INTERPRETER; + else if (strcmp(var.value, "enabled") == 0) + Config.Cpu = CPU_DYNAREC; + + psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec; + if (psxCpu != prev_cpu) { + prev_cpu->Shutdown(); + psxCpu->Init(); + psxCpu->Reset(); // not really a reset.. + } + } +#endif + + if (in_flight) { + // inform core things about possible config changes + plugin_call_rearmed_cbs(); + + if (GPU_open != NULL && GPU_close != NULL) { + GPU_close(); + GPU_open(&gpuDisp, "PCSX", NULL); + } + + dfinput_activate(); + } +} + void retro_run(void) { int i; input_poll_cb(); + + bool updated = false; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) + update_variables(true); + in_keystate = 0; for (i = 0; i < RETRO_PSX_MAP_LEN; i++) if (input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, i)) @@ -342,28 +902,94 @@ void retro_run(void) if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, i)) in_keystate |= retro_psx_map[i]; + if (in_type1 == PSE_PAD_TYPE_ANALOGPAD) + { + in_a1[0] = (input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X) / 256) + 128; + in_a1[1] = (input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / 256) + 128; + in_a2[0] = (input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) / 256) + 128; + in_a2[1] = (input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / 256) + 128; + } + stop = 0; psxCpu->Execute(); - samples_to_send += 44100 / 60; + samples_to_send += is_pal_mode ? 44100 / 50 : 44100 / 60; + + video_cb((vout_fb_dirty || !vout_can_dupe || !duping_enable) ? vout_buf : NULL, + vout_width, vout_height, vout_width * 2); + vout_fb_dirty = 0; +} + +static bool try_use_bios(const char *path) +{ + FILE *f; + long size; + const char *name; + + f = fopen(path, "rb"); + if (f == NULL) + return false; + + fseek(f, 0, SEEK_END); + size = ftell(f); + fclose(f); + + if (size != 512 * 1024) + return false; + + name = strrchr(path, SLASH); + if (name++ == NULL) + name = path; + snprintf(Config.Bios, sizeof(Config.Bios), "%s", name); + return true; } +#if 1 +#include +#include + +static bool find_any_bios(const char *dirpath, char *path, size_t path_size) +{ + DIR *dir; + struct dirent *ent; + bool ret = false; + + dir = opendir(dirpath); + if (dir == NULL) + return false; + + while ((ent = readdir(dir))) { + if (strncasecmp(ent->d_name, "scph", 4) != 0) + continue; + + snprintf(path, path_size, "%s/%s", dirpath, ent->d_name); + ret = try_use_bios(path); + if (ret) + break; + } + closedir(dir); + return ret; +} +#else +#define find_any_bios(...) false +#endif + void retro_init(void) { const char *bios[] = { "scph1001", "scph5501", "scph7001" }; const char *dir; char path[256]; - FILE *f = NULL; int i, ret, level; + bool found_bios = false; ret = emu_core_preinit(); ret |= emu_core_init(); if (ret != 0) { - printf("PCSX init failed, sorry\n"); + SysPrintf("PCSX init failed.\n"); exit(1); } - vout_buf = malloc(640 * 512 * 2); + posix_memalign(&vout_buf, 16, VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2); if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir) { @@ -371,22 +997,54 @@ void retro_init(void) for (i = 0; i < sizeof(bios) / sizeof(bios[0]); i++) { snprintf(path, sizeof(path), "%s/%s.bin", dir, bios[i]); - f = fopen(path, "r"); - if (f != NULL) { - snprintf(Config.Bios, sizeof(Config.Bios), "%s.bin", bios[i]); + found_bios = try_use_bios(path); + if (found_bios) break; - } } + + if (!found_bios) + found_bios = find_any_bios(dir, path, sizeof(path)); } - if (f != NULL) { - printf("found BIOS file: %s\n", Config.Bios); - fclose(f); + if (found_bios) { + SysPrintf("found BIOS file: %s\n", Config.Bios); } else - printf("no BIOS files found.\n"); + { + SysPrintf("no BIOS files found.\n"); + struct retro_message msg = + { + "no BIOS found, expect bugs!", + 180 + }; + environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, (void*)&msg); + } level = 1; environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level); + + environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &vout_can_dupe); + environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &disk_control); + + /* Set how much slower PSX CPU runs * 100 (so that 200 is 2 times) + * we have to do this because cache misses and some IO penalties + * are not emulated. Warning: changing this may break compatibility. */ +#ifdef __ARM_ARCH_7A__ + cycle_multiplier = 175; +#else + cycle_multiplier = 200; +#endif + + McdDisable[0] = 0; + McdDisable[1] = 1; + init_memcard(Mcd1Data); + + SaveFuncs.open = save_open; + SaveFuncs.read = save_read; + SaveFuncs.write = save_write; + SaveFuncs.seek = save_seek; + SaveFuncs.close = save_close; + + update_variables(false); } void retro_deinit(void) @@ -395,4 +1053,3 @@ void retro_deinit(void) free(vout_buf); vout_buf = NULL; } -