#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 "cspace.h"
#include "main.h"
#include "plugin.h"
#include "plugin_lib.h"
static int samples_sent, samples_to_send;
static int plugins_opened;
+static int is_pal_mode;
/* memory card data */
extern char Mcd1Data[MCD_SIZE];
void pl_timing_prepare(int is_pal)
{
+ is_pal_mode = is_pal;
}
void plat_trigger_vibrate(int is_strong)
}
/* 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" },
+#ifdef __ARM_NEON__
+ { "neon_interlace_enable", "Enable interlacing mode(s); disabled|enabled" },
+#if 0
+ { "neon_enhancement_enable", "Enhanced resolution (slow); disabled|enabled" },
+#endif
+#endif
+ { 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; }
{
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;
return ret == 0 ? true : false;
}
+/* cheats */
void retro_cheat_reset(void)
{
ClearAllCheats();
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';
+ }
+}
+
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)) {
}
#endif
+ if (info == NULL || info->path == NULL) {
+ SysPrintf("info->path required\n");
+ return false;
+ }
+
if (plugins_opened) {
ClosePlugins();
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) {
}
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;
}
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 Mcd1Data;
+ if (id == RETRO_MEMORY_SAVE_RAM)
+ return Mcd1Data;
+ else
+ return NULL;
}
size_t retro_get_memory_size(unsigned id)
{
- return MCD_SIZE;
+ if (id == RETRO_MEMORY_SAVE_RAM)
+ return MCD_SIZE;
+ else
+ return 0;
}
void retro_reset(void)
};
#define RETRO_PSX_MAP_LEN (sizeof(retro_psx_map) / sizeof(retro_psx_map[0]))
+static void update_variables(void)
+{
+ 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;
+ }
+#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;
+ }
+
+#if 0
+ 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;
+ }
+#endif
+#endif
+}
+
void retro_run(void)
{
int i;
input_poll_cb();
+
+ bool updated = false;
+ if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
+ update_variables();
+
in_keystate = 0;
for (i = 0; i < RETRO_PSX_MAP_LEN; i++)
if (input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, i))
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) ? vout_buf : NULL,
vout_width, vout_height, vout_width * 2);
fclose(f);
}
else
+ {
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
SaveFuncs.write = save_write;
SaveFuncs.seek = save_seek;
SaveFuncs.close = save_close;
+
+ update_variables();
}
void retro_deinit(void)