diff --git a/cpuexec.h b/cpuexec.h index 7e65b313..8d201d01 100644 --- a/cpuexec.h +++ b/cpuexec.h @@ -281,7 +281,7 @@ static inline void S9xCheckInterrupts (void) if (PPU.HTimerEnabled) { int32 htimepos = PPU.HTimerPosition; - if (CPU.Cycles >= Timings.H_Max) + if (CPU.Cycles >= Timings.H_Max && htimepos < CPU.PrevCycles) htimepos += Timings.H_Max; if (CPU.PrevCycles >= htimepos || CPU.Cycles < htimepos) @@ -291,7 +291,7 @@ static inline void S9xCheckInterrupts (void) if (PPU.VTimerEnabled) { int32 vcounter = CPU.V_Counter; - if (CPU.Cycles >= Timings.H_Max) + if (CPU.Cycles >= Timings.H_Max && (!PPU.HTimerEnabled || PPU.HTimerPosition < CPU.PrevCycles)) vcounter++; if (vcounter != PPU.VTimerPosition) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index 12f04ad8..90dc874d 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -21,7 +21,6 @@ #include #include - static retro_video_refresh_t s9x_video_cb = NULL; static retro_audio_sample_t s9x_audio_cb = NULL; static retro_audio_sample_batch_t s9x_audio_batch_cb = NULL; @@ -54,7 +53,8 @@ void retro_set_input_state(retro_input_state_t cb) } static retro_environment_t environ_cb; -static bool use_overscan; +static bool use_overscan = false; +static bool rom_loaded = false; void retro_set_environment(retro_environment_t cb) { environ_cb = cb; @@ -87,10 +87,10 @@ void retro_get_system_av_info(struct retro_system_av_info *info) memset(info,0,sizeof(retro_system_av_info)); info->geometry.base_width = SNES_WIDTH; - info->geometry.base_height = SNES_HEIGHT; + info->geometry.base_height = use_overscan ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT; info->geometry.max_width = MAX_SNES_WIDTH; info->geometry.max_height = MAX_SNES_HEIGHT; - info->geometry.aspect_ratio = 4.0 / 3.0; + info->geometry.aspect_ratio = 4.0f / 3.0f; info->timing.sample_rate = 32040.5; info->timing.fps = retro_get_region() == RETRO_REGION_NTSC ? 21477272.0 / 357366.0 : 21281370.0 / 425568.0; } @@ -153,19 +153,18 @@ void retro_cheat_set(unsigned, bool, const char*) bool retro_load_game(const struct retro_game_info *game) { - int loaded = 0; if(game->data == NULL && game->size == NULL && game->path != NULL) - loaded = Memory.LoadROM(game->path); + rom_loaded = Memory.LoadROM(game->path); else - loaded = Memory.LoadROMMem((const uint8_t*)game->data ,game->size); + rom_loaded = Memory.LoadROMMem((const uint8_t*)game->data ,game->size); - if (!loaded) + if (!rom_loaded) { fprintf(stderr, "[libretro]: Rom loading failed...\n"); } - return loaded; + return rom_loaded; } void retro_unload_game(void) @@ -174,53 +173,55 @@ void retro_unload_game(void) bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info) { - int loaded = 0; switch (game_type) { case RETRO_GAME_TYPE_BSX: if(num_info == 1) { - loaded = Memory.LoadROMMem((const uint8_t*)info[0].data,info[0].size); + rom_loaded = Memory.LoadROMMem((const uint8_t*)info[0].data,info[0].size); } else if(num_info == 2) { memcpy(Memory.BIOSROM,(const uint8_t*)info[0].data,info[0].size); - loaded = Memory.LoadROMMem((const uint8_t*)info[1].data,info[1].size); + rom_loaded = Memory.LoadROMMem((const uint8_t*)info[1].data,info[1].size); } - if (!loaded) + if (!rom_loaded) { fprintf(stderr, "[libretro]: BSX Rom loading failed...\n"); } - return loaded; + break; case RETRO_GAME_TYPE_BSX_SLOTTED: if(num_info == 2) - loaded = Memory.LoadMultiCartMem((const uint8_t*)info[0].data, info[0].size, + rom_loaded = Memory.LoadMultiCartMem((const uint8_t*)info[0].data, info[0].size, (const uint8_t*)info[1].data, info[1].size, NULL, NULL); - if (!loaded) + if (!rom_loaded) { fprintf(stderr, "[libretro]: Multirom loading failed...\n"); } - return loaded; + break; case RETRO_GAME_TYPE_SUFAMI_TURBO: if(num_info == 3) - loaded = Memory.LoadMultiCartMem((const uint8_t*)info[1].data, info[1].size, + rom_loaded = Memory.LoadMultiCartMem((const uint8_t*)info[1].data, info[1].size, (const uint8_t*)info[2].data, info[2].size, (const uint8_t*)info[0].data, info[0].size); - if (!loaded) + if (!rom_loaded) { fprintf(stderr, "[libretro]: Sufami Turbo Rom loading failed...\n"); } - return loaded; + break; default: - return false; + rom_loaded = false; + break; } + + return rom_loaded; } static void map_buttons(); @@ -251,16 +252,14 @@ void retro_init() Settings.InitialInfoStringTimeout = 120; Settings.HDMATimingHack = 100; Settings.BlockInvalidVRAMAccessMaster = TRUE; - Settings.StopEmulation = TRUE; Settings.WrongMovieStateProtection = TRUE; Settings.DumpStreamsMaxFrames = -1; Settings.StretchScreenshots = 0; Settings.SnapshotScreenshots = FALSE; - Settings.SkipFrames = AUTO_FRAMERATE; - Settings.TurboSkipFrames = 15; Settings.CartAName[0] = 0; Settings.CartBName[0] = 0; Settings.AutoSaveDelay = 1; + Settings.DontSaveOopsSnapshot = TRUE; CPU.Flags = 0; @@ -510,7 +509,10 @@ void* retro_get_memory_data(unsigned type) break; case RETRO_MEMORY_SYSTEM_RAM: data = Memory.RAM; - break; + break; + case RETRO_MEMORY_VIDEO_RAM: + data = Memory.VRAM; + break; default: data = NULL; break; @@ -541,9 +543,12 @@ size_t retro_get_memory_size(unsigned type) case RETRO_MEMORY_RTC: size = (Settings.SRTC || Settings.SPC7110RTC)?20:0; break; - case RETRO_MEMORY_SYSTEM_RAM: - size = 128 * 1024; - break; + case RETRO_MEMORY_SYSTEM_RAM: + size = 128 * 1024; + break; + case RETRO_MEMORY_VIDEO_RAM: + size = 64 * 1024; + break; default: size = 0; break; @@ -554,7 +559,7 @@ size_t retro_get_memory_size(unsigned type) size_t retro_serialize_size() { - return S9xFreezeSize(); + return rom_loaded ? S9xFreezeSize() : 0; } bool retro_serialize(void *data, size_t size) diff --git a/libretro/libretro.h b/libretro/libretro.h index 3a1599e1..fcd3bbc6 100644 --- a/libretro/libretro.h +++ b/libretro/libretro.h @@ -7,8 +7,14 @@ #ifdef __cplusplus extern "C" { #else +#if defined(_MSC_VER) && !defined(__cplusplus) +#define bool unsigned char +#define true 1 +#define false 0 +#else #include #endif +#endif #define RETRO_API_VERSION 1 @@ -48,7 +54,7 @@ extern "C" { #define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3 #define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4 #define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5 -#define RETRO_DEVICE_ID_LIGHTGUN_START 6 +#define RETRO_DEVICE_ID_LIGHTGUN_START 6 #define RETRO_REGION_NTSC 0 #define RETRO_REGION_PAL 1 @@ -57,6 +63,7 @@ extern "C" { #define RETRO_MEMORY_SAVE_RAM 0 #define RETRO_MEMORY_RTC 1 #define RETRO_MEMORY_SYSTEM_RAM 2 +#define RETRO_MEMORY_VIDEO_RAM 3 #define RETRO_MEMORY_SNES_BSX_RAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM) #define RETRO_MEMORY_SNES_BSX_PRAM ((2 << 8) | RETRO_MEMORY_SAVE_RAM) @@ -82,7 +89,7 @@ extern "C" { // Boolean value whether or not the implementation should use overscan, or crop away overscan. // #define RETRO_ENVIRONMENT_GET_CAN_DUPE 3 // bool * -- - // Boolean value whether or not SSNES supports frame duping, + // Boolean value whether or not RetroArch supports frame duping, // passing NULL to video frame callback. // #define RETRO_ENVIRONMENT_GET_VARIABLE 4 // struct retro_variable * -- @@ -99,20 +106,31 @@ extern "C" { // #define RETRO_ENVIRONMENT_SET_MESSAGE 6 // const struct retro_message * -- // Sets a message to be displayed in implementation-specific manner for a certain amount of 'frames'. + // Should not be used for trivial messages, which should simply be logged to stderr. struct retro_message { - const char *msg; - unsigned frames; + const char *msg; // Message to be displayed. + unsigned frames; // Duration in frames of message. }; struct retro_system_info { - const char *library_name; - const char *library_version; - const char *valid_extensions; - bool need_fullpath; - bool block_extract; + const char *library_name; // Descriptive name of library. Should not contain any version numbers, etc. + const char *library_version; // Descriptive version of core. + + const char *valid_extensions; // A string listing probably rom extensions the core will be able to load, separated with pipe. + // I.e. "bin|rom|iso". + // Typically used for a GUI to filter out extensions. + + bool need_fullpath; // If true, retro_load_game() is guaranteed to provide a valid pathname in retro_game_info::path. + // ::data and ::size are both invalid. + // If false, ::data and ::size are guaranteed to be valid, but ::path might not be valid. + // This is typically set to true for libretro implementations that must load from file. + // Implementations should strive for setting this to false, as it allows the frontend to perform patching, etc. + + bool block_extract; // If true, the frontend is not allowed to extract any archives before loading the real ROM. + // Necessary for certain libretro implementations that load games from zipped archives. }; struct retro_game_geometry @@ -152,32 +170,39 @@ struct retro_game_info { const char *path; // Path to game, UTF-8 encoded. Usually used as a reference. // May be NULL if rom was loaded from stdin or similar. - // SET_NEED_FULLPATH path guaranteed that this path is valid. - const void *data; // Memory buffer of loaded game. - // If the game is too big to load in one go. - // SET_NEED_FULLPATH should be used. - // In this case, data and size will be 0, - // and game can be loaded from path. + // retro_system_info::need_fullpath guaranteed that this path is valid. + const void *data; // Memory buffer of loaded game. Will be NULL if need_fullpath was set. size_t size; // Size of memory buffer. const char *meta; // String of implementation specific meta-data. }; +// Callbacks +// +// Environment callback. Gives implementations a way of performing uncommon tasks. Extensible. typedef bool (*retro_environment_t)(unsigned cmd, void *data); + +// Render a frame. Pixel format is 15-bit XRGB1555 native endian. +// Width and height specify dimensions of buffer. +// Pitch specifices length in bytes between two lines in buffer. typedef void (*retro_video_refresh_t)(const void *data, unsigned width, unsigned height, size_t pitch); + +// Renders a single audio frame. Should only be used if implementation generates a single sample at a time. +// Format is signed 16-bit native endian. typedef void (*retro_audio_sample_t)(int16_t left, int16_t right); +// Renders multiple audio frames in one go. One frame is defined as a sample of left and right channels, interleaved. +// I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames. +// Only one of the audio callbacks must ever be used. typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data, size_t frames); +// Polls input. typedef void (*retro_input_poll_t)(void); +// Queries for input for player 'port'. device will be masked with RETRO_DEVICE_MASK. +// Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that have been set with retro_set_controller_port_device() +// will still use the higher level RETRO_DEVICE_JOYPAD to request input. typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device, unsigned index, unsigned id); -void retro_init(void); -void retro_deinit(void); - -unsigned retro_api_version(void); - -void retro_get_system_info(struct retro_system_info *info); -void retro_get_system_av_info(struct retro_system_av_info *info); - +// Sets callbacks. retro_set_environment() is guaranteed to be called before retro_init(). +// The rest of the set_* functions are guaranteed to have been called before the first call to retro_run() is made. void retro_set_environment(retro_environment_t); void retro_set_video_refresh(retro_video_refresh_t); void retro_set_audio_sample(retro_audio_sample_t); @@ -185,29 +210,63 @@ void retro_set_audio_sample_batch(retro_audio_sample_batch_t); void retro_set_input_poll(retro_input_poll_t); void retro_set_input_state(retro_input_state_t); +// Library global initialization/deinitialization. +void retro_init(void); +void retro_deinit(void); + +// Must return RETRO_API_VERSION. Used to validate ABI compatibility when the API is revised. +unsigned retro_api_version(void); + +// Gets statically known system info. Pointers provided in *info must be statically allocated. +// Can be called at any time, even before retro_init(). +void retro_get_system_info(struct retro_system_info *info); + +// Gets information about system audio/video timings and geometry. +// Can be called only after retro_load_game() has successfully completed. +void retro_get_system_av_info(struct retro_system_av_info *info); + +// Sets device to be used for player 'port'. void retro_set_controller_port_device(unsigned port, unsigned device); +// Resets the current game. void retro_reset(void); + +// Runs the game for one video frame. +// During retro_run(), input_poll callback must be called at least once. +// +// If a frame is not rendered for reasons where a game "dropped" a frame, +// this still counts as a frame, and retro_run() should explicitly dupe a frame if GET_CAN_DUPE returns true. +// In this case, the video callback can take a NULL argument for data. void retro_run(void); +// Returns the amount of data the implementation requires to serialize internal state (save states). +// Beetween calls to retro_load_game() and retro_unload_game(), the returned size is never allowed to be larger than a previous returned value, to +// ensure that the frontend can allocate a save state buffer once. size_t retro_serialize_size(void); + +// Serializes internal state. If failed, or size is lower than retro_serialize_size(), it should return false, true otherwise. bool retro_serialize(void *data, size_t size); bool retro_unserialize(const void *data, size_t size); void retro_cheat_reset(void); void retro_cheat_set(unsigned index, bool enabled, const char *code); +// Loads a game. bool retro_load_game(const struct retro_game_info *game); +// Loads a "special" kind of game. Should not be used except in extreme cases. bool retro_load_game_special( unsigned game_type, const struct retro_game_info *info, size_t num_info ); +// Unloads a currently loaded game. void retro_unload_game(void); +// Gets region of game. unsigned retro_get_region(void); +// Gets region of memory. void *retro_get_memory_data(unsigned id); size_t retro_get_memory_size(unsigned id); diff --git a/ppu.cpp b/ppu.cpp index 0907021b..59d11f25 100644 --- a/ppu.cpp +++ b/ppu.cpp @@ -1498,6 +1498,11 @@ void S9xSetCPU (uint8 Byte, uint16 Address) Timings.NMITriggerPos = CPU.Cycles + 6 + 6; } + #ifdef DEBUGGER + S9xTraceFormattedMessage("--- IRQ Timer Enable HTimer:%d Pos:%04d VTimer:%d Pos:%03d", + PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition); + #endif + break; case 0x4201: // WRIO diff --git a/snapshot.cpp b/snapshot.cpp index 282198f5..b816fd43 100644 --- a/snapshot.cpp +++ b/snapshot.cpp @@ -1171,7 +1171,6 @@ void S9xResetSaveTimer (bool8 dontsave) uint32 S9xFreezeSize() { - if(Settings.StopEmulation) return 0; nulStream stream; S9xFreezeToStream(&stream); return stream.size(); diff --git a/win32/CGLCG.cpp b/win32/CGLCG.cpp index 0d75a999..182314d2 100644 --- a/win32/CGLCG.cpp +++ b/win32/CGLCG.cpp @@ -776,7 +776,7 @@ bool CGLCG::loadPngImage(const TCHAR *name, int &outWidth, int &outHeight, bool info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); - png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return false; } @@ -792,7 +792,7 @@ bool CGLCG::loadPngImage(const TCHAR *name, int &outWidth, int &outHeight, bool if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated * with the png_ptr and info_ptr */ - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); /* If we get here, we had a * problem reading the file */ @@ -826,11 +826,11 @@ bool CGLCG::loadPngImage(const TCHAR *name, int &outWidth, int &outHeight, bool * PNG_TRANSFORM_EXPAND forces to * expand a palette into RGB */ - png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, png_voidp_NULL); + png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, (png_voidp)NULL); - outWidth = info_ptr->width; - outHeight = info_ptr->height; - switch (info_ptr->color_type) { + outWidth = png_get_image_width(png_ptr, info_ptr); + outHeight = png_get_image_height(png_ptr, info_ptr); + switch (png_get_color_type(png_ptr, info_ptr)) { case PNG_COLOR_TYPE_RGBA: outHasAlpha = true; break; @@ -853,7 +853,7 @@ bool CGLCG::loadPngImage(const TCHAR *name, int &outWidth, int &outHeight, bool /* Clean up after the read, * and free any memory allocated */ - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* Close the file */ fclose(fp); diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index cb8c8883..510c5914 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -5041,7 +5041,7 @@ INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPar unsigned int newRewindBufSize = SendDlgItemMessage(hDlg, IDC_REWIND_BUFFER_SPIN, UDM_GETPOS, 0,0); if(GUI.rewindBufferSize != newRewindBufSize) { GUI.rewindBufferSize = newRewindBufSize; - stateMan.init(GUI.rewindBufferSize * 1024 * 1024); + if(!Settings.StopEmulation) stateMan.init(GUI.rewindBufferSize * 1024 * 1024); } WinSaveConfigFile();