Merge pull request #710 from bladeoner/msu1

Add MSU1 audio support by qwertymodo
This commit is contained in:
dborth 2018-01-17 20:55:42 -07:00 committed by GitHub
commit ecfc899496
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 558 additions and 9 deletions

View File

@ -106,7 +106,7 @@ export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET)
$(BUILD): $(BUILD):
@[ -d $@ ] || mkdir -p $@ @[ -d $@ ] || mkdir -p $@
@[ -d $(TARGETDIR) ] || mkdir -p $(TARGETDIR) @[ -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: clean:

View File

@ -106,7 +106,7 @@ export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET)
$(BUILD): $(BUILD):
@[ -d $@ ] || mkdir -p $@ @[ -d $@ ] || mkdir -p $@
@[ -d $(TARGETDIR) ] || mkdir -p $(TARGETDIR) @[ -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: clean:

View File

@ -108,7 +108,7 @@ export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET)
$(BUILD): $(BUILD):
@[ -d $@ ] || mkdir -p $@ @[ -d $@ ] || mkdir -p $@
@[ -d $(TARGETDIR) ] || mkdir -p $(TARGETDIR) @[ -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: clean:

View File

@ -509,6 +509,7 @@ int BrowserLoadFile()
// store the filename (w/o ext) - used for sram/freeze naming // store the filename (w/o ext) - used for sram/freeze naming
StripExt(Memory.ROMFilename, browserList[browser.selIndex].filename); StripExt(Memory.ROMFilename, browserList[browser.selIndex].filename);
snprintf(GCSettings.LastFileLoaded, MAXPATHLEN, "%s", browserList[browser.selIndex].filename); snprintf(GCSettings.LastFileLoaded, MAXPATHLEN, "%s", browserList[browser.selIndex].filename);
strncpy(Memory.ROMFilePath, browser.dir, PATH_MAX);
SNESROMSize = 0; SNESROMSize = 0;
S9xDeleteCheats(); S9xDeleteCheats();

View File

@ -472,8 +472,8 @@ DefaultSettings ()
Settings.SixteenBitSound = true; Settings.SixteenBitSound = true;
Settings.Stereo = true; Settings.Stereo = true;
Settings.ReverseStereo = true; Settings.ReverseStereo = true;
Settings.SoundPlaybackRate = 32000; Settings.SoundPlaybackRate = 32040;
Settings.SoundInputRate = 31953; Settings.SoundInputRate = 32040;
// Graphics // Graphics
Settings.Transparency = true; Settings.Transparency = true;

View File

@ -145,6 +145,9 @@
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2011 zones (c) Copyright 2001 - 2011 zones
MSU-1 code
(c) Copyright 2016 qwertymodo
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
individual files. individual files.
@ -179,12 +182,13 @@
#include <math.h> #include <math.h>
#include "snes9x.h" #include "snes9x.h"
#include "apu.h" #include "apu.h"
#include "msu1.h"
#include "snapshot.h" #include "snapshot.h"
#include "display.h" #include "display.h"
#include "linear_resampler.h" #include "linear_resampler.h"
#include "hermite_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_COUNT 512
#define APU_MINIMUM_SAMPLE_BLOCK 128 #define APU_MINIMUM_SAMPLE_BLOCK 128
#define APU_NUMERATOR_NTSC 15664 #define APU_NUMERATOR_NTSC 15664
@ -235,6 +239,15 @@ namespace spc
static uint32 ratio_denominator = APU_DENOMINATOR_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 EightBitize (uint8 *, int);
static void DeStereo (uint8 *, int); static void DeStereo (uint8 *, int);
static void ReverseStereo (uint8 *, int); static void ReverseStereo (uint8 *, int);
@ -304,10 +317,18 @@ bool8 S9xMixSamples (uint8 *buffer, int sample_count)
else else
dest = buffer; 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) if (Settings.Mute)
{ {
memset(dest, 0, sample_count << 1); memset(dest, 0, sample_count << 1);
spc::resampler->clear(); spc::resampler->clear();
msu::resampler->clear();
return (FALSE); return (FALSE);
} }
@ -318,6 +339,18 @@ bool8 S9xMixSamples (uint8 *buffer, int sample_count)
spc::resampler->read((short *) dest, sample_count); spc::resampler->read((short *) dest, sample_count);
if (spc::lag == spc::lag_master) if (spc::lag == spc::lag_master)
spc::lag = 0; 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 else
{ {
@ -356,8 +389,12 @@ int S9xGetSampleCount (void)
void S9xFinalizeSamples (void) void S9xFinalizeSamples (void)
{ {
bool drop_current_msu1_samples = TRUE;
if (!Settings.Mute) if (!Settings.Mute)
{ {
drop_current_msu1_samples = FALSE;
if (!spc::resampler->push((short *) spc::landing_buffer, spc_core->sample_count())) if (!spc::resampler->push((short *) spc::landing_buffer, spc_core->sample_count()))
{ {
/* We weren't able to process the entire buffer. Potential overrun. */ /* We weren't able to process the entire buffer. Potential overrun. */
@ -365,6 +402,24 @@ void S9xFinalizeSamples (void)
if (Settings.SoundSync && !Settings.TurboMode) if (Settings.SoundSync && !Settings.TurboMode)
return; 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) void S9xClearSamples (void)
{ {
spc::resampler->clear(); spc::resampler->clear();
if (Settings.MSU1)
msu::resampler->clear();
spc::lag = spc::lag_master; 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); double time_ratio = (double) Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator);
spc::resampler->time_ratio(time_ratio); 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) 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 // buffer_ms : buffer size given in millisecond
// lag_ms : allowable time-lag given in millisecond // lag_ms : allowable time-lag given in millisecond
int sample_count = buffer_ms * 32000 / 1000; int sample_count = buffer_ms * 32040 / 1000;
int lag_sample_count = lag_ms * 32000 / 1000; int lag_sample_count = lag_ms * 32040 / 1000;
spc::lag_master = lag_sample_count; spc::lag_master = lag_sample_count;
if (Settings.Stereo) if (Settings.Stereo)
@ -439,6 +499,7 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms)
spc::buffer_size <<= 1; spc::buffer_size <<= 1;
if (Settings.SixteenBitSound) if (Settings.SixteenBitSound)
spc::buffer_size <<= 1; 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); 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]; spc::landing_buffer = new uint8[spc::buffer_size * 2];
if (!spc::landing_buffer) if (!spc::landing_buffer)
return (FALSE); 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 /* The resampler and spc unit use samples (16-bit short) as
arguments. Use 2x in the resampler for buffer leveling with SoundSync */ arguments. Use 2x in the resampler for buffer leveling with SoundSync */
@ -462,6 +528,19 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms)
else else
spc::resampler->resize(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); 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); spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
UpdatePlaybackRate(); UpdatePlaybackRate();
@ -508,6 +587,7 @@ bool8 S9xInitAPU (void)
spc::landing_buffer = NULL; spc::landing_buffer = NULL;
spc::shrink_buffer = NULL; spc::shrink_buffer = NULL;
spc::resampler = NULL; spc::resampler = NULL;
msu::resampler = NULL;
return (TRUE); return (TRUE);
} }
@ -537,6 +617,24 @@ void S9xDeinitAPU (void)
delete[] spc::shrink_buffer; delete[] spc::shrink_buffer;
spc::shrink_buffer = NULL; 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) 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_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
spc::resampler->clear(); spc::resampler->clear();
msu::resampler->clear();
} }
void S9xSoftResetAPU (void) 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_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
spc::resampler->clear(); spc::resampler->clear();
msu::resampler->clear();
} }
static void from_apu_to_state (uint8 **buf, void *var, size_t size) static void from_apu_to_state (uint8 **buf, void *var, size_t size)

View File

@ -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 <stddef.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#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<T> (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 T>
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 <new>
#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 <stdint.h> for int8_t etc.
#if defined (HAVE_STDINT_H)
#include <stdint.h>
#define BOOST
// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
#elif defined (HAVE_INTTYPES_H)
#include <inttypes.h>
#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

View File

@ -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

View File

@ -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 <endian.h>
#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

View File

@ -282,6 +282,7 @@ void S9xReset (void)
S9xResetPPU(); S9xResetPPU();
S9xResetDMA(); S9xResetDMA();
S9xResetAPU(); S9xResetAPU();
S9xResetMSU();
if (Settings.DSP) if (Settings.DSP)
S9xResetDSP(); S9xResetDSP();
@ -299,6 +300,8 @@ void S9xReset (void)
S9xResetOBC1(); S9xResetOBC1();
if (Settings.SRTC) if (Settings.SRTC)
S9xResetSRTC(); S9xResetSRTC();
if (Settings.MSU1)
S9xMSU1Init();
S9xInitCheatData(); S9xInitCheatData();
} }
@ -316,6 +319,7 @@ void S9xSoftReset (void)
S9xSoftResetPPU(); S9xSoftResetPPU();
S9xResetDMA(); S9xResetDMA();
S9xSoftResetAPU(); S9xSoftResetAPU();
S9xResetMSU();
if (Settings.DSP) if (Settings.DSP)
S9xResetDSP(); S9xResetDSP();
@ -333,6 +337,8 @@ void S9xSoftReset (void)
S9xResetOBC1(); S9xResetOBC1();
if (Settings.SRTC) if (Settings.SRTC)
S9xResetSRTC(); S9xResetSRTC();
if (Settings.MSU1)
S9xMSU1Init();
S9xInitCheatData(); S9xInitCheatData();
} }

View File

@ -186,6 +186,7 @@
#include "obc1.h" #include "obc1.h"
#include "seta.h" #include "seta.h"
#include "bsx.h" #include "bsx.h"
#include "msu1.h"
#if (S9X_ACCURACY_LEVEL >= 2) #if (S9X_ACCURACY_LEVEL >= 2)

View File

@ -219,6 +219,7 @@ struct SSPC7110Snapshot s7snap;
struct SSRTCSnapshot srtcsnap; struct SSRTCSnapshot srtcsnap;
struct SRTCData RTCData; struct SRTCData RTCData;
struct SBSX BSX; struct SBSX BSX;
struct SMSU1 MSU1;
struct SMulti Multi; struct SMulti Multi;
struct SSettings Settings; struct SSettings Settings;
struct SSNESGameFixes SNESGameFixes; struct SSNESGameFixes SNESGameFixes;

View File

@ -245,6 +245,7 @@ struct CMemory
uint8 ExtendedFormat; uint8 ExtendedFormat;
char ROMFilename[PATH_MAX + 1]; char ROMFilename[PATH_MAX + 1];
char ROMFilePath[PATH_MAX + 1];
char ROMName[ROM_NAME_LEN]; char ROMName[ROM_NAME_LEN];
char RawROMName[ROM_NAME_LEN]; char RawROMName[ROM_NAME_LEN];
char ROMId[5]; char ROMId[5];

View File

@ -495,6 +495,9 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
S9xTraceFormattedMessage("--- HDMA PPU %04X -> %02X", Address, Byte); S9xTraceFormattedMessage("--- HDMA PPU %04X -> %02X", Address, Byte);
#endif #endif
if (Settings.MSU1 && (Address & 0xfff8) == 0x2000) // MSU-1
S9xMSU1WritePort(Address & 7, Byte);
else
if ((Address & 0xffc0) == 0x2140) // APUIO0, APUIO1, APUIO2, APUIO3 if ((Address & 0xffc0) == 0x2140) // APUIO0, APUIO1, APUIO2, APUIO3
// write_port will run the APU until given clock before writing value // write_port will run the APU until given clock before writing value
S9xAPUWritePort(Address & 3, Byte); S9xAPUWritePort(Address & 3, Byte);
@ -1257,6 +1260,9 @@ uint8 S9xGetPPU (uint16 Address)
{ {
// MAP_PPU: $2000-$3FFF // MAP_PPU: $2000-$3FFF
if (Settings.MSU1 && (Address & 0xfff8) == 0x2000)
return (S9xMSU1ReadPort(Address & 7));
if (Address < 0x2100) if (Address < 0x2100)
return (OpenBus); return (OpenBus);

View File

@ -144,6 +144,9 @@
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2010 zones
MSU-1 code
(c) Copyright 2016 qwertymodo
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
individual files. individual files.
@ -1105,6 +1108,23 @@ static FreezeData SnapBSX[] =
ARRAY_ENTRY(6, test2192, 32, uint8_ARRAY_V) 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 #undef STRUCT
#define STRUCT struct SnapshotScreenshotInfo #define STRUCT struct SnapshotScreenshotInfo
@ -1341,6 +1361,9 @@ void S9xFreezeToStream (STREAM stream)
if (Settings.BS) if (Settings.BS)
FreezeStruct(stream, "BSX", &BSX, SnapBSX, COUNT(SnapBSX)); FreezeStruct(stream, "BSX", &BSX, SnapBSX, COUNT(SnapBSX));
if (Settings.MSU1)
FreezeStruct(stream, "MSU", &MSU1, SnapMSU1, COUNT(SnapMSU1));
if (Settings.SnapshotScreenshots) if (Settings.SnapshotScreenshots)
{ {
SnapshotScreenshotInfo *ssi = new SnapshotScreenshotInfo; SnapshotScreenshotInfo *ssi = new SnapshotScreenshotInfo;
@ -1441,6 +1464,7 @@ int S9xUnfreezeFromStream (STREAM stream)
uint8 *local_srtc = NULL; uint8 *local_srtc = NULL;
uint8 *local_rtc_data = NULL; uint8 *local_rtc_data = NULL;
uint8 *local_bsx_data = NULL; uint8 *local_bsx_data = NULL;
uint8 *local_msu1_data = NULL;
uint8 *local_screenshot = NULL; uint8 *local_screenshot = NULL;
uint8 *local_movie_data = NULL; uint8 *local_movie_data = NULL;
@ -1546,6 +1570,10 @@ int S9xUnfreezeFromStream (STREAM stream)
if (result != SUCCESS && Settings.BS) if (result != SUCCESS && Settings.BS)
break; 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); result = UnfreezeStructCopy(stream, "SHO", &local_screenshot, SnapScreenshot, COUNT(SnapScreenshot), version);
SnapshotMovieInfo mi; SnapshotMovieInfo mi;
@ -1660,6 +1688,9 @@ int S9xUnfreezeFromStream (STREAM stream)
if (local_bsx_data) if (local_bsx_data)
UnfreezeStructFromCopy(&BSX, SnapBSX, COUNT(SnapBSX), local_bsx_data, version); 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); CPU.Flags |= old_flags & (DEBUG_MODE_FLAG | TRACE_FLAG | SINGLE_STEP_FLAG | FRAME_ADVANCE_FLAG);
ICPU.ShiftedPB = Registers.PB << 16; ICPU.ShiftedPB = Registers.PB << 16;
ICPU.ShiftedDB = Registers.DB << 16; ICPU.ShiftedDB = Registers.DB << 16;
@ -1707,6 +1738,9 @@ int S9xUnfreezeFromStream (STREAM stream)
if (local_bsx_data) if (local_bsx_data)
S9xBSXPostLoadState(); S9xBSXPostLoadState();
if (local_msu1_data)
S9xMSU1PostLoadState();
if (local_movie_data) if (local_movie_data)
{ {
// restore last displayed pad_read status // restore last displayed pad_read status

View File

@ -144,6 +144,9 @@
(c) Copyright 1998 - 2001 John Stiles (c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2010 zones (c) Copyright 2001 - 2010 zones
MSU-1 code
(c) Copyright 2016 qwertymodo
Specific ports contains the works of other authors. See headers in Specific ports contains the works of other authors. See headers in
individual files. individual files.
@ -179,7 +182,7 @@
#define _SNAPSHOT_H_ #define _SNAPSHOT_H_
#define SNAPSHOT_MAGIC "#!s9xsnp" #define SNAPSHOT_MAGIC "#!s9xsnp"
#define SNAPSHOT_VERSION 6 #define SNAPSHOT_VERSION 7
#define SUCCESS 1 #define SUCCESS 1
#define WRONG_FORMAT (-1) #define WRONG_FORMAT (-1)

View File

@ -359,6 +359,7 @@ struct SSettings
bool8 BS; bool8 BS;
bool8 BSXItself; bool8 BSXItself;
bool8 BSXBootup; bool8 BSXBootup;
bool8 MSU1;
bool8 MouseMaster; bool8 MouseMaster;
bool8 SuperScopeMaster; bool8 SuperScopeMaster;
bool8 JustifierMaster; bool8 JustifierMaster;