2 Commits

Author SHA1 Message Date
clobber 6b1495d48b Merge pull request #8 from ShutOstrich/master
Update to Snes9x 1.62.3
2023-04-29 20:53:21 -06:00
ShutOstrich c0e0b5580c Update to Snes9x 1.62.3 2023-04-30 00:32:42 +02:00
38 changed files with 1341 additions and 1837 deletions
+1 -1
View File
@@ -19,7 +19,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.61</string>
<string>1.62.3</string>
<key>NSPrincipalClass</key>
<string>OEGameCoreController</string>
<key>OEGameCoreClass</key>
+8
View File
@@ -37,6 +37,7 @@
87709EEE294EDD590084AEE0 /* tileimpl-n2x1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 87709EEB294EDD580084AEE0 /* tileimpl-n2x1.cpp */; };
8D5B49B0048680CD000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; };
8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; };
8F6CC7A029FD51E2006C7D59 /* fscompat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F6CC79E29FD51E2006C7D59 /* fscompat.cpp */; };
94790D7A14C0C46900B30798 /* apu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94790CDC14C0C46900B30798 /* apu.cpp */; };
94790D8114C0C46900B30798 /* bsx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94790CF014C0C46900B30798 /* bsx.cpp */; };
94790D8214C0C46900B30798 /* c4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94790CF214C0C46900B30798 /* c4.cpp */; };
@@ -158,6 +159,8 @@
87709EEB294EDD580084AEE0 /* tileimpl-n2x1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "tileimpl-n2x1.cpp"; path = "src/tileimpl-n2x1.cpp"; sourceTree = "<group>"; };
8D5B49B6048680CD000E48DA /* SNES9x.oecoreplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SNES9x.oecoreplugin; sourceTree = BUILT_PRODUCTS_DIR; };
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8F6CC79E29FD51E2006C7D59 /* fscompat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fscompat.cpp; path = src/fscompat.cpp; sourceTree = "<group>"; };
8F6CC79F29FD51E2006C7D59 /* fscompat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fscompat.h; path = src/fscompat.h; sourceTree = "<group>"; };
94790CDA14C0C46900B30798 /* 65c816.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = 65c816.h; path = src/65c816.h; sourceTree = "<group>"; };
94790CDC14C0C46900B30798 /* apu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = apu.cpp; sourceTree = "<group>"; };
94790CDD14C0C46900B30798 /* apu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apu.h; sourceTree = "<group>"; };
@@ -394,6 +397,8 @@
94790D0F14C0C46900B30798 /* dsp3.cpp */,
94790D1014C0C46900B30798 /* dsp4.cpp */,
94790D1114C0C46900B30798 /* font.h */,
8F6CC79E29FD51E2006C7D59 /* fscompat.cpp */,
8F6CC79F29FD51E2006C7D59 /* fscompat.h */,
94790D1214C0C46900B30798 /* fxdbg.cpp */,
94790D1314C0C46900B30798 /* fxemu.cpp */,
94790D1414C0C46900B30798 /* fxemu.h */,
@@ -668,6 +673,7 @@
94790DA714C0C46900B30798 /* netplay.cpp in Sources */,
94790DA814C0C46900B30798 /* obc1.cpp in Sources */,
94790DA914C0C46900B30798 /* ppu.cpp in Sources */,
8F6CC7A029FD51E2006C7D59 /* fscompat.cpp in Sources */,
87431C061B02F20700F82158 /* stream.cpp in Sources */,
94790DAB14C0C46900B30798 /* sa1.cpp in Sources */,
94790DAC14C0C46900B30798 /* sa1cpu.cpp in Sources */,
@@ -716,6 +722,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_ARC = YES;
COMBINE_HIDPI_IMAGES = YES;
HEADER_SEARCH_PATHS = (
@@ -745,6 +752,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_ARC = YES;
COMBINE_HIDPI_IMAGES = YES;
GCC_STRICT_ALIASING = YES;
+6 -54
View File
@@ -101,9 +101,8 @@ static __weak SNESGameCore *_current;
Settings.SoundInputRate = 32040;
Settings.DynamicRateControl = false;
Settings.DynamicRateLimit = 5;
Settings.SupportHiRes = true;
Settings.Transparency = true;
GFX.InfoString = NULL;
GFX.InfoString.clear();
GFX.InfoStringTimeout = 0;
Settings.DontSaveOopsSnapshot = true;
Settings.NoPatch = true;
@@ -123,7 +122,6 @@ static __weak SNESGameCore *_current;
_indirectVideoBuffer = (uint16_t *)malloc(MAX_SNES_WIDTH * MAX_SNES_HEIGHT * sizeof(uint16_t));
GFX.Pitch = 512 * 2;
GFX.Screen = _indirectVideoBuffer;
S9xUnmapAllControls();
@@ -666,7 +664,7 @@ static __weak SNESGameCore *_current;
- (void)stopEmulation
{
// Save SRAM
NSURL *url = [NSURL fileURLWithPath:@(Memory.ROMFilename)];
NSURL *url = [NSURL fileURLWithPath:@(Memory.ROMFilename.c_str())];
NSString *extensionlessFilename = url.lastPathComponent.stringByDeletingPathExtension;
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:self.batterySavesDirectoryPath];
NSURL *saveFileURL = [batterySavesDirectory URLByAppendingPathComponent:[extensionlessFilename stringByAppendingPathExtension:@"sav"]];
@@ -907,7 +905,7 @@ NSString *SNESEmulatorKeys[] = { @"Up", @"Down", @"Left", @"Right", @"A", @"B",
const char *cheatCode = [singleCode stringByReplacingOccurrencesOfString:@":" withString:@""].UTF8String;
S9xAddCheatGroup("OpenEmu", cheatCode);
S9xEnableCheatGroup(Cheat.g.size () - 1);
S9xEnableCheatGroup(Cheat.group.size() - 1);
}
}
}
@@ -935,42 +933,7 @@ void S9xMessage(int type, int number, const char *message)
NSLog(@"[Snes9x] %s", message);
}
void _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext)
{
// This function is mostly used for various Snes9x generated snapshots (functionality that belongs in the frontend instead), but defined anyway
NSString *nsPath = @(path);
drive[0] = '\0';
NSString *extension = nsPath.pathExtension;
NSArray *components = nsPath.pathComponents;
NSArray *dirComponents = [nsPath.pathComponents subarrayWithRange:NSMakeRange(0, components.count - 1)];
NSString *fileName = [nsPath.lastPathComponent stringByDeletingPathExtension];
NSString *directory = [NSString pathWithComponents:dirComponents];
strcpy(dir, directory.UTF8String);
strcpy(fname, fileName.UTF8String);
strcpy(ext, extension.UTF8String);
}
void _makepath(char *path, const char *drive, const char *dir, const char *fname, const char *ext)
{
// This function is mostly used for Snes9x internal soft patching, but defined anyway
#pragma unused (drive)
NSString *directory = @(dir);
NSString *fileName = @(fname);
NSString *extension = @(ext);
fileName = [fileName stringByAppendingPathExtension:extension];
NSString *fullPath = [directory stringByAppendingPathComponent:fileName];
NSURL *fullURL = [NSURL fileURLWithPath:fullPath];
strcpy(path, fullURL.fileSystemRepresentation);
}
const char *S9xGetDirectory(enum s9x_getdirtype dirtype)
std::string S9xGetDirectory(enum s9x_getdirtype dirtype)
{
// We don't seem to use this function, but defined anyway
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:_current.batterySavesDirectoryPath];
@@ -982,7 +945,7 @@ const char *S9xGetDirectory(enum s9x_getdirtype dirtype)
case SRAM_DIR: return batterySavesDirectory.fileSystemRepresentation; break;
case BIOS_DIR: return biosDirectoryURL.fileSystemRepresentation; break;
case SAT_DIR: return biosDirectoryURL.fileSystemRepresentation; break;
default: return NULL; break;
default: return ""; break;
}
}
@@ -1019,27 +982,16 @@ unsigned char S9xContinueUpdate(int width, int height)
return true;
}
const char *S9xBasename(const char *filename)
{
// Called by S9xFreezeGame/S9xUnfreezeGame -- useless for us
return NULL;
}
const char *S9xStringInput(const char *message)
{
return NULL;
}
const char *S9xGetFilename(const char *extension, enum s9x_getdirtype dirtype)
std::string S9xGetFilenameInc(std::string, enum s9x_getdirtype)
{
return "";
}
const char *S9xGetFilenameInc(const char *, enum s9x_getdirtype)
{
return NULL;
}
bool S9xPollButton(uint32 id, bool *pressed)
{
return true;
+4 -4
View File
@@ -21,7 +21,7 @@
(c) Copyright 2006 - 2007 nitsuja
(c) Copyright 2009 - 2022 BearOso,
(c) Copyright 2009 - 2023 BearOso,
OV2
(c) Copyright 2017 qwertymodo
@@ -139,7 +139,7 @@
(c) Copyright 2006 - 2007 Shay Green
GTK+ GUI code
(c) Copyright 2004 - 2022 BearOso
(c) Copyright 2004 - 2023 BearOso
Win32 GUI code
(c) Copyright 2003 - 2006 blip,
@@ -147,13 +147,13 @@
Matthew Kendora,
Nach,
nitsuja
(c) Copyright 2009 - 2022 OV2
(c) Copyright 2009 - 2023 OV2
Original Mac OS GUI code
(c) Copyright 1998 - 2001 John Stiles
(c) Copyright 2001 - 2011 zones
New MacOS GUI code
(c) Copyright 2022 Michael Donald Buckley
(c) Copyright 2022 - 2023 Michael Donald Buckley
Libretro port
(c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
+54 -91
View File
@@ -5,6 +5,7 @@
\*****************************************************************************/
#include <cmath>
#include <vector>
#include "../snes9x.h"
#include "apu.h"
#include "../msu1.h"
@@ -36,10 +37,10 @@ namespace spc {
static apu_callback callback = NULL;
static void *callback_data = NULL;
static bool8 sound_in_sync = TRUE;
static bool8 sound_enabled = FALSE;
static bool8 sound_in_sync = true;
static bool8 sound_enabled = false;
static Resampler *resampler = NULL;
static Resampler resampler;
static int32 reference_time;
static uint32 remainder;
@@ -56,9 +57,8 @@ static double dynamic_rate_multiplier = 1.0;
namespace msu {
// Always 16-bit, Stereo; 1.5x dsp buffer to never overflow
static Resampler *resampler = NULL;
static int16 *resample_buffer = NULL;
static int resample_buffer_size = 0;
static Resampler resampler;
static std::vector<int16_t> resampler_buffer;
} // namespace msu
static void UpdatePlaybackRate(void);
@@ -74,44 +74,32 @@ bool8 S9xMixSamples(uint8 *dest, int sample_count)
{
memset(out, 0, sample_count << 1);
S9xClearSamples();
spc::sound_in_sync = true;
return true;
}
else
if (spc::resampler.avail() < sample_count)
{
if (spc::resampler->avail() >= sample_count)
{
spc::resampler->read((short *)out, sample_count);
memset(out, 0, sample_count << 1);
return false;
}
if (Settings.MSU1)
{
if (msu::resampler->avail() >= sample_count)
{
if (msu::resample_buffer_size < sample_count)
{
if (msu::resample_buffer)
delete[] msu::resample_buffer;
msu::resample_buffer = new int16[sample_count];
msu::resample_buffer_size = sample_count;
}
msu::resampler->read(msu::resample_buffer,
sample_count);
for (int i = 0; i < sample_count; ++i)
{
int32 mixed = (int32)out[i] + msu::resample_buffer[i];
out[i] = ((int16)mixed != mixed) ? (mixed >> 31) ^ 0x7fff : mixed;
}
}
else // should never occur
assert(0);
}
}
else
spc::resampler.read((short *)out, sample_count);
if (Settings.MSU1)
{
if ((int)msu::resampler_buffer.size() < sample_count)
msu::resampler_buffer.resize(sample_count);
msu::resampler.read(msu::resampler_buffer.data(), sample_count);
for (int i = 0; i < sample_count; ++i)
{
memset(out, 0, sample_count << 1);
return false;
int32 mixed = (int32)out[i] + msu::resampler_buffer[i];
out[i] = ((int16)mixed != mixed) ? (mixed >> 31) ^ 0x7fff : mixed;
}
}
if (spc::resampler->space_empty() >= 535 * 2 || !Settings.SoundSync ||
if (spc::resampler.space_empty() >= 535 * 2 || !Settings.SoundSync ||
Settings.TurboMode || Settings.Mute)
spc::sound_in_sync = true;
else
@@ -122,7 +110,10 @@ bool8 S9xMixSamples(uint8 *dest, int sample_count)
int S9xGetSampleCount(void)
{
return spc::resampler->avail();
int avail = spc::resampler.avail();
if (Settings.MSU1) // return minimum available samples, otherwise we can run into the assert above due to partial sample generation in msu1
avail = Resampler::min(avail, msu::resampler.avail());
return avail;
}
void S9xLandSamples(void)
@@ -130,7 +121,7 @@ void S9xLandSamples(void)
if (spc::callback != NULL)
spc::callback(spc::callback_data);
if (spc::resampler->space_empty() >= 535 * 2 || !Settings.SoundSync ||
if (spc::resampler.space_empty() >= 535 * 2 || !Settings.SoundSync ||
Settings.TurboMode || Settings.Mute)
spc::sound_in_sync = true;
else
@@ -139,15 +130,15 @@ void S9xLandSamples(void)
void S9xClearSamples(void)
{
spc::resampler->clear();
spc::resampler.clear();
if (Settings.MSU1)
msu::resampler->clear();
msu::resampler.clear();
}
bool8 S9xSyncSound(void)
{
if (!Settings.SoundSync || spc::sound_in_sync)
return (TRUE);
return true;
S9xLandSamples();
@@ -180,12 +171,12 @@ static void UpdatePlaybackRate(void)
time_ratio *= spc::dynamic_rate_multiplier;
}
spc::resampler->time_ratio(time_ratio);
spc::resampler.time_ratio(time_ratio);
if (Settings.MSU1)
{
time_ratio = (44100.0 / Settings.SoundPlaybackRate) * (Settings.SoundInputRate / 32040.0);
msu::resampler->time_ratio(time_ratio);
time_ratio = time_ratio * 44100 / 32040;
msu::resampler.time_ratio(time_ratio);
}
}
@@ -198,27 +189,11 @@ bool8 S9xInitSound(int buffer_ms)
if (requested_buffer_size_samples > buffer_size_samples)
buffer_size_samples = requested_buffer_size_samples;
if (!spc::resampler)
{
spc::resampler = new Resampler(buffer_size_samples);
if (!spc::resampler)
return (FALSE);
}
else
spc::resampler->resize(buffer_size_samples);
spc::resampler.resize(buffer_size_samples);
msu::resampler.resize(buffer_size_samples * 3 / 2);
if (!msu::resampler)
{
msu::resampler = new Resampler(buffer_size_samples * 3 / 2);
if (!msu::resampler)
return (FALSE);
}
else
msu::resampler->resize(buffer_size_samples * 3 / 2);
SNES::dsp.spc_dsp.set_output(spc::resampler);
S9xMSU1SetOutput(msu::resampler);
SNES::dsp.spc_dsp.set_output(&spc::resampler);
S9xMSU1SetOutput(&msu::resampler);
UpdatePlaybackRate();
@@ -236,7 +211,7 @@ void S9xSetSoundMute(bool8 mute)
{
Settings.Mute = mute;
if (!spc::sound_enabled)
Settings.Mute = TRUE;
Settings.Mute = true;
}
void S9xDumpSPCSnapshot(void)
@@ -246,33 +221,22 @@ void S9xDumpSPCSnapshot(void)
static void SPCSnapshotCallback(void)
{
S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR));
S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR).c_str());
printf("Dumped key-on triggered spc snapshot.\n");
}
bool8 S9xInitAPU(void)
{
spc::resampler = NULL;
msu::resampler = NULL;
spc::resampler.clear();
msu::resampler.clear();
return (TRUE);
return true;
}
void S9xDeinitAPU(void)
{
if (spc::resampler)
{
delete spc::resampler;
spc::resampler = NULL;
}
if (msu::resampler)
{
delete msu::resampler;
msu::resampler = NULL;
}
S9xMSU1DeInit();
msu::resampler_buffer.clear();
}
static inline int S9xAPUGetClock(int32 cpucycles)
@@ -306,10 +270,10 @@ void S9xAPUSetReferenceTime(int32 cpucycles)
void S9xAPUExecute(void)
{
SNES::smp.clock -= S9xAPUGetClock(CPU.Cycles);
SNES::smp.enter();
int cycles = S9xAPUGetClock(CPU.Cycles);
spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles);
SNES::smp.clock -= cycles;
SNES::smp.enter();
S9xAPUSetReferenceTime(CPU.Cycles);
}
@@ -319,7 +283,7 @@ void S9xAPUEndScanline(void)
S9xAPUExecute();
SNES::dsp.synchronize();
if (spc::resampler->space_filled() >= APU_SAMPLE_BLOCK || !spc::sound_in_sync)
if (spc::resampler.space_filled() >= APU_SAMPLE_BLOCK)
S9xLandSamples();
}
@@ -386,7 +350,6 @@ void S9xAPULoadState(uint8 *block)
SNES::smp.load_state(&ptr);
SNES::dsp.load_state(&ptr);
spc::reference_time = SNES::get_le32(ptr);
ptr += sizeof(int32);
spc::remainder = SNES::get_le32(ptr);
@@ -515,9 +478,9 @@ bool8 S9xSPCDump(const char *filename)
fs = fopen(filename, "wb");
if (!fs)
return (FALSE);
return false;
S9xSetSoundMute(TRUE);
S9xSetSoundMute(true);
SNES::smp.save_spc(buf);
@@ -530,7 +493,7 @@ bool8 S9xSPCDump(const char *filename)
fclose(fs);
S9xSetSoundMute(FALSE);
S9xSetSoundMute(false);
return (TRUE);
return true;
}
+9 -1
View File
@@ -55,9 +55,11 @@ static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] =
// Access global DSP register
#define REG(n) m.regs [r_##n]
#define XREG(n) m.external_regs [r_##n]
// Access voice DSP register
#define VREG(r,n) r [v_##n]
#define XVREG(r,n) (m.external_regs + (r - m.regs))[v_##n]
#define WRITE_SAMPLES( l, r, out ) \
{\
@@ -927,6 +929,7 @@ inline VOICE_CLOCK( V7 )
{
// Update ENDX
REG(endx) = m.endx_buf;
XREG(endx) = m.endx_buf;
m.envx_buf = v->t_envx_out;
}
@@ -934,11 +937,13 @@ inline VOICE_CLOCK( V8 )
{
// Update OUTX
VREG(v->regs,outx) = m.outx_buf;
XVREG(v->regs,outx) = m.outx_buf;
}
inline VOICE_CLOCK( V9 )
{
// Update ENVX
VREG(v->regs,envx) = m.envx_buf;
XVREG(v->regs,envx) = m.envx_buf;
}
// Most voices do all these in one clock, so make a handy composite
@@ -1237,7 +1242,9 @@ void SPC_DSP::soft_reset()
void SPC_DSP::load( uint8_t const regs [register_count] )
{
memcpy( m.regs, regs, sizeof m.regs );
memcpy( m.external_regs, regs, sizeof m.regs );
memset( m.regs, 0, sizeof m.regs);
m.regs[r_flg] = 0xE0;
memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count );
// Internal state
@@ -1398,6 +1405,7 @@ void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy )
SPC_COPY( uint16_t, m.t_echo_ptr );
SPC_COPY( uint8_t, m.t_looped );
copier.copy(m.external_regs, register_count);
copier.extra();
}
#endif
+4 -1
View File
@@ -204,6 +204,8 @@ private:
sample_t extra [extra_size];
uint8_t separate_echo_buffer [0x10000];
uint8_t external_regs [register_count];
};
state_t m;
@@ -260,7 +262,7 @@ inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; }
inline int SPC_DSP::read( int addr ) const
{
assert( (unsigned) addr < register_count );
return m.regs [addr];
return m.external_regs [addr];
}
inline void SPC_DSP::write( int addr, int data )
@@ -268,6 +270,7 @@ inline void SPC_DSP::write( int addr, int data )
assert( (unsigned) addr < register_count );
m.regs [addr] = (uint8_t) data;
m.external_regs [addr] = (uint8_t) data;
switch ( addr & 0x0F )
{
case v_envx:
+5 -3
View File
@@ -65,10 +65,9 @@ class Resampler
Resampler(int num_samples)
{
this->buffer_size = num_samples;
buffer = new int16_t[this->buffer_size];
buffer = NULL;
resize(num_samples);
r_step = 1.0;
clear();
}
~Resampler()
@@ -220,6 +219,9 @@ class Resampler
{
if (buffer)
delete[] buffer;
// Only allow even buffer sizes
if (num_samples & 1)
num_samples++;
buffer_size = num_samples;
buffer = new int16_t[buffer_size];
clear();
+15 -23
View File
@@ -738,16 +738,14 @@ void S9xBSXSetStream1 (uint8 count)
if (BSX.sat_stream1.is_open())
BSX.sat_stream1.close(); //If Stream already opened for one file: Close it.
char path[PATH_MAX + 1], name[PATH_MAX + 1];
std::string path = S9xGetDirectory(SAT_DIR) + SLASH_STR;
strcpy(path, S9xGetDirectory(SAT_DIR));
strcat(path, SLASH_STR);
snprintf(name, PATH_MAX + 1, "BSX%04X-%d.bin", (BSX.PPU[0x2188 - BSXPPUBASE] | (BSX.PPU[0x2189 - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin
strcat(path, name);
char name[PATH_MAX];
snprintf(name, PATH_MAX, "BSX%04X-%d.bin", (BSX.PPU[0x2188 - BSXPPUBASE] | (BSX.PPU[0x2189 - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin
path += name;
BSX.sat_stream1.clear();
BSX.sat_stream1.open(path, std::ios::in | std::ios::binary);
BSX.sat_stream1.open(path.c_str(), std::ios::in | std::ios::binary);
if (BSX.sat_stream1.good())
{
BSX.sat_stream1.seekg(0, BSX.sat_stream1.end);
@@ -770,16 +768,15 @@ void S9xBSXSetStream2 (uint8 count)
if (BSX.sat_stream2.is_open())
BSX.sat_stream2.close(); //If Stream already opened for one file: Close it.
char path[PATH_MAX + 1], name[PATH_MAX + 1];
strcpy(path, S9xGetDirectory(SAT_DIR));
strcat(path, SLASH_STR);
std::string path = S9xGetDirectory(SAT_DIR) + SLASH_STR;
snprintf(name, PATH_MAX + 1, "BSX%04X-%d.bin", (BSX.PPU[0x218E - BSXPPUBASE] | (BSX.PPU[0x218F - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin
strcat(path, name);
char name[PATH_MAX];
snprintf(name, PATH_MAX, "BSX%04X-%d.bin", (BSX.PPU[0x218E - BSXPPUBASE] | (BSX.PPU[0x218F - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin
path += name;
BSX.sat_stream2.clear();
BSX.sat_stream2.open(path, std::ios::in | std::ios::binary);
BSX.sat_stream2.open(path.c_str(), std::ios::in | std::ios::binary);
if (BSX.sat_stream2.good())
{
BSX.sat_stream2.seekg(0, BSX.sat_stream2.end);
@@ -1207,20 +1204,15 @@ uint8 * S9xGetBasePointerBSX (uint32 address)
static bool8 BSX_LoadBIOS (void)
{
FILE *fp;
char path[PATH_MAX + 1], name[PATH_MAX + 1];
bool8 r = FALSE;
strcpy(path, S9xGetDirectory(BIOS_DIR));
strcat(path, SLASH_STR);
strcpy(name, path);
strcat(name, "BS-X.bin");
std::string name = S9xGetDirectory(BIOS_DIR) + SLASH_STR + "BS-X.bin";
fp = fopen(name, "rb");
fp = fopen(name.c_str(), "rb");
if (!fp)
{
strcpy(name, path);
strcat(name, "BS-X.bios");
fp = fopen(name, "rb");
name = S9xGetDirectory(BIOS_DIR) + SLASH_STR + "BS-X.bios";
fp = fopen(name.c_str(), "rb");
}
if (fp)
@@ -1255,7 +1247,7 @@ void S9xInitBSX (void)
{
Settings.BS = FALSE;
if (is_BSX_BIOS(Memory.ROM,Memory.CalculatedSize))
if (is_BSX_BIOS(Memory.ROM,Memory.CalculatedSize))
{
// BS-X itself
-106
View File
@@ -37,112 +37,6 @@
(s) == S9X_24_BITS ? (((int32) ((*((m) + (o)) + (*((m) + (o) + 1) << 8) + (*((m) + (o) + 2) << 16)) << 8)) >> 8): \
((int32) (*((m) + (o)) + (*((m) + (o) + 1) << 8) + (*((m) + (o) + 2) << 16) + (*((m) + (o) + 3) << 24))))
static bool8 S9xAllHex (const char *, int);
static bool8 S9xAllHex (const char *code, int len)
{
for (int i = 0; i < len; i++)
if ((code[i] < '0' || code[i] > '9') && (code[i] < 'a' || code[i] > 'f') && (code[i] < 'A' || code[i] > 'F'))
return (FALSE);
return (TRUE);
}
const char * S9xProActionReplayToRaw (const char *code, uint32 &address, uint8 &byte)
{
uint32 data = 0;
if (strlen(code) != 8 || !S9xAllHex(code, 8) || sscanf(code, "%x", &data) != 1)
return ("Invalid Pro Action Replay code - should be 8 hex digits in length.");
address = data >> 8;
byte = (uint8) data;
return (NULL);
}
const char * S9xGoldFingerToRaw (const char *code, uint32 &address, bool8 &sram, uint8 &num_bytes, uint8 bytes[3])
{
char tmp[15];
int i;
if (strlen(code) != 14)
return ("Invalid Gold Finger code - should be 14 hex digits in length.");
strncpy(tmp, code, 5);
tmp[5] = 0;
if (sscanf(tmp, "%x", &address) != 1)
return ("Invalid Gold Finger code.");
// Correct GoldFinger Address
address = (address & 0x7FFF) | ((address & 0x7F8000) << 1) | 0x8000;
for (i = 0; i < 3; i++)
{
unsigned int byte;
strncpy(tmp, code + 5 + i * 2, 2);
tmp[2] = 0;
if (sscanf(tmp, "%x", &byte) != 1)
break;
bytes[i] = (uint8) byte;
}
num_bytes = i;
sram = code[13] == '1';
return (NULL);
}
const char * S9xGameGenieToRaw (const char *code, uint32 &address, uint8 &byte)
{
char new_code[12];
if (strlen(code) != 9 || *(code + 4) != '-' || !S9xAllHex(code, 4) || !S9xAllHex(code + 5, 4))
return ("Invalid Game Genie(tm) code - should be 'xxxx-xxxx'.");
strcpy(new_code, "0x");
strncpy(new_code + 2, code, 4);
strcpy(new_code + 6, code + 5);
static const char *real_hex = "0123456789ABCDEF";
static const char *genie_hex = "DF4709156BC8A23E";
for (int i = 2; i < 10; i++)
{
if (islower(new_code[i]))
new_code[i] = toupper(new_code[i]);
int j;
for (j = 0; j < 16; j++)
{
if (new_code[i] == genie_hex[j])
{
new_code[i] = real_hex[j];
break;
}
}
if (j == 16)
return ("Invalid hex-character in Game Genie(tm) code.");
}
uint32 data = 0;
sscanf(new_code, "%x", &data);
byte = (uint8) (data >> 24);
address = data & 0xffffff;
address = ((address & 0x003c00) << 10) +
((address & 0x00003c) << 14) +
((address & 0xf00000) >> 8) +
((address & 0x000003) << 10) +
((address & 0x00c000) >> 6) +
((address & 0x0f0000) >> 12) +
((address & 0x0003c0) >> 6);
return (NULL);
}
void S9xStartCheatSearch (SCheatData *d)
{
memmove(d->CWRAM, d->RAM, 0x20000);
+17 -21
View File
@@ -23,14 +23,14 @@ struct SCheat
struct SCheatGroup
{
char *name;
std::string name;
bool8 enabled;
std::vector<struct SCheat> c;
std::vector<struct SCheat> cheat;
};
struct SCheatData
{
std::vector<struct SCheatGroup> g;
std::vector<struct SCheatGroup> group;
bool8 enabled;
uint8 CWRAM[0x20000];
uint8 CSRAM[0x80000];
@@ -73,20 +73,20 @@ typedef enum
extern SCheatData Cheat;
extern Watch watches[16];
int S9xAddCheatGroup (const char *name, const char *cheat);
int S9xModifyCheatGroup (uint32 index, const char *name, const char *cheat);
void S9xEnableCheatGroup (uint32 index);
void S9xDisableCheatGroup (uint32 index);
void S9xDeleteCheats (void);
char *S9xCheatGroupToText (uint32 index);
void S9xDeleteCheatGroup (uint32 index);
bool8 S9xLoadCheatFile (const char *filename);
bool8 S9xSaveCheatFile (const char *filename);
void S9xUpdateCheatsInMemory (void);
int S9xImportCheatsFromDatabase(const char *filename);
void S9xCheatsDisable (void);
void S9xCheatsEnable (void);
char *S9xCheatValidate (const char *cheat);
int S9xAddCheatGroup(const std::string &name, const std::string &cheat);
int S9xModifyCheatGroup(uint32 index, const std::string &name, const std::string &cheat);
void S9xEnableCheatGroup(uint32 index);
void S9xDisableCheatGroup(uint32 index);
void S9xDeleteCheats(void);
std::string S9xCheatGroupToText(uint32 index);
void S9xDeleteCheatGroup(uint32 index);
bool8 S9xLoadCheatFile(const std::string &filename);
bool8 S9xSaveCheatFile(const std::string &filename);
void S9xUpdateCheatsInMemory(void);
int S9xImportCheatsFromDatabase(const std::string &filename);
void S9xCheatsDisable(void);
void S9xCheatsEnable(void);
std::string S9xCheatValidate(const std::string &cheat);
void S9xInitCheatData (void);
void S9xInitWatchedAddress (void);
@@ -96,8 +96,4 @@ void S9xSearchForValue (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize,
void S9xSearchForAddress (SCheatData *, S9xCheatComparisonType, S9xCheatDataSize, uint32, bool8);
void S9xOutputCheatSearchResults (SCheatData *);
const char * S9xGameGenieToRaw (const char *, uint32 &, uint8 &);
const char * S9xProActionReplayToRaw (const char *, uint32 &, uint8 &);
const char * S9xGoldFingerToRaw (const char *, uint32 &, bool8 &, uint8 &, uint8 bytes[3]);
#endif
+299 -283
View File
@@ -4,37 +4,24 @@
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
#include <ctype.h>
#include "bml.h"
#include "cheats.h"
#include "snes9x.h"
#include "memmap.h"
#include "cheats.h"
#include "bml.h"
static inline char *trim (char *string)
static inline uint8 S9xGetByteFree(uint32 Address)
{
int start;
int end;
for (start = 0; string[start] && isspace (string[start]); start++) {}
for (end = start; string[end] && !isspace (string[end]); end++) {}
string[end] = '\0';
return &string[start];
}
static inline uint8 S9xGetByteFree (uint32 Address)
{
int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
uint8 *GetAddress = Memory.Map[block];
uint8 byte;
if (GetAddress >= (uint8 *) CMemory::MAP_LAST)
if (GetAddress >= (uint8 *)CMemory::MAP_LAST)
{
byte = *(GetAddress + (Address & 0xffff));
return (byte);
}
switch ((pint) GetAddress)
switch ((pint)GetAddress)
{
case CMemory::MAP_CPU:
byte = S9xGetCPU(Address & 0xffff);
@@ -108,18 +95,18 @@ static inline uint8 S9xGetByteFree (uint32 Address)
}
}
static inline void S9xSetByteFree (uint8 Byte, uint32 Address)
static inline void S9xSetByteFree(uint8 Byte, uint32 Address)
{
int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
uint8 *SetAddress = Memory.Map[block];
if (SetAddress >= (uint8 *) CMemory::MAP_LAST)
if (SetAddress >= (uint8 *)CMemory::MAP_LAST)
{
*(SetAddress + (Address & 0xffff)) = Byte;
return;
}
switch ((pint) SetAddress)
switch ((pint)SetAddress)
{
case CMemory::MAP_CPU:
S9xSetCPU(Byte, Address & 0xffff);
@@ -197,165 +184,229 @@ static inline void S9xSetByteFree (uint8 Byte, uint32 Address)
}
}
void S9xInitWatchedAddress (void)
void S9xInitWatchedAddress(void)
{
for (unsigned int i = 0; i < sizeof(watches) / sizeof(watches[0]); i++)
watches[i].on = false;
}
void S9xInitCheatData (void)
void S9xInitCheatData(void)
{
Cheat.RAM = Memory.RAM;
Cheat.SRAM = Memory.SRAM;
Cheat.FillRAM = Memory.FillRAM;
}
static inline std::string trim(const std::string &&string)
{
auto start = string.find_first_not_of(" \t\n\r");
auto end = string.find_last_not_of(" \t\n\r");
if (start != std::string::npos && end != std::string::npos)
return string.substr(start, end - start + 1);
return "";
}
void S9xUpdateCheatInMemory (SCheat *c)
void S9xUpdateCheatInMemory(SCheat &c)
{
uint8 byte;
if (!c->enabled)
if (!c.enabled)
return;
byte = S9xGetByteFree (c->address);
byte = S9xGetByteFree(c.address);
if (byte != c->byte)
if (byte != c.byte)
{
/* The game wrote a different byte to the address, update saved_byte */
c->saved_byte = byte;
c.saved_byte = byte;
if (c->conditional)
if (c.conditional)
{
if (c->saved_byte != c->cond_byte && c->cond_true)
if (c.saved_byte != c.cond_byte && c.cond_true)
{
/* Condition is now false, let the byte stand */
c->cond_true = false;
c.cond_true = false;
}
else if (c->saved_byte == c->cond_byte && !c->cond_true)
else if (c.saved_byte == c.cond_byte && !c.cond_true)
{
c->cond_true = true;
S9xSetByteFree (c->byte, c->address);
c.cond_true = true;
S9xSetByteFree(c.byte, c.address);
}
}
else
S9xSetByteFree (c->byte, c->address);
S9xSetByteFree(c.byte, c.address);
}
else if (c->conditional)
else if (c.conditional)
{
if (byte == c->cond_byte)
if (byte == c.cond_byte)
{
c->cond_true = true;
c->saved_byte = byte;
S9xSetByteFree (c->byte, c->address);
c.cond_true = true;
c.saved_byte = byte;
S9xSetByteFree(c.byte, c.address);
}
}
}
void S9xDisableCheat (SCheat *c)
void S9xDisableCheat(SCheat &c)
{
if (!c->enabled)
if (!c.enabled)
return;
if (!Cheat.enabled)
{
c->enabled = false;
c.enabled = false;
return;
}
/* Make sure we restore the up-to-date written byte */
S9xUpdateCheatInMemory (c);
c->enabled = false;
S9xUpdateCheatInMemory(c);
c.enabled = false;
if (c->conditional && !c->cond_true)
if (c.conditional && !c.cond_true)
return;
S9xSetByteFree (c->saved_byte, c->address);
c->cond_true = false;
S9xSetByteFree (c.saved_byte, c.address);
c.cond_true = false;
}
void S9xDeleteCheatGroup (uint32 g)
void S9xDeleteCheatGroup(uint32 g)
{
unsigned int i;
if (g >= Cheat.g.size ())
if (g >= Cheat.group.size())
return;
for (i = 0; i < Cheat.g[g].c.size (); i++)
for (i = 0; i < Cheat.group[g].cheat.size(); i++)
{
S9xDisableCheat (&Cheat.g[g].c[i]);
S9xDisableCheat(Cheat.group[g].cheat[i]);
}
delete[] Cheat.g[g].name;
Cheat.g.erase (Cheat.g.begin () + g);
Cheat.group.erase(Cheat.group.begin() + g);
}
void S9xDeleteCheats (void)
void S9xDeleteCheats(void)
{
unsigned int i;
for (i = 0; i < Cheat.g.size (); i++)
for (size_t i = 0; i < Cheat.group.size(); i++)
{
S9xDisableCheatGroup (i);
delete[] Cheat.g[i].name;
S9xDisableCheatGroup(i);
}
Cheat.g.clear ();
Cheat.group.clear();
}
void S9xEnableCheat (SCheat *c)
void S9xEnableCheat(SCheat &c)
{
uint8 byte;
if (c->enabled)
if (c.enabled)
return;
c->enabled = true;
c.enabled = true;
if (!Cheat.enabled)
return;
byte = S9xGetByteFree(c->address);
byte = S9xGetByteFree(c.address);
if (c->conditional)
if (c.conditional)
{
if (byte != c->cond_byte)
if (byte != c.cond_byte)
return;
c->cond_true = true;
c.cond_true = true;
}
c->saved_byte = byte;
S9xSetByteFree (c->byte, c->address);
c.saved_byte = byte;
S9xSetByteFree(c.byte, c.address);
}
void S9xEnableCheatGroup (uint32 num)
void S9xEnableCheatGroup(uint32 num)
{
unsigned int i;
for (auto &c : Cheat.group[num].cheat)
S9xEnableCheat(c);
for (i = 0; i < Cheat.g[num].c.size (); i++)
{
S9xEnableCheat (&Cheat.g[num].c[i]);
}
Cheat.g[num].enabled = true;
Cheat.group[num].enabled = true;
}
void S9xDisableCheatGroup (uint32 num)
void S9xDisableCheatGroup(uint32 num)
{
unsigned int i;
for (auto &c : Cheat.group[num].cheat)
S9xDisableCheat(c);
for (i = 0; i < Cheat.g[num].c.size (); i++)
{
S9xDisableCheat (&Cheat.g[num].c[i]);
}
Cheat.g[num].enabled = false;
Cheat.group[num].enabled = false;
}
SCheat S9xTextToCheat (char *text)
static bool is_all_hex(const std::string &code)
{
for (const auto &c : code)
{
if ((c < '0' || c > '9') &&
(c < 'a' || c > 'f') &&
(c < 'A' || c > 'F'))
return false;
}
return true;
}
bool S9xProActionReplayToRaw(const std::string &code, uint32 &address, uint8 &byte)
{
if (code.length() != 8 || !is_all_hex(code))
return false;
uint32 data = std::strtoul(code.c_str(), nullptr, 16);
address = data >> 8;
byte = (uint8)data;
return true;
}
bool S9xGameGenieToRaw(const std::string &code, uint32 &address, uint8 &byte)
{
if (code.length() != 9)
return false;
if (code[4] != '-')
return false;
if (!is_all_hex(code.substr(0, 4)))
return false;
if (!is_all_hex(code.substr(5, 4)))
return false;
auto new_code = code.substr(0, 4) + code.substr(5, 4);
static const char *real_hex = "0123456789ABCDEF";
static const char *genie_hex = "DF4709156BC8A23E";
for (auto &c : new_code)
{
c = toupper(c);
for (int i = 0; i < 16; i++)
{
if (genie_hex[i] == c)
{
c = real_hex[i];
break;
}
}
}
uint32 data = strtoul(new_code.c_str(), nullptr, 16);
byte = (uint8)(data >> 24);
address = data & 0xffffff;
address = ((address & 0x003c00) << 10) +
((address & 0x00003c) << 14) +
((address & 0xf00000) >> 8) +
((address & 0x000003) << 10) +
((address & 0x00c000) >> 6) +
((address & 0x0f0000) >> 12) +
((address & 0x0003c0) >> 6);
return true;
}
SCheat S9xTextToCheat(const std::string &text)
{
SCheat c;
unsigned int byte = 0;
@@ -364,34 +415,28 @@ SCheat S9xTextToCheat (char *text)
c.enabled = false;
c.conditional = false;
if (!S9xGameGenieToRaw (text, c.address, c.byte))
if (S9xGameGenieToRaw(text, c.address, c.byte))
{
byte = c.byte;
}
else if (!S9xProActionReplayToRaw (text, c.address, c.byte))
else if (S9xProActionReplayToRaw(text, c.address, c.byte))
{
byte = c.byte;
}
else if (sscanf (text, "%x = %x ? %x", &c.address, &cond_byte, &byte) == 3)
else if (sscanf(text.c_str(), "%x = %x ? %x", &c.address, &cond_byte, &byte) == 3)
{
c.conditional = true;
}
else if (sscanf (text, "%x = %x", &c.address, &byte) == 2)
else if (sscanf(text.c_str(), "%x = %x", &c.address, &byte) == 2)
{
}
else if (sscanf (text, "%x / %x / %x", &c.address, &cond_byte, &byte) == 3)
else if (sscanf(text.c_str(), "%x / %x / %x", &c.address, &cond_byte, &byte) == 3)
{
c.conditional = true;
}
else if (sscanf (text, "%x / %x", &c.address, &byte) == 2)
else if (sscanf(text.c_str(), "%x / %x", &c.address, &byte) == 2)
{
}
else
{
c.address = 0;
@@ -404,313 +449,287 @@ SCheat S9xTextToCheat (char *text)
return c;
}
SCheatGroup S9xCreateCheatGroup (const char *name, const char *cheat)
std::vector<std::string> split_string(const std::string &str, unsigned char delim)
{
SCheatGroup g;
char *code_string = strdup (cheat);
char *code_ptr = code_string;
int len;
std::vector<std::string> tokens;
size_t pos = 0;
size_t index;
g.name = strdup (name);
g.enabled = false;
for (len = strcspn (code_ptr, "+"); len; len = strcspn (code_ptr, "+"))
while (pos < str.length())
{
char *code = code_ptr;
code_ptr += len + (code_ptr[len] == '\0' ? 0 : 1);
code[len] = '\0';
code = trim (code);
index = str.find(delim, pos);
if (index == std::string::npos)
{
if (pos < str.length())
{
tokens.push_back(trim(str.substr(pos)));
}
SCheat c = S9xTextToCheat (code);
if (c.address)
g.c.push_back (c);
break;
}
else if (index > pos)
{
tokens.push_back(trim(str.substr(pos, index - pos)));
}
pos = index + 1;
}
free(code_string);
return tokens;
}
SCheatGroup S9xCreateCheatGroup(const std::string &name, const std::string &cheat)
{
SCheatGroup g;
g.name = name;
g.enabled = false;
auto cheats = split_string(cheat, '+');
for (const auto &c : cheats)
{
SCheat new_cheat = S9xTextToCheat(c);
if (new_cheat.address)
g.cheat.push_back(new_cheat);
}
return g;
}
int S9xAddCheatGroup (const char *name, const char *cheat)
int S9xAddCheatGroup(const std::string &name, const std::string &cheat)
{
SCheatGroup g = S9xCreateCheatGroup (name, cheat);
if (g.c.size () == 0)
SCheatGroup g = S9xCreateCheatGroup(name, cheat);
if (g.cheat.size() == 0)
return -1;
Cheat.g.push_back (g);
Cheat.group.push_back(g);
return Cheat.g.size () - 1;
return Cheat.group.size() - 1;
}
int S9xModifyCheatGroup (uint32 num, const char *name, const char *cheat)
int S9xModifyCheatGroup(uint32 num, const std::string &name, const std::string &cheat)
{
if (num >= Cheat.g.size())
if (num >= Cheat.group.size())
return -1;
S9xDisableCheatGroup (num);
delete[] Cheat.g[num].name;
S9xDisableCheatGroup(num);
Cheat.g[num] = S9xCreateCheatGroup (name, cheat);
Cheat.group[num] = S9xCreateCheatGroup(name, cheat);
return num;
}
char *S9xCheatToText (SCheat *c)
std::string S9xCheatToText(const SCheat &c)
{
int size = 10; /* 6 address, 1 =, 2 byte, 1 NUL */
char *text;
char output[256]{};
if (c->conditional)
size += 3; /* additional 2 byte, 1 ? */
text = new char[size];
if (c->conditional)
snprintf (text, size, "%06x=%02x?%02x", c->address, c->cond_byte, c->byte);
if (c.conditional)
sprintf(output, "%06x=%02x?%02x", c.address, c.cond_byte, c.byte);
else
snprintf (text, size, "%06x=%02x", c->address, c->byte);
sprintf(output, "%06x=%02x", c.address, c.byte);
return std::string(output);
}
std::string S9xCheatGroupToText(SCheatGroup &g)
{
std::string text = "";
for (size_t i = 0; i < g.cheat.size(); i++)
{
text += S9xCheatToText(g.cheat[i]);
if (i != g.cheat.size() - 1)
text += "+";
}
return text;
}
char *S9xCheatGroupToText (SCheatGroup *g)
std::string S9xCheatValidate(const std::string &code_string)
{
std::string text = "";
unsigned int i;
SCheatGroup g = S9xCreateCheatGroup("temp", code_string);
if (g->c.size () == 0)
return NULL;
for (i = 0; i < g->c.size (); i++)
if (g.cheat.size() > 0)
{
char *tmp = S9xCheatToText (&g->c[i]);
if (i != 0)
text += " + ";
text += tmp;
delete[] tmp;
return S9xCheatGroupToText(g);
}
return strdup (text.c_str ());
return "";
}
char *S9xCheatValidate (const char *code_string)
std::string S9xCheatGroupToText(uint32 num)
{
SCheatGroup g = S9xCreateCheatGroup ("temp", code_string);
if (num >= Cheat.group.size())
return "";
delete[] g.name;
if (g.c.size() > 0)
{
return S9xCheatGroupToText (&g);
}
return NULL;
return S9xCheatGroupToText(Cheat.group[num]);
}
char *S9xCheatGroupToText (uint32 num)
void S9xUpdateCheatsInMemory(void)
{
if (num >= Cheat.g.size ())
return NULL;
return S9xCheatGroupToText (&Cheat.g[num]);
}
void S9xUpdateCheatsInMemory (void)
{
unsigned int i;
unsigned int j;
if (!Cheat.enabled)
return;
for (i = 0; i < Cheat.g.size (); i++)
{
for (j = 0; j < Cheat.g[i].c.size (); j++)
{
S9xUpdateCheatInMemory (&Cheat.g[i].c[j]);
}
}
for (auto &group : Cheat.group)
for (auto &cheat : group.cheat)
S9xUpdateCheatInMemory(cheat);
}
static int S9xCheatIsDuplicate (const char *name, const char *code)
static bool S9xCheatIsDuplicate(const std::string &name, const std::string &code)
{
unsigned int i;
for (i = 0; i < Cheat.g.size(); i++)
for (size_t i = 0; i < Cheat.group.size(); i++)
{
if (!strcmp (name, Cheat.g[i].name))
if (Cheat.group[i].name == name)
{
char *code_string = S9xCheatGroupToText (i);
char *validated = S9xCheatValidate (code);
auto code_string = S9xCheatGroupToText(i);
auto validated_string = S9xCheatValidate(code);
if (validated && !strcmp (code_string, validated))
{
free (code_string);
free (validated);
return TRUE;
}
free (code_string);
free (validated);
if (validated_string == code_string)
return true;
}
}
return FALSE;
return false;
}
static void S9xLoadCheatsFromBMLNode (bml_node *n)
static void S9xLoadCheatsFromBMLNode(bml_node &n)
{
unsigned int i;
for (i = 0; i < n->child.size (); i++)
for (auto &c : n.child)
{
if (!strcasecmp (n->child[i].name.c_str(), "cheat"))
{
const char *desc = NULL;
const char *code = NULL;
bool8 enabled = false;
if (strcasecmp(c.name.c_str(), "cheat"))
continue;
bml_node *c = &n->child[i];
bml_node *tmp = NULL;
auto subnode = c.find_subnode("code");
if (!subnode)
continue;
std::string code = subnode->data;
tmp = c->find_subnode("name");
if (!tmp)
desc = (char *) "";
else
desc = tmp->data.c_str();
std::string name;
subnode = c.find_subnode("name");
if (subnode)
name = subnode->data;
tmp = c->find_subnode("code");
if (tmp)
code = tmp->data.c_str();
bool enable = false;
if (c.find_subnode("enable"))
enable = true;
if (c->find_subnode("enable"))
enabled = true;
if (S9xCheatIsDuplicate(name, code))
continue;
if (code && !S9xCheatIsDuplicate (desc, code))
{
int index = S9xAddCheatGroup (desc, code);
if (enabled)
S9xEnableCheatGroup (index);
}
}
auto index = S9xAddCheatGroup(name, code);
if (enable)
S9xEnableCheatGroup(index);
}
return;
}
static bool8 S9xLoadCheatFileClassic (const char *filename)
static bool8 S9xLoadCheatFileClassic(const std::string &filename)
{
FILE *fs;
uint8 data[28];
fs = fopen(filename, "rb");
fs = fopen(filename.c_str(), "rb");
if (!fs)
return (FALSE);
while (fread ((void *) data, 1, 28, fs) == 28)
while (fread(data, 1, 28, fs) == 28)
{
SCheat c;
char name[21];
char cheat[10];
c.enabled = (data[0] & 4) == 0;
c.byte = data[1];
c.address = data[2] | (data[3] << 8) | (data[4] << 16);
memcpy (name, &data[8], 20);
name[20] = 0;
c.address = data[2] | (data[3] << 8) | (data[4] << 16);
snprintf (cheat, 10, "%x=%x", c.address, c.byte);
S9xAddCheatGroup (name, cheat);
std::string name((const char *)&data[8], 20);
char code[32]{};
sprintf(code, "%x=%x", c.address, c.byte);
std::string cheat(code);
S9xAddCheatGroup(name, cheat);
if (c.enabled)
S9xEnableCheatGroup (Cheat.g.size () - 1);
S9xEnableCheatGroup(Cheat.group.size() - 1);
}
fclose(fs);
return (TRUE);
return TRUE;
}
bool8 S9xLoadCheatFile (const char *filename)
bool8 S9xLoadCheatFile(const std::string &filename)
{
bml_node bml;
if (!bml.parse_file(filename))
{
return S9xLoadCheatFileClassic (filename);
return S9xLoadCheatFileClassic(filename);
}
bml_node *n = bml.find_subnode("cheat");
if (n)
{
S9xLoadCheatsFromBMLNode (&bml);
S9xLoadCheatsFromBMLNode(bml);
}
if (!n)
{
return S9xLoadCheatFileClassic (filename);
return S9xLoadCheatFileClassic(filename);
}
return (TRUE);
}
bool8 S9xSaveCheatFile (const char *filename)
bool8 S9xSaveCheatFile(const std::string &filename)
{
unsigned int i;
FILE *file = NULL;
if (Cheat.g.size () == 0)
if (Cheat.group.size() == 0)
{
remove (filename);
remove(filename.c_str());
return TRUE;
}
file = fopen (filename, "w");
file = fopen(filename.c_str(), "w");
if (!file)
return FALSE;
for (i = 0; i < Cheat.g.size (); i++)
for (i = 0; i < Cheat.group.size(); i++)
{
char *txt = S9xCheatGroupToText (i);
fprintf (file,
"cheat\n"
" name: %s\n"
" code: %s\n"
"%s\n",
Cheat.g[i].name ? Cheat.g[i].name : "",
txt,
Cheat.g[i].enabled ? " enable\n" : ""
);
delete[] txt;
fprintf(file,
"cheat\n"
" name: %s\n"
" code: %s\n"
"%s\n",
Cheat.group[i].name.c_str(),
S9xCheatGroupToText(i).c_str(),
Cheat.group[i].enabled ? " enable\n" : "");
}
fclose (file);
fclose(file);
return TRUE;
}
void S9xCheatsDisable (void)
void S9xCheatsDisable(void)
{
unsigned int i;
if (!Cheat.enabled)
return;
for (i = 0; i < Cheat.g.size (); i++)
for (i = 0; i < Cheat.group.size(); i++)
{
if (Cheat.g[i].enabled)
if (Cheat.group[i].enabled)
{
S9xDisableCheatGroup (i);
Cheat.g[i].enabled = TRUE;
S9xDisableCheatGroup(i);
Cheat.group[i].enabled = TRUE;
}
}
Cheat.enabled = FALSE;
}
void S9xCheatsEnable (void)
void S9xCheatsEnable(void)
{
unsigned int i;
@@ -719,17 +738,17 @@ void S9xCheatsEnable (void)
Cheat.enabled = TRUE;
for (i = 0; i < Cheat.g.size (); i++)
for (i = 0; i < Cheat.group.size(); i++)
{
if (Cheat.g[i].enabled)
if (Cheat.group[i].enabled)
{
Cheat.g[i].enabled = FALSE;
S9xEnableCheatGroup (i);
Cheat.group[i].enabled = FALSE;
S9xEnableCheatGroup(i);
}
}
}
int S9xImportCheatsFromDatabase (const char *filename)
int S9xImportCheatsFromDatabase(const std::string &filename)
{
char sha256_txt[65];
char hextable[] = "0123456789abcdef";
@@ -746,19 +765,16 @@ int S9xImportCheatsFromDatabase (const char *filename)
}
sha256_txt[64] = '\0';
for (i = 0; i < bml.child.size (); i++)
for (auto &c : bml.child)
{
if (!strcasecmp (bml.child[i].name.c_str(), "cartridge"))
if (!strcasecmp(c.name.c_str(), "cartridge"))
{
bml_node *n;
auto n = c.find_subnode("sha256");
if ((n = bml.child[i].find_subnode ("sha256")))
if (n && !strcasecmp(n->data.c_str(), sha256_txt))
{
if (!strcasecmp (n->data.c_str(), sha256_txt))
{
S9xLoadCheatsFromBMLNode (&bml.child[i]);
return 0;
}
S9xLoadCheatsFromBMLNode(c);
return 0;
}
}
}
+39 -66
View File
@@ -328,14 +328,12 @@ static void DoGunLatch (int x, int y)
if (x > 295)
x = 295;
else
if (x < 40)
else if (x < 40)
x = 40;
if (y > PPU.ScreenHeight - 1)
y = PPU.ScreenHeight - 1;
else
if (y < 0)
else if (y < 0)
y = 0;
PPU.GunVLatch = (uint16) (y + 1);
@@ -1164,8 +1162,7 @@ s9xcommand_t S9xGetCommandT (const char *name)
if (!strcmp(name, "None"))
cmd.type = S9xNoMapping;
else
if (!strncmp(name, "Joypad", 6))
else if (!strncmp(name, "Joypad", 6))
{
if (name[6] < '1' || name[6] > '8' || name[7] != ' ')
return (cmd);
@@ -1176,24 +1173,15 @@ s9xcommand_t S9xGetCommandT (const char *name)
s = name + 13;
if (!strncmp(s, "Left/Right ", 11)) { j = 0; i = 0; s += 11; }
else
if (!strncmp(s, "Right/Left ", 11)) { j = 0; i = 1; s += 11; }
else
if (!strncmp(s, "Up/Down ", 8)) { j = 1; i = 0; s += 8; }
else
if (!strncmp(s, "Down/Up ", 8)) { j = 1; i = 1; s += 8; }
else
if (!strncmp(s, "Y/A ", 4)) { j = 2; i = 0; s += 4; }
else
if (!strncmp(s, "A/Y ", 4)) { j = 2; i = 1; s += 4; }
else
if (!strncmp(s, "X/B ", 4)) { j = 3; i = 0; s += 4; }
else
if (!strncmp(s, "B/X ", 4)) { j = 3; i = 1; s += 4; }
else
if (!strncmp(s, "L/R ", 4)) { j = 4; i = 0; s += 4; }
else
if (!strncmp(s, "R/L ", 4)) { j = 4; i = 1; s += 4; }
else if (!strncmp(s, "Right/Left ", 11)) { j = 0; i = 1; s += 11; }
else if (!strncmp(s, "Up/Down ", 8)) { j = 1; i = 0; s += 8; }
else if (!strncmp(s, "Down/Up ", 8)) { j = 1; i = 1; s += 8; }
else if (!strncmp(s, "Y/A ", 4)) { j = 2; i = 0; s += 4; }
else if (!strncmp(s, "A/Y ", 4)) { j = 2; i = 1; s += 4; }
else if (!strncmp(s, "X/B ", 4)) { j = 3; i = 0; s += 4; }
else if (!strncmp(s, "B/X ", 4)) { j = 3; i = 1; s += 4; }
else if (!strncmp(s, "L/R ", 4)) { j = 4; i = 0; s += 4; }
else if (!strncmp(s, "R/L ", 4)) { j = 4; i = 1; s += 4; }
else
return (cmd);
@@ -1374,8 +1362,7 @@ s9xcommand_t S9xGetCommandT (const char *name)
if (*s == 'h')
cmd.axis.pointer.HV = 0;
else
if (*s == 'v')
else if (*s == 'v')
cmd.axis.pointer.HV = 1;
else
return (cmd);
@@ -1523,8 +1510,7 @@ s9xcommand_t S9xGetCommandT (const char *name)
j = i;
}
else
if (name[i] == ',')
else if (name[i] == ',')
{
free(c);
return (cmd);
@@ -1537,8 +1523,7 @@ s9xcommand_t S9xGetCommandT (const char *name)
{
if (name[i] == '+')
press = 1;
else
if (name[i] == '-')
else if (name[i] == '-')
press = 2;
else
{
@@ -2007,14 +1992,12 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
uint16 x = r; r = st; st = x;
x = s; s = t; t = x;
}
else
if (cmd.button.joypad.turbo)
else if (cmd.button.joypad.turbo)
{
uint16 x = r; r = t; t = x;
x = s; s = st; st = x;
}
else
if (cmd.button.joypad.sticky)
else if (cmd.button.joypad.sticky)
{
uint16 x = r; r = s; s = x;
x = t; t = st; st = x;
@@ -2276,16 +2259,12 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
case LoadOopsFile:
{
char filename[PATH_MAX + 1];
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
std::string filename = S9xGetFilename("oops", SNAPSHOT_DIR);
_splitpath(Memory.ROMFilename, drive, dir, def, ext);
snprintf(filename, PATH_MAX + 1, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, _MAX_EXT - 1, "oops");
if (S9xUnfreezeGame(filename))
if (S9xUnfreezeGame(filename.c_str()))
{
snprintf(buf, 256, "%s.%.*s loaded", def, _MAX_EXT - 1, "oops");
S9xSetInfoString (buf);
snprintf(buf, 256, "%.240s.oops loaded", S9xBasename(Memory.ROMFilename).c_str());
S9xSetInfoString(buf);
}
else
S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, "Oops file not found");
@@ -2313,15 +2292,15 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
case QuickLoad009:
case QuickLoad010:
{
char filename[PATH_MAX + 1];
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
std::string ext = std::to_string(i - QuickLoad000);
while (ext.length() < 3)
ext = '0' + ext;
_splitpath(Memory.ROMFilename, drive, dir, def, ext);
snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickLoad000);
auto filename = S9xGetFilename(ext, SNAPSHOT_DIR);
if (S9xUnfreezeGame(filename))
if (S9xUnfreezeGame(filename.c_str()))
{
snprintf(buf, 256, "%s.%03d loaded", def, i - QuickLoad000);
snprintf(buf, 256, "Quick save-state %s loaded", ext.c_str());
S9xSetInfoString(buf);
}
else
@@ -2342,16 +2321,16 @@ void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
case QuickSave009:
case QuickSave010:
{
char filename[PATH_MAX + 1];
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
std::string ext = std::to_string(i - QuickLoad000);
while (ext.length() < 3)
ext = '0' + ext;
_splitpath(Memory.ROMFilename, drive, dir, def, ext);
snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickSave000);
auto filename = S9xGetFilename(ext, SNAPSHOT_DIR);
snprintf(buf, 256, "%s.%03d saved", def, i - QuickSave000);
snprintf(buf, 256, "Quick save-state %s saved", ext.c_str());
S9xSetInfoString(buf);
S9xFreezeGame(filename);
S9xFreezeGame(filename.c_str());
break;
}
@@ -2771,14 +2750,12 @@ static void UpdatePolledMouse (int i)
mouse[i - MOUSE0].delta_x = 0xff;
mouse[i - MOUSE0].old_x -= 127;
}
else
if (j < 0)
else if (j < 0)
{
mouse[i - MOUSE0].delta_x = 0x80 | -j;
mouse[i - MOUSE0].old_x = mouse[i - MOUSE0].cur_x;
}
else
if (j > 127)
else if (j > 127)
{
mouse[i - MOUSE0].delta_x = 0x7f;
mouse[i - MOUSE0].old_x += 127;
@@ -2796,14 +2773,12 @@ static void UpdatePolledMouse (int i)
mouse[i - MOUSE0].delta_y = 0xff;
mouse[i - MOUSE0].old_y -= 127;
}
else
if (j < 0)
else if (j < 0)
{
mouse[i - MOUSE0].delta_y = 0x80 | -j;
mouse[i - MOUSE0].old_y = mouse[i - MOUSE0].cur_y;
}
else
if (j > 127)
else if (j > 127)
{
mouse[i - MOUSE0].delta_y = 0x7f;
mouse[i - MOUSE0].old_y += 127;
@@ -3265,8 +3240,7 @@ void S9xControlEOF (void)
pseudopointer[n].x += pseudopointer[n].H_adj;
if (pseudopointer[n].x < 0)
pseudopointer[n].x = 0;
else
if (pseudopointer[n].x > 255)
else if (pseudopointer[n].x > 255)
pseudopointer[n].x = 255;
if (pseudopointer[n].H_var)
@@ -3289,8 +3263,7 @@ void S9xControlEOF (void)
pseudopointer[n].y += pseudopointer[n].V_adj;
if (pseudopointer[n].y < 0)
pseudopointer[n].y = 0;
else
if (pseudopointer[n].y > PPU.ScreenHeight - 1)
else if (pseudopointer[n].y > PPU.ScreenHeight - 1)
pseudopointer[n].y = PPU.ScreenHeight - 1;
if (pseudopointer[n].V_var)
+2 -5
View File
@@ -13,7 +13,6 @@
#include "srtc.h"
#include "snapshot.h"
#include "cheats.h"
#include "logger.h"
#ifdef DEBUGGER
#include "debug.h"
#endif
@@ -76,7 +75,6 @@ static void S9xSoftResetCPU (void)
SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation);
ClearFlags(Decimal);
Timings.InterlaceField = FALSE;
Timings.H_Max = Timings.H_Max_Master;
Timings.V_Max = Timings.V_Max_Master;
Timings.NMITriggerPos = 0xffff;
@@ -99,10 +97,9 @@ static void S9xSoftResetCPU (void)
void S9xReset (void)
{
S9xResetSaveTimer(FALSE);
S9xResetLogger();
memset(Memory.RAM, 0x55, 0x20000);
memset(Memory.VRAM, 0x00, 0x10000);
memset(Memory.RAM, 0x55, sizeof(Memory.RAM));
memset(Memory.VRAM, 0x00, sizeof(Memory.VRAM));
memset(Memory.FillRAM, 0, 0x8000);
S9xResetBSX();
-1
View File
@@ -513,7 +513,6 @@ static inline uint32 StackRelativeIndirectIndexed (AccessMode a) // (d,S),Y
if (a & READ)
OpenBus = (uint8) (addr >> 8);
addr = (addr + Registers.Y.W + ICPU.ShiftedDB) & 0xffffff;
AddCycles(ONE_CYCLE);
return (addr);
}
+9 -11
View File
@@ -132,13 +132,6 @@ void S9xMainLoop (void)
if (CPU.Flags & SCAN_KEYS_FLAG)
{
#ifdef DEBUGGER
if (!(CPU.Flags & FRAME_ADVANCE_FLAG))
#endif
{
S9xSyncSpeed();
}
break;
}
@@ -276,7 +269,6 @@ void S9xDoHEventProcessing (void)
if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1
{
CPU.V_Counter = 0;
Timings.InterlaceField ^= 1;
// From byuu:
// [NTSC]
@@ -285,7 +277,7 @@ void S9xDoHEventProcessing (void)
// [PAL] <PAL info is unverified on hardware>
// interlace mode has 625 scanlines: 313 on the even frame, and 312 on the odd.
// non-interlace mode has 624 scanlines: 312 scanlines on both even and odd frames.
if (IPPU.Interlace && !Timings.InterlaceField)
if (IPPU.Interlace && S9xInterlaceField())
Timings.V_Max = Timings.V_Max_Master + 1; // 263 (NTSC), 313?(PAL)
else
Timings.V_Max = Timings.V_Max_Master; // 262 (NTSC), 312?(PAL)
@@ -306,14 +298,14 @@ void S9xDoHEventProcessing (void)
// In interlace mode, there are always 341 dots per scanline. Even frames have 263 scanlines,
// and odd frames have 262 scanlines.
// Interlace mode scanline 240 on odd frames is not missing a dot.
if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField) // V=240
if (CPU.V_Counter == 240 && !IPPU.Interlace && S9xInterlaceField()) // V=240
Timings.H_Max = Timings.H_Max_Master - ONE_DOT_CYCLE; // HC=1360
else
Timings.H_Max = Timings.H_Max_Master; // HC=1364
if (Model->_5A22 == 2)
{
if (CPU.V_Counter != 240 || IPPU.Interlace || !Timings.InterlaceField) // V=240
if (CPU.V_Counter != 240 || IPPU.Interlace || !S9xInterlaceField()) // V=240
{
if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE) // HC=534
Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; // HC=538
@@ -327,6 +319,12 @@ void S9xDoHEventProcessing (void)
if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240).
{
S9xEndScreenRefresh();
#ifdef DEBUGGER
if (!(CPU.Flags & FRAME_ADVANCE_FLAG))
#endif
{
S9xSyncSpeed();
}
CPU.Flags |= SCAN_KEYS_FLAG;
+15 -7
View File
@@ -1406,11 +1406,13 @@ bOP(70Slow, RelativeSlow, CheckOverflow(), 0, CheckEmulation())
static void Op82 (void)
{
S9xSetPCBase(ICPU.ShiftedPB + RelativeLong(JUMP));
AddCycles(ONE_CYCLE);
}
static void Op82Slow (void)
{
S9xSetPCBase(ICPU.ShiftedPB + RelativeLongSlow(JUMP));
AddCycles(ONE_CYCLE);
}
/* Flag Instructions ******************************************************* */
@@ -2847,6 +2849,7 @@ static void Op22E1 (void)
// Note: JSL is a new instruction,
// and so doesn't respect the emu-mode stack bounds.
uint32 addr = AbsoluteLong(JSR);
AddCycles(ONE_CYCLE);
PushB(Registers.PB);
PushW(Registers.PCw - 1);
Registers.SH = 1;
@@ -2856,6 +2859,7 @@ static void Op22E1 (void)
static void Op22E0 (void)
{
uint32 addr = AbsoluteLong(JSR);
AddCycles(ONE_CYCLE);
PushB(Registers.PB);
PushW(Registers.PCw - 1);
S9xSetPCBase(addr);
@@ -2864,6 +2868,7 @@ static void Op22E0 (void)
static void Op22Slow (void)
{
uint32 addr = AbsoluteLongSlow(JSR);
AddCycles(ONE_CYCLE);
PushB(Registers.PB);
PushW(Registers.PCw - 1);
if (CheckEmulation())
@@ -3381,16 +3386,19 @@ static void Op42 (void)
#endif
case 0x42: // "WDM" = Snapshot
char filename[PATH_MAX + 1], drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[PATH_MAX + 1], ext[_MAX_EXT + 1];
{
char tmp[PATH_MAX + 1];
SplitPath split = splitpath(Memory.ROMFilename);
_splitpath(Memory.ROMFilename, drive, dir, def, ext);
snprintf(filename, PATH_MAX, "%s%s%s-%06X.wdm", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, Registers.PBPC & 0xffffff);
sprintf(def, "WDM Snapshot at $%02X:%04X: %s", Registers.PB, Registers.PCw, filename);
S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, def);
S9xFreezeGame(filename);
snprintf(tmp, PATH_MAX, "%s-%06X", split.stem.c_str(), Registers.PBPC & 0xffffff);
std::string filename = makepath(split.dir, S9xGetDirectory(SNAPSHOT_DIR), tmp, ".wdm");
break;
sprintf(tmp, "WDM Snapshot at $%02X:%04X: %s", Registers.PB, Registers.PCw, filename.c_str());
S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, tmp);
S9xFreezeGame(filename.c_str());
break;
}
default:
break;
}
-22
View File
@@ -9,24 +9,6 @@
#include "snes9x.h"
enum s9x_getdirtype
{
DEFAULT_DIR = 0,
HOME_DIR,
ROMFILENAME_DIR,
ROM_DIR,
SRAM_DIR,
SNAPSHOT_DIR,
SCREENSHOT_DIR,
SPC_DIR,
CHEAT_DIR,
PATCH_DIR,
BIOS_DIR,
LOG_DIR,
SAT_DIR,
LAST_DIR
};
void S9xUsage (void);
char * S9xParseArgs (char **, int);
void S9xParseArgsForCheats (char **, int);
@@ -44,10 +26,6 @@ void S9xToggleSoundChannel (int);
bool8 S9xOpenSnapshotFile (const char *, bool8, STREAM *);
void S9xCloseSnapshotFile (STREAM);
const char * S9xStringInput (const char *);
const char * S9xGetDirectory (enum s9x_getdirtype);
const char * S9xGetFilename (const char *, enum s9x_getdirtype);
const char * S9xGetFilenameInc (const char *, enum s9x_getdirtype);
const char * S9xBasename (const char *);
// Routines the port has to implement if it uses command-line
+29
View File
@@ -1,3 +1,32 @@
Snes9x 1.62
- Fixed SA1 division with negative dividend again. (Atari2)
- Fixed timing on several instructions. (pi1541)
- MSU1 audio with no loop point will not repeat from start.
- Modernized some old memory-related code.
- Fixed a desynchronization in interlaced modes and reporting.
- Remove SA1 access to WRAM.
- Added second set of registers between S-DSP and S-SMP. Fixes
PAL version of Virtual Bart.
Gtk + Windows:
- Added a Vulkan graphics output method. Similar to OpenGL, this
can use libretro's slang shaders.
- Changed the automatic frame skip throttle to take place immediately
before showing the frame, making VRR work better.
- Add menu item to clear recent files entries.
- Add fixed window size changes up to 10x.
Windows:
- Improved the shader parameters dialog with sliders and resize.
- Allow disabling adding registry entries. Deletes any existing
entries when the option is disabled.
Gtk:
- Switched to CMake for build system. Removed meson.
- Fixed some keys not working with modifiers. (Gutawer)
- Removed graphics options most people won't understand or need.
- Improved wayland support. Handle fractional DPI properly.
Snes9x 1.61
- Restructured tile.cpp tile renderer from heavy macros into C++
templates, significantly lowering compile time. (yoffy)
+238
View File
@@ -0,0 +1,238 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
#include <cstring>
#include <string>
#include "display.h"
#include "fscompat.h"
#include "port.h"
#include "memmap.h"
using std::string;
bool SplitPath::ext_is(const string &other)
{
if (strcasecmp(ext.c_str(), other.c_str()) == 0)
return true;
if (other[0] != '.' && (strcasecmp(other.c_str(), &(ext.c_str()[1])) == 0))
return true;
return false;
}
std::string makepath(const SplitPath &path)
{
return makepath(path.drive, path.dir, path.stem, path.ext);
}
std::string S9xGetFilename(string filename, string ext, enum s9x_getdirtype dirtype)
{
auto path = splitpath(filename);
auto dir = S9xGetDirectory(dirtype);
return makepath(path.drive, dir, path.stem, ext);
}
std::string S9xGetFilename(string ext, enum s9x_getdirtype dirtype)
{
return S9xGetFilename(Memory.ROMFilename, ext, dirtype);
}
std::string S9xBasename(std::string filename)
{
auto path = splitpath(filename);
return path.stem + path.ext;
}
std::string S9xBasenameNoExt(std::string filename)
{
return splitpath(filename).stem;
}
#if __cplusplus >= 201703L && 0
#include <filesystem>
namespace fs = std::filesystem;
SplitPath splitpath(string str)
{
SplitPath output{};
fs::path path(str);
if (path.has_root_name())
output.drive = path.root_name().string();
if (path.has_filename())
{
output.stem = path.stem().string();
output.ext = path.extension().string();
path.remove_filename();
}
if (!path.empty())
output.dir = path.string();
return output;
}
string makepath(const string &drive, const string &dir, const string &stem, const string &ext)
{
auto dot_position = ext.find('.');
if (dot_position == string::npos)
{
fs::path path(drive);
path = path / dir / stem;
path.replace_extension(ext);
return path.string();
}
auto filename = stem + ext;
fs::path path(drive);
path = path / dir / filename;
return path.string();
}
#else
constexpr auto npos = std::string::npos;
SplitPath splitpath(string path)
{
SplitPath output{};
#ifdef _WIN32
if (path.length() > 2 && path[1] == ':')
{
output.drive = path.substr(0, 2);
path = path.substr(2);
}
#endif
auto slash = path.rfind(SLASH_CHAR);
auto dot = path.rfind('.');
if (dot != npos && slash != npos && dot < slash)
{
dot = npos;
}
else if (dot != npos)
{
output.ext = path.substr(dot);
}
if (slash != npos)
{
output.dir = path.substr(0, slash + 1);
output.stem = path.substr(slash + 1, dot - slash - 1);
}
else
{
output.stem = path.substr(0, dot);
}
return output;
}
string makepath(const string &drive, const string &dir, const string &stem, const string &ext)
{
string output;
if (!drive.empty())
{
if (!(dir.length() > 2 && dir[1] == ':'))
{
output += drive + ":";
if (!dir.empty() && dir[0] != SLASH_CHAR)
output += SLASH_CHAR;
}
}
if (!dir.empty())
{
output += dir;
if (output[output.length() - 1] != SLASH_CHAR)
output += SLASH_CHAR;
}
if (!stem.empty())
{
output += stem;
}
if (!ext.empty())
{
if (ext.find('.') == string::npos)
output += '.';
output += ext;
}
return output;
}
#ifndef _WIN32
void _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext)
{
char *slash = strrchr((char *)path, SLASH_CHAR);
char *dot = strrchr((char *)path, '.');
*drive = '\0';
if (dot && slash && dot < slash)
{
dot = 0;
}
if (!slash)
{
*dir = '\0';
strcpy(fname, path);
if (dot)
{
fname[dot - path] = '\0';
strcpy(ext, dot + 1);
}
else
{
*ext = '\0';
}
}
else
{
strcpy(dir, path);
dir[slash - path] = '\0';
strcpy(fname, slash + 1);
if (dot)
{
fname[(dot - slash) - 1] = '\0';
strcpy(ext, dot + 1);
}
else
{
*ext = '\0';
}
}
}
void _makepath(char *path, const char *drive, const char *dir, const char *fname, const char *ext)
{
if (dir && *dir)
{
strcpy(path, dir);
strcat(path, "/");
}
else
*path = '\0';
strcat(path, fname);
if (ext && *ext)
{
if (!strchr(ext, '.'))
strcat(path, ".");
strcat(path, ext);
}
}
#endif
#endif
+52
View File
@@ -0,0 +1,52 @@
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
#pragma once
#ifdef __cplusplus
#include <string>
enum s9x_getdirtype
{
DEFAULT_DIR = 0,
HOME_DIR,
ROMFILENAME_DIR,
ROM_DIR,
SRAM_DIR,
SNAPSHOT_DIR,
SCREENSHOT_DIR,
SPC_DIR,
CHEAT_DIR,
PATCH_DIR,
BIOS_DIR,
LOG_DIR,
SAT_DIR,
LAST_DIR
};
struct SplitPath
{
bool ext_is(const std::string &ext);
std::string drive;
std::string dir;
std::string stem;
std::string ext;
};
SplitPath splitpath(std::string filename);
std::string makepath(const std::string &drive,
const std::string &directory,
const std::string &stem,
const std::string &extension);
std::string makepath(const SplitPath &);
std::string S9xBasename (std::string);
std::string S9xBasenameNoExt (std::string);
std::string S9xGetFilename (std::string ext, enum s9x_getdirtype dirtype);
std::string S9xGetFilename (std::string filename, std::string ext, enum s9x_getdirtype dirtype);
std::string S9xGetDirectory (enum s9x_getdirtype);
std::string S9xGetFilenameInc (std::string, enum s9x_getdirtype);
#endif
+1 -1
View File
@@ -196,7 +196,7 @@ static void FxReset (struct FxInfo_s *psFxInfo)
else
{
b %= GSU.nRomBanks * 2;
GSU.apvRomBank[i] = &GSU.pvRom[(b << 16) + 0x200000];
GSU.apvRomBank[i] = &GSU.pvRom[(b << 16) + 0x800000];
}
}
+44 -82
View File
@@ -49,15 +49,14 @@ bool8 S9xGraphicsInit (void)
S9xInitTileRenderer();
memset(BlackColourMap, 0, 256 * sizeof(uint16));
GFX.RealPPL = GFX.Pitch >> 1;
IPPU.OBJChanged = TRUE;
Settings.BG_Forced = 0;
S9xFixColourBrightness();
S9xBuildDirectColourMaps();
GFX.ScreenBuffer.resize(MAX_SNES_WIDTH * (MAX_SNES_HEIGHT + 64));
GFX.Screen = &GFX.ScreenBuffer[GFX.RealPPL * 32];
GFX.ZERO = (uint16 *) malloc(sizeof(uint16) * 0x10000);
GFX.ScreenSize = GFX.Pitch / 2 * SNES_HEIGHT_EXTENDED * (Settings.SupportHiRes ? 2 : 1);
GFX.SubScreen = (uint16 *) malloc(GFX.ScreenSize * sizeof(uint16));
GFX.ZBuffer = (uint8 *) malloc(GFX.ScreenSize);
GFX.SubZBuffer = (uint8 *) malloc(GFX.ScreenSize);
@@ -118,27 +117,19 @@ void S9xGraphicsScreenResize (void)
IPPU.Interlace = Memory.FillRAM[0x2133] & 1;
IPPU.InterlaceOBJ = Memory.FillRAM[0x2133] & 2;
IPPU.PseudoHires = Memory.FillRAM[0x2133] & 8;
if (Settings.SupportHiRes && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires))
if (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires)
{
GFX.RealPPL = GFX.Pitch >> 1;
IPPU.DoubleWidthPixels = TRUE;
IPPU.RenderedScreenWidth = SNES_WIDTH << 1;
}
else
{
#ifdef USE_OPENGL
if (Settings.OpenGLEnable)
GFX.RealPPL = SNES_WIDTH;
else
#endif
GFX.RealPPL = GFX.Pitch >> 1;
IPPU.DoubleWidthPixels = FALSE;
IPPU.RenderedScreenWidth = SNES_WIDTH;
}
if (Settings.SupportHiRes && IPPU.Interlace)
if (IPPU.Interlace)
{
GFX.PPL = GFX.RealPPL << 1;
IPPU.DoubleHeightPixels = TRUE;
@@ -150,7 +141,7 @@ void S9xGraphicsScreenResize (void)
GFX.PPL = GFX.RealPPL;
IPPU.DoubleHeightPixels = FALSE;
IPPU.RenderedScreenHeight = PPU.ScreenHeight;
}
}
}
void S9xBuildDirectColourMaps (void)
@@ -164,13 +155,12 @@ void S9xBuildDirectColourMaps (void)
void S9xStartScreenRefresh (void)
{
GFX.InterlaceFrame = !GFX.InterlaceFrame;
if (GFX.DoInterlace)
GFX.DoInterlace--;
if (IPPU.RenderThisFrame)
{
if (!GFX.DoInterlace || !GFX.InterlaceFrame)
if (!GFX.DoInterlace || !S9xInterlaceField())
{
if (!S9xInitUpdate())
{
@@ -199,7 +189,7 @@ void S9xStartScreenRefresh (void)
}
if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0)
GFX.InfoString = NULL;
GFX.InfoString.clear();
IPPU.TotalEmulatedFrames++;
}
@@ -210,7 +200,7 @@ void S9xEndScreenRefresh (void)
{
FLUSH_REDRAW();
if (GFX.DoInterlace && GFX.InterlaceFrame == 0)
if (GFX.DoInterlace && S9xInterlaceField() == 0)
{
S9xControlEOF();
S9xContinueUpdate(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight);
@@ -324,7 +314,7 @@ static inline void RenderScreen (bool8 sub)
if (!sub)
{
GFX.S = GFX.Screen;
if (GFX.DoInterlace && GFX.InterlaceFrame)
if (GFX.DoInterlace && S9xInterlaceField())
GFX.S += GFX.RealPPL;
GFX.DB = GFX.ZBuffer;
GFX.Clip = IPPU.Clip[0];
@@ -467,55 +457,31 @@ void S9xUpdateScreen (void)
PPU.RecomputeClipWindows = FALSE;
}
if (Settings.SupportHiRes)
if (!IPPU.DoubleWidthPixels && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires))
{
if (!IPPU.DoubleWidthPixels && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires))
// Have to back out of the regular speed hack
for (uint32 y = 0; y < GFX.StartY; y++)
{
#ifdef USE_OPENGL
if (Settings.OpenGLEnable && GFX.RealPPL == 256)
{
// Have to back out of the speed up hack where the low res.
// SNES image was rendered into a 256x239 sized buffer,
// ignoring the true, larger size of the buffer.
GFX.RealPPL = GFX.Pitch >> 1;
uint16 *p = GFX.Screen + y * GFX.PPL + 255;
uint16 *q = GFX.Screen + y * GFX.PPL + 510;
for (int32 y = (int32) GFX.StartY - 1; y >= 0; y--)
{
uint16 *p = GFX.Screen + y * GFX.PPL + 255;
uint16 *q = GFX.Screen + y * GFX.RealPPL + 510;
for (int x = 255; x >= 0; x--, p--, q -= 2)
*q = *(q + 1) = *p;
}
GFX.PPL = GFX.RealPPL; // = GFX.Pitch >> 1 above
}
else
#endif
// Have to back out of the regular speed hack
for (uint32 y = 0; y < GFX.StartY; y++)
{
uint16 *p = GFX.Screen + y * GFX.PPL + 255;
uint16 *q = GFX.Screen + y * GFX.PPL + 510;
for (int x = 255; x >= 0; x--, p--, q -= 2)
*q = *(q + 1) = *p;
}
IPPU.DoubleWidthPixels = TRUE;
IPPU.RenderedScreenWidth = 512;
for (int x = 255; x >= 0; x--, p--, q -= 2)
*q = *(q + 1) = *p;
}
if (!IPPU.DoubleHeightPixels && IPPU.Interlace && (PPU.BGMode == 5 || PPU.BGMode == 6))
{
IPPU.DoubleHeightPixels = TRUE;
IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
GFX.PPL = GFX.RealPPL << 1;
GFX.DoInterlace = 2;
IPPU.DoubleWidthPixels = TRUE;
IPPU.RenderedScreenWidth = 512;
}
for (int32 y = (int32) GFX.StartY - 2; y >= 0; y--)
memmove(GFX.Screen + (y + 1) * GFX.PPL, GFX.Screen + y * GFX.RealPPL, GFX.PPL * sizeof(uint16));
}
if (!IPPU.DoubleHeightPixels && IPPU.Interlace && (PPU.BGMode == 5 || PPU.BGMode == 6))
{
IPPU.DoubleHeightPixels = TRUE;
IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
GFX.PPL = GFX.RealPPL << 1;
GFX.DoInterlace = 2;
for (int32 y = (int32) GFX.StartY - 2; y >= 0; y--)
memmove(GFX.Screen + (y + 1) * GFX.PPL, GFX.Screen + y * GFX.RealPPL, GFX.PPL * sizeof(uint16));
}
if ((Memory.FillRAM[0x2130] & 0x30) != 0x30 && (Memory.FillRAM[0x2131] & 0x3f))
@@ -534,7 +500,7 @@ void S9xUpdateScreen (void)
const uint16 black = BUILD_PIXEL(0, 0, 0);
GFX.S = GFX.Screen + GFX.StartY * GFX.PPL;
if (GFX.DoInterlace && GFX.InterlaceFrame)
if (GFX.DoInterlace && S9xInterlaceField())
GFX.S += GFX.RealPPL;
for (uint32 l = GFX.StartY; l <= GFX.EndY; l++, GFX.S += GFX.PPL)
@@ -595,7 +561,7 @@ static void SetupOBJ (void)
int inc = IPPU.InterlaceOBJ ? 2 : 1;
int startline = (IPPU.InterlaceOBJ && GFX.InterlaceFrame) ? 1 : 0;
int startline = (IPPU.InterlaceOBJ && S9xInterlaceField()) ? 1 : 0;
// OK, we have three cases here. Either there's no priority, priority is
// normal FirstSprite, or priority is FirstSprite+Y. The first two are
@@ -642,8 +608,7 @@ static void SetupOBJ (void)
{
if (HPos < 0)
GFX.OBJVisibleTiles[S] = (GFX.OBJWidths[S] + HPos + 7) >> 3;
else
if (HPos + GFX.OBJWidths[S] > 255)
else if (HPos + GFX.OBJWidths[S] > 255)
GFX.OBJVisibleTiles[S] = (256 - HPos + 7) >> 3;
else
GFX.OBJVisibleTiles[S] = GFX.OBJWidths[S] >> 3;
@@ -714,8 +679,7 @@ static void SetupOBJ (void)
{
if (HPos < 0)
GFX.OBJVisibleTiles[S] = (GFX.OBJWidths[S] + HPos + 7) >> 3;
else
if (HPos + GFX.OBJWidths[S] >= 257)
else if (HPos + GFX.OBJWidths[S] >= 257)
GFX.OBJVisibleTiles[S] = (257 - HPos + 7) >> 3;
else
GFX.OBJVisibleTiles[S] = GFX.OBJWidths[S] >> 3;
@@ -792,10 +756,10 @@ static void DrawOBJS (int D)
void (*DrawClippedTile) (uint32, uint32, uint32, uint32, uint32, uint32) = NULL;
int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1;
BG.InterlaceLine = GFX.InterlaceFrame ? 8 : 0;
BG.InterlaceLine = S9xInterlaceField() ? 8 : 0;
GFX.Z1 = 2;
int sprite_limit = (Settings.MaxSpriteTilesPerLine == 128) ? 128 : 32;
for (uint32 Y = GFX.StartY, Offset = Y * GFX.PPL; Y <= GFX.EndY; Y++, Offset += GFX.PPL)
{
int I = 0;
@@ -927,7 +891,7 @@ static void DrawBackground (int bg, uint8 Zh, uint8 Zl)
for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
{
uint32 Y2 = HiresInterlace ? Y * 2 + GFX.InterlaceFrame : Y;
uint32 Y2 = HiresInterlace ? Y * 2 + S9xInterlaceField() : Y;
uint32 VOffset = LineData[Y].BG[bg].VOffset + (HiresInterlace ? 1 : 0);
uint32 HOffset = LineData[Y].BG[bg].HOffset;
int VirtAlign = ((Y2 + VOffset) & 7) >> (HiresInterlace ? 1 : 0);
@@ -1321,7 +1285,7 @@ static void DrawBackgroundOffset (int bg, uint8 Zh, uint8 Zl, int VOffOff)
for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
{
uint32 Y2 = HiresInterlace ? Y * 2 + GFX.InterlaceFrame : Y;
uint32 Y2 = HiresInterlace ? Y * 2 + S9xInterlaceField() : Y;
uint32 VOff = LineData[Y].BG[2].VOffset - 1;
uint32 HOff = LineData[Y].BG[2].HOffset;
uint32 HOffsetRow = VOff >> Offset2Shift;
@@ -1843,7 +1807,7 @@ static void S9xDisplayStringType (const char *string, int linesFromBottom, int p
static void DisplayTime (void)
{
char string[10];
time_t rawtime;
struct tm *timeinfo;
@@ -2016,7 +1980,7 @@ static void DisplayWatchedAddresses (void)
break;
int32 displayNumber = 0;
char buf[32];
char buf[64];
for (int r = 0; r < watches[i].size; r++)
displayNumber += (Cheat.CWatchRAM[(watches[i].address - 0x7E0000) + r]) << (8 * r);
@@ -2030,11 +1994,9 @@ static void DisplayWatchedAddresses (void)
{
if (watches[i].size == 1)
displayNumber = (int32) ((int8) displayNumber);
else
if (watches[i].size == 2)
else if (watches[i].size == 2)
displayNumber = (int32) ((int16) displayNumber);
else
if (watches[i].size == 3)
else if (watches[i].size == 3)
if (displayNumber >= 8388608)
displayNumber -= 16777216;
@@ -2049,7 +2011,7 @@ void S9xDisplayMessages (uint16 *screen, int ppl, int width, int height, int sca
{
if (Settings.DisplayTime)
DisplayTime();
if (Settings.DisplayFrameRate)
DisplayFrameRate();
@@ -2062,8 +2024,8 @@ void S9xDisplayMessages (uint16 *screen, int ppl, int width, int height, int sca
if (Settings.DisplayMovieFrame && S9xMovieActive())
S9xDisplayString(GFX.FrameDisplayString, 1, 1, false);
if (GFX.InfoString && *GFX.InfoString)
S9xDisplayString(GFX.InfoString, 5, 1, true);
if (!GFX.InfoString.empty())
S9xDisplayString(GFX.InfoString.c_str(), 5, 1, true);
}
static uint16 get_crosshair_color (uint8 color)
+6 -5
View File
@@ -8,19 +8,21 @@
#define _GFX_H_
#include "port.h"
#include <vector>
struct SGFX
{
const uint32 Pitch = sizeof(uint16) * MAX_SNES_WIDTH;
const uint32 RealPPL = MAX_SNES_WIDTH; // true PPL of Screen buffer
const uint32 ScreenSize = MAX_SNES_WIDTH * MAX_SNES_HEIGHT;
std::vector<uint16> ScreenBuffer;
uint16 *Screen;
uint16 *SubScreen;
uint8 *ZBuffer;
uint8 *SubZBuffer;
uint32 Pitch;
uint32 ScreenSize;
uint16 *S;
uint8 *DB;
uint16 *ZERO;
uint32 RealPPL; // true PPL of Screen buffer
uint32 PPL; // number of pixels on each of Screen buffer
uint32 LinesPerTile; // number of lines in 1 tile (4 or 8 due to interlace)
uint16 *ScreenColors; // screen colors for rendering main
@@ -29,7 +31,6 @@ struct SGFX
uint8 Z2; // depth to save
uint32 FixedColour;
uint8 DoInterlace;
uint8 InterlaceFrame;
uint32 StartY;
uint32 EndY;
bool8 ClipColors;
@@ -63,7 +64,7 @@ struct SGFX
void (*DrawMode7BG2Math) (uint32, uint32, int);
void (*DrawMode7BG2Nomath) (uint32, uint32, int);
const char *InfoString;
std::string InfoString;
uint32 InfoStringTimeout;
char FrameDisplayString[256];
};
+339 -910
View File
File diff suppressed because it is too large Load Diff
+18 -10
View File
@@ -12,10 +12,13 @@
#define MEMMAP_SHIFT (12)
#define MEMMAP_MASK (MEMMAP_BLOCK_SIZE - 1)
#include <string>
#include <vector>
struct CMemory
{
enum
{ MAX_ROM_SIZE = 0x800000 };
{ MAX_ROM_SIZE = 0xC00000 };
enum file_formats
{ FILE_ZIP, FILE_JMA, FILE_DEFAULT };
@@ -53,10 +56,13 @@ struct CMemory
uint8 NSRTHeader[32];
int32 HeaderCount;
uint8 *RAM;
uint8 *ROM;
uint8 RAM[0x20000];
std::vector<uint8_t> ROMStorage;
uint8 *ROM;
std::vector<uint8_t> SRAMStorage;
uint8 *SRAM;
uint8 *VRAM;
const size_t SRAM_SIZE = 0x80000;
uint8 VRAM[0x10000];
uint8 *FillRAM;
uint8 *BWRAM;
uint8 *C4RAM;
@@ -70,9 +76,8 @@ struct CMemory
uint8 BlockIsROM[MEMMAP_NUM_BLOCKS];
uint8 ExtendedFormat;
char ROMFilename[PATH_MAX + 1];
std::string ROMFilename;
char ROMName[ROM_NAME_LEN];
char RawROMName[ROM_NAME_LEN];
char ROMId[5];
int32 CompanyId;
uint8 ROMRegion;
@@ -103,8 +108,7 @@ struct CMemory
int First512BytesCountZeroes() const;
uint32 HeaderRemove (uint32, uint8 *);
uint32 FileLoader (uint8 *, const char *, uint32);
uint32 MemLoader (uint8 *, const char*, uint32);
bool8 LoadROMMem (const uint8 *, uint32);
bool8 LoadROMMem (const uint8 *, uint32, const char* optional_rom_filename = NULL);
bool8 LoadROM (const char *);
bool8 LoadROMInt (int32);
bool8 LoadMultiCartMem (const uint8 *, uint32, const uint8 *, uint32, const uint8 *, uint32);
@@ -120,8 +124,6 @@ struct CMemory
bool8 SaveSRTC (void);
bool8 SaveMPAK (const char *);
char * Safe (const char *);
char * SafeANK (const char *);
void ParseSNESHeader (uint8 *);
void InitROM (void);
@@ -170,6 +172,7 @@ struct CMemory
bool8 match_nc (const char *);
bool8 match_id (const char *);
void ApplyROMFixes (void);
std::string SafeString(std::string s, bool allow_jis = false);
void CheckForAnyPatch (const char *, bool8, int32 &);
void MakeRomInfoText (char *);
@@ -197,6 +200,11 @@ struct SMulti
extern CMemory Memory;
extern SMulti Multi;
inline bool S9xInterlaceField()
{
return (Memory.FillRAM[0x213F] & 0x80) >> 7;
}
void S9xAutoSaveSRAM (void);
bool8 LoadZip(const char *, uint32 *, uint8 *);
-1
View File
@@ -740,7 +740,6 @@ int S9xMovieCreate (const char *filename, uint8 controllers_mask, uint8 opts, co
}
Movie.ROMCRC32 = Memory.ROMCRC32;
strncpy(Movie.ROMName, Memory.RawROMName, 23);
write_movie_extrarominfo(fd, &Movie);
+20 -16
View File
@@ -57,27 +57,27 @@ static int unzFindExtension(unzFile &file, const char *ext, bool restart = TRUE,
STREAM S9xMSU1OpenFile(const char *msu_ext, bool skip_unpacked)
{
const char *filename = S9xGetFilename(msu_ext, ROMFILENAME_DIR);
auto filename = S9xGetFilename(msu_ext, ROMFILENAME_DIR);
STREAM file = 0;
if (!skip_unpacked)
{
file = OPEN_STREAM(filename, "rb");
file = OPEN_STREAM(filename.c_str(), "rb");
if (file)
printf("Using msu file %s.\n", filename);
printf("Using msu file %s.\n", filename.c_str());
}
#ifdef UNZIP_SUPPORT
// look for msu1 pack file in the rom or patch dir if msu data file not found in rom dir
if (!file)
{
const char *zip_filename = S9xGetFilename(".msu1", ROMFILENAME_DIR);
unzFile unzFile = unzOpen(zip_filename);
auto zip_filename = S9xGetFilename(".msu1", ROMFILENAME_DIR);
unzFile unzFile = unzOpen(zip_filename.c_str());
if (!unzFile)
{
zip_filename = S9xGetFilename(".msu1", PATCH_DIR);
unzFile = unzOpen(zip_filename);
unzFile = unzOpen(zip_filename.c_str());
}
if (unzFile)
@@ -85,7 +85,6 @@ STREAM S9xMSU1OpenFile(const char *msu_ext, bool skip_unpacked)
int port = unzFindExtension(unzFile, msu_ext, true, true, true);
if (port == UNZ_OK)
{
printf(" in %s.\n", zip_filename);
file = new unzStream(unzFile);
}
else
@@ -112,10 +111,9 @@ static bool AudioOpen()
AudioClose();
char ext[_MAX_EXT];
snprintf(ext, _MAX_EXT, "-%d.pcm", MSU1.MSU1_CURRENT_TRACK);
std::string extension = "-" + std::to_string(MSU1.MSU1_CURRENT_TRACK) + ".pcm";
audioStream = S9xMSU1OpenFile(ext);
audioStream = S9xMSU1OpenFile(extension.c_str());
if (audioStream)
{
if (GETC_STREAM(audioStream) != 'M')
@@ -207,15 +205,14 @@ bool S9xMSU1ROMExists(void)
return true;
}
#ifdef UNZIP_SUPPORT
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
_splitpath(Memory.ROMFilename, drive, dir, def, ext);
if (!strcasecmp(ext, ".msu1"))
if (splitpath(Memory.ROMFilename).ext_is(".msu1"))
return true;
unzFile unzFile = unzOpen(S9xGetFilename(".msu1", ROMFILENAME_DIR));
unzFile unzFile = unzOpen(S9xGetFilename(".msu1", ROMFILENAME_DIR).c_str());
if(!unzFile)
unzFile = unzOpen(S9xGetFilename(".msu1", PATCH_DIR));
unzFile = unzOpen(S9xGetFilename(".msu1", PATCH_DIR).c_str());
if (unzFile)
{
@@ -253,7 +250,14 @@ void S9xMSU1Generate(size_t sample_count)
{
if (MSU1.MSU1_STATUS & AudioRepeating)
{
MSU1.MSU1_AUDIO_POS = audioLoopPos;
if (audioLoopPos < MSU1.MSU1_AUDIO_POS)
{
MSU1.MSU1_AUDIO_POS = audioLoopPos;
}
else // if the loop point is invalid, revert to start
{
MSU1.MSU1_AUDIO_POS = 8;
}
REVERT_STREAM(audioStream, MSU1.MSU1_AUDIO_POS, 0);
}
else
+1 -1
View File
@@ -647,7 +647,7 @@ bool8 S9xNPGetROMImage (uint32 len)
S9xNPSetAction ("Receiving ROM filename...");
uint32 filename_len = len - Memory.CalculatedSize - 5;
if (filename_len > PATH_MAX ||
!S9xNPGetData (NetPlay.Socket, (uint8 *) Memory.ROMFilename, filename_len))
!S9xNPGetData (NetPlay.Socket, (uint8 *) Memory.ROMFilename.c_str(), filename_len))
{
S9xNPSetError ("Error while receiving ROM filename from server.");
S9xNPDisconnect ();
+4 -13
View File
@@ -99,11 +99,7 @@ __extension__
#endif
typedef long long int64;
typedef unsigned long long uint64;
#ifdef PTR_NOT_INT
typedef size_t pint;
#else // __PTR_NOT_INT
typedef size_t pint;
#endif // __PTR_NOT_INT
#endif // __WIN32__
#endif // HAVE_STDINT_H
#endif // snes9x_types_defined
@@ -120,22 +116,17 @@ typedef size_t pint;
#ifndef __WIN32__
#ifndef PATH_MAX
#define PATH_MAX 1024
#define PATH_MAX 1024
#endif
#define _MAX_DRIVE 1
#define _MAX_DIR PATH_MAX
#define _MAX_FNAME PATH_MAX
#define _MAX_EXT PATH_MAX
#define _MAX_PATH PATH_MAX
#else
#ifndef PATH_MAX
#define PATH_MAX _MAX_PATH
#define PATH_MAX _MAX_PATH
#endif
#endif
#include "fscompat.h"
#ifndef __WIN32__
void _splitpath (const char *, char *, char *, char *, char *);
void _makepath (char *, const char *, const char *, const char *, const char *);
#define S9xDisplayString DisplayStringFromBottom
#else // __WIN32__
#define snprintf _snprintf
+5 -6
View File
@@ -94,7 +94,7 @@ static int CyclesUntilNext (int hc, int vc)
// Add number of lines
total += (vc - vpos) * Timings.H_Max_Master;
// If line 240 is in there and we're odd, subtract a dot
if (vpos <= 240 && vc > 240 && Timings.InterlaceField & !IPPU.Interlace)
if (vpos <= 240 && vc > 240 && S9xInterlaceField() & !IPPU.Interlace)
total -= ONE_DOT_CYCLE;
}
else
@@ -105,11 +105,11 @@ static int CyclesUntilNext (int hc, int vc)
}
total += (Timings.V_Max - vpos) * Timings.H_Max_Master;
if (vpos <= 240 && Timings.InterlaceField && !IPPU.Interlace)
if (vpos <= 240 && S9xInterlaceField() && !IPPU.Interlace)
total -= ONE_DOT_CYCLE;
total += (vc) * Timings.H_Max_Master;
if (vc > 240 && !Timings.InterlaceField && !IPPU.Interlace)
if (vc > 240 && !S9xInterlaceField() && !IPPU.Interlace)
total -= ONE_DOT_CYCLE;
}
@@ -146,7 +146,7 @@ void S9xUpdateIRQPositions (bool initial)
}
// Check for short dot scanline
if (v_pos == 240 && Timings.InterlaceField && !IPPU.Interlace)
if (v_pos == 240 && S9xInterlaceField() && !IPPU.Interlace)
{
Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 322 ? ONE_DOT_CYCLE / 2 : 0;
Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 326 ? ONE_DOT_CYCLE / 2 : 0;
@@ -164,7 +164,7 @@ void S9xUpdateIRQPositions (bool initial)
Timings.NextIRQTimer = CyclesUntilNext (PPU.HTimerPosition, PPU.VTimerPosition);
// Check for short dot scanline
int field = Timings.InterlaceField;
int field = S9xInterlaceField();
if (PPU.VTimerPosition < CPU.V_Counter ||
(PPU.VTimerPosition == CPU.V_Counter && Timings.NextIRQTimer > Timings.H_Max))
@@ -1894,7 +1894,6 @@ void S9xSoftResetPPU (void)
memset(IPPU.TileCached[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES);
memset(IPPU.TileCached[TILE_4BIT_ODD], 0, MAX_4BIT_TILES);
PPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better?
GFX.InterlaceFrame = 0;
GFX.DoInterlace = 0;
IPPU.Interlace = FALSE;
IPPU.InterlaceOBJ = FALSE;
+3 -2
View File
@@ -563,8 +563,9 @@ void S9xSetSA1 (uint8 byte, uint32 address)
{
int16 dividend = (int16) SA1.op1;
uint16 divisor = (uint16) SA1.op2;
uint16 remainder = (dividend >= 0) ? dividend % divisor : (dividend % divisor) + divisor;
uint16 quotient = (dividend - remainder) / divisor;
uint32 dividend_ext = dividend + (uint32)divisor * 65536;
uint16 remainder = dividend_ext % divisor;
uint16 quotient = dividend_ext / divisor;
SA1.sum = (remainder << 16) | quotient;
}
+9 -12
View File
@@ -23,11 +23,10 @@ bool8 S9xDoScreenshot (int width, int height)
png_infop info_ptr;
png_color_8 sig_bit;
int imgwidth, imgheight;
const char *fname;
fname = S9xGetFilenameInc(".png", SCREENSHOT_DIR);
std::string fname = S9xGetFilenameInc(".png", SCREENSHOT_DIR);
fp = fopen(fname, "wb");
fp = fopen(fname.c_str(), "wb");
if (!fp)
{
S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
@@ -38,7 +37,7 @@ bool8 S9xDoScreenshot (int width, int height)
if (!png_ptr)
{
fclose(fp);
remove(fname);
remove(fname.c_str());
S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
return (FALSE);
}
@@ -48,7 +47,7 @@ bool8 S9xDoScreenshot (int width, int height)
{
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
fclose(fp);
remove(fname);
remove(fname.c_str());
S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
return (FALSE);
}
@@ -57,7 +56,7 @@ bool8 S9xDoScreenshot (int width, int height)
{
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
remove(fname);
remove(fname.c_str());
S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
return (FALSE);
}
@@ -70,8 +69,7 @@ bool8 S9xDoScreenshot (int width, int height)
if (width > SNES_WIDTH && height <= SNES_HEIGHT_EXTENDED)
imgheight = height << 1;
}
else
if (Settings.StretchScreenshots == 2)
else if (Settings.StretchScreenshots == 2)
{
if (width <= SNES_WIDTH)
imgwidth = width << 1;
@@ -130,11 +128,10 @@ bool8 S9xDoScreenshot (int width, int height)
fclose(fp);
fprintf(stderr, "%s saved.\n", fname);
fprintf(stderr, "%s saved.\n", fname.c_str());
const char *base = S9xBasename(fname);
sprintf(String, "Saved screenshot %s", base);
S9xMessage(S9X_INFO, 0, String);
std::string base = "Saved screenshot " + S9xBasename(fname);
S9xMessage(S9X_INFO, 0, base.c_str());
return (TRUE);
#else
+3 -3
View File
@@ -960,7 +960,7 @@ bool8 S9xNPSendROMImageToClient (int c)
uint8 header [7 + 1 + 4];
uint8 *ptr = header;
int len = sizeof (header) + Memory.CalculatedSize +
strlen (Memory.ROMFilename) + 1;
Memory.ROMFilename.length() + 1;
*ptr++ = NP_SERV_MAGIC;
*ptr++ = NPServer.Clients [c].SendSequenceNum++;
*ptr++ = NP_SERV_ROM_IMAGE;
@@ -972,8 +972,8 @@ bool8 S9xNPSendROMImageToClient (int c)
if (!S9xNPSSendData (NPServer.Clients [c].Socket, header, sizeof (header)) ||
!S9xNPSSendData (NPServer.Clients [c].Socket, Memory.ROM,
Memory.CalculatedSize) ||
!S9xNPSSendData (NPServer.Clients [c].Socket, (uint8 *) Memory.ROMFilename,
strlen (Memory.ROMFilename) + 1))
!S9xNPSSendData (NPServer.Clients [c].Socket, (uint8 *) Memory.ROMFilename.c_str(),
Memory.ROMFilename.length() + 1))
{
S9xNPShutdownClient (c, TRUE);
return (FALSE);
+66 -47
View File
@@ -48,7 +48,7 @@ enum
};
#define COUNT(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0]))
#define Offset(field, structure) ((int) (((char *) (&(((structure) NULL)->field))) - ((char *) NULL)))
#define Offset(field, structure) ((int) (((char *) (&(((structure) 1)->field))) - ((char *) 1)))
#define OFFSET(f) Offset(f, STRUCT *)
#define DUMMY(f) Offset(f, struct Obsolete *)
#define DELETED(f) (-1)
@@ -1009,13 +1009,9 @@ void S9xResetSaveTimer (bool8 dontsave)
if (!Settings.DontSaveOopsSnapshot && !dontsave && t != -1 && time(NULL) - t > 300)
{
char filename[PATH_MAX + 1];
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
_splitpath(Memory.ROMFilename, drive, dir, def, ext);
snprintf(filename, PATH_MAX + 1, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, _MAX_EXT - 1, "oops");
auto filename = S9xGetFilename("oops", SNAPSHOT_DIR);
S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, SAVE_INFO_OOPS);
S9xFreezeGame(filename);
S9xFreezeGame(filename.c_str());
}
t = time(NULL);
@@ -1047,11 +1043,11 @@ bool8 S9xFreezeGame (const char *filename)
S9xResetSaveTimer(TRUE);
const char *base = S9xBasename(filename);
auto base = S9xBasename(filename);
if (S9xMovieActive())
sprintf(String, MOVIE_INFO_SNAPSHOT " %s", base);
sprintf(String, MOVIE_INFO_SNAPSHOT " %s", base.c_str());
else
sprintf(String, SAVE_INFO_SNAPSHOT " %s", base);
sprintf(String, SAVE_INFO_SNAPSHOT " %s", base.c_str());
S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String);
@@ -1104,12 +1100,10 @@ void S9xMessageFromResult(int result, const char* base)
bool8 S9xUnfreezeGame (const char *filename)
{
STREAM stream = NULL;
char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];
const char *base = S9xBasename(filename);
_splitpath(filename, drive, dir, def, ext);
S9xResetSaveTimer(!strcmp(ext, "oops") || !strcmp(ext, "oop") || !strcmp(ext, ".oops") || !strcmp(ext, ".oop"));
auto base = S9xBasename(filename);
auto path = splitpath(filename);
S9xResetSaveTimer(path.ext_is(".oops") || path.ext_is(".oop"));
if (S9xOpenSnapshotFile(filename, TRUE, &stream))
{
@@ -1120,26 +1114,26 @@ bool8 S9xUnfreezeGame (const char *filename)
if (result != SUCCESS)
{
S9xMessageFromResult(result, base);
S9xMessageFromResult(result, base.c_str());
return (FALSE);
}
if (S9xMovieActive())
{
if (S9xMovieReadOnly())
sprintf(String, MOVIE_INFO_REWIND " %s", base);
sprintf(String, MOVIE_INFO_REWIND " %s", base.c_str());
else
sprintf(String, MOVIE_INFO_RERECORD " %s", base);
sprintf(String, MOVIE_INFO_RERECORD " %s", base.c_str());
}
else
sprintf(String, SAVE_INFO_LOAD " %s", base);
sprintf(String, SAVE_INFO_LOAD " %s", base.c_str());
S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String);
return (TRUE);
}
sprintf(String, SAVE_ERR_SAVE_NOT_FOUND, base);
sprintf(String, SAVE_ERR_SAVE_NOT_FOUND, base.c_str());
S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String);
return (FALSE);
@@ -1149,7 +1143,7 @@ bool8 S9xUnfreezeScreenshot(const char *filename, uint16 **image_buffer, int &wi
{
STREAM stream = NULL;
const char *base = S9xBasename(filename);
auto base = S9xBasename(filename);
if(S9xOpenSnapshotFile(filename, TRUE, &stream))
{
@@ -1160,14 +1154,14 @@ bool8 S9xUnfreezeScreenshot(const char *filename, uint16 **image_buffer, int &wi
if(result != SUCCESS)
{
S9xMessageFromResult(result, base);
S9xMessageFromResult(result, base.c_str());
return (FALSE);
}
return (TRUE);
}
sprintf(String, SAVE_ERR_SAVE_NOT_FOUND, base);
sprintf(String, SAVE_ERR_SAVE_NOT_FOUND, base.c_str());
S9xMessage(S9X_INFO, S9X_FREEZE_FILE_INFO, String);
return (FALSE);
@@ -1181,7 +1175,7 @@ void S9xFreezeToStream (STREAM stream)
sprintf(buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
WRITE_STREAM(buffer, strlen(buffer), stream);
sprintf(buffer, "NAM:%06d:%s%c", (int) strlen(Memory.ROMFilename) + 1, Memory.ROMFilename, 0);
sprintf(buffer, "NAM:%06d:%s%c", (int) Memory.ROMFilename.length() + 1, Memory.ROMFilename.c_str(), 0);
WRITE_STREAM(buffer, strlen(buffer) + 1, stream);
FreezeStruct(stream, "CPU", &CPU, SnapCPU, COUNT(SnapCPU));
@@ -1195,11 +1189,11 @@ void S9xFreezeToStream (STREAM stream)
dma_snap.dma[d] = DMA[d];
FreezeStruct(stream, "DMA", &dma_snap, SnapDMA, COUNT(SnapDMA));
FreezeBlock (stream, "VRA", Memory.VRAM, 0x10000);
FreezeBlock (stream, "VRA", Memory.VRAM, sizeof(Memory.VRAM));
FreezeBlock (stream, "RAM", Memory.RAM, 0x20000);
FreezeBlock (stream, "RAM", Memory.RAM, sizeof(Memory.RAM));
FreezeBlock (stream, "SRA", Memory.SRAM, 0x80000);
FreezeBlock (stream, "SRA", Memory.SRAM, Memory.SRAM_SIZE);
FreezeBlock (stream, "FIL", Memory.FillRAM, 0x8000);
@@ -1210,6 +1204,7 @@ void S9xFreezeToStream (STREAM stream)
S9xControlPreSaveState(&ctl_snap);
FreezeStruct(stream, "CTL", &ctl_snap, SnapControls, COUNT(SnapControls));
Timings.InterlaceField = S9xInterlaceField();
FreezeStruct(stream, "TIM", &Timings, SnapTimings, COUNT(SnapTimings));
if (Settings.SuperFX)
@@ -1397,16 +1392,16 @@ int S9xUnfreezeFromStream (STREAM stream)
break;
if (fast)
result = UnfreezeBlock(stream, "RAM", Memory.RAM, 0x20000);
result = UnfreezeBlock(stream, "RAM", Memory.RAM, sizeof(Memory.RAM));
else
result = UnfreezeBlockCopy(stream, "RAM", &local_ram, 0x20000);
result = UnfreezeBlockCopy(stream, "RAM", &local_ram, sizeof(Memory.RAM));
if (result != SUCCESS)
break;
if (fast)
result = UnfreezeBlock(stream, "SRA", Memory.SRAM, 0x80000);
result = UnfreezeBlock(stream, "SRA", Memory.SRAM, Memory.SRAM_SIZE);
else
result = UnfreezeBlockCopy (stream, "SRA", &local_sram, 0x80000);
result = UnfreezeBlockCopy (stream, "SRA", &local_sram, Memory.SRAM_SIZE);
if (result != SUCCESS)
break;
@@ -1576,21 +1571,46 @@ int S9xUnfreezeFromStream (STREAM stream)
memcpy(Memory.RAM, local_ram, 0x20000);
if (local_sram)
memcpy(Memory.SRAM, local_sram, 0x80000);
memcpy(Memory.SRAM, local_sram, Memory.SRAM_SIZE);
if (local_fillram)
memcpy(Memory.FillRAM, local_fillram, 0x8000);
if(version < SNAPSHOT_VERSION_BAPU) {
if (version < SNAPSHOT_VERSION_BAPU)
{
printf("Using Blargg APU snapshot loading (snapshot version %d, current is %d)\n...", version, SNAPSHOT_VERSION);
S9xAPULoadBlarggState(local_apu_sound);
} else
S9xAPULoadState(local_apu_sound);
}
else if (version < 12)
{
printf("Adjusting old APU snapshot (snapshot version %d, current is %d)\n", version, SNAPSHOT_VERSION);
const size_t spc_block_size = 65700;
const size_t old_dsp_block_size = 514;
const size_t added_bytes_v12 = 128;
const size_t bytes_afterward = 16;
// Shift end to make room for extra 128 bytes
memmove(local_apu_sound + spc_block_size + old_dsp_block_size + added_bytes_v12,
local_apu_sound + spc_block_size + old_dsp_block_size,
bytes_afterward);
// Copy saved internal registers to external registers
const size_t new_dsp_registers_position = spc_block_size + 513;
struct SControlSnapshot ctl_snap;
UnfreezeStructFromCopy(&ctl_snap, SnapControls, COUNT(SnapControls), local_control_data, version);
memmove(local_apu_sound + new_dsp_registers_position,
local_apu_sound + spc_block_size,
added_bytes_v12);
// the extra 0 byte between external registers and bytes_afterward is already present due to memset in S9xAPUSaveState
UnfreezeStructFromCopy(&Timings, SnapTimings, COUNT(SnapTimings), local_timing_data, version);
S9xAPULoadState(local_apu_sound);
}
else if (version >= 12)
{
S9xAPULoadState(local_apu_sound);
}
struct SControlSnapshot ctl_snap;
UnfreezeStructFromCopy(&ctl_snap, SnapControls, COUNT(SnapControls), local_control_data, version);
UnfreezeStructFromCopy(&Timings, SnapTimings, COUNT(SnapTimings), local_timing_data, version);
if (local_superfx)
{
@@ -1695,12 +1715,11 @@ int S9xUnfreezeFromStream (STREAM stream)
IPPU.ColorsChanged = TRUE;
IPPU.OBJChanged = TRUE;
IPPU.RenderThisFrame = TRUE;
GFX.InterlaceFrame = Timings.InterlaceField;
GFX.DoInterlace = 0;
S9xGraphicsScreenResize();
if (Settings.FastSavestates == 0)
memset(GFX.Screen,0,GFX.Pitch * MAX_SNES_HEIGHT);
@@ -1754,11 +1773,11 @@ int S9xUnfreezeFromStream (STREAM stream)
UnfreezeStructFromCopy(ssi, SnapScreenshot, COUNT(SnapScreenshot), local_screenshot, version);
IPPU.RenderedScreenWidth = min(ssi->Width, IMAGE_WIDTH);
IPPU.RenderedScreenHeight = min(ssi->Height, IMAGE_HEIGHT);
IPPU.RenderedScreenWidth = min(ssi->Width, MAX_SNES_WIDTH);
IPPU.RenderedScreenHeight = min(ssi->Height, MAX_SNES_HEIGHT);
const bool8 scaleDownX = IPPU.RenderedScreenWidth < ssi->Width;
const bool8 scaleDownY = IPPU.RenderedScreenHeight < ssi->Height && ssi->Height > SNES_HEIGHT_EXTENDED;
GFX.DoInterlace = Settings.SupportHiRes ? ssi->Interlaced : 0;
GFX.DoInterlace = ssi->Interlaced;
uint8 *rowpix = ssi->Data;
uint16 *screen = GFX.Screen;
@@ -1795,7 +1814,7 @@ int S9xUnfreezeFromStream (STREAM stream)
}
// black out what we might have missed
for (uint32 y = IPPU.RenderedScreenHeight; y < (uint32) (IMAGE_HEIGHT); y++)
for (uint32 y = IPPU.RenderedScreenHeight; y < (uint32) (MAX_SNES_HEIGHT); y++)
memset(GFX.Screen + y * GFX.RealPPL, 0, GFX.RealPPL * 2);
delete ssi;
@@ -1893,8 +1912,8 @@ int S9xUnfreezeScreenshotFromStream(STREAM stream, uint16 **image_buffer, int &w
UnfreezeStructFromCopy(ssi, SnapScreenshot, COUNT(SnapScreenshot), local_screenshot, version);
width = min(ssi->Width, IMAGE_WIDTH);
height = min(ssi->Height, IMAGE_HEIGHT);
width = min(ssi->Width, MAX_SNES_WIDTH);
height = min(ssi->Height, MAX_SNES_HEIGHT);
*image_buffer = (uint16 *)malloc(width * height * sizeof(uint16));
+1 -1
View File
@@ -13,7 +13,7 @@
#define SNAPSHOT_VERSION_IRQ 7
#define SNAPSHOT_VERSION_BAPU 8
#define SNAPSHOT_VERSION_IRQ_2018 11 // irq changes were introduced earlier, since this we store NextIRQTimer directly
#define SNAPSHOT_VERSION 11
#define SNAPSHOT_VERSION 12
#define SUCCESS 1
#define WRONG_FORMAT (-1)
+9 -20
View File
@@ -39,26 +39,19 @@ static bool parse_controller_spec (int port, const char *arg)
{
if (!strcasecmp(arg, "none"))
S9xSetController(port, CTL_NONE, 0, 0, 0, 0);
else
if (!strncasecmp(arg, "pad", 3) && arg[3] >= '1' && arg[3] <= '8' && arg[4] == '\0')
else if (!strncasecmp(arg, "pad", 3) && arg[3] >= '1' && arg[3] <= '8' && arg[4] == '\0')
S9xSetController(port, CTL_JOYPAD, arg[3] - '1', 0, 0, 0);
else
if (!strncasecmp(arg, "mouse", 5) && arg[5] >= '1' && arg[5] <= '2' && arg[6] == '\0')
else if (!strncasecmp(arg, "mouse", 5) && arg[5] >= '1' && arg[5] <= '2' && arg[6] == '\0')
S9xSetController(port, CTL_MOUSE, arg[5] - '1', 0, 0, 0);
else
if (!strcasecmp(arg, "superscope"))
else if (!strcasecmp(arg, "superscope"))
S9xSetController(port, CTL_SUPERSCOPE, 0, 0, 0, 0);
else
if (!strcasecmp(arg, "justifier"))
else if (!strcasecmp(arg, "justifier"))
S9xSetController(port, CTL_JUSTIFIER, 0, 0, 0, 0);
else
if (!strcasecmp(arg, "two-justifiers"))
else if (!strcasecmp(arg, "two-justifiers"))
S9xSetController(port, CTL_JUSTIFIER, 1, 0, 0, 0);
else
if (!strcasecmp(arg, "macsrifle"))
else if (!strcasecmp(arg, "macsrifle"))
S9xSetController(port, CTL_MACSRIFLE, 0, 0, 0, 0);
else
if (!strncasecmp(arg, "mp5:", 4) && ((arg[4] >= '1' && arg[4] <= '8') || arg[4] == 'n') &&
else if (!strncasecmp(arg, "mp5:", 4) && ((arg[4] >= '1' && arg[4] <= '8') || arg[4] == 'n') &&
((arg[5] >= '1' && arg[5] <= '8') || arg[5] == 'n') &&
((arg[6] >= '1' && arg[6] <= '8') || arg[6] == 'n') &&
((arg[7] >= '1' && arg[7] <= '8') || arg[7] == 'n') && arg[8] == '\0')
@@ -247,7 +240,6 @@ void S9xLoadConfigFiles (char **argv, int argc)
// Display
Settings.SupportHiRes = conf.GetBool("Display::HiRes", true);
Settings.Transparency = conf.GetBool("Display::Transparency", true);
Settings.DisableGraphicWindows = !conf.GetBool("Display::GraphicWindows", true);
Settings.DisplayTime = conf.GetBool("Display::DisplayTime", false);
@@ -471,7 +463,7 @@ void S9xParseArgsForCheats (char **argv, int argc)
}
else
{
S9xEnableCheatGroup (Cheat.g.size() - 1);
S9xEnableCheatGroup (Cheat.group.size() - 1);
}
}
else
@@ -550,9 +542,6 @@ char * S9xParseArgs (char **argv, int argc)
if (!strcasecmp(argv[i], "-displaykeypress"))
Settings.DisplayPressedKeys = TRUE;
else
if (!strcasecmp(argv[i], "-nohires"))
Settings.SupportHiRes = FALSE;
else
if (!strcasecmp(argv[i], "-notransparency"))
Settings.Transparency = FALSE;
else
@@ -658,7 +647,7 @@ char * S9xParseArgs (char **argv, int argc)
}
else
{
S9xEnableCheatGroup (Cheat.g.size() - 1);
S9xEnableCheatGroup (Cheat.group.size() - 1);
}
}
else
+6 -7
View File
@@ -8,7 +8,7 @@
#define _SNES9X_H_
#ifndef VERSION
#define VERSION "1.61"
#define VERSION "1.62.3"
#endif
#include "port.h"
@@ -58,11 +58,13 @@
#define SNES_HEIGHT_EXTENDED 239
#define MAX_SNES_WIDTH (SNES_WIDTH * 2)
#define MAX_SNES_HEIGHT (SNES_HEIGHT_EXTENDED * 2)
#define IMAGE_WIDTH (Settings.SupportHiRes ? MAX_SNES_WIDTH : SNES_WIDTH)
#define IMAGE_HEIGHT (Settings.SupportHiRes ? MAX_SNES_HEIGHT : SNES_HEIGHT_EXTENDED)
#define NTSC_MASTER_CLOCK 21477272.727272 // 21477272 + 8/11 exact
#define PAL_MASTER_CLOCK 21281370.0
#define NTSC_PROGRESSIVE_FRAME_RATE 60.09881389744051
#define NTSC_INTERLACED_FRAME_RATE 59.94005994
#define PAL_PROGRESSIVE_FRAME_RATE 50.006977968
#define SNES_MAX_NTSC_VCOUNTER 262
#define SNES_MAX_PAL_VCOUNTER 312
@@ -215,7 +217,7 @@ struct SSettings
bool8 JustifierMaster;
bool8 MultiPlayer5Master;
bool8 MacsRifleMaster;
bool8 ForceLoROM;
bool8 ForceHiROM;
bool8 ForceHeader;
@@ -242,7 +244,6 @@ struct SSettings
int32 DynamicRateLimit; /* Multiplied by 1000 */
int32 InterpolationMethod;
bool8 SupportHiRes;
bool8 Transparency;
uint8 BG_Forced;
bool8 DisableGraphicWindows;
@@ -303,8 +304,6 @@ struct SSettings
bool8 DontSaveOopsSnapshot;
bool8 UpAndDown;
bool8 OpenGLEnable;
bool8 SeparateEchoBuffer;
uint32 SuperFXClockMultiplier;
int OverclockMode;