snes9x2005/libretro.c

939 lines
25 KiB
C
Raw Normal View History

#include "copyright"
2014-10-28 02:13:05 +00:00
#include <stdio.h>
#include "snes9x.h"
#include "soundux.h"
#include "memmap.h"
#include "apu.h"
#include "cheats.h"
#include "display.h"
#include "gfx.h"
#include "cpuexec.h"
#include "spc7110.h"
#include "srtc.h"
2014-11-01 11:58:18 +00:00
#include "sa1.h"
2014-10-28 02:13:05 +00:00
2014-10-31 08:12:09 +00:00
#ifdef PSP
#include <pspkernel.h>
#include <pspgu.h>
#endif
2014-10-28 02:13:05 +00:00
#include <libretro.h>
#ifdef _3DS
void* linearMemAlign(size_t size, size_t alignment);
void linearFree(void* mem);
#endif
2014-10-28 02:13:05 +00:00
static retro_log_printf_t log_cb = NULL;
static retro_video_refresh_t video_cb = NULL;
static retro_input_poll_t poll_cb = NULL;
static retro_input_state_t input_cb = NULL;
static retro_audio_sample_batch_t audio_batch_cb = NULL;
static retro_environment_t environ_cb = NULL;
struct retro_perf_callback perf_cb;
2015-09-14 04:14:51 +00:00
char retro_save_directory[PATH_MAX];
char retro_base_name[PATH_MAX];
#ifdef _WIN32
char slash = '\\';
#else
char slash = '/';
#endif
static float samples_per_frame = 0.0;
static float samplerate = (((SNES_CLOCK_SPEED * 6) / (32 * ONE_APU_CYCLE)));
2014-10-31 06:47:19 +00:00
#ifdef PERF_TEST
#define RETRO_PERFORMANCE_INIT(name) \
retro_perf_tick_t current_ticks;\
static struct retro_perf_counter name = {#name};\
if (!name.registered) perf_cb.perf_register(&(name));\
current_ticks = name.total
#define RETRO_PERFORMANCE_START(name) perf_cb.perf_start(&(name))
#define RETRO_PERFORMANCE_STOP(name) \
perf_cb.perf_stop(&(name));\
current_ticks = name.total - current_ticks;
#else
#define RETRO_PERFORMANCE_INIT(name)
#define RETRO_PERFORMANCE_START(name)
#define RETRO_PERFORMANCE_STOP(name)
#endif
2014-10-28 02:13:05 +00:00
void retro_set_environment(retro_environment_t cb)
{
struct retro_log_callback log;
environ_cb = cb;
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
log_cb = log.log;
else
log_cb = NULL;
environ_cb(RETRO_ENVIRONMENT_GET_PERF_INTERFACE, &perf_cb);
}
void retro_set_video_refresh(retro_video_refresh_t cb)
{
video_cb = cb;
}
void retro_set_audio_sample(retro_audio_sample_t cb)
2017-01-16 22:39:57 +00:00
{
}
2014-10-28 02:13:05 +00:00
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
{
audio_batch_cb = cb;
}
void retro_set_input_poll(retro_input_poll_t cb)
{
poll_cb = cb;
}
void retro_set_input_state(retro_input_state_t cb)
{
input_cb = cb;
}
void retro_set_controller_port_device(unsigned port, unsigned device) {}
2014-10-29 23:23:30 +00:00
unsigned retro_api_version()
{
return RETRO_API_VERSION;
}
2014-10-28 02:13:05 +00:00
void S9xMessage(const char* message)
2014-10-28 02:13:05 +00:00
{
#define MAX_MESSAGE_LEN (36 * 3)
2014-10-28 02:13:05 +00:00
2014-10-29 23:23:30 +00:00
static char buffer [MAX_MESSAGE_LEN + 1];
2014-10-28 02:13:05 +00:00
2014-10-29 23:23:30 +00:00
printf("%s\n", message);
strncpy(buffer, message, MAX_MESSAGE_LEN);
buffer [MAX_MESSAGE_LEN] = 0;
S9xSetInfoString(buffer);
2014-10-28 02:13:05 +00:00
}
2014-10-29 23:23:30 +00:00
void S9xDeinitDisplay(void)
2014-10-28 02:13:05 +00:00
{
#ifdef DS2_DMA
if (GFX.Screen_buffer) AlignedFree(GFX.Screen, PtrAdj.GFXScreen);
#elif defined(_3DS)
if (GFX.Screen_buffer) linearFree(GFX.Screen_buffer);
2014-10-28 02:13:05 +00:00
#else
if (GFX.Screen_buffer) free(GFX.Screen_buffer);
2014-10-28 02:13:05 +00:00
#endif
if (GFX.SubScreen_buffer) free(GFX.SubScreen_buffer);
if (GFX.ZBuffer_buffer) free(GFX.ZBuffer_buffer);
if (GFX.SubZBuffer_buffer) free(GFX.SubZBuffer_buffer);
GFX.Screen = NULL;
GFX.Screen_buffer = NULL;
GFX.SubScreen = NULL;
GFX.SubScreen_buffer = NULL;
GFX.ZBuffer = NULL;
GFX.ZBuffer_buffer = NULL;
GFX.SubZBuffer = NULL;
GFX.SubZBuffer_buffer = NULL;
2014-10-28 02:13:05 +00:00
}
2014-10-29 23:23:30 +00:00
void S9xInitDisplay(void)
2014-10-28 02:13:05 +00:00
{
int32_t h = IMAGE_HEIGHT;
int32_t safety = 32;
2014-10-28 02:13:05 +00:00
GFX.Pitch = IMAGE_WIDTH * 2;
#ifdef DS2_DMA
GFX.Screen_buffer = (uint8_t *) AlignedMalloc(GFX.Pitch * h + safety, 32, &PtrAdj.GFXScreen);
#elif defined(_3DS)
safety = 0x80;
GFX.Screen_buffer = (uint8_t *) linearMemAlign(GFX.Pitch * h + safety, 0x80);
2014-10-28 02:13:05 +00:00
#else
GFX.Screen_buffer = (uint8_t *) malloc(GFX.Pitch * h + safety);
2014-10-28 02:13:05 +00:00
#endif
GFX.SubScreen_buffer = (uint8_t *) malloc(GFX.Pitch * h + safety);
GFX.ZBuffer_buffer = (uint8_t *) malloc((GFX.Pitch >> 1) * h + safety);
GFX.SubZBuffer_buffer = (uint8_t *) malloc((GFX.Pitch >> 1) * h + safety);
GFX.Screen = GFX.Screen_buffer + safety;
GFX.SubScreen = GFX.SubScreen_buffer + safety;
GFX.ZBuffer = GFX.ZBuffer_buffer + safety;
GFX.SubZBuffer = GFX.SubZBuffer_buffer + safety;
2014-10-28 02:13:05 +00:00
GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
}
2014-11-03 14:26:54 +00:00
bool S9xInitUpdate()
2014-10-28 02:13:05 +00:00
{
2014-11-03 14:26:54 +00:00
return (true);
2014-10-28 02:13:05 +00:00
}
#ifndef __WIN32__
2014-10-29 23:23:30 +00:00
void _makepath(char* path, const char* drive, const char* dir,
const char* fname, const char* ext)
{
if (dir && *dir)
{
strcpy(path, dir);
strcat(path, "/");
}
2014-10-28 02:13:05 +00:00
else
2014-10-29 23:23:30 +00:00
*path = 0;
if (fname)
strcat(path, fname);
2014-10-29 23:23:30 +00:00
if (ext && *ext)
2014-10-28 02:13:05 +00:00
{
2014-10-29 23:23:30 +00:00
strcat(path, ".");
strcat(path, ext);
}
}
void _splitpath(const char* path, char* drive, char* dir, char* fname,
char* ext)
{
*drive = 0;
char* slash = strrchr((char*)path, '/');
if (!slash)
slash = strrchr((char*)path, '\\');
char* dot = strrchr((char*)path, '.');
if (dot && slash && dot < slash)
dot = NULL;
if (!slash)
{
strcpy(dir, "");
strcpy(fname, path);
if (dot)
{
* (fname + (dot - path)) = 0;
strcpy(ext, dot + 1);
}
else
strcpy(ext, "");
2014-10-28 02:13:05 +00:00
}
else
2014-10-29 23:23:30 +00:00
{
strcpy(dir, path);
* (dir + (slash - path)) = 0;
strcpy(fname, slash + 1);
if (dot)
{
* (fname + (dot - slash) - 1) = 0;
strcpy(ext, dot + 1);
}
else
strcpy(ext, "");
}
2014-10-28 02:13:05 +00:00
}
#endif
2014-10-29 23:23:30 +00:00
const char* S9xGetFilename(const char* ex)
2014-10-28 02:13:05 +00:00
{
2014-10-29 23:23:30 +00:00
static char filename [PATH_MAX + 1];
char drive [_MAX_DRIVE + 1];
char dir [_MAX_DIR + 1];
char fname [_MAX_FNAME + 1];
char ext [_MAX_EXT + 1];
_splitpath(Memory.ROMFilename, drive, dir, fname, ext);
2014-11-02 06:00:31 +00:00
_makepath(filename, drive, dir, fname, ex);
2014-10-28 02:13:05 +00:00
2014-10-29 23:23:30 +00:00
return (filename);
2014-10-28 02:13:05 +00:00
}
2015-09-14 04:14:51 +00:00
void GetBaseName(const char* ex)
{
char drive [_MAX_DRIVE + 1];
char dir [_MAX_DIR + 1];
char fname [_MAX_FNAME + 1];
char ext [_MAX_EXT + 1];
_splitpath(Memory.ROMFilename, drive, dir, fname, ext);
snprintf(retro_base_name,sizeof(retro_base_name),"%s",fname);
}
2014-10-28 02:13:05 +00:00
void init_sfc_setting(void)
{
memset(&Settings, 0, sizeof(Settings));
2014-11-03 14:26:54 +00:00
Settings.JoystickEnabled = false;
Settings.SoundPlaybackRate = samplerate;
2014-10-29 23:23:30 +00:00
Settings.CyclesPercentage = 100;
2014-11-03 14:26:54 +00:00
Settings.DisableSoundEcho = false;
Settings.InterpolatedSound = true;
Settings.APUEnabled = true;
2014-10-28 02:13:05 +00:00
2014-10-29 23:23:30 +00:00
Settings.H_Max = SNES_CYCLES_PER_SCANLINE;
Settings.SkipFrames = AUTO_FRAMERATE;
2014-11-03 14:26:54 +00:00
Settings.ShutdownMaster = true;
2014-10-29 23:23:30 +00:00
Settings.FrameTimePAL = 20000;
Settings.FrameTimeNTSC = 16667;
2014-11-03 14:26:54 +00:00
Settings.DisableMasterVolume = false;
Settings.Mouse = true;
Settings.SuperScope = true;
Settings.MultiPlayer5 = true;
2014-10-29 23:23:30 +00:00
Settings.ControllerOption = SNES_JOYPAD;
2014-11-03 14:26:54 +00:00
Settings.Transparency = true;
Settings.SupportHiRes = true;
#ifdef USE_BLARGG_APU
2014-11-03 14:26:54 +00:00
Settings.SoundSync = false;
#endif
Settings.ApplyCheats = true;
2014-10-29 23:23:30 +00:00
Settings.StretchScreenshots = 1;
2014-10-28 02:13:05 +00:00
Settings.HBlankStart = (256 * Settings.H_Max) / SNES_HCOUNTER_MAX;
}
#ifdef USE_BLARGG_APU
static void S9xAudioCallback()
{
size_t avail;
/* Just pick a big buffer. We won't use it all. */
static int16_t audio_buf[0x20000];
S9xFinalizeSamples();
avail = S9xGetSampleCount();
S9xMixSamples(audio_buf, avail);
audio_batch_cb(audio_buf, avail >> 1);
}
#endif
2014-10-29 23:23:30 +00:00
void retro_init(void)
2014-10-28 02:13:05 +00:00
{
struct retro_log_callback log;
enum retro_pixel_format rgb565;
2015-10-06 00:24:03 +00:00
static const struct retro_variable vars[] = {
2015-11-01 22:32:10 +00:00
{ "catsfc_VideoMode", "Video Mode; auto|NTSC|PAL" },
2015-10-06 00:24:03 +00:00
{ NULL, NULL },
};
2014-10-28 02:13:05 +00:00
if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
log_cb = log.log;
else
log_cb = NULL;
rgb565 = RETRO_PIXEL_FORMAT_RGB565;
2014-10-29 23:23:30 +00:00
if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb565) && log_cb)
log_cb(RETRO_LOG_INFO,
"Frontend supports RGB565 - will use that instead of XRGB1555.\n");
2014-10-28 02:13:05 +00:00
init_sfc_setting();
2014-11-02 06:52:33 +00:00
S9xInitMemory();
2014-10-30 02:10:39 +00:00
S9xInitAPU();
2014-10-29 23:23:30 +00:00
S9xInitDisplay();
2014-11-02 06:52:33 +00:00
S9xInitGFX();
#ifdef USE_BLARGG_APU
S9xInitSound(1000, 0); //just give it a 1 second buffer
S9xSetSamplesAvailableCallback(S9xAudioCallback);
#else
2016-10-16 18:07:08 +00:00
S9xInitSound();
#endif
2015-10-06 00:24:03 +00:00
environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars);
2014-10-28 02:13:05 +00:00
}
2014-10-30 02:41:40 +00:00
void retro_deinit(void)
{
if (Settings.SPC7110)
2014-11-02 06:52:33 +00:00
(*CleanUp7110)();
S9xDeinitGFX();
2014-10-30 02:41:40 +00:00
S9xDeinitDisplay();
S9xDeinitAPU();
2014-11-02 06:52:33 +00:00
S9xDeinitMemory();
2014-10-31 06:47:19 +00:00
#ifdef PERF_TEST
perf_cb.perf_log();
#endif
2014-10-30 02:41:40 +00:00
}
2014-10-28 02:13:05 +00:00
uint32_t S9xReadJoypad(int32_t port)
2014-10-28 02:13:05 +00:00
{
2014-11-03 14:26:54 +00:00
static const uint32_t snes_lut[] =
2014-10-29 23:23:30 +00:00
{
SNES_B_MASK,
SNES_Y_MASK,
SNES_SELECT_MASK,
SNES_START_MASK,
SNES_UP_MASK,
SNES_DOWN_MASK,
SNES_LEFT_MASK,
SNES_RIGHT_MASK,
SNES_A_MASK,
SNES_X_MASK,
SNES_TL_MASK,
SNES_TR_MASK
2014-10-28 02:13:05 +00:00
};
int32_t i;
2014-11-03 14:26:54 +00:00
uint32_t joypad = 0;
2014-10-28 02:13:05 +00:00
2014-10-29 23:23:30 +00:00
for (i = RETRO_DEVICE_ID_JOYPAD_B; i <= RETRO_DEVICE_ID_JOYPAD_R; i++)
2014-10-28 02:13:05 +00:00
if (input_cb(port, RETRO_DEVICE_JOYPAD, 0, i))
joypad |= snes_lut[i];
return joypad;
}
2015-10-06 00:24:03 +00:00
static void check_variables(void)
{
struct retro_variable var;
2015-11-01 22:32:10 +00:00
var.key = "catsfc_VideoMode";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
Settings.ForceNTSC = !strcmp(var.value, "NTSC");
Settings.ForcePAL = !strcmp(var.value, "PAL");
}
2015-10-06 00:24:03 +00:00
}
2014-11-02 10:04:37 +00:00
#ifdef PSP
#define FRAMESKIP
#endif
2014-11-01 12:25:00 +00:00
static float samples_to_play = 0.0;
2014-10-29 23:23:30 +00:00
void retro_run(void)
2014-10-28 02:13:05 +00:00
{
2015-10-06 00:24:03 +00:00
bool updated = false;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
check_variables();
2014-10-28 02:13:05 +00:00
2014-11-01 12:25:00 +00:00
#ifdef NO_VIDEO_OUTPUT
video_cb(NULL, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, GFX.Pitch);
IPPU.RenderThisFrame = false;
#endif
2014-11-01 11:58:18 +00:00
2014-10-28 02:13:05 +00:00
poll_cb();
2014-10-31 06:47:19 +00:00
RETRO_PERFORMANCE_INIT(S9xMainLoop_func);
RETRO_PERFORMANCE_START(S9xMainLoop_func);
2014-10-28 02:13:05 +00:00
S9xMainLoop();
2014-10-31 06:47:19 +00:00
RETRO_PERFORMANCE_STOP(S9xMainLoop_func);
2014-10-28 02:13:05 +00:00
#ifndef USE_BLARGG_APU
static int16_t audio_buf[2048];
samples_to_play += samples_per_frame;
if (samples_to_play > 512)
{
S9xMixSamples(audio_buf, ((int32_t)samples_to_play) * 2);
audio_batch_cb(audio_buf, (int32_t)samples_to_play);
samples_to_play -= (int32_t)samples_to_play;
}
#endif
2014-11-01 12:25:00 +00:00
#ifdef NO_VIDEO_OUTPUT
return;
#endif
2014-11-01 11:58:18 +00:00
2014-11-01 09:27:16 +00:00
#ifdef FRAMESKIP
if (IPPU.RenderThisFrame)
{
#endif
2014-10-28 02:13:05 +00:00
2014-10-31 08:12:09 +00:00
#ifdef PSP
2014-11-01 09:27:16 +00:00
static unsigned int __attribute__((aligned(16))) d_list[32];
void* const texture_vram_p = (void*)(0x44200000 - (512 *
512)); // max VRAM address - frame size
2014-10-31 08:12:09 +00:00
2014-11-01 12:25:00 +00:00
sceKernelDcacheWritebackRange(GFX.Screen,
GFX.Pitch * IPPU.RenderedScreenHeight);
2014-10-31 08:12:09 +00:00
2014-11-01 09:27:16 +00:00
sceGuStart(GU_DIRECT, d_list);
2014-10-31 08:12:09 +00:00
2014-11-01 12:25:00 +00:00
sceGuCopyImage(GU_PSM_4444, 0, 0, IPPU.RenderedScreenWidth,
IPPU.RenderedScreenHeight, GFX.Pitch >> 1, GFX.Screen, 0,
2014-11-01 09:27:16 +00:00
0,
512, texture_vram_p);
2014-10-31 08:12:09 +00:00
2014-11-01 09:27:16 +00:00
sceGuTexSync();
sceGuTexImage(0, 512, 512, 512, texture_vram_p);
sceGuTexMode(GU_PSM_5551, 0, 0, GU_FALSE);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
sceGuDisable(GU_BLEND);
2014-10-31 08:12:09 +00:00
2014-11-01 09:27:16 +00:00
sceGuFinish();
2014-10-31 08:12:09 +00:00
2014-11-01 12:25:00 +00:00
video_cb(texture_vram_p, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight,
GFX.Pitch);
2014-10-31 08:12:09 +00:00
#else
2014-11-01 12:25:00 +00:00
video_cb(GFX.Screen, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight,
GFX.Pitch);
2014-10-31 08:12:09 +00:00
#endif
2014-10-28 02:13:05 +00:00
#ifdef FRAMESKIP
IPPU.RenderThisFrame = false;
2014-11-01 09:27:16 +00:00
}
2014-10-28 02:13:05 +00:00
else
{
2014-11-01 09:27:16 +00:00
video_cb(NULL, IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight, GFX.Pitch);
2014-10-28 02:13:05 +00:00
IPPU.RenderThisFrame = true;
}
#endif
}
bool S9xReadMousePosition(int32_t which1, int32_t* x, int32_t* y, uint32_t* buttons)
2014-10-28 02:13:05 +00:00
{
2014-11-03 14:26:54 +00:00
return (false);
2014-10-28 02:13:05 +00:00
}
bool S9xReadSuperScopePosition(int32_t* x, int32_t* y, uint32_t* buttons)
2014-10-28 02:13:05 +00:00
{
2014-11-03 14:26:54 +00:00
return (true);
2014-10-28 02:13:05 +00:00
}
bool JustifierOffscreen()
{
2014-11-03 14:26:54 +00:00
return (false);
2014-10-28 02:13:05 +00:00
}
2014-11-03 14:26:54 +00:00
void JustifierButtons(uint32_t* justifiers)
2014-10-28 02:13:05 +00:00
{
}
char* osd_GetPackDir()
{
2014-10-29 23:23:30 +00:00
static char filename[_MAX_PATH];
memset(filename, 0, _MAX_PATH);
2014-11-02 06:00:31 +00:00
char dir [_MAX_DIR + 1];
char drive [_MAX_DRIVE + 1];
char name [_MAX_FNAME + 1];
char ext [_MAX_EXT + 1];
_splitpath(Memory.ROMFilename, drive, dir, name, ext);
_makepath(filename, drive, dir, NULL, NULL);
2014-10-29 23:23:30 +00:00
if (!strncmp((char*)&Memory.ROM [0xffc0], "SUPER POWER LEAG 4 ", 21))
{
if (getenv("SPL4PACK"))
return getenv("SPL4PACK");
else
strcat(filename, "/SPL4-SP7");
}
else if (!strncmp((char*)&Memory.ROM [0xffc0], "MOMOTETSU HAPPY ", 21))
{
if (getenv("MDHPACK"))
return getenv("MDHPACK");
else
strcat(filename, "/SMHT-SP7");
}
else if (!strncmp((char*)&Memory.ROM [0xffc0], "HU TENGAI MAKYO ZERO ", 21))
{
if (getenv("FEOEZPACK"))
return getenv("FEOEZPACK");
else
strcat(filename, "/FEOEZSP7");
}
else if (!strncmp((char*)&Memory.ROM [0xffc0], "JUMP TENGAIMAKYO ZERO", 21))
{
if (getenv("SJNSPACK"))
return getenv("SJNSPACK");
else
strcat(filename, "/SJUMPSP7");
}
else strcat(filename, "/MISC-SP7");
return filename;
}
unsigned retro_get_region(void)
2014-10-28 02:13:05 +00:00
{
return Settings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC;
}
2017-01-16 22:39:57 +00:00
2014-10-29 23:23:30 +00:00
void retro_get_system_info(struct retro_system_info* info)
2014-10-28 02:13:05 +00:00
{
2014-11-02 05:31:17 +00:00
#ifdef LOAD_FROM_MEMORY_TEST
2016-08-05 16:27:32 +00:00
info->need_fullpath = false;
2014-11-02 05:31:17 +00:00
#else
2016-08-05 16:27:32 +00:00
info->need_fullpath = true;
2014-11-02 05:31:17 +00:00
#endif
2014-10-28 02:13:05 +00:00
info->valid_extensions = "smc|fig|sfc|gd3|gd7|dx2|bsx|swc";
2016-12-09 22:34:44 +00:00
#ifndef GIT_VERSION
#define GIT_VERSION ""
#endif
info->library_version = "v1.36" GIT_VERSION;
#ifdef USE_BLARGG_APU
2016-08-05 16:37:11 +00:00
info->library_name = "Snes9x 2005 Plus";
#else
2016-08-05 16:37:11 +00:00
info->library_name = "Snes9x 2005";
#endif
2016-08-05 16:27:32 +00:00
info->block_extract = false;
2014-10-28 02:13:05 +00:00
}
2014-10-29 23:23:30 +00:00
void retro_get_system_av_info(struct retro_system_av_info* info)
2014-10-28 02:13:05 +00:00
{
info->geometry.base_width = 256;
info->geometry.base_height = 224;
info->geometry.max_width = 512;
info->geometry.max_height = 512;
info->geometry.aspect_ratio = 4.0 / 3.0;
if (!Settings.PAL)
2014-11-01 12:25:00 +00:00
info->timing.fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE *
SNES_MAX_NTSC_VCOUNTER));
else
2014-11-01 12:25:00 +00:00
info->timing.fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE *
SNES_MAX_PAL_VCOUNTER));
2014-10-28 02:13:05 +00:00
info->timing.sample_rate = samplerate;
2014-10-28 02:13:05 +00:00
}
void retro_reset(void)
{
2014-10-30 02:41:40 +00:00
CPU.Flags = 0;
S9xReset();
2014-10-28 02:13:05 +00:00
}
size_t retro_serialize_size(void)
{
return sizeof(CPU) + sizeof(ICPU) + sizeof(PPU) + sizeof(DMA) +
0x10000 + 0x20000 + 0x20000 + 0x8000 +
#ifndef USE_BLARGG_APU
sizeof(APU) + sizeof(IAPU) + 0x10000
#else
SPC_SAVE_STATE_BLOCK_SIZE
#endif
+ sizeof(SA1) +
sizeof(s7r) + sizeof(rtc_f9);
2014-10-28 02:13:05 +00:00
}
2014-10-29 23:23:30 +00:00
bool retro_serialize(void* data, size_t size)
{
int32_t i;
S9xUpdateRTC();
S9xSRTCPreSaveState();
uint8_t* buffer = data;
memcpy(buffer, &CPU, sizeof(CPU));
buffer += sizeof(CPU);
memcpy(buffer, &ICPU, sizeof(ICPU));
buffer += sizeof(ICPU);
memcpy(buffer, &PPU, sizeof(PPU));
buffer += sizeof(PPU);
memcpy(buffer, &DMA, sizeof(DMA));
buffer += sizeof(DMA);
memcpy(buffer, Memory.VRAM, 0x10000);
buffer += 0x10000;
memcpy(buffer, Memory.RAM, 0x20000);
buffer += 0x20000;
memcpy(buffer, Memory.SRAM, 0x20000);
buffer += 0x20000;
memcpy(buffer, Memory.FillRAM, 0x8000);
buffer += 0x8000;
#ifndef USE_BLARGG_APU
memcpy(buffer, &APU, sizeof(APU));
buffer += sizeof(APU);
memcpy(buffer, &IAPU, sizeof(IAPU));
buffer += sizeof(IAPU);
memcpy(buffer, IAPU.RAM, 0x10000);
buffer += 0x10000;
#else
S9xAPUSaveState(buffer);
buffer += SPC_SAVE_STATE_BLOCK_SIZE;
#endif
SA1.Registers.PC = SA1.PC - SA1.PCBase;
S9xSA1PackStatus();
memcpy(buffer, &SA1, sizeof(SA1));
buffer += sizeof(SA1);
memcpy(buffer, &s7r, sizeof(s7r));
buffer += sizeof(s7r);
memcpy(buffer, &rtc_f9, sizeof(rtc_f9));
return true;
2014-10-28 02:13:05 +00:00
}
2017-01-16 22:39:57 +00:00
2014-10-29 23:23:30 +00:00
bool retro_unserialize(const void* data, size_t size)
2014-11-01 12:25:00 +00:00
{
const uint8_t* buffer = data;
if (size != retro_serialize_size())
return false;
S9xReset();
#ifndef USE_BLARGG_APU
2014-11-03 14:26:54 +00:00
uint8_t* IAPU_RAM_current = IAPU.RAM;
uint32_t IAPU_RAM_offset;
#endif
memcpy(&CPU, buffer, sizeof(CPU));
buffer += sizeof(CPU);
memcpy(&ICPU, buffer, sizeof(ICPU));
buffer += sizeof(ICPU);
memcpy(&PPU, buffer, sizeof(PPU));
buffer += sizeof(PPU);
memcpy(&DMA, buffer, sizeof(DMA));
buffer += sizeof(DMA);
memcpy(Memory.VRAM, buffer, 0x10000);
buffer += 0x10000;
memcpy(Memory.RAM, buffer, 0x20000);
buffer += 0x20000;
memcpy(Memory.SRAM, buffer, 0x20000);
buffer += 0x20000;
memcpy(Memory.FillRAM, buffer, 0x8000);
buffer += 0x8000;
#ifndef USE_BLARGG_APU
memcpy(&APU, buffer, sizeof(APU));
buffer += sizeof(APU);
memcpy(&IAPU, buffer, sizeof(IAPU));
buffer += sizeof(IAPU);
IAPU_RAM_offset = IAPU_RAM_current - IAPU.RAM;
IAPU.PC += IAPU_RAM_offset;
IAPU.DirectPage += IAPU_RAM_offset;
IAPU.WaitAddress1 += IAPU_RAM_offset;
IAPU.WaitAddress2 += IAPU_RAM_offset;
IAPU.RAM = IAPU_RAM_current;
memcpy(IAPU.RAM, buffer, 0x10000);
buffer += 0x10000;
#else
S9xAPULoadState(buffer);
buffer += SPC_SAVE_STATE_BLOCK_SIZE;
#endif
memcpy(&SA1, buffer, sizeof(SA1));
buffer += sizeof(SA1);
memcpy(&s7r, buffer, sizeof(s7r));
buffer += sizeof(s7r);
memcpy(&rtc_f9, buffer, sizeof(rtc_f9));
S9xFixSA1AfterSnapshotLoad();
FixROMSpeed();
2014-11-03 14:26:54 +00:00
IPPU.ColorsChanged = true;
IPPU.OBJChanged = true;
CPU.InDMA = false;
S9xFixColourBrightness();
S9xSA1UnpackStatus();
#ifndef USE_BLARGG_APU
S9xAPUUnpackStatus();
S9xFixSoundAfterSnapshotLoad();
#endif
ICPU.ShiftedPB = ICPU.Registers.PB << 16;
ICPU.ShiftedDB = ICPU.Registers.DB << 16;
S9xSetPCBase(ICPU.ShiftedPB + ICPU.Registers.PC);
S9xUnpackStatus();
S9xFixCycles();
S9xReschedule();
return true;
2014-10-28 02:13:05 +00:00
}
void retro_cheat_reset(void)
{
2014-12-06 20:55:19 +00:00
#ifdef WANT_CHEATS
S9xDeleteCheats();
S9xApplyCheats();
#endif
2014-10-28 02:13:05 +00:00
}
2014-12-06 20:55:19 +00:00
#ifdef WANT_CHEATS
extern SCheatData Cheat;
#endif
2014-10-29 23:23:30 +00:00
void retro_cheat_set(unsigned index, bool enabled, const char* code)
2014-10-28 02:13:05 +00:00
{
2014-12-06 20:55:19 +00:00
#ifdef WANT_CHEATS
uint32_t address;
uint8_t val;
bool sram;
uint8_t bytes[3];//used only by GoldFinger, ignored for now
if (S9xGameGenieToRaw(code, &address, &val)!=NULL &&
S9xProActionReplayToRaw(code, &address, &val)!=NULL &&
S9xGoldFingerToRaw(code, &address, &sram, &val, bytes)!=NULL)
{ // bad code, ignore
return;
}
if (index > Cheat.num_cheats)
return; // cheat added in weird order, ignore
if (index == Cheat.num_cheats)
Cheat.num_cheats++;
Cheat.c[index].address = address;
Cheat.c[index].byte = val;
Cheat.c[index].enabled = enabled;
Cheat.c[index].saved = false; // it'll be saved next time cheats run anyways
Settings.ApplyCheats=true;
S9xApplyCheats();
#endif
2014-10-28 02:13:05 +00:00
}
2014-12-05 14:54:31 +00:00
static void init_descriptors(void)
{
struct retro_input_descriptor desc[] = {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 0 },
};
environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
}
2014-10-29 23:23:30 +00:00
bool retro_load_game(const struct retro_game_info* game)
2014-10-28 02:13:05 +00:00
{
struct retro_system_av_info av_info;
if (!game)
return false;
2014-10-30 02:41:40 +00:00
CPU.Flags = 0;
init_descriptors();
check_variables();
2014-10-31 04:29:24 +00:00
2014-11-02 05:31:17 +00:00
#ifdef LOAD_FROM_MEMORY_TEST
if (!LoadROM(game))
#else
if (!LoadROM(game->path))
2014-11-02 05:31:17 +00:00
#endif
return false;
2014-10-30 02:41:40 +00:00
Settings.FrameTime = (Settings.PAL ? Settings.FrameTimePAL :
Settings.FrameTimeNTSC);
2014-10-30 02:41:40 +00:00
retro_get_system_av_info(&av_info);
#ifdef USE_BLARGG_APU
Settings.SoundPlaybackRate = av_info.timing.sample_rate;
#else
samples_per_frame = av_info.timing.sample_rate / av_info.timing.fps;
S9xSetPlaybackRate(Settings.SoundPlaybackRate);
#endif
return true;
2014-10-28 02:13:05 +00:00
}
2014-10-29 23:23:30 +00:00
bool retro_load_game_special(unsigned game_type,
const struct retro_game_info* info, size_t num_info)
2014-10-28 02:13:05 +00:00
{
return false;
}
2017-01-16 22:39:57 +00:00
2014-10-28 02:13:05 +00:00
void retro_unload_game(void)
{
}
void* retro_get_memory_data(unsigned type)
2014-10-28 02:13:05 +00:00
{
2016-08-09 18:46:23 +00:00
uint8_t* data = NULL;
switch(type)
{
case RETRO_MEMORY_SAVE_RAM:
data = Memory.SRAM;
break;
case RETRO_MEMORY_SYSTEM_RAM:
data = Memory.RAM;
break;
case RETRO_MEMORY_VIDEO_RAM:
data = Memory.VRAM;
break;
default:
break;
}
return data;
2014-10-28 02:13:05 +00:00
}
size_t retro_get_memory_size(unsigned type)
2014-10-28 02:13:05 +00:00
{
uint32_t size;
switch(type)
{
case RETRO_MEMORY_SAVE_RAM:
size = (uint32_t) (Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0);
if (size > 0x20000)
size = 0x20000;
break;
case RETRO_MEMORY_RTC:
2017-01-16 22:39:57 +00:00
size = (Settings.SRTC || Settings.SPC7110RTC) ? 20 : 0;
break;
case RETRO_MEMORY_SYSTEM_RAM:
size = 128 * 1024;
break;
case RETRO_MEMORY_VIDEO_RAM:
size = 64 * 1024;
break;
default:
size = 0;
break;
}
return size;
2014-10-28 02:13:05 +00:00
}