diff --git a/Makefile.gc b/Makefile.gc index d3a870b..fffb6ef 100644 --- a/Makefile.gc +++ b/Makefile.gc @@ -106,7 +106,7 @@ export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) $(BUILD): @[ -d $@ ] || mkdir -p $@ @[ -d $(TARGETDIR) ] || mkdir -p $(TARGETDIR) - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.gc + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.gc #--------------------------------------------------------------------------------- clean: diff --git a/Makefile.wii b/Makefile.wii index 4e0d79a..a5ec54d 100644 --- a/Makefile.wii +++ b/Makefile.wii @@ -106,7 +106,7 @@ export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) $(BUILD): @[ -d $@ ] || mkdir -p $@ @[ -d $(TARGETDIR) ] || mkdir -p $(TARGETDIR) - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.wii + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.wii #--------------------------------------------------------------------------------- clean: diff --git a/Makefile.xenon b/Makefile.xenon index f97ab71..d691ea5 100644 --- a/Makefile.xenon +++ b/Makefile.xenon @@ -108,7 +108,7 @@ export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) $(BUILD): @[ -d $@ ] || mkdir -p $@ @[ -d $(TARGETDIR) ] || mkdir -p $(TARGETDIR) - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.xenon + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.xenon #--------------------------------------------------------------------------------- clean: diff --git a/source/filebrowser.cpp b/source/filebrowser.cpp index 88b2a08..9a36420 100644 --- a/source/filebrowser.cpp +++ b/source/filebrowser.cpp @@ -509,6 +509,7 @@ int BrowserLoadFile() // store the filename (w/o ext) - used for sram/freeze naming StripExt(Memory.ROMFilename, browserList[browser.selIndex].filename); snprintf(GCSettings.LastFileLoaded, MAXPATHLEN, "%s", browserList[browser.selIndex].filename); + strncpy(Memory.ROMFilePath, browser.dir, PATH_MAX); SNESROMSize = 0; S9xDeleteCheats(); diff --git a/source/preferences.cpp b/source/preferences.cpp index 6639b4d..785c1f7 100644 --- a/source/preferences.cpp +++ b/source/preferences.cpp @@ -472,8 +472,8 @@ DefaultSettings () Settings.SixteenBitSound = true; Settings.Stereo = true; Settings.ReverseStereo = true; - Settings.SoundPlaybackRate = 32000; - Settings.SoundInputRate = 31953; + Settings.SoundPlaybackRate = 32040; + Settings.SoundInputRate = 32040; // Graphics Settings.Transparency = true; diff --git a/source/snes9x/apu/apu.cpp b/source/snes9x/apu/apu.cpp index f0fd8f9..d9b07f6 100644 --- a/source/snes9x/apu/apu.cpp +++ b/source/snes9x/apu/apu.cpp @@ -145,6 +145,9 @@ (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2011 zones + MSU-1 code + (c) Copyright 2016 qwertymodo + Specific ports contains the works of other authors. See headers in individual files. @@ -179,12 +182,13 @@ #include #include "snes9x.h" #include "apu.h" +#include "msu1.h" #include "snapshot.h" #include "display.h" #include "linear_resampler.h" #include "hermite_resampler.h" -#define APU_DEFAULT_INPUT_RATE 32000 +#define APU_DEFAULT_INPUT_RATE 32040 #define APU_MINIMUM_SAMPLE_COUNT 512 #define APU_MINIMUM_SAMPLE_BLOCK 128 #define APU_NUMERATOR_NTSC 15664 @@ -234,6 +238,15 @@ namespace spc static uint32 ratio_numerator = APU_NUMERATOR_NTSC; static uint32 ratio_denominator = APU_DENOMINATOR_NTSC; } + +namespace msu +{ + static int buffer_size; + static uint8 *landing_buffer = NULL; + static Resampler *resampler = NULL; + static int resample_buffer_size = -1; + static uint8 *resample_buffer = NULL; +} static void EightBitize (uint8 *, int); static void DeStereo (uint8 *, int); @@ -303,11 +316,19 @@ bool8 S9xMixSamples (uint8 *buffer, int sample_count) } else dest = buffer; + + if (Settings.MSU1 && msu::resample_buffer_size < (sample_count << 3)) + { + delete[] msu::resample_buffer; + msu::resample_buffer = new uint8[sample_count << 3]; + msu::resample_buffer_size = sample_count << 3; + } if (Settings.Mute) { memset(dest, 0, sample_count << 1); spc::resampler->clear(); + msu::resampler->clear(); return (FALSE); } @@ -318,6 +339,18 @@ bool8 S9xMixSamples (uint8 *buffer, int sample_count) spc::resampler->read((short *) dest, sample_count); if (spc::lag == spc::lag_master) spc::lag = 0; + + if (Settings.MSU1) + { + if (msu::resampler->avail() >= sample_count) + { + msu::resampler->read((short *)msu::resample_buffer, sample_count); + for (int32 i = 0; i < sample_count; ++i) + *((int16*)(dest+(i * 2))) += *((int16*)(msu::resample_buffer+(i * 2))); + } + else // should never occur + assert(0); + } } else { @@ -356,8 +389,12 @@ int S9xGetSampleCount (void) void S9xFinalizeSamples (void) { + bool drop_current_msu1_samples = TRUE; + if (!Settings.Mute) { + drop_current_msu1_samples = FALSE; + if (!spc::resampler->push((short *) spc::landing_buffer, spc_core->sample_count())) { /* We weren't able to process the entire buffer. Potential overrun. */ @@ -365,6 +402,24 @@ void S9xFinalizeSamples (void) if (Settings.SoundSync && !Settings.TurboMode) return; + + // since we drop the current dsp samples we also want to drop generated msu1 samples + drop_current_msu1_samples = TRUE; + } + } + + // only generate msu1 if we really consumed the dsp samples (sample_count() resets at end of function), + // otherwise we will generate multiple times for the same samples - so this needs to be after all early + // function returns + if (Settings.MSU1) + { + // generate the same number of msu1 samples as dsp samples were generated + S9xMSU1SetOutput((int16 *)msu::landing_buffer, msu::buffer_size); + S9xMSU1Generate(spc_core->sample_count()); + if (!drop_current_msu1_samples && !msu::resampler->push((short *)msu::landing_buffer, S9xMSU1Samples())) + { + // should not occur, msu buffer is larger and we drop msu samples if spc buffer overruns + assert(0); } } @@ -390,6 +445,8 @@ void S9xLandSamples (void) void S9xClearSamples (void) { spc::resampler->clear(); + if (Settings.MSU1) + msu::resampler->clear(); spc::lag = spc::lag_master; } @@ -416,6 +473,9 @@ void UpdatePlaybackRate (void) double time_ratio = (double) Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator); spc::resampler->time_ratio(time_ratio); + + time_ratio = (44100.0 / Settings.SoundPlaybackRate) * (Settings.SoundInputRate / 32040.0); + msu::resampler->time_ratio(time_ratio); } bool8 S9xInitSound (int buffer_ms, int lag_ms) @@ -423,8 +483,8 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms) // buffer_ms : buffer size given in millisecond // lag_ms : allowable time-lag given in millisecond - int sample_count = buffer_ms * 32000 / 1000; - int lag_sample_count = lag_ms * 32000 / 1000; + int sample_count = buffer_ms * 32040 / 1000; + int lag_sample_count = lag_ms * 32040 / 1000; spc::lag_master = lag_sample_count; if (Settings.Stereo) @@ -439,6 +499,7 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms) spc::buffer_size <<= 1; if (Settings.SixteenBitSound) spc::buffer_size <<= 1; + msu::buffer_size = sample_count << 3; // Always 16-bit, Stereo; x2 to never overflow before dsp buffer printf("Sound buffer size: %d (%d samples)\n", spc::buffer_size, sample_count); @@ -447,6 +508,11 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms) spc::landing_buffer = new uint8[spc::buffer_size * 2]; if (!spc::landing_buffer) return (FALSE); + if (msu::landing_buffer) + delete[] msu::landing_buffer; + msu::landing_buffer = new uint8[msu::buffer_size * 2]; + if (!msu::landing_buffer) + return (FALSE); /* The resampler and spc unit use samples (16-bit short) as arguments. Use 2x in the resampler for buffer leveling with SoundSync */ @@ -461,6 +527,19 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms) } else spc::resampler->resize(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); + + + if (!msu::resampler) + { + msu::resampler = new APU_DEFAULT_RESAMPLER(msu::buffer_size >> (Settings.SoundSync ? 0 : 1)); + if (!msu::resampler) + { + delete[] msu::landing_buffer; + return (FALSE); + } + } + else + msu::resampler->resize(msu::buffer_size); spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); @@ -508,6 +587,7 @@ bool8 S9xInitAPU (void) spc::landing_buffer = NULL; spc::shrink_buffer = NULL; spc::resampler = NULL; + msu::resampler = NULL; return (TRUE); } @@ -537,6 +617,24 @@ void S9xDeinitAPU (void) delete[] spc::shrink_buffer; spc::shrink_buffer = NULL; } + + if (msu::resampler) + { + delete msu::resampler; + msu::resampler = NULL; + } + + if (msu::landing_buffer) + { + delete[] msu::landing_buffer; + msu::landing_buffer = NULL; + } + + if (msu::resample_buffer) + { + delete[] msu::resample_buffer; + msu::resample_buffer = NULL; + } } static inline int S9xAPUGetClock (int32 cpucycles) @@ -612,6 +710,7 @@ void S9xResetAPU (void) spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); spc::resampler->clear(); + msu::resampler->clear(); } void S9xSoftResetAPU (void) @@ -622,6 +721,7 @@ void S9xSoftResetAPU (void) spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); spc::resampler->clear(); + msu::resampler->clear(); } static void from_apu_to_state (uint8 **buf, void *var, size_t size) diff --git a/source/snes9x/apu/bapu/dsp/blargg_common.h b/source/snes9x/apu/bapu/dsp/blargg_common.h new file mode 100644 index 0000000..75edff3 --- /dev/null +++ b/source/snes9x/apu/bapu/dsp/blargg_common.h @@ -0,0 +1,186 @@ +// Sets up common environment for Shay Green's libraries. +// To change configuration options, modify blargg_config.h, not this file. + +// snes_spc 0.9.0 +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +#include +#include +#include +#include + +#undef BLARGG_COMMON_H +// allow blargg_config.h to #include blargg_common.h +#include "blargg_config.h" +#ifndef BLARGG_COMMON_H +#define BLARGG_COMMON_H + +// BLARGG_RESTRICT: equivalent to restrict, where supported +#if defined (__GNUC__) || _MSC_VER >= 1100 + #define BLARGG_RESTRICT __restrict +#else + #define BLARGG_RESTRICT +#endif + +// STATIC_CAST(T,expr): Used in place of static_cast (expr) +#ifndef STATIC_CAST + #define STATIC_CAST(T,expr) ((T) (expr)) +#endif + +// blargg_err_t (0 on success, otherwise error string) +#ifndef blargg_err_t + typedef const char* blargg_err_t; +#endif + +// blargg_vector - very lightweight vector of POD types (no constructor/destructor) +template +class blargg_vector { + T* begin_; + size_t size_; +public: + blargg_vector() : begin_( 0 ), size_( 0 ) { } + ~blargg_vector() { free( begin_ ); } + size_t size() const { return size_; } + T* begin() const { return begin_; } + T* end() const { return begin_ + size_; } + blargg_err_t resize( size_t n ) + { + // TODO: blargg_common.cpp to hold this as an outline function, ugh + void* p = realloc( begin_, n * sizeof (T) ); + if ( p ) + begin_ = (T*) p; + else if ( n > size_ ) // realloc failure only a problem if expanding + return "Out of memory"; + size_ = n; + return 0; + } + void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); } + T& operator [] ( size_t n ) const + { + assert( n <= size_ ); // <= to allow past-the-end value + return begin_ [n]; + } +}; + +#ifndef BLARGG_DISABLE_NOTHROW + // throw spec mandatory in ISO C++ if operator new can return NULL + #if __cplusplus >= 199711 || defined (__GNUC__) + #define BLARGG_THROWS( spec ) throw spec + #else + #define BLARGG_THROWS( spec ) + #endif + #define BLARGG_DISABLE_NOTHROW \ + void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\ + void operator delete ( void* p ) { free( p ); } + #define BLARGG_NEW new +#else + #include + #define BLARGG_NEW new (std::nothrow) +#endif + +// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant) +#define BLARGG_4CHAR( a, b, c, d ) \ + ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF)) + +// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0. +#ifndef BOOST_STATIC_ASSERT + #ifdef _MSC_VER + // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified + #define BOOST_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] ) + #else + // Some other compilers fail when declaring same function multiple times in class, + // so differentiate them by line + #define BOOST_STATIC_ASSERT( expr ) \ + void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] ) + #endif +#endif + +// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1, +// compiler is assumed to support bool. If undefined, availability is determined. +#ifndef BLARGG_COMPILER_HAS_BOOL + #if defined (__MWERKS__) + #if !__option(bool) + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif + #elif defined (_MSC_VER) + #if _MSC_VER < 1100 + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif + #elif defined (__GNUC__) + // supports bool + #elif __cplusplus < 199711 + #define BLARGG_COMPILER_HAS_BOOL 0 + #endif +#endif +#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL + // If you get errors here, modify your blargg_config.h file + typedef int bool; + const bool true = 1; + const bool false = 0; +#endif + +// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough + +#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF + typedef long blargg_long; +#else + typedef int blargg_long; +#endif + +#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF + typedef unsigned long blargg_ulong; +#else + typedef unsigned blargg_ulong; +#endif + +// BOOST::int8_t etc. + +// HAVE_STDINT_H: If defined, use for int8_t etc. +#if defined (HAVE_STDINT_H) + #include + #define BOOST + +// HAVE_INTTYPES_H: If defined, use for int8_t etc. +#elif defined (HAVE_INTTYPES_H) + #include + #define BOOST + +#else + struct BOOST + { + #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F + typedef signed char int8_t; + typedef unsigned char uint8_t; + #else + // No suitable 8-bit type available + typedef struct see_blargg_common_h int8_t; + typedef struct see_blargg_common_h uint8_t; + #endif + + #if USHRT_MAX == 0xFFFF + typedef short int16_t; + typedef unsigned short uint16_t; + #else + // No suitable 16-bit type available + typedef struct see_blargg_common_h int16_t; + typedef struct see_blargg_common_h uint16_t; + #endif + + #if ULONG_MAX == 0xFFFFFFFF + typedef long int32_t; + typedef unsigned long uint32_t; + #elif UINT_MAX == 0xFFFFFFFF + typedef int int32_t; + typedef unsigned int uint32_t; + #else + // No suitable 32-bit type available + typedef struct see_blargg_common_h int32_t; + typedef struct see_blargg_common_h uint32_t; + #endif + }; +#endif + +#endif +#endif diff --git a/source/snes9x/apu/bapu/dsp/blargg_config.h b/source/snes9x/apu/bapu/dsp/blargg_config.h new file mode 100644 index 0000000..d85d266 --- /dev/null +++ b/source/snes9x/apu/bapu/dsp/blargg_config.h @@ -0,0 +1,24 @@ +// snes_spc 0.9.0 user configuration file. Don't replace when updating library. + +// snes_spc 0.9.0 +#ifndef BLARGG_CONFIG_H +#define BLARGG_CONFIG_H + +// Uncomment to disable debugging checks +#define NDEBUG 1 + +// Uncomment to enable platform-specific (and possibly non-portable) optimizations +//#define BLARGG_NONPORTABLE 1 + +// Uncomment if automatic byte-order determination doesn't work +//#define BLARGG_BIG_ENDIAN 1 + +// Uncomment if you get errors in the bool section of blargg_common.h +//#define BLARGG_COMPILER_HAS_BOOL 1 + +// Use standard config.h if present +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#endif diff --git a/source/snes9x/apu/bapu/dsp/blargg_endian.h b/source/snes9x/apu/bapu/dsp/blargg_endian.h new file mode 100644 index 0000000..f2daca6 --- /dev/null +++ b/source/snes9x/apu/bapu/dsp/blargg_endian.h @@ -0,0 +1,185 @@ +// CPU Byte Order Utilities + +// snes_spc 0.9.0 +#ifndef BLARGG_ENDIAN +#define BLARGG_ENDIAN + +#include "blargg_common.h" + +// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16) +#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \ + defined (__x86_64__) || defined (__ia64__) || defined (__i386__) + #define BLARGG_CPU_X86 1 + #define BLARGG_CPU_CISC 1 +#endif + +#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc) + #define BLARGG_CPU_POWERPC 1 + #define BLARGG_CPU_RISC 1 +#endif + +// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only +// one may be #defined to 1. Only needed if something actually depends on byte order. +#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN) +#ifdef __GLIBC__ + // GCC handles this for us + #include + #if __BYTE_ORDER == __LITTLE_ENDIAN + #define BLARGG_LITTLE_ENDIAN 1 + #elif __BYTE_ORDER == __BIG_ENDIAN + #define BLARGG_BIG_ENDIAN 1 + #endif +#else + +#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \ + (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234) + #define BLARGG_LITTLE_ENDIAN 1 +#endif + +#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \ + defined (__sparc__) || BLARGG_CPU_POWERPC || \ + (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321) + #define BLARGG_BIG_ENDIAN 1 +#elif !defined (__mips__) + // No endian specified; assume little-endian, since it's most common + #define BLARGG_LITTLE_ENDIAN 1 +#endif +#endif +#endif + +#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN + #undef BLARGG_LITTLE_ENDIAN + #undef BLARGG_BIG_ENDIAN +#endif + +inline void blargg_verify_byte_order() +{ + #ifndef NDEBUG + #if BLARGG_BIG_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i == 0 ); + #elif BLARGG_LITTLE_ENDIAN + volatile int i = 1; + assert( *(volatile char*) &i != 0 ); + #endif + #endif +} + +inline unsigned get_le16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [1] << 8 | + (unsigned) ((unsigned char const*) p) [0]; +} + +inline unsigned get_be16( void const* p ) +{ + return (unsigned) ((unsigned char const*) p) [0] << 8 | + (unsigned) ((unsigned char const*) p) [1]; +} + +inline blargg_ulong get_le32( void const* p ) +{ + return (blargg_ulong) ((unsigned char const*) p) [3] << 24 | + (blargg_ulong) ((unsigned char const*) p) [2] << 16 | + (blargg_ulong) ((unsigned char const*) p) [1] << 8 | + (blargg_ulong) ((unsigned char const*) p) [0]; +} + +inline blargg_ulong get_be32( void const* p ) +{ + return (blargg_ulong) ((unsigned char const*) p) [0] << 24 | + (blargg_ulong) ((unsigned char const*) p) [1] << 16 | + (blargg_ulong) ((unsigned char const*) p) [2] << 8 | + (blargg_ulong) ((unsigned char const*) p) [3]; +} + +inline void set_le16( void* p, unsigned n ) +{ + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [0] = (unsigned char) n; +} + +inline void set_be16( void* p, unsigned n ) +{ + ((unsigned char*) p) [0] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) n; +} + +inline void set_le32( void* p, blargg_ulong n ) +{ + ((unsigned char*) p) [0] = (unsigned char) n; + ((unsigned char*) p) [1] = (unsigned char) (n >> 8); + ((unsigned char*) p) [2] = (unsigned char) (n >> 16); + ((unsigned char*) p) [3] = (unsigned char) (n >> 24); +} + +inline void set_be32( void* p, blargg_ulong n ) +{ + ((unsigned char*) p) [3] = (unsigned char) n; + ((unsigned char*) p) [2] = (unsigned char) (n >> 8); + ((unsigned char*) p) [1] = (unsigned char) (n >> 16); + ((unsigned char*) p) [0] = (unsigned char) (n >> 24); +} + +#if BLARGG_NONPORTABLE + // Optimized implementation if byte order is known + #if BLARGG_LITTLE_ENDIAN + #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr)) + #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr)) + #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + #elif BLARGG_BIG_ENDIAN + #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr)) + #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr)) + #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data)) + #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data)) + + #if BLARGG_CPU_POWERPC + // PowerPC has special byte-reversed instructions + #if defined (__MWERKS__) + #define GET_LE16( addr ) (__lhbrx( addr, 0 )) + #define GET_LE32( addr ) (__lwbrx( addr, 0 )) + #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 )) + #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 )) + #elif defined (__GNUC__) + #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;}) + #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;}) + #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );}) + #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );}) + #endif + #endif + #endif +#endif + +#ifndef GET_LE16 + #define GET_LE16( addr ) get_le16( addr ) + #define SET_LE16( addr, data ) set_le16( addr, data ) +#endif + +#ifndef GET_LE32 + #define GET_LE32( addr ) get_le32( addr ) + #define SET_LE32( addr, data ) set_le32( addr, data ) +#endif + +#ifndef GET_BE16 + #define GET_BE16( addr ) get_be16( addr ) + #define SET_BE16( addr, data ) set_be16( addr, data ) +#endif + +#ifndef GET_BE32 + #define GET_BE32( addr ) get_be32( addr ) + #define SET_BE32( addr, data ) set_be32( addr, data ) +#endif + +// auto-selecting versions + +inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); } +inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); } +inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); } +inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); } +inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); } +inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); } +inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); } +inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); } + +#endif diff --git a/source/snes9x/cpu.cpp b/source/snes9x/cpu.cpp index f2efb4c..3eeede1 100644 --- a/source/snes9x/cpu.cpp +++ b/source/snes9x/cpu.cpp @@ -282,6 +282,7 @@ void S9xReset (void) S9xResetPPU(); S9xResetDMA(); S9xResetAPU(); + S9xResetMSU(); if (Settings.DSP) S9xResetDSP(); @@ -299,6 +300,8 @@ void S9xReset (void) S9xResetOBC1(); if (Settings.SRTC) S9xResetSRTC(); + if (Settings.MSU1) + S9xMSU1Init(); S9xInitCheatData(); } @@ -316,6 +319,7 @@ void S9xSoftReset (void) S9xSoftResetPPU(); S9xResetDMA(); S9xSoftResetAPU(); + S9xResetMSU(); if (Settings.DSP) S9xResetDSP(); @@ -333,6 +337,8 @@ void S9xSoftReset (void) S9xResetOBC1(); if (Settings.SRTC) S9xResetSRTC(); + if (Settings.MSU1) + S9xMSU1Init(); S9xInitCheatData(); } diff --git a/source/snes9x/getset.h b/source/snes9x/getset.h index bf5557b..14fef5e 100644 --- a/source/snes9x/getset.h +++ b/source/snes9x/getset.h @@ -186,6 +186,7 @@ #include "obc1.h" #include "seta.h" #include "bsx.h" +#include "msu1.h" #if (S9X_ACCURACY_LEVEL >= 2) diff --git a/source/snes9x/globals.cpp b/source/snes9x/globals.cpp index 60d7959..54312dc 100644 --- a/source/snes9x/globals.cpp +++ b/source/snes9x/globals.cpp @@ -219,6 +219,7 @@ struct SSPC7110Snapshot s7snap; struct SSRTCSnapshot srtcsnap; struct SRTCData RTCData; struct SBSX BSX; +struct SMSU1 MSU1; struct SMulti Multi; struct SSettings Settings; struct SSNESGameFixes SNESGameFixes; diff --git a/source/snes9x/memmap.h b/source/snes9x/memmap.h index 153ae17..e34c854 100644 --- a/source/snes9x/memmap.h +++ b/source/snes9x/memmap.h @@ -245,6 +245,7 @@ struct CMemory uint8 ExtendedFormat; char ROMFilename[PATH_MAX + 1]; + char ROMFilePath[PATH_MAX + 1]; char ROMName[ROM_NAME_LEN]; char RawROMName[ROM_NAME_LEN]; char ROMId[5]; diff --git a/source/snes9x/ppu.cpp b/source/snes9x/ppu.cpp index 898c6f4..b28ed8d 100644 --- a/source/snes9x/ppu.cpp +++ b/source/snes9x/ppu.cpp @@ -495,6 +495,9 @@ void S9xSetPPU (uint8 Byte, uint16 Address) S9xTraceFormattedMessage("--- HDMA PPU %04X -> %02X", Address, Byte); #endif + if (Settings.MSU1 && (Address & 0xfff8) == 0x2000) // MSU-1 + S9xMSU1WritePort(Address & 7, Byte); + else if ((Address & 0xffc0) == 0x2140) // APUIO0, APUIO1, APUIO2, APUIO3 // write_port will run the APU until given clock before writing value S9xAPUWritePort(Address & 3, Byte); @@ -1257,6 +1260,9 @@ uint8 S9xGetPPU (uint16 Address) { // MAP_PPU: $2000-$3FFF + if (Settings.MSU1 && (Address & 0xfff8) == 0x2000) + return (S9xMSU1ReadPort(Address & 7)); + if (Address < 0x2100) return (OpenBus); diff --git a/source/snes9x/snapshot.cpp b/source/snes9x/snapshot.cpp index 13934f0..cf1a819 100644 --- a/source/snes9x/snapshot.cpp +++ b/source/snes9x/snapshot.cpp @@ -144,6 +144,9 @@ (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2010 zones + MSU-1 code + (c) Copyright 2016 qwertymodo + Specific ports contains the works of other authors. See headers in individual files. @@ -1105,6 +1108,23 @@ static FreezeData SnapBSX[] = ARRAY_ENTRY(6, test2192, 32, uint8_ARRAY_V) }; +#undef STRUCT +#define STRUCT struct SMSU1 + +static FreezeData SnapMSU1[] = +{ + INT_ENTRY(7, MSU1_STATUS), + INT_ENTRY(7, MSU1_DATA_SEEK), + INT_ENTRY(7, MSU1_DATA_POS), + INT_ENTRY(7, MSU1_TRACK_SEEK), + INT_ENTRY(7, MSU1_CURRENT_TRACK), + INT_ENTRY(7, MSU1_RESUME_TRACK), + INT_ENTRY(7, MSU1_VOLUME), + INT_ENTRY(7, MSU1_CONTROL), + INT_ENTRY(7, MSU1_AUDIO_POS), + INT_ENTRY(7, MSU1_RESUME_POS) +}; + #undef STRUCT #define STRUCT struct SnapshotScreenshotInfo @@ -1341,6 +1361,9 @@ void S9xFreezeToStream (STREAM stream) if (Settings.BS) FreezeStruct(stream, "BSX", &BSX, SnapBSX, COUNT(SnapBSX)); + if (Settings.MSU1) + FreezeStruct(stream, "MSU", &MSU1, SnapMSU1, COUNT(SnapMSU1)); + if (Settings.SnapshotScreenshots) { SnapshotScreenshotInfo *ssi = new SnapshotScreenshotInfo; @@ -1441,6 +1464,7 @@ int S9xUnfreezeFromStream (STREAM stream) uint8 *local_srtc = NULL; uint8 *local_rtc_data = NULL; uint8 *local_bsx_data = NULL; + uint8 *local_msu1_data = NULL; uint8 *local_screenshot = NULL; uint8 *local_movie_data = NULL; @@ -1546,6 +1570,10 @@ int S9xUnfreezeFromStream (STREAM stream) if (result != SUCCESS && Settings.BS) break; + result = UnfreezeStructCopy(stream, "MSU", &local_msu1_data, SnapMSU1, COUNT(SnapMSU1), version); + if (result != SUCCESS && Settings.MSU1) + break; + result = UnfreezeStructCopy(stream, "SHO", &local_screenshot, SnapScreenshot, COUNT(SnapScreenshot), version); SnapshotMovieInfo mi; @@ -1660,6 +1688,9 @@ int S9xUnfreezeFromStream (STREAM stream) if (local_bsx_data) UnfreezeStructFromCopy(&BSX, SnapBSX, COUNT(SnapBSX), local_bsx_data, version); + if (local_msu1_data) + UnfreezeStructFromCopy(&MSU1, SnapMSU1, COUNT(SnapMSU1), local_msu1_data, version); + CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG | SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG); ICPU.ShiftedPB = Registers.PB << 16; ICPU.ShiftedDB = Registers.DB << 16; @@ -1707,6 +1738,9 @@ int S9xUnfreezeFromStream (STREAM stream) if (local_bsx_data) S9xBSXPostLoadState(); + if (local_msu1_data) + S9xMSU1PostLoadState(); + if (local_movie_data) { // restore last displayed pad_read status diff --git a/source/snes9x/snapshot.h b/source/snes9x/snapshot.h index b3ead24..b03408d 100644 --- a/source/snes9x/snapshot.h +++ b/source/snes9x/snapshot.h @@ -144,6 +144,9 @@ (c) Copyright 1998 - 2001 John Stiles (c) Copyright 2001 - 2010 zones + MSU-1 code + (c) Copyright 2016 qwertymodo + Specific ports contains the works of other authors. See headers in individual files. @@ -179,7 +182,7 @@ #define _SNAPSHOT_H_ #define SNAPSHOT_MAGIC "#!s9xsnp" -#define SNAPSHOT_VERSION 6 +#define SNAPSHOT_VERSION 7 #define SUCCESS 1 #define WRONG_FORMAT (-1) diff --git a/source/snes9x/snes9x.h b/source/snes9x/snes9x.h index f2e5ca9..dcb75e6 100644 --- a/source/snes9x/snes9x.h +++ b/source/snes9x/snes9x.h @@ -359,6 +359,7 @@ struct SSettings bool8 BS; bool8 BSXItself; bool8 BSXBootup; + bool8 MSU1; bool8 MouseMaster; bool8 SuperScopeMaster; bool8 JustifierMaster;