Update snes9x code from 1.53 to 1.6.0.
Notable differences from upstream:
* Did not use the same #include setup for the new byuu apu and instead chose to do things more traditionally, as the latter is also much easier to deal with in Visual Studio than just including .cpp files into other .cpp files...
* MSU1 support not included (I see no need for this in a plugin meant to be used for original SNES music).
* The dynamic rate control on the APU not included (I also see no need for it in this plugin).
* The extra resamplers I added in were removed as the original hermite resampler was folded into a single non-inhertiable resampler.
* Bits of cleanup.
--- a/src/in_snsf/CMakeLists.txt
+++ b/src/in_snsf/CMakeLists.txt
@@ -1,19 +1,14 @@
set(HEADERS
snes9x/65c816.h
snes9x/apu/apu.h
- snes9x/apu/blargg_common.h
- snes9x/apu/blargg_config.h
- snes9x/apu/blargg_endian.h
- snes9x/apu/bspline_resampler.h
- snes9x/apu/hermite_resampler.h
- snes9x/apu/linear_resampler.h
- snes9x/apu/osculating_resampler.h
+ snes9x/apu/bapu/dsp/blargg_common.h
+ snes9x/apu/bapu/dsp/blargg_config.h
+ snes9x/apu/bapu/dsp/blargg_endian.h
+ snes9x/apu/bapu/dsp/sdsp.hpp
+ snes9x/apu/bapu/dsp/SPC_DSP.h
+ snes9x/apu/bapu/smp/smp.hpp
+ snes9x/apu/bapu/snes/snes.hpp
snes9x/apu/resampler.h
- snes9x/apu/ring_buffer.h
- snes9x/apu/sinc_resampler.h
- snes9x/apu/SNES_SPC.h
- snes9x/apu/SPC_CPU.h
- snes9x/apu/SPC_DSP.h
snes9x/cpuaddr.h
snes9x/cpuexec.h
snes9x/cpumacro.h
@@ -28,9 +23,14 @@
XSFConfigDialog_SNSF.h)
set(SNES9X_SOURCES
snes9x/apu/apu.cpp
- snes9x/apu/SNES_SPC.cpp
- snes9x/apu/SNES_SPC_misc.cpp
- snes9x/apu/SPC_DSP.cpp
+ snes9x/apu/bapu/dsp/sdsp.cpp
+ snes9x/apu/bapu/dsp/SPC_DSP.cpp
+ snes9x/apu/bapu/smp/algorithms.cpp
+ snes9x/apu/bapu/smp/core.cpp
+ snes9x/apu/bapu/smp/iplrom.cpp
+ snes9x/apu/bapu/smp/memory.cpp
+ snes9x/apu/bapu/smp/smp.cpp
+ snes9x/apu/bapu/smp/timing.cpp
snes9x/cpu.cpp
snes9x/cpuexec.cpp
snes9x/cpuops.cpp
@@ -56,7 +56,7 @@
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Header Files" FILES ${HEADERS})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOURCES})
target_compile_options(in_snsf PUBLIC
- $<$<CXX_COMPILER_ID:MSVC>:/wd4127 /wd4245 /wd6385 /wd6386 /wd26453 /wd26495 /wd26812 /wd26819>)
+ $<$<CXX_COMPILER_ID:MSVC>:/wd4127 /wd4245 /wd4389 /wd6385 /wd6386 /wd26439 /wd26453 /wd26495 /wd26812 /wd26819>)
target_link_libraries(in_snsf
in_xsf_framework)
--- a/src/in_snsf/XSFConfigDialog_SNSF.cpp
+++ b/src/in_snsf/XSFConfigDialog_SNSF.cpp
@@ -31,19 +31,19 @@
XSFConfigDialog_SNSF::XSFConfigDialog_SNSF(XSFConfig &newConfig, wxWindow *parent, const wxString &title) : XSFConfigDialog(newConfig, parent, title)
{
- auto reverseStereoCheckBox = new wxCheckBox(this->outputPanel, wxID_ANY, "Reverse Stereo", wxDefaultPosition, wxDefaultSize, 0, wxGenericValidator{ &this->reverseStereo });
- this->outputSizer->Add(reverseStereoCheckBox, { 4, 0 }, { 1, 2 }, wxALL, 5);
+ auto separateEchoBufferCheckBox = new wxCheckBox(this->outputPanel, wxID_ANY, "Separate Echo Buffer", wxDefaultPosition, wxDefaultSize, 0, wxGenericValidator{ &this->separateEchoBuffer });
+ this->outputSizer->Add(separateEchoBufferCheckBox, { 4, 0 }, { 1, 2 }, wxALL, 5);
- auto resamplerLabel = new wxStaticText(this->outputPanel, wxID_ANY, "Resampler");
- this->outputSizer->Add(resamplerLabel, { 5, 0 }, { 1, 1 }, wxALIGN_CENTER_VERTICAL | wxALL, 5);
- wxArrayString resamplerChoices;
- resamplerChoices.Add("Linear Resampler");
- resamplerChoices.Add("Hermite Resampler");
- resamplerChoices.Add("Bspline Resampler");
- resamplerChoices.Add("Osculating Resampler");
- resamplerChoices.Add("Sinc Resampler");
- auto resamplerChoice = new wxChoice(this->outputPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, resamplerChoices, 0, wxGenericValidator{ &this->resampler });
- this->outputSizer->Add(resamplerChoice, { 5, 1 }, { 1, 1 }, wxALL, 5);
+ auto interpolationLabel = new wxStaticText(this->outputPanel, wxID_ANY, "Interpolation");
+ this->outputSizer->Add(interpolationLabel, { 5, 0 }, { 1, 1 }, wxALIGN_CENTER_VERTICAL | wxALL, 5);
+ wxArrayString interpolationChoices;
+ interpolationChoices.Add("None");
+ interpolationChoices.Add("Linear");
+ interpolationChoices.Add("Guassian");
+ interpolationChoices.Add("Cubic");
+ interpolationChoices.Add("Sinc");
+ auto interpolationChoice = new wxChoice(this->outputPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, interpolationChoices, 0, wxGenericValidator{ &this->interpolation });
+ this->outputSizer->Add(interpolationChoice, { 5, 1 }, { 1, 1 }, wxALL, 5);
auto muteLabel = new wxStaticText(this->outputPanel, wxID_ANY, "Mute");
this->outputSizer->Add(muteLabel, { 6, 0 }, { 1, 1 }, wxALIGN_CENTER_VERTICAL | wxALL, 5);
--- a/src/in_snsf/XSFConfigDialog_SNSF.h
+++ b/src/in_snsf/XSFConfigDialog_SNSF.h
@@ -31,8 +31,8 @@
public:
XSFConfigDialog_SNSF(XSFConfig &newConfig, wxWindow *parent, const wxString &title);
- bool reverseStereo;
- int resampler;
+ bool separateEchoBuffer;
+ int interpolation;
wxArrayInt mute;
};
--- a/src/in_snsf/XSFConfig_SNSF.cpp
+++ b/src/in_snsf/XSFConfig_SNSF.cpp
@@ -3,10 +3,6 @@
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
*
* Partially based on the vio*sf framework
- *
- * NOTE: 16-bit sound is always enabled, the player is currently limited to
- * creating a 16-bit PCM for Winamp and can not handle 8-bit sound from
- * snes9x.
*/
#include <bitset>
@@ -40,7 +36,7 @@
return new XSFConfig_SNSF();
}
-XSFConfig_SNSF::XSFConfig_SNSF() : XSFConfig(), /*sixteenBitSound(false), */reverseStereo(false), mutes(), resampler(0)
+XSFConfig_SNSF::XSFConfig_SNSF() : XSFConfig(), separateEchoBuffer(false), interpolation(0), mutes()
{
this->supportedSampleRates.push_back(8000);
this->supportedSampleRates.push_back(11025);
@@ -57,26 +53,24 @@
void XSFConfig_SNSF::LoadSpecificConfig()
{
- //this->sixteenBitSound = this->configIO->GetValue("SixteenBitSound", XSFConfig_SNSF::initSixteenBitSound);
- this->reverseStereo = this->configIO->GetValue("ReverseStereo", XSFConfig_SNSF::initReverseStereo);
- this->resampler = this->configIO->GetValue("Resampler", XSFConfig_SNSF::initResampler);
+ this->separateEchoBuffer = this->configIO->GetValue("SeparateEchoBuffer", XSFConfig_SNSF::initSeparateEchoBuffer);
+ this->interpolation = this->configIO->GetValue("Interpolation", XSFConfig_SNSF::initInterpolation);
std::stringstream mutesSS(this->configIO->GetValue("Mutes", XSFConfig_SNSF::initMutes));
mutesSS >> this->mutes;
}
void XSFConfig_SNSF::SaveSpecificConfig()
{
- //this->configIO->SetValue("SixteenBitSound", this->sixteenBitSound);
- this->configIO->SetValue("ReverseStereo", this->reverseStereo);
- this->configIO->SetValue("Resampler", this->resampler);
+ this->configIO->SetValue("SeparateEchoBuffer", this->separateEchoBuffer);
+ this->configIO->SetValue("Interpolation", this->interpolation);
this->configIO->SetValue("Mutes", this->mutes.to_string<char>());
}
void XSFConfig_SNSF::InitializeSpecificConfigDialog(XSFConfigDialog *dialog)
{
auto snsfDialog = static_cast<XSFConfigDialog_SNSF *>(dialog);
- snsfDialog->reverseStereo = this->reverseStereo;
- snsfDialog->resampler = static_cast<int>(this->resampler);
+ snsfDialog->separateEchoBuffer = this->separateEchoBuffer;
+ snsfDialog->interpolation = static_cast<int>(this->interpolation);
for (std::size_t x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
if (this->mutes[x])
snsfDialog->mute.Add(x);
@@ -85,8 +79,8 @@
void XSFConfig_SNSF::ResetSpecificConfigDefaults(XSFConfigDialog *dialog)
{
auto snsfDialog = static_cast<XSFConfigDialog_SNSF *>(dialog);
- snsfDialog->reverseStereo = XSFConfig_SNSF::initReverseStereo;
- snsfDialog->resampler = XSFConfig_SNSF::initResampler;
+ snsfDialog->separateEchoBuffer = XSFConfig_SNSF::initSeparateEchoBuffer;
+ snsfDialog->interpolation = XSFConfig_SNSF::initInterpolation;
snsfDialog->mute.Clear();
auto tmpMutes = std::bitset<8>(XSFConfig_SNSF::initMutes);
for (std::size_t x = 0, numMutes = tmpMutes.size(); x < numMutes; ++x)
@@ -97,8 +91,8 @@
void XSFConfig_SNSF::SaveSpecificConfigDialog(XSFConfigDialog *dialog)
{
auto snsfDialog = static_cast<XSFConfigDialog_SNSF *>(dialog);
- this->reverseStereo = snsfDialog->reverseStereo;
- this->resampler = snsfDialog->resampler;
+ this->separateEchoBuffer = snsfDialog->separateEchoBuffer;
+ this->interpolation = snsfDialog->interpolation;
for (std::size_t x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
this->mutes[x] = snsfDialog->mute.Index(x) != wxNOT_FOUND;
}
@@ -108,8 +102,8 @@
if (preLoad)
{
memset(&Settings, 0, sizeof(Settings));
- //Settings.SixteenBitSound = this->sixteenBitSound;
- Settings.ReverseStereo = this->reverseStereo;
+ Settings.SeparateEchoBuffer = this->separateEchoBuffer;
+ Settings.InterpolationMethod = this->interpolation;
}
else
S9xSetSoundControl(static_cast<std::uint8_t>(this->mutes.to_ulong()) ^ 0xFF);
@@ -118,7 +112,7 @@
void XSFConfig_SNSF::About(HWND parent)
{
MessageBoxW(parent, ConvertFuncs::StringToWString(XSFConfig::commonName + " v" + XSFConfig::versionNumber + ", using xSF Winamp plugin framework (based on the vio*sf plugins) by Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]\n\n"
- "Utilizes modified snes9x v1.53 for audio playback.").c_str(), ConvertFuncs::StringToWString(XSFConfig::commonName + " v" + XSFConfig::versionNumber).c_str(), MB_OK);
+ "Utilizes modified snes9x v" VERSION " for audio playback.").c_str(), ConvertFuncs::StringToWString(XSFConfig::commonName + " v" + XSFConfig::versionNumber).c_str(), MB_OK);
}
XSFConfigDialog *XSFConfig_SNSF::CreateDialogBox(wxWindow *window, const std::string &title)
--- a/src/in_snsf/XSFConfig_SNSF.h
+++ b/src/in_snsf/XSFConfig_SNSF.h
@@ -3,10 +3,6 @@
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
*
* Partially based on the vio*sf framework
- *
- * NOTE: 16-bit sound is always enabled, the player is currently limited to
- * creating a 16-bit PCM for Winamp and can not handle 8-bit sound from
- * snes9x.
*/
#pragma once
@@ -23,12 +19,13 @@
class XSFConfig_SNSF : public XSFConfig
{
protected:
- static constexpr bool /*initSixteenBitSound = true, */initReverseStereo = false;
- static constexpr unsigned initResampler = 1;
+ static constexpr bool initSeparateEchoBuffer = false;
+ static constexpr unsigned initInterpolation = 2;
inline static const std::string initMutes = "00000000";
friend class XSFConfig;
- bool /*sixteenBitSound, */reverseStereo;
+ bool separateEchoBuffer;
+ unsigned interpolation;
std::bitset<8> mutes;
XSFConfig_SNSF();
@@ -39,8 +36,6 @@
void SaveSpecificConfigDialog(XSFConfigDialog *dialog) override;
void CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad) override;
public:
- unsigned resampler;
-
void About(HWND parent) override;
XSFConfigDialog *CreateDialogBox(wxWindow *window, const std::string &title) override;
};
--- a/src/in_snsf/XSFPlayer_SNSF.cpp
+++ b/src/in_snsf/XSFPlayer_SNSF.cpp
@@ -20,18 +20,13 @@
#include <cstdint>
#include <zlib.h>
#include "XSFCommon.h"
-#include "XSFConfig_SNSF.h"
+#include "XSFConfig.h"
#include "XSFPlayer.h"
#undef min
#undef max
#include "snes9x/apu/apu.h"
-#include "snes9x/apu/linear_resampler.h"
-#include "snes9x/apu/hermite_resampler.h"
-#include "snes9x/apu/bspline_resampler.h"
-#include "snes9x/apu/osculating_resampler.h"
-#include "snes9x/apu/sinc_resampler.h"
#include "snes9x/memmap.h"
class XSFPlayer_SNSF : public XSFPlayer
@@ -211,23 +206,12 @@
Settings.SoundSync = true;
Settings.Mute = false;
Settings.SoundPlaybackRate = this->sampleRate;
- Settings.SixteenBitSound = true;
Settings.Stereo = true;
Memory.Init();
S9xInitAPU();
- XSFConfig_SNSF *xSFConfig_SNSF = dynamic_cast<XSFConfig_SNSF *>(xSFConfig.get());
- if (xSFConfig_SNSF->resampler == 4)
- S9xInitSound<SincResampler>(10, 0);
- else if (xSFConfig_SNSF->resampler == 3)
- S9xInitSound<OsculatingResampler>(10, 0);
- else if (xSFConfig_SNSF->resampler == 2)
- S9xInitSound<BsplineResampler>(10, 0);
- else if (xSFConfig_SNSF->resampler == 1)
- S9xInitSound<HermiteResampler>(10, 0);
- else
- S9xInitSound<LinearResampler>(10, 0);
+ S9xInitSound(10);
if (!buffer.Init())
return false;
--- a/src/in_snsf/snes9x/65c816.h
+++ b/src/in_snsf/snes9x/65c816.h
@@ -1,191 +1,20 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
-const uint16_t Carry = 1;
-const uint16_t Zero = 2;
-const uint16_t IRQ = 4;
-const uint16_t Decimal = 8;
-const uint16_t IndexFlag = 16;
-const uint16_t MemoryFlag = 32;
-const uint16_t Overflow = 64;
-const uint16_t Negative = 128;
-const uint16_t Emulation = 256;
+inline constexpr uint16_t Carry = 1;
+inline constexpr uint16_t Zero = 2;
+inline constexpr uint16_t IRQ = 4;
+inline constexpr uint16_t Decimal = 8;
+inline constexpr uint16_t IndexFlag = 16;
+inline constexpr uint16_t MemoryFlag = 32;
+inline constexpr uint16_t Overflow = 64;
+inline constexpr uint16_t Negative = 128;
+inline constexpr uint16_t Emulation = 256;
union pair
{
--- /dev/null
+++ b/src/in_snsf/snes9x/LICENSE
@@ -1,1 +1,199 @@
+ Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+ (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
+ Jerremy Koot (jkoot@snes9x.com)
+
+ (c) Copyright 2002 - 2004 Matthew Kendora
+
+ (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
+
+ (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
+
+ (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
+
+ (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
+ Kris Bleakley (codeviolation@hotmail.com)
+
+ (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
+ Nach (n-a-c-h@users.sourceforge.net),
+
+ (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
+
+ (c) Copyright 2006 - 2007 nitsuja
+
+ (c) Copyright 2009 - 2019 BearOso,
+ OV2
+
+ (c) Copyright 2017 qwertymodo
+
+ (c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
+ Daniel De Matteis
+ (Under no circumstances will commercial rights be given)
+
+
+ BS-X C emulator code
+ (c) Copyright 2005 - 2006 Dreamer Nom,
+ zones
+
+ C4 x86 assembler and some C emulation code
+ (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
+ Nach,
+ zsKnight (zsknight@zsnes.com)
+
+ C4 C++ code
+ (c) Copyright 2003 - 2006 Brad Jorsch,
+ Nach
+
+ DSP-1 emulator code
+ (c) Copyright 1998 - 2006 _Demo_,
+ Andreas Naive (andreasnaive@gmail.com),
+ Gary Henderson,
+ Ivar (ivar@snes9x.com),
+ John Weidman,
+ Kris Bleakley,
+ Matthew Kendora,
+ Nach,
+ neviksti (neviksti@hotmail.com)
+
+ DSP-2 emulator code
+ (c) Copyright 2003 John Weidman,
+ Kris Bleakley,
+ Lord Nightmare (lord_nightmare@users.sourceforge.net),
+ Matthew Kendora,
+ neviksti
+
+ DSP-3 emulator code
+ (c) Copyright 2003 - 2006 John Weidman,
+ Kris Bleakley,
+ Lancer,
+ z80 gaiden
+
+ DSP-4 emulator code
+ (c) Copyright 2004 - 2006 Dreamer Nom,
+ John Weidman,
+ Kris Bleakley,
+ Nach,
+ z80 gaiden
+
+ OBC1 emulator code
+ (c) Copyright 2001 - 2004 zsKnight,
+ pagefault (pagefault@zsnes.com),
+ Kris Bleakley
+ Ported from x86 assembler to C by sanmaiwashi
+
+ SPC7110 and RTC C++ emulator code used in 1.39-1.51
+ (c) Copyright 2002 Matthew Kendora with research by
+ zsKnight,
+ John Weidman,
+ Dark Force
+
+ SPC7110 and RTC C++ emulator code used in 1.52+
+ (c) Copyright 2009 byuu,
+ neviksti
+
+ S-DD1 C emulator code
+ (c) Copyright 2003 Brad Jorsch with research by
+ Andreas Naive,
+ John Weidman
+
+ S-RTC C emulator code
+ (c) Copyright 2001 - 2006 byuu,
+ John Weidman
+
+ ST010 C++ emulator code
+ (c) Copyright 2003 Feather,
+ John Weidman,
+ Kris Bleakley,
+ Matthew Kendora
+
+ Super FX x86 assembler emulator code
+ (c) Copyright 1998 - 2003 _Demo_,
+ pagefault,
+ zsKnight
+
+ Super FX C emulator code
+ (c) Copyright 1997 - 1999 Ivar,
+ Gary Henderson,
+ John Weidman
+
+ Sound emulator code used in 1.5-1.51
+ (c) Copyright 1998 - 2003 Brad Martin
+ (c) Copyright 1998 - 2006 Charles Bilyue'
+
+ Sound emulator code used in 1.52+
+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
+
+ S-SMP emulator code used in 1.54+
+ (c) Copyright 2016 byuu
+
+ SH assembler code partly based on x86 assembler code
+ (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
+
+ 2xSaI filter
+ (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
+
+ HQ2x, HQ3x, HQ4x filters
+ (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
+
+ NTSC filter
+ (c) Copyright 2006 - 2007 Shay Green
+
+ GTK+ GUI code
+ (c) Copyright 2004 - 2019 BearOso
+
+ Win32 GUI code
+ (c) Copyright 2003 - 2006 blip,
+ funkyass,
+ Matthew Kendora,
+ Nach,
+ nitsuja
+ (c) Copyright 2009 - 2019 OV2
+
+ Mac OS GUI code
+ (c) Copyright 1998 - 2001 John Stiles
+ (c) Copyright 2001 - 2011 zones
+
+ Libretro port
+ (c) Copyright 2011 - 2017 Hans-Kristian Arntzen,
+ Daniel De Matteis
+ (Under no circumstances will commercial rights be given)
+
+
+ Specific ports contains the works of other authors. See headers in
+ individual files.
+
+
+ Snes9x homepage: http://www.snes9x.com/
+ Snes9x source code: https://github.com/snes9xgit/snes9x/
+
+ Permission to use, copy, modify and/or distribute Snes9x in both binary
+ and source form, for non-commercial purposes, is hereby granted without
+ fee, providing that this license information and copyright notice appear
+ with all copies and any derived work.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event shall the authors be held liable for any damages
+ arising from the use of this software or it's derivatives.
+
+ Snes9x is freeware for PERSONAL USE only. Commercial users should
+ seek permission of the copyright holders first. Commercial use includes,
+ but is not limited to, charging money for Snes9x or software derived from
+ Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
+ using Snes9x as a promotion for your commercial product.
+
+ The copyright holders request that bug fixes and improvements to the code
+ should be forwarded to them so everyone can benefit from the modifications
+ in future versions.
+
+ Super NES and Super Nintendo Entertainment System are trademarks of
+ Nintendo Co., Limited and its subsidiary companies.
+
+-------------------------------------------------------------------------------
+
+Some parts included in Snes9x are usually available under a different license,
+their authors have granted exception for their use in Snes9x (and/or they are
+licensed as LGPL):
+ - JMA: GPL/LGPL, see jma/license.txt
+ - snes_ntsc: LGPL, see filter/snes_ntsc-license.txt
+ - xBRZ: GPLv3, see filter/xbrz-license.txt
+
--- a/src/in_snsf/snes9x/apu/SNES_SPC.cpp
+++ /dev/null
@@ -1,328 +1,1 @@
-// Core SPC emulation: CPU, timers, SMP registers, memory
-// snes_spc 0.9.0. http://www.slack.net/~ant/
-
-#include <algorithm>
-#include <cstring>
-#include "SNES_SPC.h"
-
-/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
-can redistribute it and/or modify it under the terms of the GNU Lesser
-General Public License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version. This
-module is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details. You should have received a copy of the GNU Lesser General Public
-License along with this module; if not, write to the Free Software Foundation,
-Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
-
-//// Timers
-
-#ifdef SPC_DISABLE_TEMPO
-template<typename T> static inline T TIMER_DIV(SNES_SPC::Timer *t, const T &n) { return n >> t->prescaler; }
-template<typename T> static inline T TIMER_MUL(SNES_SPC::Timer *t, const T &n) { return n << t->prescaler; }
-#else
-template<typename T> static inline T TIMER_DIV(SNES_SPC::Timer *t, const T &n) { return n / t->prescaler; }
-template<typename T> static inline T TIMER_MUL(SNES_SPC::Timer *t, const T &n) { return n * t->prescaler; }
-#endif
-
-auto SNES_SPC::run_timer_(Timer *t, rel_time_t time) -> Timer *
-{
- int elapsed = TIMER_DIV(t, time - t->next_time) + 1;
- t->next_time += TIMER_MUL(t, elapsed);
-
- if (t->enabled)
- {
- int remain = IF_0_THEN_256(t->period - t->divider);
- int divider = t->divider + elapsed;
- int over = elapsed - remain;
- if (over >= 0)
- {
- int n = over / t->period;
- t->counter = (t->counter + 1 + n) & 0x0F;
- divider = over - n * t->period;
- }
- t->divider = static_cast<uint8_t>(divider);
- }
- return t;
-}
-
-auto SNES_SPC::run_timer(Timer *t, rel_time_t time) -> Timer *
-{
- if (time >= t->next_time)
- t = this->run_timer_(t, time);
- return t;
-}
-
-//// ROM
-
-void SNES_SPC::enable_rom(bool enable)
-{
- if (this->m.rom_enabled != enable)
- {
- this->m.rom_enabled = this->dsp.rom_enabled = enable;
- if (enable)
- std::copy_n(&this->m.ram.ram[rom_addr], static_cast<int>(rom_size), &this->m.hi_ram[0]);
- auto data = enable ? &this->m.rom[0] : &this->m.hi_ram[0];
- std::copy_n(&data[0], static_cast<int>(rom_size), &this->m.ram.ram[rom_addr]);
- // TODO: ROM can still get overwritten when DSP writes to echo buffer
- }
-}
-
-//// DSP
-
-void SNES_SPC::RUN_DSP(rel_time_t time)
-{
- int count = time - this->m.dsp_time;
- if (count)
- {
- assert(count > 0);
- this->m.dsp_time = time;
- this->dsp.run(count);
- }
-}
-
-int SNES_SPC::dsp_read(rel_time_t time)
-{
- this->RUN_DSP(time);
-
- int result = this->dsp.read(this->m.smp_regs[0][r_dspaddr] & 0x7F);
-
-#ifdef SPC_DSP_READ_HOOK
- SPC_DSP_READ_HOOK(spc_time + time, this->m.smp_regs[0][r_dspaddr] & 0x7F, result);
-#endif
-
- return result;
-}
-
-void SNES_SPC::dsp_write(int data, rel_time_t time)
-{
- this->RUN_DSP(time);
-
-#ifdef SPC_DSP_WRITE_HOOK
- SPC_DSP_WRITE_HOOK(this->m.spc_time + time, this->m.smp_regs[0][r_dspaddr], static_cast<uint8_t>(data));
-#endif
-
- if (this->m.smp_regs[0][r_dspaddr] <= 0x7F)
- this->dsp.write(this->m.smp_regs[0][r_dspaddr], data);
-}
-
-//// CPU write
-
-// divided into multiple functions to keep rarely-used functionality separate
-// so often-used functionality can be optimized better by compiler
-
-// If write isn't preceded by read, data has this added to it
-static const int no_read_before_write = 0x2000;
-
-void SNES_SPC::cpu_write_smp_reg_(int data, rel_time_t time, int addr)
-{
- switch (addr)
- {
- case r_t0target:
- case r_t1target:
- case r_t2target:
- {
- auto t = &this->m.timers[addr - r_t0target];
- int period = IF_0_THEN_256(data);
- if (t->period != period)
- {
- t = this->run_timer(t, time);
- t->period = period;
- }
- break;
- }
-
- case r_t0out:
- case r_t1out:
- case r_t2out:
- if (data < no_read_before_write / 2)
- this->run_timer(&this->m.timers[addr - r_t0out], time - 1)->counter = 0;
- break;
-
- // Registers that act like RAM
- case 0x8:
- case 0x9:
- this->m.smp_regs[1][addr] = static_cast<uint8_t>(data);
- break;
-
- case r_test:
- break;
-
- case r_control:
- // port clears
- if (data & 0x10)
- {
- this->m.smp_regs[1][r_cpuio0] = 0;
- this->m.smp_regs[1][r_cpuio1] = 0;
- }
- if (data & 0x20)
- {
- this->m.smp_regs[1][r_cpuio2] = 0;
- this->m.smp_regs[1][r_cpuio3] = 0;
- }
-
- // timers
- for (int i = 0; i < timer_count; ++i)
- {
- auto t = &this->m.timers[i];
- bool enabled = !!((data >> i) & 1);
- if (t->enabled != enabled)
- {
- t = this->run_timer(t, time);
- t->enabled = enabled;
- if (enabled)
- t->divider = t->counter = 0;
- }
- }
- this->enable_rom(!!(data & 0x80));
- }
-}
-
-void SNES_SPC::cpu_write_smp_reg(int data, rel_time_t time, int addr)
-{
- if (addr == r_dspdata) // 99%
- this->dsp_write(data, time);
- else
- this->cpu_write_smp_reg_(data, time, addr);
-}
-
-void SNES_SPC::cpu_write_high(int data, int i, rel_time_t time)
-{
- if (i < rom_size)
- {
- this->m.hi_ram [i] = static_cast<uint8_t>(data);
- if (this->m.rom_enabled)
- this->m.ram.ram[i + rom_addr] = this->m.rom[i]; // restore overwritten ROM
- }
- else
- {
- assert(this->m.ram.ram[i + rom_addr] == static_cast<uint8_t>(data));
- this->m.ram.ram[i + rom_addr] = cpu_pad_fill; // restore overwritten padding
- this->cpu_write(data, i + rom_addr - 0x10000, time);
- }
-}
-
-static const int bits_in_int = CHAR_BIT * sizeof(int);
-
-void SNES_SPC::cpu_write(int data, int addr, rel_time_t time)
-{
- // RAM
- this->m.ram.ram[addr] = static_cast<uint8_t>(data);
- int reg = addr - 0xF0;
- if (reg >= 0) // 64%
- {
- // $F0-$FF
- if (reg < reg_count) // 87%
- {
- this->m.smp_regs[0][reg] = static_cast<uint8_t>(data);
-
- // Ports
-#ifdef SPC_PORT_WRITE_HOOK
- if (static_cast<unsigned>(reg - r_cpuio0) < port_count)
- SPC_PORT_WRITE_HOOK(this->m.spc_time + time, (reg - r_cpuio0), static_cast<uint8_t>(data), &this->m.smp_regs[0][r_cpuio0]);
-#endif
-
- // Registers other than $F2 and $F4-$F7
- //if ( reg != 2 && reg != 4 && reg != 5 && reg != 6 && reg != 7 )
- // TODO: this is a bit on the fragile side
- if (((~0x2F00 << (bits_in_int - 16)) << reg) < 0) // 36%
- this->cpu_write_smp_reg(data, time, reg);
- }
- // High mem/address wrap-around
- else
- {
- reg -= rom_addr - 0xF0;
- if (reg >= 0) // 1% in IPL ROM area or address wrapped around
- this->cpu_write_high(data, reg, time);
- }
- }
-}
-
-//// CPU read
-
-int SNES_SPC::cpu_read_smp_reg(int reg, rel_time_t time)
-{
- int result = this->m.smp_regs[1][reg];
- reg -= r_dspaddr;
- // DSP addr and data
- if (static_cast<unsigned>(reg) <= 1) // 4% 0xF2 and 0xF3
- {
- result = this->m.smp_regs[0][r_dspaddr];
- if (static_cast<unsigned>(reg) == 1)
- result = this->dsp_read(time); // 0xF3
- }
- return result;
-}
-
-int SNES_SPC::cpu_read(int addr, rel_time_t time)
-{
- // RAM
- int result = this->m.ram.ram[addr];
- int reg = addr - 0xF0;
- if (reg >= 0) // 40%
- {
- reg -= 0x10;
- if (static_cast<unsigned>(reg) >= 0xFF00) // 21%
- {
- reg += 0x10 - r_t0out;
-
- // Timers
- if (static_cast<unsigned>(reg) < timer_count) // 90%
- {
- auto t = &this->m.timers[reg];
- if (time >= t->next_time)
- t = this->run_timer_(t, time);
- result = t->counter;
- t->counter = 0;
- }
- // Other registers
- else if (reg < 0) // 10%
- result = this->cpu_read_smp_reg(reg + r_t0out, time);
- else // 1%
- {
- assert(reg + (r_t0out + 0xF0 - 0x10000) < 0x100);
- result = this->cpu_read(reg + (r_t0out + 0xF0 - 0x10000), time);
- }
- }
- }
-
- return result;
-}
-
-//// Run
-
-static const int cpu_lag_max = 12 - 1; // DIV YA,X takes 12 clocks
-
-void SNES_SPC::end_frame(time_t end_time)
-{
- // Catch CPU up to as close to end as possible. If final instruction
- // would exceed end, does NOT execute it and leaves m.spc_time < end.
- if (end_time > this->m.spc_time)
- this->run_until_(end_time);
-
- this->m.spc_time -= end_time;
- this->m.extra_clocks += end_time;
-
- // Greatest number of clocks early that emulation can stop early due to
- // not being able to execute current instruction without going over
- // allowed time.
- assert(-cpu_lag_max <= this->m.spc_time && this->m.spc_time <= cpu_lag_max);
-
- // Catch timers up to CPU
- for (int i = 0; i < timer_count; ++i)
- this->run_timer(&this->m.timers [i], 0);
-
- // Catch DSP up to CPU
- if (this->m.dsp_time < 0)
- this->RUN_DSP(0);
-
- // Save any extra samples beyond what should be generated
- if (this->m.buf_begin)
- this->save_extra();
-}
-
-// Inclusion here allows static memory access functions and better optimization
-#include "SPC_CPU.h"
-
--- a/src/in_snsf/snes9x/apu/SNES_SPC.h
+++ /dev/null
@@ -1,237 +1,1 @@
-// SNES SPC-700 APU emulator
-// snes_spc 0.9.0
-#pragma once
-
-#include "SPC_DSP.h"
-#include "blargg_endian.h"
-
-// (n ? n : 256)
-template<typename T> inline T IF_0_THEN_256(const T &n) { return static_cast<uint8_t>(n - 1) + 1; }
-
-struct SNES_SPC
-{
-public:
- // Must be called once before using
- void init();
-
- // Sample pairs generated per second
- enum { sample_rate = 32000 };
-
- // Emulator use
-
- // Sets IPL ROM data. Library does not include ROM data. Most SPC music files
- // don't need ROM, but a full emulator must provide this.
- enum { rom_size = 0x40 };
- void init_rom(const uint8_t rom[rom_size]);
-
- // Sets destination for output samples
- typedef short sample_t;
- void set_output(sample_t *out, int out_size);
-
- // Number of samples written to output since last set
- int sample_count() const;
-
- // Resets SPC to power-on state. This resets your output buffer, so you must
- // call set_output() after this.
- void reset();
-
- // Emulates pressing reset switch on SNES. This resets your output buffer, so
- // you must call set_output() after this.
- void soft_reset();
-
- // 1024000 SPC clocks per second, sample pair every 32 clocks
- typedef int time_t;
- enum { clock_rate = 1024000 };
- enum { clocks_per_sample = 32 };
-
- // Emulated port read/write at specified time
- enum { port_count = 4 };
- int read_port(time_t, int port);
- void write_port(time_t, int port, int data);
-
- // Runs SPC to end_time and starts a new time frame at 0
- void end_frame(time_t end_time);
-
- // Sound control
-
- // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events).
- // Reduces emulation accuracy.
- enum { voice_count = 8 };
- void mute_voices(int mask);
-
- // If true, prevents channels and global volumes from being phase-negated.
- // Only supported by fast DSP.
- void disable_surround(bool disable = true );
-
- // Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc.
- enum { tempo_unit = 0x100 };
- void set_tempo(int);
-
- // SPC music files
-
- // Clears echo region. Useful after loading an SPC as many have garbage in echo.
- void clear_echo();
-
- // Plays for count samples and write samples to out. Discards samples if out
- // is NULL. Count must be a multiple of 2 since output is stereo.
- void play(int count, sample_t *out);
-
- // Skips count samples. Several times faster than play() when using fast DSP.
- void skip(int count);
-
- //// Snes9x Accessor
-
- void spc_allow_time_overflow(bool);
-
- void dsp_set_stereo_switch(int);
- uint8_t dsp_reg_value(int, int);
- int dsp_envx_value(int);
-
-public:
- // Time relative to m_spc_time. Speeds up code a bit by eliminating need to
- // constantly add m_spc_time to time from CPU. CPU uses time that ends at
- // 0 to eliminate reloading end time every instruction. It pays off.
- typedef int rel_time_t;
-
- struct Timer
- {
- rel_time_t next_time; // time of next event
- int prescaler;
- int period;
- int divider;
- bool enabled;
- int counter;
- };
- enum { reg_count = 0x10 };
- enum { timer_count = 3 };
- enum { extra_size = SPC_DSP::extra_size };
-
-private:
- SPC_DSP dsp;
-
- struct state_t
- {
- Timer timers[timer_count];
-
- uint8_t smp_regs[2][reg_count];
-
- struct
- {
- int pc;
- int a;
- int x;
- int y;
- int psw;
- int sp;
- } cpu_regs;
-
- rel_time_t dsp_time;
- time_t spc_time;
-
- int tempo;
-
- int extra_clocks;
- sample_t *buf_begin;
- const sample_t *buf_end;
- sample_t *extra_pos;
- sample_t extra_buf[extra_size];
-
- bool rom_enabled;
- uint8_t rom[rom_size];
- uint8_t hi_ram[rom_size];
-
- unsigned char cycle_table[256];
-
- struct
- {
- // padding to neutralize address overflow
- union
- {
- uint8_t padding1[0x100];
- uint16_t align; // makes compiler align data for 16-bit access
- } padding1[1];
- uint8_t ram[0x10000];
- uint8_t padding2[0x100];
- } ram;
- };
- state_t m;
-
- enum { rom_addr = 0xFFC0 };
-
- enum { skipping_time = 127 };
-
- // Value that padding should be filled with
- enum { cpu_pad_fill = 0xFF };
-
- enum
- {
- r_test = 0x0,
- r_control = 0x1,
- r_dspaddr = 0x2,
- r_dspdata = 0x3,
- r_cpuio0 = 0x4,
- r_cpuio1 = 0x5,
- r_cpuio2 = 0x6,
- r_cpuio3 = 0x7,
- r_f8 = 0x8,
- r_f9 = 0x9,
- r_t0target = 0xA,
- r_t1target = 0xB,
- r_t2target = 0xC,
- r_t0out = 0xD,
- r_t1out = 0xE,
- r_t2out = 0xF
- };
-
- void timers_loaded();
- void enable_rom(bool enable);
- void reset_buf();
- void save_extra();
- void load_regs(const uint8_t in[reg_count]);
- void ram_loaded();
- void regs_loaded();
- void reset_time_regs();
- void reset_common(int timer_counter_init);
-
- Timer *run_timer_(Timer *t, rel_time_t);
- Timer *run_timer(Timer *t, rel_time_t);
- void RUN_DSP(rel_time_t);
- int dsp_read(rel_time_t);
- void dsp_write(int data, rel_time_t);
- void cpu_write_smp_reg_(int data, rel_time_t, int addr);
- void cpu_write_smp_reg(int data, rel_time_t, int addr);
- void cpu_write_high(int data, int i, rel_time_t);
- void cpu_write(int data, int addr, rel_time_t);
- int cpu_read_smp_reg(int i, rel_time_t);
- int cpu_read(int addr, rel_time_t);
- unsigned CPU_mem_bit(const uint8_t *pc, rel_time_t);
-
- bool check_echo_access(int addr);
- uint8_t *run_until_(time_t end_time);
-
- // Snes9x timing hack
- bool allow_time_overflow;
-};
-
-inline int SNES_SPC::sample_count() const { return (this->m.extra_clocks >> 5) * 2; }
-
-inline int SNES_SPC::read_port(time_t t, int port)
-{
- assert(static_cast<unsigned>(port) < port_count);
- return this->run_until_(t)[port];
-}
-
-inline void SNES_SPC::write_port(time_t t, int port, int data)
-{
- assert(static_cast<unsigned>(port) < port_count);
- this->run_until_(t)[0x10 + port] = data;
- this->m.ram.ram[0xF4 + port] = data;
-}
-
-inline void SNES_SPC::mute_voices(int mask) { this->dsp.mute_voices(mask); }
-
-inline void SNES_SPC::disable_surround(bool disable) { this->dsp.disable_surround(disable); }
-
-inline void SNES_SPC::spc_allow_time_overflow(bool allow) { this->allow_time_overflow = allow; }
-
--- a/src/in_snsf/snes9x/apu/SNES_SPC_misc.cpp
+++ /dev/null
@@ -1,308 +1,1 @@
-// SPC emulation support: init, sample buffering, reset, SPC loading
-// snes_spc 0.9.0. http://www.slack.net/~ant/
-
-#include <algorithm>
-#include <cstring>
-#include "SNES_SPC.h"
-
-/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
-can redistribute it and/or modify it under the terms of the GNU Lesser
-General Public License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version. This
-module is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details. You should have received a copy of the GNU Lesser General Public
-License along with this module; if not, write to the Free Software Foundation,
-Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
-
-//// Init
-
-void SNES_SPC::init()
-{
- memset(&this->m, 0, sizeof(this->m));
- this->dsp.init(this->m.ram.ram);
-
- this->m.tempo = tempo_unit;
-
- // Most SPC music doesn't need ROM, and almost all the rest only rely
- // on these two bytes
- this->m.rom[0x3E] = 0xFF;
- this->m.rom[0x3F] = 0xC0;
-
- static const unsigned char cycle_table[] =
- {
- //01 23 45 67 89 AB CD EF
- 0x28, 0x47, 0x34, 0x36, 0x26, 0x54, 0x54, 0x68, // 0
- 0x48, 0x47, 0x45, 0x56, 0x55, 0x65, 0x22, 0x46, // 1
- 0x28, 0x47, 0x34, 0x36, 0x26, 0x54, 0x54, 0x74, // 2
- 0x48, 0x47, 0x45, 0x56, 0x55, 0x65, 0x22, 0x38, // 3
- 0x28, 0x47, 0x34, 0x36, 0x26, 0x44, 0x54, 0x66, // 4
- 0x48, 0x47, 0x45, 0x56, 0x55, 0x45, 0x22, 0x43, // 5
- 0x28, 0x47, 0x34, 0x36, 0x26, 0x44, 0x54, 0x75, // 6
- 0x48, 0x47, 0x45, 0x56, 0x55, 0x55, 0x22, 0x36, // 7
- 0x28, 0x47, 0x34, 0x36, 0x26, 0x54, 0x52, 0x45, // 8
- 0x48, 0x47, 0x45, 0x56, 0x55, 0x55, 0x22, 0xC5, // 9
- 0x38, 0x47, 0x34, 0x36, 0x26, 0x44, 0x52, 0x44, // A
- 0x48, 0x47, 0x45, 0x56, 0x55, 0x55, 0x22, 0x34, // B
- 0x38, 0x47, 0x45, 0x47, 0x25, 0x64, 0x52, 0x49, // C
- 0x48, 0x47, 0x56, 0x67, 0x45, 0x55, 0x22, 0x83, // D
- 0x28, 0x47, 0x34, 0x36, 0x24, 0x53, 0x43, 0x40, // E
- 0x48, 0x47, 0x45, 0x56, 0x34, 0x54, 0x22, 0x60 // F
- };
-
- // unpack cycle table
- for (int i = 0; i < 128; ++i)
- {
- int n = cycle_table[i];
- this->m.cycle_table[i * 2] = n >> 4;
- this->m.cycle_table[i * 2 + 1] = n & 0x0F;
- }
-
- this->allow_time_overflow = false;
-
- this->dsp.rom = this->m.rom;
- this->dsp.hi_ram = this->m.hi_ram;
-
- this->reset();
-}
-
-void SNES_SPC::init_rom(const uint8_t in[rom_size])
-{
- std::copy_n(&in[0], static_cast<int>(rom_size), &this->m.rom[0]);
-}
-
-void SNES_SPC::set_tempo(int t)
-{
- this->m.tempo = t;
- static const int timer2_shift = 4; // 64 kHz
- static const int other_shift = 3; // 8 kHz
-
-#ifdef SPC_DISABLE_TEMPO
- this->m.timers[2].prescaler = timer2_shift;
- this->m.timers[1].prescaler = timer2_shift + other_shift;
- this->m.timers[0].prescaler = timer2_shift + other_shift;
-#else
- if (!t)
- t = 1;
- static const int timer2_rate = 1 << timer2_shift;
- int rate = (timer2_rate * tempo_unit + (t >> 1)) / t;
- if (rate < timer2_rate / 4)
- rate = timer2_rate / 4; // max 4x tempo
- this->m.timers[2].prescaler = rate;
- this->m.timers[1].prescaler = rate << other_shift;
- this->m.timers[0].prescaler = rate << other_shift;
-#endif
-}
-
-// Timer registers have been loaded. Applies these to the timers. Does not
-// reset timer prescalers or dividers.
-void SNES_SPC::timers_loaded()
-{
- for (int i = 0; i < timer_count; ++i)
- {
- auto &t = this->m.timers[i];
- t.period = IF_0_THEN_256(this->m.smp_regs[0][r_t0target + i]);
- t.enabled = !!((this->m.smp_regs[0][r_control] >> i) & 1);
- t.counter = this->m.smp_regs[1][r_t0out + i] & 0x0F;
- }
-
- this->set_tempo(this->m.tempo);
-}
-
-// Loads registers from unified 16-byte format
-void SNES_SPC::load_regs(const uint8_t in[reg_count])
-{
- std::copy_n(&in[0], static_cast<int>(reg_count), &this->m.smp_regs[0][0]);
- std::copy_n(&this->m.smp_regs[0][0], static_cast<int>(reg_count), &this->m.smp_regs[1][0]);
-
- // These always read back as 0
- this->m.smp_regs[1][r_test] = this->m.smp_regs[1][r_control] = this->m.smp_regs[1][r_t0target] = this->m.smp_regs[1][r_t1target] = this->m.smp_regs[1][r_t2target] = 0;
-}
-
-// RAM was just loaded from SPC, with $F0-$FF containing SMP registers
-// and timer counts. Copies these to proper registers.
-void SNES_SPC::ram_loaded()
-{
- this->m.rom_enabled = this->dsp.rom_enabled = false;
- this->load_regs(&this->m.ram.ram[0xF0]);
-
- // Put STOP instruction around memory to catch PC underflow/overflow
- memset(this->m.ram.padding1, cpu_pad_fill, sizeof(this->m.ram.padding1));
- memset(this->m.ram.padding2, cpu_pad_fill, sizeof(this->m.ram.padding2));
-}
-
-// Registers were just loaded. Applies these new values.
-void SNES_SPC::regs_loaded()
-{
- this->enable_rom(!!(this->m.smp_regs[0][r_control] & 0x80));
- this->timers_loaded();
-}
-
-void SNES_SPC::reset_time_regs()
-{
- this->m.spc_time = 0;
- this->m.dsp_time = 0;
-
- std::for_each(&this->m.timers[0], &this->m.timers[timer_count], [](Timer &t)
- {
- t.next_time = 1;
- t.divider = 0;
- });
-
- this->regs_loaded();
-
- this->m.extra_clocks = 0;
- this->reset_buf();
-}
-
-void SNES_SPC::reset_common(int timer_counter_init)
-{
- std::fill_n(&this->m.smp_regs[1][r_t0out], static_cast<int>(timer_count), timer_counter_init);
-
- // Run IPL ROM
- memset(&this->m.cpu_regs, 0, sizeof(this->m.cpu_regs));
- this->m.cpu_regs.pc = rom_addr;
-
- this->m.smp_regs[0][r_test] = 0x0A;
- this->m.smp_regs[0][r_control] = 0xB0; // ROM enabled, clear ports
- std::fill_n(&this->m.smp_regs[1][r_cpuio0], static_cast<int>(port_count), 0);
-
- this->reset_time_regs();
-}
-
-void SNES_SPC::soft_reset()
-{
- this->reset_common(0);
- this->dsp.soft_reset();
-}
-
-void SNES_SPC::reset()
-{
- this->m.cpu_regs.pc = 0xFFC0;
- this->m.cpu_regs.a = this->m.cpu_regs.x = this->m.cpu_regs.y = 0x00;
- this->m.cpu_regs.psw = 0x02;
- this->m.cpu_regs.sp = 0xEF;
- std::fill_n(&this->m.ram.ram[0], 0x10000, 0);
- this->ram_loaded();
- this->reset_common(0x0F);
- this->dsp.reset();
-}
-
-void SNES_SPC::clear_echo()
-{
- if (!(this->dsp.read(SPC_DSP::r_flg) & 0x20))
- {
- int addr = 0x100 * this->dsp.read(SPC_DSP::r_esa);
- int end = addr + 0x800 * (this->dsp.read(SPC_DSP::r_edl) & 0x0F);
- if (end > 0x10000)
- end = 0x10000;
- std::fill(&this->m.ram.ram[addr], &this->m.ram.ram[end], 0xFF);
- }
-}
-
-//// Sample output
-
-void SNES_SPC::reset_buf()
-{
- // Start with half extra buffer of silence
- sample_t *out = this->m.extra_buf;
- while (out < &this->m.extra_buf[extra_size / 2])
- *out++ = 0;
-
- this->m.extra_pos = out;
- this->m.buf_begin = nullptr;
-
- this->dsp.set_output(nullptr, 0);
-}
-
-void SNES_SPC::set_output(sample_t *out, int size)
-{
- assert(!(size & 1)); // size must be even
-
- this->m.extra_clocks &= clocks_per_sample - 1;
- if (out)
- {
- auto out_end = out + size;
- this->m.buf_begin = out;
- this->m.buf_end = out_end;
-
- // Copy extra to output
- auto in = this->m.extra_buf;
- while (in < this->m.extra_pos && out < out_end)
- *out++ = *in++;
-
- // Handle output being full already
- if (out >= out_end)
- {
- // Have DSP write to remaining extra space
- out = this->dsp.extra();
- out_end = &this->dsp.extra()[extra_size];
-
- // Copy any remaining extra samples as if DSP wrote them
- while (in < m.extra_pos)
- *out++ = *in++;
- assert(out <= out_end);
- }
-
- this->dsp.set_output(out, out_end - out);
- }
- else
- this->reset_buf();
-}
-
-void SNES_SPC::save_extra()
-{
- // Get end pointers
- auto main_end = this->m.buf_end; // end of data written to buf
- auto dsp_end = this->dsp.out_pos(); // end of data written to dsp.extra()
- if (this->m.buf_begin <= dsp_end && dsp_end <= main_end)
- {
- main_end = dsp_end;
- dsp_end = this->dsp.extra(); // nothing in DSP's extra
- }
-
- // Copy any extra samples at these ends into extra_buf
- auto out = this->m.extra_buf;
- for (auto in = this->m.buf_begin + this->sample_count(); in < main_end; ++in)
- *out++ = *in;
- for (auto in = this->dsp.extra(); in < dsp_end; ++in)
- *out++ = *in;
-
- this->m.extra_pos = out;
- assert(out <= &this->m.extra_buf[extra_size]);
-}
-
-void SNES_SPC::play(int count, sample_t *out)
-{
- assert(!(count & 1)); // must be even
- if (count)
- {
- this->set_output(out, count);
- this->end_frame(count * (clocks_per_sample / 2));
- }
-}
-
-void SNES_SPC::skip(int count)
-{
- this->play(count, nullptr);
-}
-
-//// Snes9x Accessor
-
-void SNES_SPC::dsp_set_stereo_switch(int value)
-{
- this->dsp.set_stereo_switch(value);
-}
-
-uint8_t SNES_SPC::dsp_reg_value(int ch, int addr)
-{
- return this->dsp.reg_value(ch, addr);
-}
-
-int SNES_SPC::dsp_envx_value(int ch)
-{
- return this->dsp.envx_value(ch);
-}
-
--- a/src/in_snsf/snes9x/apu/SPC_CPU.h
+++ /dev/null
@@ -1,1174 +1,1 @@
-// snes_spc 0.9.0. http://www.slack.net/~ant/
-/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
-can redistribute it and/or modify it under the terms of the GNU Lesser
-General Public License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version. This
-module is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details. You should have received a copy of the GNU Lesser General Public
-License along with this module; if not, write to the Free Software Foundation,
-Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
-
-#pragma once
-
-//// Memory access
-
-// TODO: remove non-wrapping versions?
-#define SPC_NO_SP_WRAPAROUND 0
-
-unsigned SNES_SPC::CPU_mem_bit(const uint8_t *pc, rel_time_t rel_time)
-{
- unsigned addr = get_le16(pc);
- unsigned t = this->cpu_read(addr & 0x1FFF, rel_time) >> (addr >> 13);
- return (t << 8) & 0x100;
-}
-
-//// Status flag handling
-
-// Hex value in name to clarify code and bit shifting.
-// Flag stored in indicated variable during emulation
-const int n80 = 0x80; // nz
-const int v40 = 0x40; // psw
-const int p20 = 0x20; // dp
-const int b10 = 0x10; // psw
-const int h08 = 0x08; // psw
-const int i04 = 0x04; // psw
-const int z02 = 0x02; // nz
-const int c01 = 0x01; // c
-
-const int nz_neg_mask = 0x880; // either bit set indicates N flag set
-
-uint8_t *SNES_SPC::run_until_(time_t end_time)
-{
- rel_time_t rel_time = this->m.spc_time - end_time;
- /*assert( rel_time <= 0 );*/
- this->m.spc_time = end_time;
- this->m.dsp_time += rel_time;
- this->m.timers[0].next_time += rel_time;
- this->m.timers[1].next_time += rel_time;
- this->m.timers[2].next_time += rel_time;
-
- auto ram = this->m.ram.ram;
- int a = this->m.cpu_regs.a;
- int x = this->m.cpu_regs.x;
- int y = this->m.cpu_regs.y;
- const uint8_t *pc;
- uint8_t *sp;
- int psw;
- int c;
- int nz;
- int dp;
-
- // timers are by far the most common thing read from dp
- auto CPU_READ_TIMER = [&](rel_time_t offset, int addr_) -> int
- {
- int out;
- rel_time_t adj_time = rel_time + offset;
- int dp_addr = addr_;
- int ti = dp_addr - (r_t0out + 0xF0);
- if (static_cast<unsigned>(ti) < timer_count)
- {
- auto t = &this->m.timers[ti];
- if (adj_time >= t->next_time)
- t = this->run_timer_(t, adj_time);
- out = t->counter;
- t->counter = 0;
- }
- else
- {
- out = ram[dp_addr];
- int i = dp_addr - 0xF0;
- if (static_cast<unsigned>(i) < 0x10)
- out = this->cpu_read_smp_reg(i, adj_time);
- }
- return out;
- };
-
- auto DP_ADDR = [&](int addr) { return dp + addr; };
-
- auto READ_PROG16 = [&](int addr) { return get_le16(ram + addr); };
-
- auto SET_PC = [&](int n) { pc = ram + n; };
- auto GET_PC = [&]() { return pc - ram; };
-
- auto SET_SP = [&](int v) { sp = ram + 0x101 + v; };
- auto GET_SP = [&]() { return sp - 0x101 - ram; };
-
- auto PUSH16 = [&](int data)
- {
- sp -= 2;
-#if !SPC_NO_SP_WRAPAROUND
- int addr = sp - ram;
- if (addr > 0x100)
-#endif
- set_le16(sp, data);
-#if !SPC_NO_SP_WRAPAROUND
- else
- {
- ram[static_cast<uint8_t>(addr) + 0x100] = static_cast<uint8_t>(data);
- sp[1] = static_cast<uint8_t>(data >> 8);
- sp += 0x100;
- }
-#endif
- };
- auto PUSH = [&](int data)
- {
- *--sp = static_cast<uint8_t>(data);
-#if !SPC_NO_SP_WRAPAROUND
- if (sp - ram == 0x100)
- sp += 0x100;
-#endif
- };
- auto POP = [&](int &out)
- {
- out = *sp++;
-#if !SPC_NO_SP_WRAPAROUND
- if (sp - ram == 0x201)
- {
- out = sp[-0x101];
- sp -= 0x100;
- }
-#endif
- };
-
- auto MEM_BIT = [&](rel_time_t rel) { return this->CPU_mem_bit(pc, rel_time + rel); };
-
- auto GET_PSW = [&](int &out)
- {
- out = psw & ~(n80 | p20 | z02 | c01);
- out |= (c >> 8) & c01;
- out |= (dp >> 3) & p20;
- out |= ((nz >> 4) | nz) & n80;
- if (!static_cast<uint8_t>(nz))
- out |= z02;
- };
- auto SET_PSW = [&](int in)
- {
- psw = in;
- c = in << 8;
- dp = (in << 3) & 0x100;
- nz = ((in << 4) & 0x800) | (~in & z02);
- };
-
- SET_PC(this->m.cpu_regs.pc);
- SET_SP(this->m.cpu_regs.sp);
- SET_PSW(this->m.cpu_regs.psw);
-
- goto loop;
-
- // Main loop
-
-cbranch_taken_loop:
- pc += *reinterpret_cast<const int8_t *>(pc);
-inc_pc_loop:
- ++pc;
-loop:
- unsigned data;
-
- unsigned opcode = *pc;
- if (this->allow_time_overflow && rel_time >= 0)
- goto stop;
- if ((rel_time += this->m.cycle_table[opcode]) > 0 && !this->allow_time_overflow)
- goto out_of_time;
-
-#ifdef SPC_CPU_OPCODE_HOOK
- SPC_CPU_OPCODE_HOOK(GET_PC(), opcode);
-#endif
-
- // TODO: if PC is at end of memory, this will get wrong operand (very obscure)
- data = *++pc;
- switch (opcode)
- {
- // Common instructions
-
-#define BRANCH(cond) \
-{ \
- ++pc; \
- pc += static_cast<int8_t>(data); \
- if (cond) \
- goto loop; \
- pc -= static_cast<int8_t>(data); \
- rel_time -= 2; \
- goto loop; \
-}
-
- case 0xF0: // BEQ
- BRANCH(!static_cast<uint8_t>(nz)) // 89% taken
-
- case 0xD0: // BNE
- BRANCH(static_cast<uint8_t>(nz))
-
- case 0x3F: // CALL
- {
- int old_addr = GET_PC() + 2;
- SET_PC(get_le16(pc));
- PUSH16(old_addr);
- goto loop;
- }
-
- case 0x6F:// RET
-#if SPC_NO_SP_WRAPAROUND
- SET_PC(get_le16(sp));
- sp += 2;
-#else
- {
- int addr = sp - ram;
- SET_PC(get_le16(sp));
- sp += 2;
- if (addr < 0x1FF)
- goto loop;
-
- SET_PC(sp[-0x101] * 0x100 + ram[static_cast<uint8_t>(addr) + 0x100]);
- sp -= 0x100;
- }
-#endif
- goto loop;
-
- case 0xE4: // MOV a,dp
- ++pc;
- // 80% from timer
- a = nz = CPU_READ_TIMER(0, DP_ADDR(data));
- goto loop;
-
- case 0xFA: // MOV dp,dp
- {
- int temp = CPU_READ_TIMER(-2, DP_ADDR(data));
- data = temp + no_read_before_write;
- }
- // fall through
- case 0x8F: // MOV dp,#imm
- {
- int temp = *(pc + 1);
- pc += 2;
- {
- int i = dp + temp;
- ram[i] = static_cast<uint8_t>(data);
- i -= 0xF0;
- if (static_cast<unsigned>(i) < 0x10) // 76%
- {
- this->m.smp_regs[0][i] = static_cast<uint8_t>(data);
-
- // Registers other than $F2 and $F4-$F7
- //if ( i != 2 && i != 4 && i != 5 && i != 6 && i != 7 )
- if (((~0x2F00 << (bits_in_int - 16)) << i) < 0) // 12%
- this->cpu_write_smp_reg(data, rel_time, i);
- }
- }
- goto loop;
- }
-
- case 0xC4: // MOV dp,a
- ++pc;
- {
- int i = dp + data;
- ram[i] = static_cast<uint8_t>(a);
- i -= 0xF0;
- if (static_cast<unsigned>(i) < 0x10) // 39%
- {
- unsigned sel = i - 2;
- this->m.smp_regs[0][i] = static_cast<uint8_t>(a);
-
- if (sel == 1) // 51% $F3
- this->dsp_write(a, rel_time);
- else if (sel > 1) // 1% not $F2 or $F3
- this->cpu_write_smp_reg_(a, rel_time, i);
- }
- }
- goto loop;
-
-#define CASE(n) case n:
-
-// Define common address modes based on opcode for immediate mode. Execution
-// ends with data set to the address of the operand.
-#define ADDR_MODES_(op) \
- CASE(op - 0x02) /* (X) */ \
- data = x + dp; \
- --pc; \
- goto end_##op; \
- CASE(op + 0x0F) /* (dp)+Y */ \
- data = READ_PROG16(data + dp) + y; \
- goto end_##op; \
- CASE(op - 0x01) /* (dp+X) */ \
- data = READ_PROG16(static_cast<uint8_t>(data + x) + dp); \
- goto end_##op; \
- CASE(op + 0x0E) /* abs+Y */ \
- data += y; \
- goto abs_##op; \
- CASE(op + 0x0D) /* abs+X */ \
- data += x; \
- CASE(op - 0x03) /* abs */ \
- abs_##op: \
- data += 0x100 * *(++pc); \
- goto end_##op; \
- CASE(op + 0x0C) /* dp+X */ \
- data = static_cast<uint8_t>(data + x);
-
-#define ADDR_MODES_NO_DP(op) \
- ADDR_MODES_(op) \
- data += dp; \
- end_##op:
-
-#define ADDR_MODES(op) \
- ADDR_MODES_(op) \
- CASE(op - 0x04) /* dp */ \
- data += dp; \
- end_##op:
-
- // 1. 8-bit Data Transmission Commands. Group I
-
- ADDR_MODES_NO_DP(0xE8) // MOV A,addr
- a = nz = this->cpu_read(data, rel_time);
- goto inc_pc_loop;
-
- case 0xBF: // MOV A,(X)+
- {
- int temp = x + dp;
- x = static_cast<uint8_t>(x + 1);
- a = nz = this->cpu_read(temp, rel_time - 1);
- goto loop;
- }
-
- case 0xE8: // MOV A,imm
- a = data;
- nz = data;
- goto inc_pc_loop;
-
- case 0xF9: // MOV X,dp+Y
- data = static_cast<uint8_t>(data + y);
- case 0xF8: // MOV X,dp
- x = nz = CPU_READ_TIMER(0, DP_ADDR(data));
- goto inc_pc_loop;
-
- case 0xE9: // MOV X,abs
- data = get_le16(pc);
- ++pc;
- data = this->cpu_read(data, rel_time);
- case 0xCD: // MOV X,imm
- x = data;
- nz = data;
- goto inc_pc_loop;
-
- case 0xFB: // MOV Y,dp+X
- data = static_cast<uint8_t>(data + x);
- case 0xEB: // MOV Y,dp
- // 70% from timer
- ++pc;
- y = nz = CPU_READ_TIMER(0, DP_ADDR(data));
- goto loop;
-
- case 0xEC: // MOV Y,abs
- {
- int temp = get_le16(pc);
- pc += 2;
- y = nz = CPU_READ_TIMER(0, temp);
- //y = nz = this->cpu_read(temp, rel_time);
- goto loop;
- }
-
- case 0x8D: // MOV Y,imm
- y = data;
- nz = data;
- goto inc_pc_loop;
-
- // 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2
-
- ADDR_MODES_NO_DP(0xC8) // MOV addr,A
- this->cpu_write(a, data, rel_time);
- goto inc_pc_loop;
-
- {
- int temp;
- case 0xCC: // MOV abs,Y
- temp = y;
- goto mov_abs_temp;
- case 0xC9: // MOV abs,X
- temp = x;
- mov_abs_temp:
- this->cpu_write(temp, get_le16(pc), rel_time);
- pc += 2;
- goto loop;
- }
-
- case 0xD9: // MOV dp+Y,X
- data = static_cast<uint8_t>(data + y);
- case 0xD8: // MOV dp,X
- this->cpu_write(x, data + dp, rel_time);
- goto inc_pc_loop;
-
- case 0xDB: // MOV dp+X,Y
- data = static_cast<uint8_t>(data + x);
- case 0xCB: // MOV dp,Y
- this->cpu_write(y, data + dp, rel_time);
- goto inc_pc_loop;
-
- // 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3.
-
- case 0x7D: // MOV A,X
- a = nz = x;
- goto loop;
-
- case 0xDD: // MOV A,Y
- a = nz = y;
- goto loop;
-
- case 0x5D: // MOV X,A
- x = nz = a;
- goto loop;
-
- case 0xFD: // MOV Y,A
- y = nz = a;
- goto loop;
-
- case 0x9D: // MOV X,SP
- x = nz = GET_SP();
- goto loop;
-
- case 0xBD: // MOV SP,X
- SET_SP(x);
- goto loop;
-
- //case 0xC6: // MOV (X),A (handled by MOV addr,A in group 2)
-
- case 0xAF: // MOV (X)+,A
- this->cpu_write(a + no_read_before_write, DP_ADDR(x), rel_time);
- ++x;
- goto loop;
-
- // 5. 8-BIT LOGIC OPERATION COMMANDS
-
-#define LOGICAL_OP(op, func) \
- ADDR_MODES(op) /* addr */ \
- data = this->cpu_read(data, rel_time); \
- case op: /* imm */ \
- nz = a func##= data; \
- goto inc_pc_loop; \
- { \
- unsigned addr; \
- case op + 0x11: /* X,Y */ \
- data = this->cpu_read(DP_ADDR(y), rel_time - 2); \
- addr = x + dp; \
- goto addr_##op; \
- case op + 0x01: /* dp,dp */ \
- data = this->cpu_read(DP_ADDR(data), rel_time - 3); \
- case op + 0x10: /*dp,imm*/ \
- { \
- auto addr2 = pc + 1; \
- pc += 2; \
- addr = *addr2 + dp; \
- } \
- addr_##op: \
- nz = data func this->cpu_read(addr, rel_time - 1); \
- this->cpu_write(nz, addr, rel_time); \
- goto loop; \
- }
-
- LOGICAL_OP(0x28, &); // AND
-
- LOGICAL_OP(0x08, |); // OR
-
- LOGICAL_OP(0x48, ^); // EOR
-
- // 4. 8-BIT ARITHMETIC OPERATION COMMANDS
-
- ADDR_MODES(0x68) // CMP addr
- data = this->cpu_read(data, rel_time);
- case 0x68: // CMP imm
- nz = a - data;
- c = ~nz;
- nz &= 0xFF;
- goto inc_pc_loop;
-
- case 0x79: // CMP (X),(Y)
- data = this->cpu_read(DP_ADDR(y), rel_time - 2);
- nz = this->cpu_read(DP_ADDR(x), rel_time - 1) - data;
- c = ~nz;
- nz &= 0xFF;
- goto loop;
-
- case 0x69: // CMP dp,dp
- data = this->cpu_read(DP_ADDR(data), rel_time - 3);
- case 0x78: // CMP dp,imm
- nz = this->cpu_read(DP_ADDR(*(++pc)), rel_time - 1) - data;
- c = ~nz;
- nz &= 0xFF;
- goto inc_pc_loop;
-
- case 0x3E: // CMP X,dp
- data += dp;
- goto cmp_x_addr;
- case 0x1E: // CMP X,abs
- data = get_le16(pc);
- ++pc;
- cmp_x_addr:
- data = this->cpu_read(data, rel_time);
- case 0xC8: // CMP X,imm
- nz = x - data;
- c = ~nz;
- nz &= 0xFF;
- goto inc_pc_loop;
-
- case 0x7E: // CMP Y,dp
- data += dp;
- goto cmp_y_addr;
- case 0x5E: // CMP Y,abs
- data = get_le16(pc);
- ++pc;
- cmp_y_addr:
- data = this->cpu_read(data, rel_time);
- case 0xAD: // CMP Y,imm
- nz = y - data;
- c = ~nz;
- nz &= 0xFF;
- goto inc_pc_loop;
-
- {
- int addr;
- case 0xB9: // SBC (x),(y)
- case 0x99: // ADC (x),(y)
- --pc; // compensate for inc later
- data = this->cpu_read(DP_ADDR(y), rel_time - 2);
- addr = x + dp;
- goto adc_addr;
- case 0xA9: // SBC dp,dp
- case 0x89: // ADC dp,dp
- data = this->cpu_read(DP_ADDR(data), rel_time - 3);
- case 0xB8: // SBC dp,imm
- case 0x98: // ADC dp,imm
- addr = *(++pc) + dp;
- adc_addr:
- nz = this->cpu_read(addr, rel_time - 1);
- goto adc_data;
-
- // catch ADC and SBC together, then decode later based on operand
-#undef CASE
-#define CASE(n) case n: case (n) + 0x20:
- ADDR_MODES(0x88) // ADC/SBC addr
- data = this->cpu_read(data, rel_time);
- case 0xA8: // SBC imm
- case 0x88: // ADC imm
- addr = -1; // A
- nz = a;
- adc_data:
- {
- int flags;
- if (opcode >= 0xA0) // SBC
- data ^= 0xFF;
-
- flags = data ^ nz;
- nz += data + (c >> 8 & 1);
- flags ^= nz;
-
- psw = (psw & ~(v40 | h08)) | ((flags >> 1) & h08) | (((flags + 0x80) >> 2) & v40);
- c = nz;
- if (addr < 0)
- {
- a = static_cast<uint8_t>(nz);
- goto inc_pc_loop;
- }
- this->cpu_write(/*(uint8_t)*/nz, addr, rel_time);
- goto inc_pc_loop;
- }
- }
-
- // 6. ADDITION & SUBTRACTION COMMANDS
-
-#define INC_DEC_REG(reg, op) \
- nz = reg op; \
- reg = static_cast<uint8_t>(nz); \
- goto loop;
-
- case 0xBC: INC_DEC_REG(a, + 1) // INC A
- case 0x3D: INC_DEC_REG(x, + 1) // INC X
- case 0xFC: INC_DEC_REG(y, + 1) // INC Y
-
- case 0x9C: INC_DEC_REG(a, - 1) // DEC A
- case 0x1D: INC_DEC_REG(x, - 1) // DEC X
- case 0xDC: INC_DEC_REG(y, - 1) // DEC Y
-
- case 0x9B: // DEC dp+X
- case 0xBB: // INC dp+X
- data = static_cast<uint8_t>(data + x);
- case 0x8B: // DEC dp
- case 0xAB: // INC dp
- data += dp;
- goto inc_abs;
- case 0x8C: // DEC abs
- case 0xAC: // INC abs
- data = get_le16(pc);
- ++pc;
- inc_abs:
- nz = ((opcode >> 4) & 2) - 1;
- nz += this->cpu_read(data, rel_time - 1);
- this->cpu_write(/*(uint8_t)*/ nz, data, rel_time);
- goto inc_pc_loop;
-
- // 7. SHIFT, ROTATION COMMANDS
-
- case 0x5C: // LSR A
- c = 0;
- case 0x7C: // ROR A
- {
- nz = ((c >> 1) & 0x80) | (a >> 1);
- c = a << 8;
- a = nz;
- goto loop;
- }
-
- case 0x1C: // ASL A
- c = 0;
- case 0x3C: // ROL A
- {
- int temp = c >> 8 & 1;
- c = a << 1;
- nz = c | temp;
- a = static_cast<uint8_t>(nz);
- goto loop;
- }
-
- case 0x0B: // ASL dp
- c = 0;
- data += dp;
- goto rol_mem;
- case 0x1B: // ASL dp+X
- c = 0;
- case 0x3B: // ROL dp+X
- data = static_cast<uint8_t>(data + x);
- case 0x2B: // ROL dp
- data += dp;
- goto rol_mem;
- case 0x0C: // ASL abs
- c = 0;
- case 0x2C: // ROL abs
- data = get_le16(pc);
- ++pc;
- rol_mem:
- nz = c >> 8 & 1;
- nz |= (c = this->cpu_read(data, rel_time - 1) << 1);
- this->cpu_write(/*(uint8_t)*/ nz, data, rel_time);
- goto inc_pc_loop;
-
- case 0x4B: // LSR dp
- c = 0;
- data += dp;
- goto ror_mem;
- case 0x5B: // LSR dp+X
- c = 0;
- case 0x7B: // ROR dp+X
- data = static_cast<uint8_t>(data + x);
- case 0x6B: // ROR dp
- data += dp;
- goto ror_mem;
- case 0x4C: // LSR abs
- c = 0;
- case 0x6C: // ROR abs
- data = get_le16(pc);
- ++pc;
- ror_mem:
- {
- int temp = this->cpu_read(data, rel_time - 1);
- nz = (c >> 1 & 0x80) | (temp >> 1);
- c = temp << 8;
- this->cpu_write(nz, data, rel_time);
- goto inc_pc_loop;
- }
-
- case 0x9F: // XCN
- nz = a = (a >> 4) | static_cast<uint8_t>(a << 4);
- goto loop;
-
- // 8. 16-BIT TRANSMISION COMMANDS
-
- case 0xBA: // MOVW YA,dp
- a = this->cpu_read(DP_ADDR(data), rel_time - 2);
- nz = (a & 0x7F) | (a >> 1);
- y = this->cpu_read(DP_ADDR(static_cast<uint8_t>(data + 1)), rel_time);
- nz |= y;
- goto inc_pc_loop;
-
- case 0xDA: // MOVW dp,YA
- this->cpu_write(a, DP_ADDR(data), rel_time - 1);
- this->cpu_write(y + no_read_before_write, DP_ADDR(static_cast<uint8_t>(data + 1)), rel_time);
- goto inc_pc_loop;
-
- // 9. 16-BIT OPERATION COMMANDS
-
- case 0x3A: // INCW dp
- case 0x1A: // DECW dp
- {
- int temp;
- // low byte
- data += dp;
- temp = this->cpu_read(data, rel_time - 3);
- temp += (opcode >> 4 & 2) - 1; // +1 for INCW, -1 for DECW
- nz = ((temp >> 1) | temp) & 0x7F;
- this->cpu_write(/*(uint8_t)*/ temp, data, rel_time - 2);
-
- // high byte
- data = static_cast<uint8_t>(data + 1) + dp;
- temp = static_cast<uint8_t>((temp >> 8) + this->cpu_read(data, rel_time - 1));
- nz |= temp;
- this->cpu_write(temp, data, rel_time);
-
- goto inc_pc_loop;
- }
-
- case 0x7A: // ADDW YA,dp
- case 0x9A: // SUBW YA,dp
- {
- int lo = this->cpu_read(DP_ADDR(data), rel_time - 2);
- int hi = this->cpu_read(DP_ADDR(static_cast<uint8_t>(data + 1)), rel_time);
-
- if (opcode == 0x9A) // SUBW
- {
- lo = (lo ^ 0xFF) + 1;
- hi ^= 0xFF;
- }
-
- lo += a;
- int result = y + hi + (lo >> 8);
- int flags = hi ^ y ^ result;
-
- psw = (psw & ~(v40 | h08)) | (flags >> 1 & h08) | ((flags + 0x80) >> 2 & v40);
- c = result;
- a = static_cast<uint8_t>(lo);
- result = static_cast<uint8_t>(result);
- y = result;
- nz = (((lo >> 1) | lo) & 0x7F) | result;
-
- goto inc_pc_loop;
- }
-
- case 0x5A: // CMPW YA,dp
- {
- int temp = a - this->cpu_read(DP_ADDR(data), rel_time - 1);
- nz = ((temp >> 1) | temp) & 0x7F;
- temp = y + (temp >> 8);
- temp -= this->cpu_read(DP_ADDR(static_cast<uint8_t>(data + 1)), rel_time);
- nz |= temp;
- c = ~temp;
- nz &= 0xFF;
- goto inc_pc_loop;
- }
-
- // 10. MULTIPLICATION & DIVISON COMMANDS
-
- case 0xCF: // MUL YA
- {
- unsigned temp = y * a;
- a = static_cast<uint8_t>(temp);
- nz = ((temp >> 1) | temp) & 0x7F;
- y = temp >> 8;
- nz |= y;
- goto loop;
- }
-
- case 0x9E: // DIV YA,X
- {
- unsigned ya = y * 0x100 + a;
-
- psw &= ~(h08 | v40);
-
- if (y >= x)
- psw |= v40;
-
- if ((y & 15) >= (x & 15))
- psw |= h08;
-
- if (y < x * 2)
- {
- a = ya / x;
- y = ya - a * x;
- }
- else
- {
- a = 255 - (ya - x * 0x200) / (256 - x);
- y = x + (ya - x * 0x200) % (256 - x);
- }
-
- nz = static_cast<uint8_t>(a);
- a = static_cast<uint8_t>(a);
-
- goto loop;
- }
-
- // 11. DECIMAL COMPENSATION COMMANDS
-
- case 0xDF: // DAA
- if (a > 0x99 || c & 0x100)
- {
- a += 0x60;
- c = 0x100;
- }
-
- if ((a & 0x0F) > 9 || psw & h08)
- a += 0x06;
-
- nz = a;
- a = static_cast<uint8_t>(a);
- goto loop;
-
- case 0xBE: // DAS
- if (a > 0x99 || !(c & 0x100))
- {
- a -= 0x60;
- c = 0;
- }
-
- if ((a & 0x0F) > 9 || !(psw & h08))
- a -= 0x06;
-
- nz = a;
- a = static_cast<uint8_t>(a);
- goto loop;
-
- // 12. BRANCHING COMMANDS
-
- case 0x2F: // BRA rel
- pc += static_cast<int8_t>(data);
- goto inc_pc_loop;
-
- case 0x30: // BMI
- BRANCH(nz & nz_neg_mask)
-
- case 0x10: // BPL
- BRANCH(!(nz & nz_neg_mask))
-
- case 0xB0: // BCS
- BRANCH(c & 0x100)
-
- case 0x90: // BCC
- BRANCH(!(c & 0x100))
-
- case 0x70: // BVS
- BRANCH(psw & v40)
-
- case 0x50: // BVC
- BRANCH(!(psw & v40))
-
-#define CBRANCH(cond) \
-{ \
- ++pc; \
- if (cond) \
- goto cbranch_taken_loop; \
- rel_time -= 2; \
- goto inc_pc_loop; \
-}
-
- case 0x03: // BBS dp.bit,rel
- case 0x23:
- case 0x43:
- case 0x63:
- case 0x83:
- case 0xA3:
- case 0xC3:
- case 0xE3:
- CBRANCH((this->cpu_read(DP_ADDR(data), rel_time - 4) >> (opcode >> 5)) & 1)
-
- case 0x13: // BBC dp.bit,rel
- case 0x33:
- case 0x53:
- case 0x73:
- case 0x93:
- case 0xB3:
- case 0xD3:
- case 0xF3:
- CBRANCH(!((this->cpu_read(DP_ADDR(data), rel_time - 4) >> (opcode >> 5)) & 1))
-
- case 0xDE: // CBNE dp+X,rel
- data = static_cast<uint8_t>(data + x);
- // fall through
- case 0x2E: // CBNE dp,rel
- {
- // 61% from timer
- int temp = CPU_READ_TIMER(-4, DP_ADDR(data));
- CBRANCH(temp != a)
- }
-
- case 0x6E: // DBNZ dp,rel
- {
- unsigned temp = this->cpu_read(DP_ADDR(data), rel_time - 4) - 1;
- this->cpu_write(/*(uint8_t)*/ temp + no_read_before_write, DP_ADDR(static_cast<uint8_t>(data)), rel_time - 3);
- CBRANCH(temp)
- }
-
- case 0xFE: // DBNZ Y,rel
- y = static_cast<uint8_t>(y - 1);
- BRANCH(y)
-
- case 0x1F: // JMP [abs+X]
- SET_PC(get_le16(pc) + x);
- // fall through
- case 0x5F: // JMP abs
- SET_PC(get_le16(pc));
- goto loop;
-
- // 13. SUB-ROUTINE CALL RETURN COMMANDS
-
- case 0x0F: // BRK
- {
- int temp;
- int ret_addr = GET_PC();
- SET_PC(READ_PROG16(0xFFDE)); // vector address verified
- PUSH16(ret_addr);
- GET_PSW(temp);
- psw = (psw | b10) & ~i04;
- PUSH(temp);
- goto loop;
- }
-
- case 0x4F: // PCALL offset
- {
- int ret_addr = GET_PC() + 1;
- SET_PC(0xFF00 | data);
- PUSH16(ret_addr);
- goto loop;
- }
-
- case 0x01: // TCALL n
- case 0x11:
- case 0x21:
- case 0x31:
- case 0x41:
- case 0x51:
- case 0x61:
- case 0x71:
- case 0x81:
- case 0x91:
- case 0xA1:
- case 0xB1:
- case 0xC1:
- case 0xD1:
- case 0xE1:
- case 0xF1:
- {
- int ret_addr = GET_PC();
- SET_PC(READ_PROG16(0xFFDE - (opcode >> 3)));
- PUSH16(ret_addr);
- goto loop;
- }
-
- // 14. STACK OPERATION COMMANDS
-
- {
- int temp;
- case 0x7F: // RET1
- temp = *sp;
- SET_PC(get_le16(sp + 1));
- sp += 3;
- goto set_psw;
- case 0x8E: // POP PSW
- POP(temp);
- set_psw:
- SET_PSW(temp);
- goto loop;
- }
-
- case 0x0D: // PUSH PSW
- {
- int temp;
- GET_PSW(temp);
- PUSH(temp);
- goto loop;
- }
-
- case 0x2D: // PUSH A
- PUSH(a);
- goto loop;
-
- case 0x4D: // PUSH X
- PUSH(x);
- goto loop;
-
- case 0x6D: // PUSH Y
- PUSH(y);
- goto loop;
-
- case 0xAE: // POP A
- POP(a);
- goto loop;
-
- case 0xCE: // POP X
- POP(x);
- goto loop;
-
- case 0xEE: // POP Y
- POP(y);
- goto loop;
-
- // 15. BIT OPERATION COMMANDS
-
- case 0x02: // SET1
- case 0x22:
- case 0x42:
- case 0x62:
- case 0x82:
- case 0xA2:
- case 0xC2:
- case 0xE2:
- case 0x12: // CLR1
- case 0x32:
- case 0x52:
- case 0x72:
- case 0x92:
- case 0xB2:
- case 0xD2:
- case 0xF2:
- {
- int bit = 1 << (opcode >> 5);
- int mask = ~bit;
- if (opcode & 0x10)
- bit = 0;
- data += dp;
- this->cpu_write((this->cpu_read(data, rel_time - 1) & mask) | bit, data, rel_time);
- goto inc_pc_loop;
- }
-
- case 0x0E: // TSET1 abs
- case 0x4E: // TCLR1 abs
- data = get_le16(pc);
- pc += 2;
- {
- unsigned temp = this->cpu_read(data, rel_time - 2);
- nz = static_cast<uint8_t>(a - temp);
- temp &= ~a;
- if (opcode == 0x0E)
- temp |= a;
- this->cpu_write(temp, data, rel_time);
- }
- goto loop;
-
- case 0x4A: // AND1 C,mem.bit
- c &= MEM_BIT(0);
- pc += 2;
- goto loop;
-
- case 0x6A: // AND1 C,/mem.bit
- c &= ~MEM_BIT(0);
- pc += 2;
- goto loop;
-
- case 0x0A: // OR1 C,mem.bit
- c |= MEM_BIT(-1);
- pc += 2;
- goto loop;
-
- case 0x2A: // OR1 C,/mem.bit
- c |= ~MEM_BIT(-1);
- pc += 2;
- goto loop;
-
- case 0x8A: // EOR1 C,mem.bit
- c ^= MEM_BIT(-1);
- pc += 2;
- goto loop;
-
- case 0xEA: // NOT1 mem.bit
- data = get_le16(pc);
- pc += 2;
- {
- unsigned temp = this->cpu_read(data & 0x1FFF, rel_time - 1);
- temp ^= 1 << (data >> 13);
- this->cpu_write(temp, data & 0x1FFF, rel_time);
- }
- goto loop;
-
- case 0xCA: // MOV1 mem.bit,C
- data = get_le16(pc);
- pc += 2;
- {
- unsigned temp = this->cpu_read(data & 0x1FFF, rel_time - 2);
- unsigned bit = data >> 13;
- temp = (temp & ~(1 << bit)) | ((c >> 8 & 1) << bit);
- this->cpu_write(temp + no_read_before_write, data & 0x1FFF, rel_time);
- }
- goto loop;
-
- case 0xAA: // MOV1 C,mem.bit
- c = MEM_BIT(0);
- pc += 2;
- goto loop;
-
- // 16. PROGRAM PSW FLAG OPERATION COMMANDS
-
- case 0x60: // CLRC
- c = 0;
- goto loop;
-
- case 0x80: // SETC
- c = ~0;
- goto loop;
-
- case 0xED: // NOTC
- c ^= 0x100;
- goto loop;
-
- case 0xE0: // CLRV
- psw &= ~(v40 | h08);
- goto loop;
-
- case 0x20: // CLRP
- dp = 0;
- goto loop;
-
- case 0x40: // SETP
- dp = 0x100;
- goto loop;
-
- case 0xA0: // EI
- psw |= i04;
- goto loop;
-
- case 0xC0: // DI
- psw &= ~i04;
- goto loop;
-
- // 17. OTHER COMMANDS
-
- case 0x00: // NOP
- goto loop;
-
- case 0xFF: // STOP
- {
- // handle PC wrap-around
- unsigned addr = GET_PC() - 1;
- if (addr >= 0x10000)
- {
- addr &= 0xFFFF;
- SET_PC(addr);
- goto loop;
- }
- }
- // fall through
- case 0xEF: // SLEEP
- --pc;
- rel_time = 0;
- goto stop;
- } // switch
-
- assert(0); // catch any unhandled instructions
-
-out_of_time:
- rel_time -= this->m.cycle_table[*pc]; // undo partial execution of opcode
-stop:
-
- // Uncache registers
- m.cpu_regs.pc = static_cast<uint16_t>(GET_PC());
- m.cpu_regs.sp = static_cast<uint8_t>(GET_SP());
- m.cpu_regs.a = static_cast<uint8_t>(a);
- m.cpu_regs.x = static_cast<uint8_t>(x);
- m.cpu_regs.y = static_cast<uint8_t>(y);
- int temp;
- GET_PSW(temp);
- m.cpu_regs.psw = static_cast<uint8_t>(temp);
-
- this->m.spc_time += rel_time;
- this->m.dsp_time -= rel_time;
- this->m.timers[0].next_time -= rel_time;
- this->m.timers[1].next_time -= rel_time;
- this->m.timers[2].next_time -= rel_time;
- /*assert( m.spc_time >= end_time );*/
- return &this->m.smp_regs[0][r_cpuio0];
-}
-
--- a/src/in_snsf/snes9x/apu/SPC_DSP.cpp
+++ /dev/null
@@ -1,849 +1,1 @@
-// snes_spc 0.9.0. http://www.slack.net/~ant/
-#include <algorithm>
-#include <cstring>
-#include "SPC_DSP.h"
-
-#include "blargg_endian.h"
-
-/* Copyright (C) 2007 Shay Green. This module is free software; you
-can redistribute it and/or modify it under the terms of the GNU Lesser
-General Public License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version. This
-module is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-details. You should have received a copy of the GNU Lesser General Public
-License along with this module; if not, write to the Free Software Foundation,
-Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
-
-#if INT_MAX < 0x7FFFFFFF
-# error "Requires that int type have at least 32 bits"
-#endif
-
-static const uint8_t initial_regs[] =
-{
- 0x45, 0x8B, 0x5A, 0x9A, 0xE4, 0x82, 0x1B, 0x78, 0x00, 0x00, 0xAA, 0x96, 0x89, 0x0E, 0xE0, 0x80,
- 0x2A, 0x49, 0x3D, 0xBA, 0x14, 0xA0, 0xAC, 0xC5, 0x00, 0x00, 0x51, 0xBB, 0x9C, 0x4E, 0x7B, 0xFF,
- 0xF4, 0xFD, 0x57, 0x32, 0x37, 0xD9, 0x42, 0x22, 0x00, 0x00, 0x5B, 0x3C, 0x9F, 0x1B, 0x87, 0x9A,
- 0x6F, 0x27, 0xAF, 0x7B, 0xE5, 0x68, 0x0A, 0xD9, 0x00, 0x00, 0x9A, 0xC5, 0x9C, 0x4E, 0x7B, 0xFF,
- 0xEA, 0x21, 0x78, 0x4F, 0xDD, 0xED, 0x24, 0x14, 0x00, 0x00, 0x77, 0xB1, 0xD1, 0x36, 0xC1, 0x67,
- 0x52, 0x57, 0x46, 0x3D, 0x59, 0xF4, 0x87, 0xA4, 0x00, 0x00, 0x7E, 0x44, 0x00, 0x4E, 0x7B, 0xFF,
- 0x75, 0xF5, 0x06, 0x97, 0x10, 0xC3, 0x24, 0xBB, 0x00, 0x00, 0x7B, 0x7A, 0xE0, 0x60, 0x12, 0x0F,
- 0xF7, 0x74, 0x1C, 0xE5, 0x39, 0x3D, 0x73, 0xC1, 0x00, 0x00, 0x7A, 0xB3, 0xFF, 0x4E, 0x7B, 0xFF
-};
-
-// if ( io < -32768 ) io = -32768;
-// if ( io > 32767 ) io = 32767;
-template<typename T> static inline void CLAMP16(T &io)
-{
- if (static_cast<int16_t>(io) != io)
- io = (io >> 31) ^ 0x7FFF;
-}
-
-void SPC_DSP::set_output(sample_t *out, int size)
-{
- assert(!(size & 1)); // must be even
- if (!out)
- {
- out = this->m.extra;
- size = extra_size;
- }
- this->m.out_begin = this->m.out = out;
- this->m.out_end = out + size;
-}
-
-// Volume registers and efb are signed! Easy to forget int8_t cast.
-// Prefixes are to avoid accidental use of locals with same names.
-
-// Gaussian interpolation
-
-static const short gauss[] =
-{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
- 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5,
- 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
- 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
- 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27,
- 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77,
- 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102,
- 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132,
- 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168,
- 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210,
- 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257,
- 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311,
- 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370,
- 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434,
- 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504,
- 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577,
- 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654,
- 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732,
- 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811,
- 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889,
- 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965,
- 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036,
- 1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102,
- 1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160,
- 1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210,
- 1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251,
- 1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280,
- 1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298,
- 1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305,
-};
-
-int SPC_DSP::interpolate(const voice_t *v)
-{
- // Make pointers into gaussian based on fractional position between samples
- int offset = (v->interp_pos >> 4) & 0xFF;
- auto fwd = gauss + 255 - offset;
- auto rev = gauss + offset; // mirror left half of gaussian
-
- auto in = &v->buf[(v->interp_pos >> 12) + v->buf_pos];
- int out = (fwd[0] * in[0]) >> 11;
- out += (fwd[256] * in[1]) >> 11;
- out += (rev[256] * in[2]) >> 11;
- out = static_cast<int16_t>(out);
- out += (rev[0] * in[3]) >> 11;
-
- CLAMP16(out);
- out &= ~1;
- return out;
-}
-
-//// Counters
-
-static const int simple_counter_range = 2048 * 5 * 3; // 30720
-
-static const unsigned counter_rates[] =
-{
- simple_counter_range + 1, // never fires
- 2048, 1536,
- 1280, 1024, 768,
- 640, 512, 384,
- 320, 256, 192,
- 160, 128, 96,
- 80, 64, 48,
- 40, 32, 24,
- 20, 16, 12,
- 10, 8, 6,
- 5, 4, 3,
- 2,
- 1
-};
-
-static const unsigned counter_offsets[] =
-{
- 1, 0, 1040,
- 536, 0, 1040,
- 536, 0, 1040,
- 536, 0, 1040,
- 536, 0, 1040,
- 536, 0, 1040,
- 536, 0, 1040,
- 536, 0, 1040,
- 536, 0, 1040,
- 536, 0, 1040,
- 0,
- 0
-};
-
-void SPC_DSP::init_counter()
-{
- this->m.counter = 0;
-}
-
-void SPC_DSP::run_counters()
-{
- if (--this->m.counter < 0)
- this->m.counter = simple_counter_range - 1;
-}
-
-unsigned SPC_DSP::read_counter(int rate)
-{
- return (static_cast<unsigned>(this->m.counter) + counter_offsets[rate]) % counter_rates[rate];
-}
-
-//// Envelope
-
-void SPC_DSP::run_envelope(voice_t *const v)
-{
- int env = v->env;
- if (v->env_mode == env_release) // 60%
- {
- if ((env -= 0x8) < 0)
- env = 0;
- v->env = env;
- }
- else
- {
- int rate;
- int env_data = v->regs[v_adsr1];
- if (this->m.t_adsr0 & 0x80) // 99% ADSR
- {
- if (v->env_mode >= env_decay) // 99%
- {
- --env;
- env -= env >> 8;
- rate = env_data & 0x1F;
- if (v->env_mode == env_decay) // 1%
- rate = ((this->m.t_adsr0 >> 3) & 0x0E) + 0x10;
- }
- else // env_attack
- {
- rate = (this->m.t_adsr0 & 0x0F) * 2 + 1;
- env += rate < 31 ? 0x20 : 0x400;
- }
- }
- else // GAIN
- {
- env_data = v->regs[v_gain];
- int mode = env_data >> 5;
- if (mode < 4) // direct
- {
- env = env_data * 0x10;
- rate = 31;
- }
- else
- {
- rate = env_data & 0x1F;
- if (mode == 4) // 4: linear decrease
- env -= 0x20;
- else if (mode < 6) // 5: exponential decrease
- {
- --env;
- env -= env >> 8;
- }
- else // 6,7: linear increase
- {
- env += 0x20;
- if (mode > 6 && static_cast<unsigned>(v->hidden_env) >= 0x600)
- env += 0x8 - 0x20; // 7: two-slope linear increase
- }
- }
- }
-
- // Sustain level
- if ((env >> 8) == (env_data >> 5) && v->env_mode == env_decay)
- v->env_mode = env_sustain;
-
- v->hidden_env = env;
-
- // unsigned cast because linear decrease going negative also triggers this
- if (static_cast<unsigned>(env) > 0x7FF)
- {
- env = env < 0 ? 0 : 0x7FF;
- if (v->env_mode == env_attack)
- v->env_mode = env_decay;
- }
-
- if (!this->read_counter(rate))
- v->env = env; // nothing else is controlled by the counter
- }
-}
-
-//// BRR Decoding
-
-void SPC_DSP::decode_brr(voice_t *v)
-{
- // Arrange the four input nybbles in 0xABCD order for easy decoding
- int nybbles = this->m.t_brr_byte * 0x100 + this->m.ram[(v->brr_addr + v->brr_offset + 1) & 0xFFFF];
-
- int header = this->m.t_brr_header;
-
- // Write to next four samples in circular buffer
- int *pos = &v->buf[v->buf_pos];
- int *end;
- if ((v->buf_pos += 4) >= brr_buf_size)
- v->buf_pos = 0;
-
- // Decode four samples
- for (end = pos + 4; pos < end; ++pos, nybbles <<= 4)
- {
- // Extract nybble and sign-extend
- int s = static_cast<int16_t>(nybbles) >> 12;
-
- // Shift sample based on header
- int shift = header >> 4;
- s = (s << shift) >> 1;
- if (shift >= 0xD) // handle invalid range
- s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0)
-
- // Apply IIR filter (8 is the most commonly used)
- int filter = header & 0x0C;
- int p1 = pos[brr_buf_size - 1];
- int p2 = pos[brr_buf_size - 2] >> 1;
- if (filter >= 8)
- {
- s += p1;
- s -= p2;
- if (filter == 8) // s += p1 * 0.953125 - p2 * 0.46875
- {
- s += p2 >> 4;
- s += (p1 * -3) >> 6;
- }
- else // s += p1 * 0.8984375 - p2 * 0.40625
- {
- s += (p1 * -13) >> 7;
- s += (p2 * 3) >> 4;
- }
- }
- else if (filter) // s += p1 * 0.46875
- {
- s += p1 >> 1;
- s += -p1 >> 5;
- }
-
- // Adjust and write sample
- CLAMP16(s);
- s = static_cast<int16_t>(s * 2);
- pos[brr_buf_size] = pos[0] = s; // second copy simplifies wrap-around
- }
-}
-
-//// Misc
-
-void SPC_DSP::misc_27()
-{
- this->m.t_pmon = this->m.regs[r_pmon] & 0xFE; // voice 0 doesn't support PMON
-}
-void SPC_DSP::misc_28()
-{
- this->m.t_non = this->m.regs[r_non];
- this->m.t_eon = this->m.regs[r_eon];
- this->m.t_dir = this->m.regs[r_dir];
-}
-void SPC_DSP::misc_29()
-{
- this->m.every_other_sample = !this->m.every_other_sample;
- if (this->m.every_other_sample)
- this->m.new_kon &= ~this->m.kon; // clears KON 63 clocks after it was last read
-}
-void SPC_DSP::misc_30()
-{
- if (this->m.every_other_sample)
- {
- this->m.kon = this->m.new_kon;
- this->m.t_koff = this->m.regs[r_koff] | this->m.mute_mask;
- }
-
- this->run_counters();
-
- // Noise
- if (!this->read_counter(this->m.regs[r_flg] & 0x1F))
- {
- int feedback = (this->m.noise << 13) ^ (this->m.noise << 14);
- this->m.noise = (feedback & 0x4000) ^ (this->m.noise >> 1);
- }
-}
-
-//// Voices
-
-void SPC_DSP::voice_V1(voice_t *const v)
-{
- this->m.t_dir_addr = this->m.t_dir * 0x100 + this->m.t_srcn * 4;
- this->m.t_srcn = v->regs[v_srcn];
-}
-void SPC_DSP::voice_V2(voice_t *const v)
-{
- // Read sample pointer (ignored if not needed)
- auto entry = &this->m.ram[m.t_dir_addr];
- if (!v->kon_delay)
- entry += 2;
- this->m.t_brr_next_addr = get_le16(entry);
-
- this->m.t_adsr0 = v->regs[v_adsr0];
-
- // Read pitch, spread over two clocks
- this->m.t_pitch = v->regs[v_pitchl];
-}
-void SPC_DSP::voice_V3a(voice_t *const v)
-{
- this->m.t_pitch += (v->regs[v_pitchh] & 0x3F) << 8;
-}
-void SPC_DSP::voice_V3b(voice_t *const v)
-{
- // Read BRR header and byte
- this->m.t_brr_byte = this->m.ram[(v->brr_addr + v->brr_offset) & 0xFFFF];
- this->m.t_brr_header = this->m.ram[v->brr_addr]; // brr_addr doesn't need masking
-}
-void SPC_DSP::voice_V3c(voice_t *const v)
-{
- // Pitch modulation using previous voice's output
- if (this->m.t_pmon & v->vbit)
- this->m.t_pitch += ((this->m.t_output >> 5) * this->m.t_pitch) >> 10;
-
- if (v->kon_delay)
- {
- // Get ready to start BRR decoding on next sample
- if (v->kon_delay == 5)
- {
- v->brr_addr = this->m.t_brr_next_addr;
- v->brr_offset = 1;
- v->buf_pos = 0;
- this->m.t_brr_header = 0; // header is ignored on this sample
- }
-
- // Envelope is never run during KON
- v->env = 0;
- v->hidden_env = 0;
-
- // Disable BRR decoding until last three samples
- v->interp_pos = 0;
- if (--v->kon_delay & 3)
- v->interp_pos = 0x4000;
-
- // Pitch is never added during KON
- this->m.t_pitch = 0;
- }
-
- // Gaussian interpolation
- int output = this->interpolate(v);
-
- // Noise
- if (this->m.t_non & v->vbit)
- output = static_cast<int16_t>(this->m.noise * 2);
-
- // Apply envelope
- this->m.t_output = (output * v->env) >> 11 & ~1;
- v->t_envx_out = static_cast<uint8_t>(v->env >> 4);
-
- // Immediate silence due to end of sample or soft reset
- if (this->m.regs[r_flg] & 0x80 || (this->m.t_brr_header & 3) == 1)
- {
- v->env_mode = env_release;
- v->env = 0;
- }
-
- if (this->m.every_other_sample)
- {
- // KOFF
- if (this->m.t_koff & v->vbit)
- v->env_mode = env_release;
-
- // KON
- if (this->m.kon & v->vbit)
- {
- v->kon_delay = 5;
- v->env_mode = env_attack;
- }
- }
-
- // Run envelope for next sample
- if (!v->kon_delay)
- this->run_envelope(v);
-}
-
-void SPC_DSP::voice_output(const voice_t *v, int ch)
-{
- // Apply left/right volume
- int amp = (this->m.t_output * static_cast<int8_t>(v->regs[v_voll + ch])) >> 7;
- amp *= (this->stereo_switch & (1 << (v->voice_number + ch * voice_count))) ? 1 : 0;
-
- // Add to output total
- this->m.t_main_out[ch] += amp;
- CLAMP16(this->m.t_main_out[ch]);
-
- // Optionally add to echo total
- if (this->m.t_eon & v->vbit)
- {
- this->m.t_echo_out[ch] += amp;
- CLAMP16(this->m.t_echo_out[ch]);
- }
-}
-void SPC_DSP::voice_V4(voice_t *const v)
-{
- // Decode BRR
- this->m.t_looped = 0;
- if (v->interp_pos >= 0x4000)
- {
- this->decode_brr(v);
-
- if ((v->brr_offset += 2) >= brr_block_size)
- {
- // Start decoding next BRR block
- assert(v->brr_offset == brr_block_size);
- v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF;
- if (this->m.t_brr_header & 1)
- {
- v->brr_addr = this->m.t_brr_next_addr;
- this->m.t_looped = v->vbit;
- }
- v->brr_offset = 1;
- }
- }
-
- // Apply pitch
- v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch;
-
- // Keep from getting too far ahead (when using pitch modulation)
- if (v->interp_pos > 0x7FFF)
- v->interp_pos = 0x7FFF;
-
- // Output left
- this->voice_output(v, 0);
-}
-void SPC_DSP::voice_V5(voice_t *const v)
-{
- // Output right
- this->voice_output(v, 1);
-
- // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier
- int endx_buf = this->m.regs[r_endx] | this->m.t_looped;
-
- // Clear bit in ENDX if KON just began
- if (v->kon_delay == 5)
- endx_buf &= ~v->vbit;
- this->m.endx_buf = static_cast<uint8_t>(endx_buf);
-}
-void SPC_DSP::voice_V6(voice_t *const)
-{
- this->m.outx_buf = static_cast<uint8_t>(this->m.t_output >> 8);
-}
-void SPC_DSP::voice_V7(voice_t *const v)
-{
- // Update ENDX
- this->m.regs[r_endx] = this->m.endx_buf;
-
- this->m.envx_buf = v->t_envx_out;
-}
-void SPC_DSP::voice_V8(voice_t *const v)
-{
- // Update OUTX
- v->regs[v_outx] = this->m.outx_buf;
-}
-void SPC_DSP::voice_V9(voice_t *const v)
-{
- // Update ENVX
- v->regs[v_envx] = this->m.envx_buf;
-}
-
-// Most voices do all these in one clock, so make a handy composite
-void SPC_DSP::voice_V3(voice_t *const v)
-{
- this->voice_V3a(v);
- this->voice_V3b(v);
- this->voice_V3c(v);
-}
-
-// Common combinations of voice steps on different voices. This greatly reduces
-// code size and allows everything to be inlined in these functions.
-void SPC_DSP::voice_V7_V4_V1(voice_t *const v) { this->voice_V7(v); this->voice_V1(v + 3); this->voice_V4(v + 1); }
-void SPC_DSP::voice_V8_V5_V2(voice_t *const v) { this->voice_V8(v); this->voice_V5(v + 1); this->voice_V2(v + 2); }
-void SPC_DSP::voice_V9_V6_V3(voice_t *const v) { this->voice_V9(v); this->voice_V6(v + 1); this->voice_V3(v + 2); }
-
-//// Echo
-
-void SPC_DSP::echo_read(int ch)
-{
- int s = static_cast<int16_t>(get_le16(this->ECHO_PTR(ch)));
- // second copy simplifies wrap-around handling
- this->ECHO_FIR(0)[ch] = this->ECHO_FIR(8)[ch] = s >> 1;
-}
-
-void SPC_DSP::echo_22()
-{
- // History
- if (++this->m.echo_hist_pos >= &this->m.echo_hist[echo_hist_size])
- this->m.echo_hist_pos = this->m.echo_hist;
-
- this->m.t_echo_ptr = (this->m.t_esa * 0x100 + this->m.echo_offset) & 0xFFFF;
- this->echo_read(0);
-
- // FIR (using l and r temporaries below helps compiler optimize)
- int l = this->CALC_FIR(0, 0);
- int r = this->CALC_FIR(0, 1);
-
- this->m.t_echo_in[0] = l;
- this->m.t_echo_in[1] = r;
-}
-void SPC_DSP::echo_23()
-{
- int l = this->CALC_FIR(1, 0) + this->CALC_FIR(2, 0);
- int r = this->CALC_FIR(1, 1) + this->CALC_FIR(2, 1);
-
- this->m.t_echo_in[0] += l;
- this->m.t_echo_in[1] += r;
-
- echo_read(1);
-}
-void SPC_DSP::echo_24()
-{
- int l = this->CALC_FIR(3, 0) + this->CALC_FIR(4, 0) + this->CALC_FIR(5, 0);
- int r = this->CALC_FIR(3, 1) + this->CALC_FIR(4, 1) + this->CALC_FIR(5, 1);
-
- this->m.t_echo_in[0] += l;
- this->m.t_echo_in[1] += r;
-}
-void SPC_DSP::echo_25()
-{
- int l = this->m.t_echo_in[0] + this->CALC_FIR(6, 0);
- int r = this->m.t_echo_in[1] + this->CALC_FIR(6, 1);
-
- l = static_cast<int16_t>(l);
- r = static_cast<int16_t>(r);
-
- l += static_cast<int16_t>(this->CALC_FIR(7, 0));
- r += static_cast<int16_t>(this->CALC_FIR(7, 1));
-
- CLAMP16(l);
- CLAMP16(r);
-
- this->m.t_echo_in[0] = l & ~1;
- this->m.t_echo_in[1] = r & ~1;
-}
-int SPC_DSP::echo_output(int ch)
-{
- int out = static_cast<int16_t>((this->m.t_main_out [ch] * static_cast<int8_t>(this->m.regs[r_mvoll + ch * 0x10])) >> 7) +
- static_cast<int16_t>((this->m.t_echo_in [ch] * static_cast<int8_t>(this->m.regs[r_evoll + ch * 0x10])) >> 7);
- CLAMP16(out);
- return out;
-}
-void SPC_DSP::echo_26()
-{
- // Left output volumes
- // (save sample for next clock so we can output both together)
- this->m.t_main_out[0] = echo_output(0);
-
- // Echo feedback
- int l = this->m.t_echo_out[0] + static_cast<int16_t>((this->m.t_echo_in[0] * static_cast<int8_t>(this->m.regs[r_efb])) >> 7);
- int r = this->m.t_echo_out[1] + static_cast<int16_t>((this->m.t_echo_in[1] * static_cast<int8_t>(this->m.regs[r_efb])) >> 7);
-
- CLAMP16(l);
- CLAMP16(r);
-
- this->m.t_echo_out[0] = l & ~1;
- this->m.t_echo_out[1] = r & ~1;
-}
-void SPC_DSP::echo_27()
-{
- // Output
- int l = this->m.t_main_out[0];
- int r = echo_output(1);
- this->m.t_main_out[0] = this->m.t_main_out[1] = 0;
-
- // TODO: global muting isn't this simple (turns DAC on and off
- // or something, causing small ~37-sample pulse when first muted)
- if (this->m.regs[r_flg] & 0x40)
- l = r = 0;
-
- // Output sample to DAC
-#ifdef SPC_DSP_OUT_HOOK
- SPC_DSP_OUT_HOOK(l, r);
-#else
- sample_t *out = this->m.out;
- out[0] = l;
- out[1] = r;
- out += 2;
- if (out >= m.out_end)
- {
- out = this->m.extra;
- this->m.out_end = &this->m.extra[extra_size];
- }
- this->m.out = out;
-#endif
-}
-void SPC_DSP::echo_28()
-{
- this->m.t_echo_enabled = this->m.regs[r_flg];
-}
-void SPC_DSP::echo_write(int ch)
-{
- if (!(this->m.t_echo_enabled & 0x20))
- {
- if (this->m.t_echo_ptr >= 0xffc0 && this->rom_enabled)
- set_le16(&this->hi_ram[this->m.t_echo_ptr + ch * 2 - 0xffc0], this->m.t_echo_out [ch]);
- else
- set_le16(this->ECHO_PTR(ch), this->m.t_echo_out[ch]);
- }
-
- this->m.t_echo_out[ch] = 0;
-}
-void SPC_DSP::echo_29()
-{
- this->m.t_esa = this->m.regs[r_esa];
-
- if (!this->m.echo_offset)
- this->m.echo_length = (this->m.regs[r_edl] & 0x0F) * 0x800;
-
- this->m.echo_offset += 4;
- if (this->m.echo_offset >= this->m.echo_length)
- this->m.echo_offset = 0;
-
- // Write left echo
- this->echo_write(0);
-
- this->m.t_echo_enabled = this->m.regs[r_flg];
-}
-void SPC_DSP::echo_30()
-{
- // Write right echo
- this->echo_write(1);
-}
-
-//// Timing
-
-// Execute clock for a particular voice
-#define V(clock, voice) voice_##clock(&this->m.voices[voice]);
-
-/* The most common sequence of clocks uses composite operations
-for efficiency. For example, the following are equivalent to the
-individual steps on the right:
-
-V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5)
-V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4)
-V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */
-
-// Voice 0 1 2 3 4 5 6 7
-#define GEN_DSP_TIMING \
-PHASE(0) V(V5, 0) V(V2, 1) \
-PHASE(1) V(V6, 0) V(V3, 1) \
-PHASE(2) V(V7_V4_V1, 0) \
-PHASE(3) V(V8_V5_V2, 0) \
-PHASE(4) V(V9_V6_V3, 0) \
-PHASE(5) V(V7_V4_V1, 1) \
-PHASE(6) V(V8_V5_V2, 1) \
-PHASE(7) V(V9_V6_V3, 1) \
-PHASE(8) V(V7_V4_V1, 2) \
-PHASE(9) V(V8_V5_V2, 2) \
-PHASE(10) V(V9_V6_V3, 2) \
-PHASE(11) V(V7_V4_V1, 3) \
-PHASE(12) V(V8_V5_V2, 3) \
-PHASE(13) V(V9_V6_V3, 3) \
-PHASE(14) V(V7_V4_V1, 4) \
-PHASE(15) V(V8_V5_V2, 4) \
-PHASE(16) V(V9_V6_V3, 4) \
-PHASE(17) V(V1, 0) V(V7, 5) V(V4, 6) \
-PHASE(18) V(V8_V5_V2, 5) \
-PHASE(19) V(V9_V6_V3, 5) \
-PHASE(20) V(V1, 1) V(V7, 6) V(V4, 7) \
-PHASE(21) V(V8, 6) V(V5, 7) V(V2, 0) /* t_brr_next_addr order dependency */ \
-PHASE(22) V(V3a, 0) V(V9, 6) V(V6, 7) echo_22(); \
-PHASE(23) V(V7, 7) echo_23(); \
-PHASE(24) V(V8, 7) echo_24(); \
-PHASE(25) V(V3b, 0) V(V9, 7) echo_25(); \
-PHASE(26) echo_26(); \
-PHASE(27) misc_27(); echo_27(); \
-PHASE(28) misc_28(); echo_28(); \
-PHASE(29) misc_29(); echo_29(); \
-PHASE(30) misc_30(); V(V3c, 0) echo_30(); \
-PHASE(31) V(V4, 0) V(V1, 2)
-
-#ifndef SPC_DSP_CUSTOM_RUN
-void SPC_DSP::run(int clocks_remain)
-{
- assert(clocks_remain > 0);
-
- int phase = this->m.phase;
- this->m.phase = (phase + clocks_remain) & 31;
- switch (phase)
- {
- loop:
-#define PHASE(n) if (n && !--clocks_remain) break; case n:
- GEN_DSP_TIMING
-#undef PHASE
-
- if (--clocks_remain)
- goto loop;
- }
-}
-#endif
-
-//// Setup
-
-void SPC_DSP::init(uint8_t *ram_64k)
-{
- this->m.ram = ram_64k;
- this->mute_voices(0);
- this->disable_surround(false);
- this->set_output(nullptr, 0);
- this->reset();
-
- this->stereo_switch = 0xffff;
-
-#ifndef NDEBUG
- // be sure this sign-extends
- assert(static_cast<int16_t>(0x8000) == -0x8000);
-
- // be sure right shift preserves sign
- assert((-1 >> 1) == -1);
-
- // check clamp macro
- int i = 0x8000;
- CLAMP16(i);
- assert(i == 0x7FFF);
-
- i = -0x8001;
- CLAMP16(i);
- assert(i == -0x8000);
-
- blargg_verify_byte_order();
-#endif
-}
-
-void SPC_DSP::soft_reset_common()
-{
- assert(this->m.ram); // init() must have been called already
-
- this->m.noise = 0x4000;
- this->m.echo_hist_pos = this->m.echo_hist;
- this->m.every_other_sample = true;
- this->m.echo_offset = 0;
- this->m.phase = 0;
-
- this->init_counter();
-
- for (int i = 0; i < voice_count; ++i)
- this->m.voices[i].voice_number = i;
-}
-
-void SPC_DSP::soft_reset()
-{
- this->m.regs[r_flg] = 0xE0;
- this->soft_reset_common();
-}
-
-void SPC_DSP::load(const uint8_t regs[register_count])
-{
- std::copy_n(®s[0], static_cast<int>(register_count), &this->m.regs[0]);
- memset(&this->m.regs[register_count], 0, offsetof(state_t, ram) - register_count);
-
- // Internal state
- for (int i = voice_count; --i >= 0;)
- {
- auto &v = this->m.voices[i];
- v.brr_offset = 1;
- v.vbit = 1 << i;
- v.regs = &this->m.regs[i * 0x10];
- }
- this->m.new_kon = this->m.regs[r_kon];
- this->m.t_dir = this->m.regs[r_dir];
- this->m.t_esa = this->m.regs[r_esa];
-
- this->soft_reset_common();
-}
-
-void SPC_DSP::reset()
-{
- this->load(initial_regs);
-}
-
-//// Snes9x Accessor
-
-void SPC_DSP::set_stereo_switch(int value)
-{
- this->stereo_switch = value;
-}
-
-uint8_t SPC_DSP::reg_value(int ch, int addr)
-{
- return this->m.voices[ch].regs[addr];
-}
-
-int SPC_DSP::envx_value(int ch)
-{
- return this->m.voices[ch].env;
-}
-
--- a/src/in_snsf/snes9x/apu/SPC_DSP.h
+++ /dev/null
@@ -1,286 +1,1 @@
-// Highly accurate SNES SPC-700 DSP emulator
-// snes_spc 0.9.0
-#pragma once
-
-#include "blargg_common.h"
-
-class SPC_DSP
-{
-public:
- // Setup
-
- // Initializes DSP and has it use the 64K RAM provided
- void init(uint8_t *ram_64k);
-
- // Sets destination for output samples. If out is NULL or out_size is 0,
- // doesn't generate any.
- typedef short sample_t;
- void set_output(sample_t *out, int out_size);
-
- // Number of samples written to output since it was last set, always
- // a multiple of 2. Undefined if more samples were generated than
- // output buffer could hold.
- int sample_count() const;
-
- // Emulation
-
- // Resets DSP to power-on state
- void reset();
-
- // Emulates pressing reset switch on SNES
- void soft_reset();
-
- // Reads/writes DSP registers. For accuracy, you must first call run()
- // to catch the DSP up to present.
- int read(int addr) const;
- void write(int addr, int data);
-
- // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks
- // a pair of samples is be generated.
- void run(int clock_count);
-
- // Sound control
-
- // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events).
- // Reduces emulation accuracy.
- enum { voice_count = 8 };
- void mute_voices(int mask);
-
- // State
-
- // Resets DSP and uses supplied values to initialize registers
- enum { register_count = 128 };
- void load(const uint8_t regs[register_count]);
-
- // Snes9x Accessor
-
- int stereo_switch;
- bool rom_enabled; // mirror
- uint8_t *rom, *hi_ram; // mirror
-
- void set_stereo_switch(int);
- uint8_t reg_value(int, int);
- int envx_value(int);
-
- // DSP register addresses
-
- // Global registers
- enum
- {
- r_mvoll = 0x0C,
- r_mvolr = 0x1C,
- r_evoll = 0x2C,
- r_evolr = 0x3C,
- r_kon = 0x4C,
- r_koff = 0x5C,
- r_flg = 0x6C,
- r_endx = 0x7C,
- r_efb = 0x0D,
- r_pmon = 0x2D,
- r_non = 0x3D,
- r_eon = 0x4D,
- r_dir = 0x5D,
- r_esa = 0x6D,
- r_edl = 0x7D,
- r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
- };
-
- // Voice registers
- enum
- {
- v_voll = 0x00,
- v_volr = 0x01,
- v_pitchl = 0x02,
- v_pitchh = 0x03,
- v_srcn = 0x04,
- v_adsr0 = 0x05,
- v_adsr1 = 0x06,
- v_gain = 0x07,
- v_envx = 0x08,
- v_outx = 0x09
- };
-
-public:
- enum { extra_size = 16 };
- sample_t *extra() { return this->m.extra; }
- const sample_t *out_pos() const { return this->m.out; }
- void disable_surround(bool) { } // not supported
-public:
- enum { echo_hist_size = 8 };
-
- enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
- enum { brr_buf_size = 12 };
- struct voice_t
- {
- int buf[brr_buf_size * 2]; // decoded samples (twice the size to simplify wrap handling)
- int buf_pos; // place in buffer where next samples will be decoded
- int interp_pos; // relative fractional position in sample (0x1000 = 1.0)
- int brr_addr; // address of current BRR block
- int brr_offset; // current decoding offset in BRR block
- uint8_t *regs; // pointer to voice's DSP registers
- int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc.
- int kon_delay; // KON delay/current setup phase
- env_mode_t env_mode;
- int env; // current envelope level
- int hidden_env; // used by GAIN mode 7, very obscure quirk
- uint8_t t_envx_out;
- int voice_number;
- };
-private:
- enum { brr_block_size = 9 };
-
- struct state_t
- {
- uint8_t regs[register_count];
-
- // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling)
- int echo_hist[echo_hist_size * 2][2];
- int (*echo_hist_pos)[2]; // &echo_hist [0 to 7]
-
- bool every_other_sample; // toggles every sample
- int kon; // KON value when last checked
- int noise;
- int counter;
- int echo_offset; // offset from ESA in echo buffer
- int echo_length; // number of bytes that echo_offset will stop at
- int phase; // next clock cycle to run (0-31)
-
- // Hidden registers also written to when main register is written to
- int new_kon;
- uint8_t endx_buf;
- uint8_t envx_buf;
- uint8_t outx_buf;
-
- // Temporary state between clocks
-
- // read once per sample
- int t_pmon;
- int t_non;
- int t_eon;
- int t_dir;
- int t_koff;
-
- // read a few clocks ahead then used
- int t_brr_next_addr;
- int t_adsr0;
- int t_brr_header;
- int t_brr_byte;
- int t_srcn;
- int t_esa;
- int t_echo_enabled;
-
- // internal state that is recalculated every sample
- int t_dir_addr;
- int t_pitch;
- int t_output;
- int t_looped;
- int t_echo_ptr;
-
- // left/right sums
- int t_main_out[2];
- int t_echo_out[2];
- int t_echo_in[2];
-
- voice_t voices[voice_count];
-
- // non-emulation state
- uint8_t *ram; // 64K shared RAM between DSP and SMP
- int mute_mask;
- sample_t *out;
- sample_t *out_end;
- sample_t *out_begin;
- sample_t extra[extra_size];
- };
- state_t m;
-
- void init_counter();
- void run_counters();
- unsigned read_counter(int rate);
-
- int interpolate(const voice_t *v);
- void run_envelope(voice_t *const v);
- void decode_brr(voice_t *v);
-
- void misc_27();
- void misc_28();
- void misc_29();
- void misc_30();
-
- void voice_output(const voice_t *v, int ch);
- void voice_V1(voice_t *const);
- void voice_V2(voice_t *const);
- void voice_V3(voice_t *const);
- void voice_V3a(voice_t *const);
- void voice_V3b(voice_t *const);
- void voice_V3c(voice_t *const);
- void voice_V4(voice_t *const);
- void voice_V5(voice_t *const);
- void voice_V6(voice_t *const);
- void voice_V7(voice_t *const);
- void voice_V8(voice_t *const);
- void voice_V9(voice_t *const);
- void voice_V7_V4_V1(voice_t *const);
- void voice_V8_V5_V2(voice_t *const);
- void voice_V9_V6_V3(voice_t *const);
-
- // Current echo buffer pointer for left/right channel
- uint8_t *ECHO_PTR(int ch) { return &this->m.ram[this->m.t_echo_ptr + ch * 2]; }
- // Sample in echo history buffer, where 0 is the oldest
- int *ECHO_FIR(size_t i) { return this->m.echo_hist_pos[i]; }
- // Calculate FIR point for left/right channel
- int CALC_FIR(size_t i, int ch) { return (this->ECHO_FIR(i + 1)[ch] * static_cast<int8_t>(this->m.regs[r_fir + i * 0x10])) >> 6; }
-
- void echo_read(int ch);
- int echo_output(int ch);
- void echo_write(int ch);
- void echo_22();
- void echo_23();
- void echo_24();
- void echo_25();
- void echo_26();
- void echo_27();
- void echo_28();
- void echo_29();
- void echo_30();
-
- void soft_reset_common();
-};
-
-inline int SPC_DSP::sample_count() const { return this->m.out - this->m.out_begin; }
-
-inline int SPC_DSP::read(int addr) const
-{
- assert(static_cast<unsigned>(addr) < register_count);
- return this->m.regs[addr];
-}
-
-inline void SPC_DSP::write(int addr, int data)
-{
- assert(static_cast<unsigned>(addr) < register_count);
-
- this->m.regs[addr] = static_cast<uint8_t>(data);
- switch (addr & 0x0F)
- {
- case v_envx:
- this->m.envx_buf = static_cast<uint8_t>(data);
- break;
-
- case v_outx:
- this->m.outx_buf = static_cast<uint8_t>(data);
- break;
-
- case 0x0C:
- if (addr == r_kon)
- this->m.new_kon = static_cast<uint8_t>(data);
-
- if (addr == r_endx) // always cleared, regardless of data written
- {
- this->m.endx_buf = 0;
- this->m.regs[r_endx] = 0;
- }
- }
-}
-
-inline void SPC_DSP::mute_voices(int mask) { this->m.mute_mask = mask; }
-
--- a/src/in_snsf/snes9x/apu/apu.cpp
+++ b/src/in_snsf/snes9x/apu/apu.cpp
@@ -1,361 +1,90 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#include <memory>
#include "apu.h"
-#include "linear_resampler.h"
-#include "hermite_resampler.h"
-#include "bspline_resampler.h"
-#include "osculating_resampler.h"
-#include "sinc_resampler.h"
-
-bool SincResampler::initializedLUTs = false;
-double SincResampler::sinc_lut[SincResampler::SINC_SAMPLES + 1];
-
-static const uint32_t APU_DEFAULT_INPUT_RATE = 32000;
-static const int APU_MINIMUM_SAMPLE_COUNT = 512;
-static const int APU_MINIMUM_SAMPLE_BLOCK = 128;
-static const uint32_t APU_NUMERATOR_NTSC = 15664;
-static const uint32_t APU_DENOMINATOR_NTSC = 328125;
-static const uint32_t APU_NUMERATOR_PAL = 34176;
-static const uint32_t APU_DENOMINATOR_PAL = 709379;
-
-static std::unique_ptr<SNES_SPC> spc_core;
-
-static const uint8_t APUROM[] =
-{
- 0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0,
- 0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78,
- 0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4,
- 0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5,
- 0xCB, 0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB,
- 0x01, 0x10, 0xEF, 0x7E, 0xF4, 0x10, 0xEB, 0xBA,
- 0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4, 0xDD,
- 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF
-};
+#include "resampler.h"
+
+#include "bapu/snes/snes.hpp"
+#include "bapu/dsp/sdsp.hpp"
+#include "bapu/smp/smp.hpp"
+
+static constexpr int APU_DEFAULT_INPUT_RATE = 31950; // ~59.94Hz
+static constexpr int APU_SAMPLE_BLOCK = 48;
+static constexpr int APU_NUMERATOR_NTSC = 15664;
+static constexpr int APU_DENOMINATOR_NTSC = 328125;
+static constexpr int APU_NUMERATOR_PAL = 34176;
+static constexpr int APU_DENOMINATOR_PAL = 709379;
+// Max number of samples we'll ever generate before call to port API and
+// moving the samples to the resampler.
+// This is 535 sample frames, which corresponds to 1 video frame + some leeway
+// for use with SoundSync, multiplied by 2, for left and right samples.
+static constexpr int MINIMUM_BUFFER_SIZE = 550 * 2;
+
+namespace SNES
+{
+ CPU cpu;
+}
namespace spc
{
static bool sound_in_sync = true;
static bool sound_enabled = false;
- static int buffer_size;
- static int lag_master = 0;
- static int lag = 0;
-
- static std::unique_ptr<uint8_t[]> landing_buffer;
- static std::unique_ptr<uint8_t[]> shrink_buffer;
-
static std::unique_ptr<Resampler> resampler;
static int32_t reference_time;
static uint32_t remainder;
- static const int timing_hack_numerator = SNES_SPC::tempo_unit;
- static int timing_hack_denominator = SNES_SPC::tempo_unit;
+ static constexpr int timing_hack_numerator = 256;
+ static int timing_hack_denominator = 256;
/* Set these to NTSC for now. Will change to PAL in S9xAPUTimingSetSpeedup
if necessary on game load. */
static uint32_t ratio_numerator = APU_NUMERATOR_NTSC;
static uint32_t ratio_denominator = APU_DENOMINATOR_NTSC;
}
-static void EightBitize(uint8_t *buffer, int sample_count)
-{
- int16_t *buf16 = reinterpret_cast<int16_t *>(buffer);
-
- for (int i = 0; i < sample_count; ++i)
- buffer[i] = static_cast<uint8_t>((buf16[i] / 256) + 128);
-}
-
-static void DeStereo(uint8_t *buffer, int sample_count)
-{
- int16_t *buf = reinterpret_cast<int16_t *>(buffer);
-
- for (int i = 0; i < sample_count >> 1; ++i)
- {
- int32_t s1 = static_cast<int32_t>(buf[2 * i]);
- int32_t s2 = static_cast<int32_t>(buf[2 * i + 1]);
- buf[i] = static_cast<int16_t>((s1 + s2) >> 1);
- }
-}
-
-static void ReverseStereo(uint8_t *src_buffer, int sample_count)
-{
- int16_t *buffer = reinterpret_cast<int16_t *>(src_buffer);
-
- for (int i = 0; i < sample_count; i += 2)
- std::swap(buffer[i], buffer[i + 1]);
-}
-
-bool S9xMixSamples(uint8_t *buffer, int sample_count)
-{
- static int shrink_buffer_size = -1;
- uint8_t *dest;
-
- if (!Settings.SixteenBitSound || !Settings.Stereo)
- {
- /* We still need both stereo samples for generating the mono sample */
- if (!Settings.Stereo)
- sample_count <<= 1;
-
- /* We still have to generate 16-bit samples for bit-dropping, too */
- if (shrink_buffer_size < (sample_count << 1))
- {
- spc::shrink_buffer.reset(new uint8_t[sample_count << 1]);
- shrink_buffer_size = sample_count << 1;
- }
-
- dest = spc::shrink_buffer.get();
- }
- else
- dest = buffer;
+void S9xClearSamples()
+{
+ spc::resampler->clear();
+}
+
+bool S9xMixSamples(uint8_t *dest, int sample_count)
+{
+ int16_t *out = reinterpret_cast<int16_t *>(dest);
if (Settings.Mute)
{
- std::fill_n(&dest[0], sample_count << 1, 0);
- spc::resampler->clear();
-
- return false;
+ std::fill_n(&out[0], sample_count, 0);
+ S9xClearSamples();
}
else
{
- if (spc::resampler->avail() >= sample_count + spc::lag)
- {
- spc::resampler->read(reinterpret_cast<short *>(dest), sample_count);
- if (spc::lag == spc::lag_master)
- spc::lag = 0;
- }
+ if (spc::resampler->avail() >= sample_count)
+ spc::resampler->read(reinterpret_cast<short *>(out), sample_count);
else
{
- std::fill_n(&buffer[0], (sample_count << (Settings.SixteenBitSound ? 1 : 0)) >> (Settings.Stereo ? 0 : 1), Settings.SixteenBitSound ? 0 : 128);
- if (!spc::lag)
- spc::lag = spc::lag_master;
-
+ std::fill_n(&out[0], sample_count, 0);
return false;
}
}
- if (Settings.ReverseStereo && Settings.Stereo)
- ReverseStereo(dest, sample_count);
-
- if (!Settings.Stereo || !Settings.SixteenBitSound)
- {
- if (!Settings.Stereo)
- {
- DeStereo(dest, sample_count);
- sample_count >>= 1;
- }
-
- if (!Settings.SixteenBitSound)
- EightBitize(dest, sample_count);
-
- std::copy_n(&dest[0], sample_count << (Settings.SixteenBitSound ? 1 : 0), &buffer[0]);
- }
+ spc::sound_in_sync = spc::resampler->space_empty() >= 535 * 2 || !Settings.SoundSync || Settings.TurboMode || Settings.Mute;
return true;
}
int S9xGetSampleCount()
{
- return spc::resampler->avail() >> (Settings.Stereo ? 0 : 1);
-}
-
-void S9xFinalizeSamples()
-{
- if (!Settings.Mute)
- {
- if (!spc::resampler->push(reinterpret_cast<short *>(spc::landing_buffer.get()), spc_core->sample_count()))
- {
- /* We weren't able to process the entire buffer. Potential overrun. */
- spc::sound_in_sync = false;
-
- if (Settings.SoundSync && !Settings.TurboMode)
- return;
- }
- }
-
- spc::sound_in_sync = !Settings.SoundSync || Settings.TurboMode || Settings.Mute || spc::resampler->space_empty() >= spc::resampler->space_filled();
-
- spc_core->set_output(reinterpret_cast<SNES_SPC::sample_t *>(spc::landing_buffer.get()), spc::buffer_size >> 1);
+ return spc::resampler->avail();
}
void S9xLandSamples()
{
- S9xFinalizeSamples();
+ spc::sound_in_sync = spc::resampler->space_empty() >= 535 * 2 || !Settings.SoundSync || Settings.TurboMode || Settings.Mute;
}
bool S9xSyncSound()
@@ -377,42 +106,20 @@
spc::resampler->time_ratio(time_ratio);
}
-template<class ResamplerClass> bool S9xInitSound(int buffer_ms, int lag_ms)
-{
- // buffer_ms : buffer size given in millisecond
- // lag_ms : allowable time-lag given in millisecond
-
- int sample_count = buffer_ms * 32000 / 1000;
- int lag_sample_count = lag_ms * 32000 / 1000;
-
- spc::lag_master = lag_sample_count;
- if (Settings.Stereo)
- spc::lag_master <<= 1;
- spc::lag = spc::lag_master;
-
- if (sample_count < APU_MINIMUM_SAMPLE_COUNT)
- sample_count = APU_MINIMUM_SAMPLE_COUNT;
-
- spc::buffer_size = sample_count;
- if (Settings.Stereo)
- spc::buffer_size <<= 1;
- if (Settings.SixteenBitSound)
- spc::buffer_size <<= 1;
-
- spc::landing_buffer.reset(new uint8_t[spc::buffer_size * 2]);
- if (!spc::landing_buffer)
+bool S9xInitSound(int buffer_ms)
+{
+ // The resampler and spc unit use samples (16-bit short) as arguments.
+ int buffer_size_samples = MINIMUM_BUFFER_SIZE;
+ int requested_buffer_size_samples = Settings.SoundPlaybackRate * buffer_ms * 2 / 1000;
+
+ if (requested_buffer_size_samples > buffer_size_samples)
+ buffer_size_samples = requested_buffer_size_samples;
+
+ spc::resampler.reset(new Resampler(buffer_size_samples));
+ if (!spc::resampler)
return false;
- /* The resampler and spc unit use samples (16-bit short) as
- * arguments. Use 2x in the resampler for buffer leveling with SoundSync */
- spc::resampler.reset(new ResamplerClass(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)));
- if (!spc::resampler)
- {
- spc::landing_buffer.reset();
- return false;
- }
-
- spc_core->set_output(reinterpret_cast<SNES_SPC::sample_t *>(spc::landing_buffer.get()), spc::buffer_size >> 1);
+ SNES::dsp.spc_dsp.set_output(spc::resampler.get());
UpdatePlaybackRate();
@@ -421,15 +128,9 @@
return spc::sound_enabled;
}
-template bool S9xInitSound<LinearResampler>(int, int);
-template bool S9xInitSound<HermiteResampler>(int, int);
-template bool S9xInitSound<BsplineResampler>(int, int);
-template bool S9xInitSound<OsculatingResampler>(int, int);
-template bool S9xInitSound<SincResampler>(int, int);
-
void S9xSetSoundControl(uint8_t voice_switch)
{
- spc_core->dsp_set_stereo_switch((voice_switch << 8) | voice_switch);
+ SNES::dsp.spc_dsp.set_stereo_switch((voice_switch << 8) | voice_switch);
}
void S9xSetSoundMute(bool mute)
@@ -441,15 +142,6 @@
bool S9xInitAPU()
{
- spc_core.reset(new SNES_SPC);
- if (!spc_core)
- return false;
-
- spc_core->init();
- spc_core->init_rom(APUROM);
-
- spc::landing_buffer.reset();
- spc::shrink_buffer.reset();
spc::resampler.reset();
return true;
@@ -457,10 +149,7 @@
void S9xDeinitAPU()
{
- spc_core.reset();
spc::resampler.reset();
- spc::landing_buffer.reset();
- spc::shrink_buffer.reset();
}
static inline int S9xAPUGetClock(int32_t cpucycles)
@@ -473,14 +162,26 @@
return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) % spc::ratio_denominator;
}
+void S9xAPUExecute()
+{
+ SNES::smp.clock -= S9xAPUGetClock(CPU.Cycles);
+ SNES::smp.enter();
+
+ spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles);
+
+ S9xAPUSetReferenceTime(CPU.Cycles);
+}
+
uint8_t S9xAPUReadPort(int port)
{
- return static_cast<uint8_t>(spc_core->read_port(S9xAPUGetClock(CPU.Cycles), port));
+ S9xAPUExecute();
+ return static_cast<uint8_t>(SNES::smp.port_read(port & 3));
}
void S9xAPUWritePort(int port, uint8_t byte)
{
- spc_core->write_port(S9xAPUGetClock(CPU.Cycles), port, byte);
+ S9xAPUExecute();
+ SNES::cpu.port_write(port & 3, byte);
}
void S9xAPUSetReferenceTime(int32_t cpucycles)
@@ -488,28 +189,18 @@
spc::reference_time = cpucycles;
}
-void S9xAPUExecute()
-{
- /* Accumulate partial APU cycles */
- spc_core->end_frame(S9xAPUGetClock(CPU.Cycles));
-
- spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles);
-
- S9xAPUSetReferenceTime(CPU.Cycles);
-}
-
void S9xAPUEndScanline()
{
S9xAPUExecute();
-
- if (spc_core->sample_count() >= APU_MINIMUM_SAMPLE_BLOCK || !spc::sound_in_sync)
+ SNES::dsp.synchronize();
+
+ if (spc::resampler->space_filled() >= APU_SAMPLE_BLOCK || !spc::sound_in_sync)
S9xLandSamples();
}
void S9xAPUTimingSetSpeedup(int ticks)
{
- spc::timing_hack_denominator = SNES_SPC::tempo_unit - ticks;
- spc_core->set_tempo(spc::timing_hack_denominator);
+ spc::timing_hack_denominator = 256 - ticks;
spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC;
spc::ratio_denominator = (Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC) * spc::timing_hack_denominator / spc::timing_hack_numerator;
@@ -517,18 +208,15 @@
UpdatePlaybackRate();
}
-void S9xAPUAllowTimeOverflow(bool allow)
-{
- spc_core->spc_allow_time_overflow(allow);
-}
-
void S9xResetAPU()
{
spc::reference_time = 0;
spc::remainder = 0;
- spc_core->reset();
- spc_core->set_output(reinterpret_cast<SNES_SPC::sample_t *>(spc::landing_buffer.get()), spc::buffer_size >> 1);
-
- spc::resampler->clear();
-}
-
+
+ SNES::cpu.reset();
+ SNES::smp.power();
+ SNES::dsp.power();
+
+ S9xClearSamples();
+}
+
--- a/src/in_snsf/snes9x/apu/apu.h
+++ b/src/in_snsf/snes9x/apu/apu.h
@@ -1,184 +1,12 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
#include "../snes9x.h"
-#include "SNES_SPC.h"
bool S9xInitAPU();
void S9xDeinitAPU();
@@ -188,9 +16,8 @@
void S9xAPUEndScanline();
void S9xAPUSetReferenceTime(int32_t);
void S9xAPUTimingSetSpeedup(int);
-void S9xAPUAllowTimeOverflow(bool);
-template<class ResamplerClass> bool S9xInitSound(int, int);
+bool S9xInitSound(int);
bool S9xOpenSoundDevice();
bool S9xSyncSound();
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/dsp/SPC_DSP.cpp
@@ -1,1 +1,1194 @@
-
+// snes_spc 0.9.0. http://www.slack.net/~ant/
+
+#include <algorithm>
+#include <cstring>
+#include "SPC_DSP.h"
+#include "../../../snes9x.h"
+
+#include "blargg_endian.h"
+
+/* Copyright (C) 2007 Shay Green. This module is free software; you
+can redistribute it and/or modify it under the terms of the GNU Lesser
+General Public License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version. This
+module is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+details. You should have received a copy of the GNU Lesser General Public
+License along with this module; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#if INT_MAX < 0x7FFFFFFF
+# error "Requires that int type have at least 32 bits"
+#endif
+
+static constexpr uint8_t initial_regs[] =
+{
+ 0x45, 0x8B, 0x5A, 0x9A, 0xE4, 0x82, 0x1B, 0x78, 0x00, 0x00, 0xAA, 0x96, 0x89, 0x0E, 0xE0, 0x80,
+ 0x2A, 0x49, 0x3D, 0xBA, 0x14, 0xA0, 0xAC, 0xC5, 0x00, 0x00, 0x51, 0xBB, 0x9C, 0x4E, 0x7B, 0xFF,
+ 0xF4, 0xFD, 0x57, 0x32, 0x37, 0xD9, 0x42, 0x22, 0x00, 0x00, 0x5B, 0x3C, 0x9F, 0x1B, 0x87, 0x9A,
+ 0x6F, 0x27, 0xAF, 0x7B, 0xE5, 0x68, 0x0A, 0xD9, 0x00, 0x00, 0x9A, 0xC5, 0x9C, 0x4E, 0x7B, 0xFF,
+ 0xEA, 0x21, 0x78, 0x4F, 0xDD, 0xED, 0x24, 0x14, 0x00, 0x00, 0x77, 0xB1, 0xD1, 0x36, 0xC1, 0x67,
+ 0x52, 0x57, 0x46, 0x3D, 0x59, 0xF4, 0x87, 0xA4, 0x00, 0x00, 0x7E, 0x44, 0x00, 0x4E, 0x7B, 0xFF,
+ 0x75, 0xF5, 0x06, 0x97, 0x10, 0xC3, 0x24, 0xBB, 0x00, 0x00, 0x7B, 0x7A, 0xE0, 0x60, 0x12, 0x0F,
+ 0xF7, 0x74, 0x1C, 0xE5, 0x39, 0x3D, 0x73, 0xC1, 0x00, 0x00, 0x7A, 0xB3, 0xFF, 0x4E, 0x7B, 0xFF
+};
+
+// if ( io < -32768 ) io = -32768;
+// if ( io > 32767 ) io = 32767;
+template<typename T> static inline void CLAMP16(T &io)
+{
+ if (static_cast<int16_t>(io) != io)
+ io = (io >> 31) ^ 0x7FFF;
+}
+
+void SPC_DSP::set_output(Resampler *newResampler)
+{
+ this->resampler = newResampler;
+}
+
+void SPC_DSP::set_output(sample_t *out, int size)
+{
+ assert(!(size & 1)); // must be even
+ this->m.out_begin = this->m.out = out;
+ this->m.out_end = out + size;
+}
+
+// Volume registers and efb are signed! Easy to forget int8_t cast.
+// Prefixes are to avoid accidental use of locals with same names.
+
+// Gaussian interpolation
+
+static constexpr short gauss[] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
+ 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+ 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
+ 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
+ 18, 19, 19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27,
+ 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 36, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 58, 59, 60, 61, 62, 64, 65, 66, 67, 69, 70, 71, 73, 74, 76, 77,
+ 78, 80, 81, 83, 84, 86, 87, 89, 90, 92, 94, 95, 97, 99, 100, 102,
+ 104, 106, 107, 109, 111, 113, 115, 117, 118, 120, 122, 124, 126, 128, 130, 132,
+ 134, 137, 139, 141, 143, 145, 147, 150, 152, 154, 156, 159, 161, 163, 166, 168,
+ 171, 173, 175, 178, 180, 183, 186, 188, 191, 193, 196, 199, 201, 204, 207, 210,
+ 212, 215, 218, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 251, 254, 257,
+ 260, 263, 267, 270, 273, 276, 280, 283, 286, 290, 293, 297, 300, 304, 307, 311,
+ 314, 318, 321, 325, 328, 332, 336, 339, 343, 347, 351, 354, 358, 362, 366, 370,
+ 374, 378, 381, 385, 389, 393, 397, 401, 405, 410, 414, 418, 422, 426, 430, 434,
+ 439, 443, 447, 451, 456, 460, 464, 469, 473, 477, 482, 486, 491, 495, 499, 504,
+ 508, 513, 517, 522, 527, 531, 536, 540, 545, 550, 554, 559, 563, 568, 573, 577,
+ 582, 587, 592, 596, 601, 606, 611, 615, 620, 625, 630, 635, 640, 644, 649, 654,
+ 659, 664, 669, 674, 678, 683, 688, 693, 698, 703, 708, 713, 718, 723, 728, 732,
+ 737, 742, 747, 752, 757, 762, 767, 772, 777, 782, 787, 792, 797, 802, 806, 811,
+ 816, 821, 826, 831, 836, 841, 846, 851, 855, 860, 865, 870, 875, 880, 884, 889,
+ 894, 899, 904, 908, 913, 918, 923, 927, 932, 937, 941, 946, 951, 955, 960, 965,
+ 969, 974, 978, 983, 988, 992, 997,1001,1005,1010,1014,1019,1023,1027,1032,1036,
+ 1040,1045,1049,1053,1057,1061,1066,1070,1074,1078,1082,1086,1090,1094,1098,1102,
+ 1106,1109,1113,1117,1121,1125,1128,1132,1136,1139,1143,1146,1150,1153,1157,1160,
+ 1164,1167,1170,1174,1177,1180,1183,1186,1190,1193,1196,1199,1202,1205,1207,1210,
+ 1213,1216,1219,1221,1224,1227,1229,1232,1234,1237,1239,1241,1244,1246,1248,1251,
+ 1253,1255,1257,1259,1261,1263,1265,1267,1269,1270,1272,1274,1275,1277,1279,1280,
+ 1282,1283,1284,1286,1287,1288,1290,1291,1292,1293,1294,1295,1296,1297,1297,1298,
+ 1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305
+};
+
+// Interpolation by Mudlord
+static constexpr short cubic[] =
+{
+ 0, -4, -8, -12, -16, -20, -23, -27, -30, -34, -37, -41, -44, -47, -50, -53,
+ -56, -59, -62, -65, -68, -71, -73, -76, -78, -81, -84, -87, -89, -91, -93, -95,
+ -98,-100,-102,-104,-106,-109,-110,-112,-113,-116,-117,-119,-121,-122,-123,-125,
+ -126,-128,-129,-131,-132,-134,-134,-136,-136,-138,-138,-140,-141,-141,-142,-143,
+ -144,-144,-145,-146,-147,-148,-147,-148,-148,-149,-149,-150,-150,-150,-150,-151,
+ -151,-151,-151,-151,-152,-152,-151,-152,-151,-152,-151,-151,-151,-151,-150,-150,
+ -150,-149,-149,-149,-149,-148,-147,-147,-146,-146,-145,-145,-144,-144,-143,-142,
+ -141,-141,-140,-139,-139,-138,-137,-136,-135,-135,-133,-133,-132,-131,-130,-129,
+ -128,-127,-126,-125,-124,-123,-121,-121,-119,-118,-117,-116,-115,-114,-112,-111,
+ -110,-109,-107,-106,-105,-104,-102,-102,-100, -99, -97, -97, -95, -94, -92, -91,
+ -90, -88, -87, -86, -85, -84, -82, -81, -79, -78, -76, -76, -74, -73, -71, -70,
+ -68, -67, -66, -65, -63, -62, -60, -60, -58, -57, -55, -55, -53, -52, -50, -49,
+ -48, -46, -45, -44, -43, -42, -40, -39, -38, -37, -36, -35, -34, -32, -31, -30,
+ -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -19, -17, -16, -15, -14,
+ -14, -13, -12, -11, -11, -10, -9, -9, -8, -8, -7, -7, -6, -5, -4, -4,
+ -3, -3, -3, -2, -2, -2, -1, -1, 0, -1, 0, -1, 0, 0, 0, 0,
+ 0,
+ 2048,2048,2048,2048,2047,2047,2046,2045,2043,2042,2041,2039,2037,2035,2033,2031,
+ 2028,2026,2024,2021,2018,2015,2012,2009,2005,2002,1999,1995,1991,1987,1982,1978,
+ 1974,1969,1965,1960,1955,1951,1946,1940,1934,1929,1924,1918,1912,1906,1900,1895,
+ 1888,1882,1875,1869,1862,1856,1849,1842,1835,1828,1821,1814,1806,1799,1791,1783,
+ 1776,1768,1760,1753,1744,1737,1728,1720,1711,1703,1695,1686,1677,1668,1659,1651,
+ 1641,1633,1623,1614,1605,1596,1587,1577,1567,1559,1549,1539,1529,1520,1510,1499,
+ 1490,1480,1470,1460,1450,1440,1430,1420,1408,1398,1389,1378,1367,1357,1346,1336,
+ 1325,1315,1304,1293,1282,1272,1261,1250,1239,1229,1218,1207,1196,1185,1174,1163,
+ 1152,1141,1130,1119,1108,1097,1086,1075,1063,1052,1042,1030,1019,1008, 997, 986,
+ 974, 964, 952, 941, 930, 919, 908, 897, 886, 875, 864, 853, 842, 831, 820, 809,
+ 798, 787, 776, 765, 754, 744, 733, 722, 711, 700, 690, 679, 668, 658, 647, 637,
+ 626, 616, 605, 595, 584, 574, 564, 554, 543, 534, 524, 514, 503, 494, 483, 473,
+ 464, 454, 444, 435, 425, 416, 407, 397, 387, 378, 370, 360, 351, 342, 333, 325,
+ 315, 307, 298, 290, 281, 273, 265, 256, 248, 241, 233, 225, 216, 209, 201, 193,
+ 186, 178, 171, 164, 157, 150, 143, 137, 129, 123, 117, 110, 103, 97, 91, 85,
+ 79, 74, 68, 62, 56, 51, 46, 41, 35, 31, 27, 22, 17, 13, 8, 4,
+ 0
+};
+
+static constexpr short sinc[] =
+{
+ 39, -315, 666, 15642, 666, -315, 39, -38,
+ 38, -302, 613, 15642, 718, -328, 41, -38,
+ 36, -288, 561, 15641, 772, -342, 42, -38,
+ 35, -275, 510, 15639, 826, -355, 44, -38,
+ 33, -263, 459, 15636, 880, -369, 46, -38,
+ 32, -250, 408, 15632, 935, -383, 47, -38,
+ 31, -237, 358, 15628, 990, -396, 49, -38,
+ 29, -224, 309, 15622, 1046, -410, 51, -38,
+ 28, -212, 259, 15616, 1103, -425, 53, -38,
+ 27, -200, 211, 15609, 1159, -439, 54, -38,
+ 25, -188, 163, 15601, 1216, -453, 56, -38,
+ 24, -175, 115, 15593, 1274, -467, 58, -38,
+ 23, -164, 68, 15583, 1332, -482, 60, -38,
+ 22, -152, 22, 15573, 1391, -496, 62, -37,
+ 21, -140, -24, 15562, 1450, -511, 64, -37,
+ 19, -128, -70, 15550, 1509, -526, 66, -37,
+ 18, -117, -115, 15538, 1569, -540, 68, -37,
+ 17, -106, -159, 15524, 1629, -555, 70, -37,
+ 16, -94, -203, 15510, 1690, -570, 72, -36,
+ 15, -83, -247, 15495, 1751, -585, 74, -36,
+ 14, -72, -289, 15479, 1813, -600, 76, -36,
+ 13, -62, -332, 15462, 1875, -616, 79, -36,
+ 12, -51, -374, 15445, 1937, -631, 81, -35,
+ 11, -40, -415, 15426, 2000, -646, 83, -35,
+ 11, -30, -456, 15407, 2063, -662, 85, -35,
+ 10, -20, -496, 15387, 2127, -677, 88, -34,
+ 9, -9, -536, 15366, 2191, -693, 90, -34,
+ 8, 1, -576, 15345, 2256, -708, 92, -34,
+ 7, 10, -614, 15323, 2321, -724, 95, -33,
+ 7, 20, -653, 15300, 2386, -740, 97, -33,
+ 6, 30, -690, 15276, 2451, -755, 99, -33,
+ 5, 39, -728, 15251, 2517, -771, 102, -32,
+ 5, 49, -764, 15226, 2584, -787, 104, -32,
+ 4, 58, -801, 15200, 2651, -803, 107, -32,
+ 3, 67, -836, 15173, 2718, -819, 109, -31,
+ 3, 76, -871, 15145, 2785, -835, 112, -31,
+ 2, 85, -906, 15117, 2853, -851, 115, -30,
+ 2, 93, -940, 15087, 2921, -867, 117, -30,
+ 1, 102, -974, 15057, 2990, -883, 120, -29,
+ 1, 110, -1007, 15027, 3059, -899, 122, -29,
+ 0, 118, -1039, 14995, 3128, -915, 125, -29,
+ 0, 127, -1071, 14963, 3198, -931, 128, -28,
+ -1, 135, -1103, 14930, 3268, -948, 131, -28,
+ -1, 142, -1134, 14896, 3338, -964, 133, -27,
+ -1, 150, -1164, 14862, 3409, -980, 136, -27,
+ -2, 158, -1194, 14827, 3480, -996, 139, -26,
+ -2, 165, -1224, 14791, 3551, -1013, 142, -26,
+ -3, 172, -1253, 14754, 3622, -1029, 144, -25,
+ -3, 179, -1281, 14717, 3694, -1045, 147, -25,
+ -3, 187, -1309, 14679, 3766, -1062, 150, -24,
+ -3, 193, -1337, 14640, 3839, -1078, 153, -24,
+ -4, 200, -1363, 14601, 3912, -1094, 156, -23,
+ -4, 207, -1390, 14561, 3985, -1110, 159, -23,
+ -4, 213, -1416, 14520, 4058, -1127, 162, -22,
+ -4, 220, -1441, 14479, 4131, -1143, 165, -22,
+ -4, 226, -1466, 14437, 4205, -1159, 168, -22,
+ -5, 232, -1490, 14394, 4279, -1175, 171, -21,
+ -5, 238, -1514, 14350, 4354, -1192, 174, -21,
+ -5, 244, -1537, 14306, 4428, -1208, 177, -20,
+ -5, 249, -1560, 14261, 4503, -1224, 180, -20,
+ -5, 255, -1583, 14216, 4578, -1240, 183, -19,
+ -5, 260, -1604, 14169, 4653, -1256, 186, -19,
+ -5, 265, -1626, 14123, 4729, -1272, 189, -18,
+ -5, 271, -1647, 14075, 4805, -1288, 192, -18,
+ -5, 276, -1667, 14027, 4881, -1304, 195, -17,
+ -6, 280, -1687, 13978, 4957, -1320, 198, -17,
+ -6, 285, -1706, 13929, 5033, -1336, 201, -16,
+ -6, 290, -1725, 13879, 5110, -1352, 204, -16,
+ -6, 294, -1744, 13829, 5186, -1368, 207, -15,
+ -6, 299, -1762, 13777, 5263, -1383, 210, -15,
+ -6, 303, -1779, 13726, 5340, -1399, 213, -14,
+ -6, 307, -1796, 13673, 5418, -1414, 216, -14,
+ -6, 311, -1813, 13620, 5495, -1430, 219, -13,
+ -5, 315, -1829, 13567, 5573, -1445, 222, -13,
+ -5, 319, -1844, 13512, 5651, -1461, 225, -13,
+ -5, 322, -1859, 13458, 5728, -1476, 229, -12,
+ -5, 326, -1874, 13402, 5806, -1491, 232, -12,
+ -5, 329, -1888, 13347, 5885, -1506, 235, -11,
+ -5, 332, -1902, 13290, 5963, -1521, 238, -11,
+ -5, 335, -1915, 13233, 6041, -1536, 241, -10,
+ -5, 338, -1928, 13176, 6120, -1551, 244, -10,
+ -5, 341, -1940, 13118, 6199, -1566, 247, -10,
+ -5, 344, -1952, 13059, 6277, -1580, 250, -9,
+ -5, 347, -1964, 13000, 6356, -1595, 253, -9,
+ -5, 349, -1975, 12940, 6435, -1609, 256, -8,
+ -4, 352, -1986, 12880, 6514, -1623, 259, -8,
+ -4, 354, -1996, 12819, 6594, -1637, 262, -8,
+ -4, 356, -2005, 12758, 6673, -1651, 265, -7,
+ -4, 358, -2015, 12696, 6752, -1665, 268, -7,
+ -4, 360, -2024, 12634, 6831, -1679, 271, -7,
+ -4, 362, -2032, 12572, 6911, -1693, 274, -6,
+ -4, 364, -2040, 12509, 6990, -1706, 277, -6,
+ -4, 366, -2048, 12445, 7070, -1719, 280, -6,
+ -3, 367, -2055, 12381, 7149, -1732, 283, -5,
+ -3, 369, -2062, 12316, 7229, -1745, 286, -5,
+ -3, 370, -2068, 12251, 7308, -1758, 289, -5,
+ -3, 371, -2074, 12186, 7388, -1771, 291, -4,
+ -3, 372, -2079, 12120, 7467, -1784, 294, -4,
+ -3, 373, -2084, 12054, 7547, -1796, 297, -4,
+ -3, 374, -2089, 11987, 7626, -1808, 300, -4,
+ -2, 375, -2094, 11920, 7706, -1820, 303, -3,
+ -2, 376, -2098, 11852, 7785, -1832, 305, -3,
+ -2, 376, -2101, 11785, 7865, -1844, 308, -3,
+ -2, 377, -2104, 11716, 7944, -1855, 311, -3,
+ -2, 377, -2107, 11647, 8024, -1866, 313, -2,
+ -2, 378, -2110, 11578, 8103, -1877, 316, -2,
+ -2, 378, -2112, 11509, 8182, -1888, 318, -2,
+ -1, 378, -2113, 11439, 8262, -1899, 321, -2,
+ -1, 378, -2115, 11369, 8341, -1909, 323, -2,
+ -1, 378, -2116, 11298, 8420, -1920, 326, -2,
+ -1, 378, -2116, 11227, 8499, -1930, 328, -1,
+ -1, 378, -2116, 11156, 8578, -1940, 331, -1,
+ -1, 378, -2116, 11084, 8656, -1949, 333, -1,
+ -1, 377, -2116, 11012, 8735, -1959, 335, -1,
+ -1, 377, -2115, 10940, 8814, -1968, 337, -1,
+ -1, 377, -2114, 10867, 8892, -1977, 340, -1,
+ -1, 376, -2112, 10795, 8971, -1985, 342, -1,
+ 0, 375, -2111, 10721, 9049, -1994, 344, -1,
+ 0, 375, -2108, 10648, 9127, -2002, 346, 0,
+ 0, 374, -2106, 10574, 9205, -2010, 348, 0,
+ 0, 373, -2103, 10500, 9283, -2018, 350, 0,
+ 0, 372, -2100, 10426, 9360, -2025, 352, 0,
+ 0, 371, -2097, 10351, 9438, -2032, 354, 0,
+ 0, 370, -2093, 10276, 9515, -2039, 355, 0,
+ 0, 369, -2089, 10201, 9592, -2046, 357, 0,
+ 0, 367, -2084, 10126, 9669, -2052, 359, 0,
+ 0, 366, -2080, 10050, 9745, -2058, 360, 0,
+ 0, 365, -2075, 9974, 9822, -2064, 362, 0,
+ 0, 363, -2070, 9898, 9898, -2070, 363, 0,
+ 0, 362, -2064, 9822, 9974, -2075, 365, 0,
+ 0, 360, -2058, 9745, 10050, -2080, 366, 0,
+ 0, 359, -2052, 9669, 10126, -2084, 367, 0,
+ 0, 357, -2046, 9592, 10201, -2089, 369, 0,
+ 0, 355, -2039, 9515, 10276, -2093, 370, 0,
+ 0, 354, -2032, 9438, 10351, -2097, 371, 0,
+ 0, 352, -2025, 9360, 10426, -2100, 372, 0,
+ 0, 350, -2018, 9283, 10500, -2103, 373, 0,
+ 0, 348, -2010, 9205, 10574, -2106, 374, 0,
+ 0, 346, -2002, 9127, 10648, -2108, 375, 0,
+ -1, 344, -1994, 9049, 10721, -2111, 375, 0,
+ -1, 342, -1985, 8971, 10795, -2112, 376, -1,
+ -1, 340, -1977, 8892, 10867, -2114, 377, -1,
+ -1, 337, -1968, 8814, 10940, -2115, 377, -1,
+ -1, 335, -1959, 8735, 11012, -2116, 377, -1,
+ -1, 333, -1949, 8656, 11084, -2116, 378, -1,
+ -1, 331, -1940, 8578, 11156, -2116, 378, -1,
+ -1, 328, -1930, 8499, 11227, -2116, 378, -1,
+ -2, 326, -1920, 8420, 11298, -2116, 378, -1,
+ -2, 323, -1909, 8341, 11369, -2115, 378, -1,
+ -2, 321, -1899, 8262, 11439, -2113, 378, -1,
+ -2, 318, -1888, 8182, 11509, -2112, 378, -2,
+ -2, 316, -1877, 8103, 11578, -2110, 378, -2,
+ -2, 313, -1866, 8024, 11647, -2107, 377, -2,
+ -3, 311, -1855, 7944, 11716, -2104, 377, -2,
+ -3, 308, -1844, 7865, 11785, -2101, 376, -2,
+ -3, 305, -1832, 7785, 11852, -2098, 376, -2,
+ -3, 303, -1820, 7706, 11920, -2094, 375, -2,
+ -4, 300, -1808, 7626, 11987, -2089, 374, -3,
+ -4, 297, -1796, 7547, 12054, -2084, 373, -3,
+ -4, 294, -1784, 7467, 12120, -2079, 372, -3,
+ -4, 291, -1771, 7388, 12186, -2074, 371, -3,
+ -5, 289, -1758, 7308, 12251, -2068, 370, -3,
+ -5, 286, -1745, 7229, 12316, -2062, 369, -3,
+ -5, 283, -1732, 7149, 12381, -2055, 367, -3,
+ -6, 280, -1719, 7070, 12445, -2048, 366, -4,
+ -6, 277, -1706, 6990, 12509, -2040, 364, -4,
+ -6, 274, -1693, 6911, 12572, -2032, 362, -4,
+ -7, 271, -1679, 6831, 12634, -2024, 360, -4,
+ -7, 268, -1665, 6752, 12696, -2015, 358, -4,
+ -7, 265, -1651, 6673, 12758, -2005, 356, -4,
+ -8, 262, -1637, 6594, 12819, -1996, 354, -4,
+ -8, 259, -1623, 6514, 12880, -1986, 352, -4,
+ -8, 256, -1609, 6435, 12940, -1975, 349, -5,
+ -9, 253, -1595, 6356, 13000, -1964, 347, -5,
+ -9, 250, -1580, 6277, 13059, -1952, 344, -5,
+ -10, 247, -1566, 6199, 13118, -1940, 341, -5,
+ -10, 244, -1551, 6120, 13176, -1928, 338, -5,
+ -10, 241, -1536, 6041, 13233, -1915, 335, -5,
+ -11, 238, -1521, 5963, 13290, -1902, 332, -5,
+ -11, 235, -1506, 5885, 13347, -1888, 329, -5,
+ -12, 232, -1491, 5806, 13402, -1874, 326, -5,
+ -12, 229, -1476, 5728, 13458, -1859, 322, -5,
+ -13, 225, -1461, 5651, 13512, -1844, 319, -5,
+ -13, 222, -1445, 5573, 13567, -1829, 315, -5,
+ -13, 219, -1430, 5495, 13620, -1813, 311, -6,
+ -14, 216, -1414, 5418, 13673, -1796, 307, -6,
+ -14, 213, -1399, 5340, 13726, -1779, 303, -6,
+ -15, 210, -1383, 5263, 13777, -1762, 299, -6,
+ -15, 207, -1368, 5186, 13829, -1744, 294, -6,
+ -16, 204, -1352, 5110, 13879, -1725, 290, -6,
+ -16, 201, -1336, 5033, 13929, -1706, 285, -6,
+ -17, 198, -1320, 4957, 13978, -1687, 280, -6,
+ -17, 195, -1304, 4881, 14027, -1667, 276, -5,
+ -18, 192, -1288, 4805, 14075, -1647, 271, -5,
+ -18, 189, -1272, 4729, 14123, -1626, 265, -5,
+ -19, 186, -1256, 4653, 14169, -1604, 260, -5,
+ -19, 183, -1240, 4578, 14216, -1583, 255, -5,
+ -20, 180, -1224, 4503, 14261, -1560, 249, -5,
+ -20, 177, -1208, 4428, 14306, -1537, 244, -5,
+ -21, 174, -1192, 4354, 14350, -1514, 238, -5,
+ -21, 171, -1175, 4279, 14394, -1490, 232, -5,
+ -22, 168, -1159, 4205, 14437, -1466, 226, -4,
+ -22, 165, -1143, 4131, 14479, -1441, 220, -4,
+ -22, 162, -1127, 4058, 14520, -1416, 213, -4,
+ -23, 159, -1110, 3985, 14561, -1390, 207, -4,
+ -23, 156, -1094, 3912, 14601, -1363, 200, -4,
+ -24, 153, -1078, 3839, 14640, -1337, 193, -3,
+ -24, 150, -1062, 3766, 14679, -1309, 187, -3,
+ -25, 147, -1045, 3694, 14717, -1281, 179, -3,
+ -25, 144, -1029, 3622, 14754, -1253, 172, -3,
+ -26, 142, -1013, 3551, 14791, -1224, 165, -2,
+ -26, 139, -996, 3480, 14827, -1194, 158, -2,
+ -27, 136, -980, 3409, 14862, -1164, 150, -1,
+ -27, 133, -964, 3338, 14896, -1134, 142, -1,
+ -28, 131, -948, 3268, 14930, -1103, 135, -1,
+ -28, 128, -931, 3198, 14963, -1071, 127, 0,
+ -29, 125, -915, 3128, 14995, -1039, 118, 0,
+ -29, 122, -899, 3059, 15027, -1007, 110, 1,
+ -29, 120, -883, 2990, 15057, -974, 102, 1,
+ -30, 117, -867, 2921, 15087, -940, 93, 2,
+ -30, 115, -851, 2853, 15117, -906, 85, 2,
+ -31, 112, -835, 2785, 15145, -871, 76, 3,
+ -31, 109, -819, 2718, 15173, -836, 67, 3,
+ -32, 107, -803, 2651, 15200, -801, 58, 4,
+ -32, 104, -787, 2584, 15226, -764, 49, 5,
+ -32, 102, -771, 2517, 15251, -728, 39, 5,
+ -33, 99, -755, 2451, 15276, -690, 30, 6,
+ -33, 97, -740, 2386, 15300, -653, 20, 7,
+ -33, 95, -724, 2321, 15323, -614, 10, 7,
+ -34, 92, -708, 2256, 15345, -576, 1, 8,
+ -34, 90, -693, 2191, 15366, -536, -9, 9,
+ -34, 88, -677, 2127, 15387, -496, -20, 10,
+ -35, 85, -662, 2063, 15407, -456, -30, 11,
+ -35, 83, -646, 2000, 15426, -415, -40, 11,
+ -35, 81, -631, 1937, 15445, -374, -51, 12,
+ -36, 79, -616, 1875, 15462, -332, -62, 13,
+ -36, 76, -600, 1813, 15479, -289, -72, 14,
+ -36, 74, -585, 1751, 15495, -247, -83, 15,
+ -36, 72, -570, 1690, 15510, -203, -94, 16,
+ -37, 70, -555, 1629, 15524, -159, -106, 17,
+ -37, 68, -540, 1569, 15538, -115, -117, 18,
+ -37, 66, -526, 1509, 15550, -70, -128, 19,
+ -37, 64, -511, 1450, 15562, -24, -140, 21,
+ -37, 62, -496, 1391, 15573, 22, -152, 22,
+ -38, 60, -482, 1332, 15583, 68, -164, 23,
+ -38, 58, -467, 1274, 15593, 115, -175, 24,
+ -38, 56, -453, 1216, 15601, 163, -188, 25,
+ -38, 54, -439, 1159, 15609, 211, -200, 27,
+ -38, 53, -425, 1103, 15616, 259, -212, 28,
+ -38, 51, -410, 1046, 15622, 309, -224, 29,
+ -38, 49, -396, 990, 15628, 358, -237, 31,
+ -38, 47, -383, 935, 15632, 408, -250, 32,
+ -38, 46, -369, 880, 15636, 459, -263, 33,
+ -38, 44, -355, 826, 15639, 510, -275, 35,
+ -38, 42, -342, 772, 15641, 561, -288, 36,
+ -38, 41, -328, 718, 15642, 613, -302, 38
+};
+
+int SPC_DSP::interpolate(const voice_t *v)
+{
+ int out;
+ auto in = &v->buf[(v->interp_pos >> 12) + v->buf_pos];
+
+ switch (Settings.InterpolationMethod)
+ {
+ case 0: // raw
+ out = in[0] & ~1;
+ break;
+
+ case 1: // linear interpolation
+ {
+ int fract = v->interp_pos & 0xFFF;
+ out = (0x1000 - fract) * in[0];
+ out += fract * in[1];
+ out >>= 12;
+
+ CLAMP16(out);
+ break;
+ }
+
+ case 3: // cubic filter
+ {
+ // Make pointers into cubic based on fractional position between samples
+ int offset = (v->interp_pos >> 4) & 0xFF;
+ auto fwd = cubic + offset;
+ auto rev = cubic + 256 - offset; // mirror left half of cubic
+
+ out = fwd[0] * in[0];
+ out += fwd[257] * in[1];
+ out += rev[257] * in[2];
+ out += rev[0] * in[3];
+ out >>= 11;
+
+ CLAMP16(out);
+ break;
+ }
+
+ case 4: // sinc filter
+ {
+ int offset = (v->interp_pos & 0xFF0) >> 1;
+ auto filt = sinc + offset;
+
+ out = filt[0] * in[0];
+ out += filt[1] * in[1];
+ out += filt[2] * in[2];
+ out += filt[3] * in[3];
+ out += filt[4] * in[4];
+ out += filt[5] * in[5];
+ out += filt[6] * in[6];
+ out += filt[7] * in[7];
+ out >>= 14;
+
+ CLAMP16(out);
+ break;
+ }
+
+ default:
+ case 2: // Original gaussian filter
+ {
+ // Make pointers into gaussian based on fractional position between samples
+ int offset = (v->interp_pos >> 4) & 0xFF;
+ auto fwd = gauss + 255 - offset;
+ auto rev = gauss + offset; // mirror left half of gaussian
+
+ out = (fwd[0] * in[0]) >> 11;
+ out += (fwd[256] * in[1]) >> 11;
+ out += (rev[256] * in[2]) >> 11;
+ out = static_cast<int16_t>(out);
+ out += (rev[0] * in[3]) >> 11;
+
+ CLAMP16(out);
+ out &= ~1;
+ }
+ }
+
+ return out;
+}
+
+//// Counters
+
+static constexpr int simple_counter_range = 2048 * 5 * 3; // 30720
+
+static constexpr unsigned counter_rates[] =
+{
+ simple_counter_range + 1, // never fires
+ 2048, 1536,
+ 1280, 1024, 768,
+ 640, 512, 384,
+ 320, 256, 192,
+ 160, 128, 96,
+ 80, 64, 48,
+ 40, 32, 24,
+ 20, 16, 12,
+ 10, 8, 6,
+ 5, 4, 3,
+ 2,
+ 1
+};
+
+static constexpr unsigned counter_offsets[] =
+{
+ 1, 0, 1040,
+ 536, 0, 1040,
+ 536, 0, 1040,
+ 536, 0, 1040,
+ 536, 0, 1040,
+ 536, 0, 1040,
+ 536, 0, 1040,
+ 536, 0, 1040,
+ 536, 0, 1040,
+ 536, 0, 1040,
+ 0,
+ 0
+};
+
+void SPC_DSP::init_counter()
+{
+ this->m.counter = 0;
+}
+
+void SPC_DSP::run_counters()
+{
+ if (--this->m.counter < 0)
+ this->m.counter = simple_counter_range - 1;
+}
+
+unsigned SPC_DSP::read_counter(int rate)
+{
+ return (static_cast<unsigned>(this->m.counter) + counter_offsets[rate]) % counter_rates[rate];
+}
+
+//// Envelope
+
+void SPC_DSP::run_envelope(voice_t *const v)
+{
+ int env = v->env;
+ if (v->env_mode == env_release) // 60%
+ {
+ if ((env -= 0x8) < 0)
+ env = 0;
+ v->env = env;
+ }
+ else
+ {
+ int rate;
+ int env_data = v->regs[v_adsr1];
+ if (this->m.t_adsr0 & 0x80) // 99% ADSR
+ {
+ if (v->env_mode >= env_decay) // 99%
+ {
+ --env;
+ env -= env >> 8;
+ rate = env_data & 0x1F;
+ if (v->env_mode == env_decay) // 1%
+ rate = ((this->m.t_adsr0 >> 3) & 0x0E) + 0x10;
+ }
+ else // env_attack
+ {
+ rate = (this->m.t_adsr0 & 0x0F) * 2 + 1;
+ env += rate < 31 ? 0x20 : 0x400;
+ }
+ }
+ else // GAIN
+ {
+ env_data = v->regs[v_gain];
+ int mode = env_data >> 5;
+ if (mode < 4) // direct
+ {
+ env = env_data * 0x10;
+ rate = 31;
+ }
+ else
+ {
+ rate = env_data & 0x1F;
+ if (mode == 4) // 4: linear decrease
+ env -= 0x20;
+ else if (mode < 6) // 5: exponential decrease
+ {
+ --env;
+ env -= env >> 8;
+ }
+ else // 6,7: linear increase
+ {
+ env += 0x20;
+ if (mode > 6 && static_cast<unsigned>(v->hidden_env) >= 0x600)
+ env += 0x8 - 0x20; // 7: two-slope linear increase
+ }
+ }
+ }
+
+ // Sustain level
+ if ((env >> 8) == (env_data >> 5) && v->env_mode == env_decay)
+ v->env_mode = env_sustain;
+
+ v->hidden_env = env;
+
+ // unsigned cast because linear decrease going negative also triggers this
+ if (static_cast<unsigned>(env) > 0x7FF)
+ {
+ env = env < 0 ? 0 : 0x7FF;
+ if (v->env_mode == env_attack)
+ v->env_mode = env_decay;
+ }
+
+ if (!this->read_counter(rate))
+ v->env = env; // nothing else is controlled by the counter
+ }
+}
+
+//// BRR Decoding
+
+void SPC_DSP::decode_brr(voice_t *v)
+{
+ // Arrange the four input nybbles in 0xABCD order for easy decoding
+ int nybbles = this->m.t_brr_byte * 0x100 + this->m.ram[(v->brr_addr + v->brr_offset + 1) & 0xFFFF];
+
+ int header = this->m.t_brr_header;
+
+ // Write to next four samples in circular buffer
+ int *pos = &v->buf[v->buf_pos];
+ int *end;
+ if ((v->buf_pos += 4) >= brr_buf_size)
+ v->buf_pos = 0;
+
+ // Decode four samples
+ for (end = pos + 4; pos < end; ++pos, nybbles <<= 4)
+ {
+ // Extract nybble and sign-extend
+ int s = static_cast<int16_t>(nybbles) >> 12;
+
+ // Shift sample based on header
+ int shift = header >> 4;
+ s = (s << shift) >> 1;
+ if (shift >= 0xD) // handle invalid range
+ s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0)
+
+ // Apply IIR filter (8 is the most commonly used)
+ int filter = header & 0x0C;
+ int p1 = pos[brr_buf_size - 1];
+ int p2 = pos[brr_buf_size - 2] >> 1;
+ if (filter >= 8)
+ {
+ s += p1;
+ s -= p2;
+ if (filter == 8) // s += p1 * 0.953125 - p2 * 0.46875
+ {
+ s += p2 >> 4;
+ s += (p1 * -3) >> 6;
+ }
+ else // s += p1 * 0.8984375 - p2 * 0.40625
+ {
+ s += (p1 * -13) >> 7;
+ s += (p2 * 3) >> 4;
+ }
+ }
+ else if (filter) // s += p1 * 0.46875
+ {
+ s += p1 >> 1;
+ s += -p1 >> 5;
+ }
+
+ // Adjust and write sample
+ CLAMP16(s);
+ s = static_cast<int16_t>(s * 2);
+ pos[brr_buf_size] = pos[0] = s; // second copy simplifies wrap-around
+ }
+}
+
+//// Misc
+
+void SPC_DSP::misc_27()
+{
+ this->m.t_pmon = this->m.regs[r_pmon] & 0xFE; // voice 0 doesn't support PMON
+}
+void SPC_DSP::misc_28()
+{
+ this->m.t_non = this->m.regs[r_non];
+ this->m.t_eon = this->m.regs[r_eon];
+ this->m.t_dir = this->m.regs[r_dir];
+}
+void SPC_DSP::misc_29()
+{
+ this->m.every_other_sample = !this->m.every_other_sample;
+ if (this->m.every_other_sample)
+ this->m.new_kon &= ~this->m.kon; // clears KON 63 clocks after it was last read
+}
+void SPC_DSP::misc_30()
+{
+ if (this->m.every_other_sample)
+ {
+ this->m.kon = this->m.new_kon;
+ this->m.t_koff = this->m.regs[r_koff] | this->m.mute_mask;
+ }
+
+ this->run_counters();
+
+ // Noise
+ if (!this->read_counter(this->m.regs[r_flg] & 0x1F))
+ {
+ int feedback = (this->m.noise << 13) ^ (this->m.noise << 14);
+ this->m.noise = (feedback & 0x4000) ^ (this->m.noise >> 1);
+ }
+}
+
+//// Voices
+
+void SPC_DSP::voice_V1(voice_t *const v)
+{
+ this->m.t_dir_addr = this->m.t_dir * 0x100 + this->m.t_srcn * 4;
+ this->m.t_srcn = v->regs[v_srcn];
+}
+void SPC_DSP::voice_V2(voice_t *const v)
+{
+ // Read sample pointer (ignored if not needed)
+ auto entry = &this->m.ram[m.t_dir_addr];
+ if (!v->kon_delay)
+ entry += 2;
+ this->m.t_brr_next_addr = get_le16(entry);
+
+ this->m.t_adsr0 = v->regs[v_adsr0];
+
+ // Read pitch, spread over two clocks
+ this->m.t_pitch = v->regs[v_pitchl];
+}
+void SPC_DSP::voice_V3a(voice_t *const v)
+{
+ this->m.t_pitch += (v->regs[v_pitchh] & 0x3F) << 8;
+}
+void SPC_DSP::voice_V3b(voice_t *const v)
+{
+ // Read BRR header and byte
+ this->m.t_brr_byte = this->m.ram[(v->brr_addr + v->brr_offset) & 0xFFFF];
+ this->m.t_brr_header = this->m.ram[v->brr_addr]; // brr_addr doesn't need masking
+}
+void SPC_DSP::voice_V3c(voice_t *const v)
+{
+ // Pitch modulation using previous voice's output
+ if (this->m.t_pmon & v->vbit)
+ this->m.t_pitch += ((this->m.t_output >> 5) * this->m.t_pitch) >> 10;
+
+ if (v->kon_delay)
+ {
+ // Get ready to start BRR decoding on next sample
+ if (v->kon_delay == 5)
+ {
+ v->brr_addr = this->m.t_brr_next_addr;
+ v->brr_offset = 1;
+ v->buf_pos = 0;
+ this->m.t_brr_header = 0; // header is ignored on this sample
+ }
+
+ // Envelope is never run during KON
+ v->env = 0;
+ v->hidden_env = 0;
+
+ // Disable BRR decoding until last three samples
+ v->interp_pos = 0;
+ if (--v->kon_delay & 3)
+ v->interp_pos = 0x4000;
+
+ // Pitch is never added during KON
+ this->m.t_pitch = 0;
+ }
+
+ // Gaussian interpolation
+ int output = this->interpolate(v);
+
+ // Noise
+ if (this->m.t_non & v->vbit)
+ output = static_cast<int16_t>(this->m.noise * 2);
+
+ // Apply envelope
+ this->m.t_output = (output * v->env) >> 11 & ~1;
+ v->t_envx_out = static_cast<uint8_t>(v->env >> 4);
+
+ // Immediate silence due to end of sample or soft reset
+ if (this->m.regs[r_flg] & 0x80 || (this->m.t_brr_header & 3) == 1)
+ {
+ v->env_mode = env_release;
+ v->env = 0;
+ }
+
+ if (this->m.every_other_sample)
+ {
+ // KOFF
+ if (this->m.t_koff & v->vbit)
+ v->env_mode = env_release;
+
+ // KON
+ if (this->m.kon & v->vbit)
+ {
+ v->kon_delay = 5;
+ v->env_mode = env_attack;
+ }
+ }
+
+ // Run envelope for next sample
+ if (!v->kon_delay)
+ this->run_envelope(v);
+}
+
+void SPC_DSP::voice_output(const voice_t *v, int ch)
+{
+ // Apply left/right volume
+ int amp = (this->m.t_output * static_cast<int8_t>(v->regs[v_voll + ch])) >> 7;
+ amp *= (this->stereo_switch & (1 << (v->voice_number + ch * voice_count))) ? 1 : 0;
+
+ // Add to output total
+ this->m.t_main_out[ch] += amp;
+ CLAMP16(this->m.t_main_out[ch]);
+
+ // Optionally add to echo total
+ if (this->m.t_eon & v->vbit)
+ {
+ this->m.t_echo_out[ch] += amp;
+ CLAMP16(this->m.t_echo_out[ch]);
+ }
+}
+void SPC_DSP::voice_V4(voice_t *const v)
+{
+ // Decode BRR
+ this->m.t_looped = 0;
+ if (v->interp_pos >= 0x4000)
+ {
+ this->decode_brr(v);
+
+ if ((v->brr_offset += 2) >= brr_block_size)
+ {
+ // Start decoding next BRR block
+ assert(v->brr_offset == brr_block_size);
+ v->brr_addr = (v->brr_addr + brr_block_size) & 0xFFFF;
+ if (this->m.t_brr_header & 1)
+ {
+ v->brr_addr = this->m.t_brr_next_addr;
+ this->m.t_looped = v->vbit;
+ }
+ v->brr_offset = 1;
+ }
+ }
+
+ // Apply pitch
+ v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch;
+
+ // Keep from getting too far ahead (when using pitch modulation)
+ if (v->interp_pos > 0x7FFF)
+ v->interp_pos = 0x7FFF;
+
+ // Output left
+ this->voice_output(v, 0);
+}
+void SPC_DSP::voice_V5(voice_t *const v)
+{
+ // Output right
+ this->voice_output(v, 1);
+
+ // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier
+ int endx_buf = this->m.regs[r_endx] | this->m.t_looped;
+
+ // Clear bit in ENDX if KON just began
+ if (v->kon_delay == 5)
+ endx_buf &= ~v->vbit;
+ this->m.endx_buf = static_cast<uint8_t>(endx_buf);
+}
+void SPC_DSP::voice_V6(voice_t *const)
+{
+ this->m.outx_buf = static_cast<uint8_t>(this->m.t_output >> 8);
+}
+void SPC_DSP::voice_V7(voice_t *const v)
+{
+ // Update ENDX
+ this->m.regs[r_endx] = this->m.endx_buf;
+
+ this->m.envx_buf = v->t_envx_out;
+}
+void SPC_DSP::voice_V8(voice_t *const v)
+{
+ // Update OUTX
+ v->regs[v_outx] = this->m.outx_buf;
+}
+void SPC_DSP::voice_V9(voice_t *const v)
+{
+ // Update ENVX
+ v->regs[v_envx] = this->m.envx_buf;
+}
+
+// Most voices do all these in one clock, so make a handy composite
+void SPC_DSP::voice_V3(voice_t *const v)
+{
+ this->voice_V3a(v);
+ this->voice_V3b(v);
+ this->voice_V3c(v);
+}
+
+// Common combinations of voice steps on different voices. This greatly reduces
+// code size and allows everything to be inlined in these functions.
+void SPC_DSP::voice_V7_V4_V1(voice_t *const v) { this->voice_V7(v); this->voice_V1(v + 3); this->voice_V4(v + 1); }
+void SPC_DSP::voice_V8_V5_V2(voice_t *const v) { this->voice_V8(v); this->voice_V5(v + 1); this->voice_V2(v + 2); }
+void SPC_DSP::voice_V9_V6_V3(voice_t *const v) { this->voice_V9(v); this->voice_V6(v + 1); this->voice_V3(v + 2); }
+
+//// Echo
+
+void SPC_DSP::echo_read(int ch)
+{
+ int s = static_cast<int16_t>(get_le16(this->ECHO_PTR(ch)));
+ // second copy simplifies wrap-around handling
+ this->ECHO_FIR(0)[ch] = this->ECHO_FIR(8)[ch] = s >> 1;
+}
+
+void SPC_DSP::echo_22()
+{
+ // History
+ if (++this->m.echo_hist_pos >= &this->m.echo_hist[echo_hist_size])
+ this->m.echo_hist_pos = this->m.echo_hist;
+
+ this->m.t_echo_ptr = (this->m.t_esa * 0x100 + this->m.echo_offset) & 0xFFFF;
+ this->echo_read(0);
+
+ // FIR (using l and r temporaries below helps compiler optimize)
+ int l = this->CALC_FIR(0, 0);
+ int r = this->CALC_FIR(0, 1);
+
+ this->m.t_echo_in[0] = l;
+ this->m.t_echo_in[1] = r;
+}
+void SPC_DSP::echo_23()
+{
+ int l = this->CALC_FIR(1, 0) + this->CALC_FIR(2, 0);
+ int r = this->CALC_FIR(1, 1) + this->CALC_FIR(2, 1);
+
+ this->m.t_echo_in[0] += l;
+ this->m.t_echo_in[1] += r;
+
+ echo_read(1);
+}
+void SPC_DSP::echo_24()
+{
+ int l = this->CALC_FIR(3, 0) + this->CALC_FIR(4, 0) + this->CALC_FIR(5, 0);
+ int r = this->CALC_FIR(3, 1) + this->CALC_FIR(4, 1) + this->CALC_FIR(5, 1);
+
+ this->m.t_echo_in[0] += l;
+ this->m.t_echo_in[1] += r;
+}
+void SPC_DSP::echo_25()
+{
+ int l = this->m.t_echo_in[0] + this->CALC_FIR(6, 0);
+ int r = this->m.t_echo_in[1] + this->CALC_FIR(6, 1);
+
+ l = static_cast<int16_t>(l);
+ r = static_cast<int16_t>(r);
+
+ l += static_cast<int16_t>(this->CALC_FIR(7, 0));
+ r += static_cast<int16_t>(this->CALC_FIR(7, 1));
+
+ CLAMP16(l);
+ CLAMP16(r);
+
+ this->m.t_echo_in[0] = l & ~1;
+ this->m.t_echo_in[1] = r & ~1;
+}
+int SPC_DSP::echo_output(int ch)
+{
+ int out = static_cast<int16_t>((this->m.t_main_out [ch] * static_cast<int8_t>(this->m.regs[r_mvoll + ch * 0x10])) >> 7) +
+ static_cast<int16_t>((this->m.t_echo_in [ch] * static_cast<int8_t>(this->m.regs[r_evoll + ch * 0x10])) >> 7);
+ CLAMP16(out);
+ return out;
+}
+void SPC_DSP::echo_26()
+{
+ // Left output volumes
+ // (save sample for next clock so we can output both together)
+ this->m.t_main_out[0] = echo_output(0);
+
+ // Echo feedback
+ int l = this->m.t_echo_out[0] + static_cast<int16_t>((this->m.t_echo_in[0] * static_cast<int8_t>(this->m.regs[r_efb])) >> 7);
+ int r = this->m.t_echo_out[1] + static_cast<int16_t>((this->m.t_echo_in[1] * static_cast<int8_t>(this->m.regs[r_efb])) >> 7);
+
+ CLAMP16(l);
+ CLAMP16(r);
+
+ this->m.t_echo_out[0] = l & ~1;
+ this->m.t_echo_out[1] = r & ~1;
+}
+void SPC_DSP::echo_27()
+{
+ // Output
+ int l = this->m.t_main_out[0];
+ int r = echo_output(1);
+ this->m.t_main_out[0] = this->m.t_main_out[1] = 0;
+
+ // TODO: global muting isn't this simple (turns DAC on and off
+ // or something, causing small ~37-sample pulse when first muted)
+ if (this->m.regs[r_flg] & 0x40)
+ l = r = 0;
+
+ // Output sample to DAC
+ this->resampler->push_sample(l, r);
+}
+void SPC_DSP::echo_28()
+{
+ this->m.t_echo_enabled = this->m.regs[r_flg];
+}
+void SPC_DSP::echo_write(int ch)
+{
+ if (!(this->m.t_echo_enabled & 0x20))
+ set_le16(this->ECHO_PTR(ch), this->m.t_echo_out[ch]);
+
+ this->m.t_echo_out[ch] = 0;
+}
+void SPC_DSP::echo_29()
+{
+ this->m.t_esa = this->m.regs[r_esa];
+
+ if (!this->m.echo_offset)
+ this->m.echo_length = (this->m.regs[r_edl] & 0x0F) * 0x800;
+
+ this->m.echo_offset += 4;
+ if (this->m.echo_offset >= this->m.echo_length)
+ this->m.echo_offset = 0;
+
+ // Write left echo
+ this->echo_write(0);
+
+ this->m.t_echo_enabled = this->m.regs[r_flg];
+}
+void SPC_DSP::echo_30()
+{
+ // Write right echo
+ this->echo_write(1);
+}
+
+//// Timing
+
+// Execute clock for a particular voice
+#define V(clock, voice) voice_##clock(&this->m.voices[voice]);
+
+/* The most common sequence of clocks uses composite operations
+for efficiency. For example, the following are equivalent to the
+individual steps on the right:
+
+V(V7_V4_V1,2) -> V(V7,2) V(V4,3) V(V1,5)
+V(V8_V5_V2,2) -> V(V8,2) V(V5,3) V(V2,4)
+V(V9_V6_V3,2) -> V(V9,2) V(V6,3) V(V3,4) */
+
+// Voice 0 1 2 3 4 5 6 7
+#define GEN_DSP_TIMING \
+PHASE(0) V(V5, 0) V(V2, 1) \
+PHASE(1) V(V6, 0) V(V3, 1) \
+PHASE(2) V(V7_V4_V1, 0) \
+PHASE(3) V(V8_V5_V2, 0) \
+PHASE(4) V(V9_V6_V3, 0) \
+PHASE(5) V(V7_V4_V1, 1) \
+PHASE(6) V(V8_V5_V2, 1) \
+PHASE(7) V(V9_V6_V3, 1) \
+PHASE(8) V(V7_V4_V1, 2) \
+PHASE(9) V(V8_V5_V2, 2) \
+PHASE(10) V(V9_V6_V3, 2) \
+PHASE(11) V(V7_V4_V1, 3) \
+PHASE(12) V(V8_V5_V2, 3) \
+PHASE(13) V(V9_V6_V3, 3) \
+PHASE(14) V(V7_V4_V1, 4) \
+PHASE(15) V(V8_V5_V2, 4) \
+PHASE(16) V(V9_V6_V3, 4) \
+PHASE(17) V(V1, 0) V(V7, 5) V(V4, 6) \
+PHASE(18) V(V8_V5_V2, 5) \
+PHASE(19) V(V9_V6_V3, 5) \
+PHASE(20) V(V1, 1) V(V7, 6) V(V4, 7) \
+PHASE(21) V(V8, 6) V(V5, 7) V(V2, 0) /* t_brr_next_addr order dependency */ \
+PHASE(22) V(V3a, 0) V(V9, 6) V(V6, 7) echo_22(); \
+PHASE(23) V(V7, 7) echo_23(); \
+PHASE(24) V(V8, 7) echo_24(); \
+PHASE(25) V(V3b, 0) V(V9, 7) echo_25(); \
+PHASE(26) echo_26(); \
+PHASE(27) misc_27(); echo_27(); \
+PHASE(28) misc_28(); echo_28(); \
+PHASE(29) misc_29(); echo_29(); \
+PHASE(30) misc_30(); V(V3c, 0) echo_30(); \
+PHASE(31) V(V4, 0) V(V1, 2)
+
+#ifndef SPC_DSP_CUSTOM_RUN
+void SPC_DSP::run(int clocks_remain)
+{
+ assert(clocks_remain > 0);
+
+ int phase = this->m.phase;
+ this->m.phase = (phase + clocks_remain) & 31;
+ switch (phase)
+ {
+ loop:
+#define PHASE(n) if (n && !--clocks_remain) break; /* Fall through */ case n:
+ GEN_DSP_TIMING
+#undef PHASE
+
+ if (--clocks_remain)
+ goto loop;
+ }
+}
+#endif
+
+//// Setup
+
+void SPC_DSP::init(uint8_t *ram_64k)
+{
+ this->m.ram = ram_64k;
+ this->mute_voices(0);
+ this->disable_surround(false);
+ this->set_output(nullptr, 0);
+ this->reset();
+
+ this->stereo_switch = 0xffff;
+
+#ifndef NDEBUG
+ // be sure this sign-extends
+ assert(static_cast<int16_t>(0x8000) == -0x8000);
+
+ // be sure right shift preserves sign
+ assert((-1 >> 1) == -1);
+
+ // check clamp macro
+ int i = 0x8000;
+ CLAMP16(i);
+ assert(i == 0x7FFF);
+
+ i = -0x8001;
+ CLAMP16(i);
+ assert(i == -0x8000);
+
+ blargg_verify_byte_order();
+#endif
+}
+
+void SPC_DSP::soft_reset_common()
+{
+ assert(this->m.ram); // init() must have been called already
+
+ this->m.noise = 0x4000;
+ this->m.echo_hist_pos = this->m.echo_hist;
+ this->m.every_other_sample = true;
+ this->m.echo_offset = 0;
+ this->m.phase = 0;
+
+ std::fill_n(&this->m.separate_echo_buffer[0], 0x10000, 0);
+
+ this->init_counter();
+
+ for (int i = 0; i < voice_count; ++i)
+ this->m.voices[i].voice_number = i;
+}
+
+void SPC_DSP::soft_reset()
+{
+ this->m.regs[r_flg] = 0xE0;
+ this->soft_reset_common();
+}
+
+void SPC_DSP::load(const uint8_t regs[register_count])
+{
+ std::copy_n(®s[0], static_cast<int>(register_count), &this->m.regs[0]);
+ memset(&this->m.regs[register_count], 0, offsetof(state_t, ram) - register_count);
+
+ // Internal state
+ for (int i = voice_count; --i >= 0;)
+ {
+ auto &v = this->m.voices[i];
+ v.brr_offset = 1;
+ v.vbit = 1 << i;
+ v.regs = &this->m.regs[i * 0x10];
+ }
+ this->m.new_kon = this->m.regs[r_kon];
+ this->m.t_dir = this->m.regs[r_dir];
+ this->m.t_esa = this->m.regs[r_esa];
+
+ this->soft_reset_common();
+}
+
+void SPC_DSP::reset()
+{
+ this->load(initial_regs);
+}
+
+//// Snes9x Accessor
+
+void SPC_DSP::set_stereo_switch(int value)
+{
+ this->stereo_switch = value;
+}
+
+uint8_t SPC_DSP::reg_value(int ch, int addr)
+{
+ return this->m.voices[ch].regs[addr];
+}
+
+int SPC_DSP::envx_value(int ch)
+{
+ return this->m.voices[ch].env;
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/dsp/SPC_DSP.h
@@ -1,1 +1,293 @@
-
+// Highly accurate SNES SPC-700 DSP emulator
+
+// snes_spc 0.9.0
+#pragma once
+
+#include "blargg_common.h"
+#include "../../resampler.h"
+#include "../../../snes9x.h"
+
+class SPC_DSP
+{
+public:
+ // Setup
+
+ // Initializes DSP and has it use the 64K RAM provided
+ void init(uint8_t *ram_64k);
+
+ // Sets destination for output samples. If out is NULL or out_size is 0,
+ // doesn't generate any.
+ typedef short sample_t;
+ void set_output(sample_t *out, int out_size);
+
+ void set_output(Resampler *resampler);
+
+ // Number of samples written to output since it was last set, always
+ // a multiple of 2. Undefined if more samples were generated than
+ // output buffer could hold.
+ int sample_count() const;
+
+ // Emulation
+
+ // Resets DSP to power-on state
+ void reset();
+
+ // Emulates pressing reset switch on SNES
+ void soft_reset();
+
+ // Reads/writes DSP registers. For accuracy, you must first call run()
+ // to catch the DSP up to present.
+ int read(int addr) const;
+ void write(int addr, int data);
+
+ // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks
+ // a pair of samples is be generated.
+ void run(int clock_count);
+
+ // Sound control
+
+ // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events).
+ // Reduces emulation accuracy.
+ enum { voice_count = 8 };
+ void mute_voices(int mask);
+
+ // State
+
+ // Resets DSP and uses supplied values to initialize registers
+ enum { register_count = 128 };
+ void load(const uint8_t regs[register_count]);
+
+ // Snes9x Accessor
+
+ int stereo_switch;
+
+ void set_stereo_switch(int);
+ uint8_t reg_value(int, int);
+ int envx_value(int);
+
+ // DSP register addresses
+
+ // Global registers
+ enum
+ {
+ r_mvoll = 0x0C,
+ r_mvolr = 0x1C,
+ r_evoll = 0x2C,
+ r_evolr = 0x3C,
+ r_kon = 0x4C,
+ r_koff = 0x5C,
+ r_flg = 0x6C,
+ r_endx = 0x7C,
+ r_efb = 0x0D,
+ r_pmon = 0x2D,
+ r_non = 0x3D,
+ r_eon = 0x4D,
+ r_dir = 0x5D,
+ r_esa = 0x6D,
+ r_edl = 0x7D,
+ r_fir = 0x0F // 8 coefficients at 0x0F, 0x1F ... 0x7F
+ };
+
+ // Voice registers
+ enum
+ {
+ v_voll = 0x00,
+ v_volr = 0x01,
+ v_pitchl = 0x02,
+ v_pitchh = 0x03,
+ v_srcn = 0x04,
+ v_adsr0 = 0x05,
+ v_adsr1 = 0x06,
+ v_gain = 0x07,
+ v_envx = 0x08,
+ v_outx = 0x09
+ };
+
+public:
+ enum { extra_size = 16 };
+ sample_t *extra() { return this->m.extra; }
+ const sample_t *out_pos() const { return this->m.out; }
+ void disable_surround(bool) { } // not supported
+public:
+ enum { echo_hist_size = 8 };
+
+ enum env_mode_t { env_release, env_attack, env_decay, env_sustain };
+ enum { brr_buf_size = 12 };
+ struct voice_t
+ {
+ int buf[brr_buf_size * 2]; // decoded samples (twice the size to simplify wrap handling)
+ int buf_pos; // place in buffer where next samples will be decoded
+ int interp_pos; // relative fractional position in sample (0x1000 = 1.0)
+ int brr_addr; // address of current BRR block
+ int brr_offset; // current decoding offset in BRR block
+ uint8_t *regs; // pointer to voice's DSP registers
+ int vbit; // bitmask for voice: 0x01 for voice 0, 0x02 for voice 1, etc.
+ int kon_delay; // KON delay/current setup phase
+ env_mode_t env_mode;
+ int env; // current envelope level
+ int hidden_env; // used by GAIN mode 7, very obscure quirk
+ uint8_t t_envx_out;
+ int voice_number;
+ };
+private:
+ enum { brr_block_size = 9 };
+
+ Resampler *resampler;
+
+ struct state_t
+ {
+ uint8_t regs[register_count];
+
+ // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling)
+ int echo_hist[echo_hist_size * 2][2];
+ int (*echo_hist_pos)[2]; // &echo_hist [0 to 7]
+
+ bool every_other_sample; // toggles every sample
+ int kon; // KON value when last checked
+ int noise;
+ int counter;
+ int echo_offset; // offset from ESA in echo buffer
+ int echo_length; // number of bytes that echo_offset will stop at
+ int phase; // next clock cycle to run (0-31)
+
+ // Hidden registers also written to when main register is written to
+ int new_kon;
+ uint8_t endx_buf;
+ uint8_t envx_buf;
+ uint8_t outx_buf;
+
+ // Temporary state between clocks
+
+ // read once per sample
+ int t_pmon;
+ int t_non;
+ int t_eon;
+ int t_dir;
+ int t_koff;
+
+ // read a few clocks ahead then used
+ int t_brr_next_addr;
+ int t_adsr0;
+ int t_brr_header;
+ int t_brr_byte;
+ int t_srcn;
+ int t_esa;
+ int t_echo_enabled;
+
+ // internal state that is recalculated every sample
+ int t_dir_addr;
+ int t_pitch;
+ int t_output;
+ int t_looped;
+ int t_echo_ptr;
+
+ // left/right sums
+ int t_main_out[2];
+ int t_echo_out[2];
+ int t_echo_in[2];
+
+ voice_t voices[voice_count];
+
+ // non-emulation state
+ uint8_t *ram; // 64K shared RAM between DSP and SMP
+ int mute_mask;
+
+ sample_t *out;
+ sample_t *out_end;
+ sample_t *out_begin;
+ sample_t extra[extra_size];
+
+ uint8_t separate_echo_buffer[0x10000];
+ };
+ state_t m;
+
+ void init_counter();
+ void run_counters();
+ unsigned read_counter(int rate);
+
+ int interpolate(const voice_t *v);
+ void run_envelope(voice_t *const v);
+ void decode_brr(voice_t *v);
+
+ void misc_27();
+ void misc_28();
+ void misc_29();
+ void misc_30();
+
+ void voice_output(const voice_t *v, int ch);
+ void voice_V1(voice_t *const);
+ void voice_V2(voice_t *const);
+ void voice_V3(voice_t *const);
+ void voice_V3a(voice_t *const);
+ void voice_V3b(voice_t *const);
+ void voice_V3c(voice_t *const);
+ void voice_V4(voice_t *const);
+ void voice_V5(voice_t *const);
+ void voice_V6(voice_t *const);
+ void voice_V7(voice_t *const);
+ void voice_V8(voice_t *const);
+ void voice_V9(voice_t *const);
+ void voice_V7_V4_V1(voice_t *const);
+ void voice_V8_V5_V2(voice_t *const);
+ void voice_V9_V6_V3(voice_t *const);
+
+ // Current echo buffer pointer for left/right channel
+ uint8_t *ECHO_PTR(int ch) { return Settings.SeparateEchoBuffer ? &this->m.separate_echo_buffer[this->m.t_echo_ptr + ch * 2] : &this->m.ram[this->m.t_echo_ptr + ch * 2]; }
+ // Sample in echo history buffer, where 0 is the oldest
+ int *ECHO_FIR(size_t i) { return this->m.echo_hist_pos[i]; }
+ // Calculate FIR point for left/right channel
+ int CALC_FIR(size_t i, int ch) { return (this->ECHO_FIR(i + 1)[ch] * static_cast<int8_t>(this->m.regs[r_fir + i * 0x10])) >> 6; }
+
+ void echo_read(int ch);
+ int echo_output(int ch);
+ void echo_write(int ch);
+ void echo_22();
+ void echo_23();
+ void echo_24();
+ void echo_25();
+ void echo_26();
+ void echo_27();
+ void echo_28();
+ void echo_29();
+ void echo_30();
+
+ void soft_reset_common();
+};
+
+inline int SPC_DSP::sample_count() const { return this->m.out - this->m.out_begin; }
+
+inline int SPC_DSP::read(int addr) const
+{
+ assert(static_cast<unsigned>(addr) < register_count);
+ return this->m.regs[addr];
+}
+
+inline void SPC_DSP::write(int addr, int data)
+{
+ assert(static_cast<unsigned>(addr) < register_count);
+
+ this->m.regs[addr] = static_cast<uint8_t>(data);
+ switch (addr & 0x0F)
+ {
+ case v_envx:
+ this->m.envx_buf = static_cast<uint8_t>(data);
+ break;
+
+ case v_outx:
+ this->m.outx_buf = static_cast<uint8_t>(data);
+ break;
+
+ case 0x0C:
+ if (addr == r_kon)
+ this->m.new_kon = static_cast<uint8_t>(data);
+
+ if (addr == r_endx) // always cleared, regardless of data written
+ {
+ this->m.endx_buf = 0;
+ this->m.regs[r_endx] = 0;
+ }
+ }
+}
+
+inline void SPC_DSP::mute_voices(int mask) { this->m.mute_mask = mask; }
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/dsp/blargg_common.h
@@ -1,1 +1,39 @@
+// Sets up common environment for Shay Green's libraries.
+// To change configuration options, modify blargg_config.h, not this file.
+// snes_spc 0.9.0
+#pragma once
+
+#include <cstddef>
+#include <cstdlib>
+#include <cassert>
+#include <climits>
+
+#include "blargg_config.h"
+
+// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1,
+// compiler is assumed to support bool. If undefined, availability is determined.
+#ifndef BLARGG_COMPILER_HAS_BOOL
+# if defined(__MWERKS__)
+# if !__option(bool)
+# define BLARGG_COMPILER_HAS_BOOL 0
+# endif
+# elif defined(_MSC_VER)
+# if _MSC_VER < 1100
+# define BLARGG_COMPILER_HAS_BOOL 0
+# endif
+# elif defined(__GNUC__)
+// supports bool
+# elif __cplusplus < 199711
+# define BLARGG_COMPILER_HAS_BOOL 0
+# endif
+#endif
+#if defined(BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
+// If you get errors here, modify your blargg_config.h file
+typedef int bool;
+const bool true = 1;
+const bool false = 0;
+#endif
+
+#include <cstdint>
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/dsp/blargg_config.h
@@ -1,1 +1,11 @@
+// snes_spc 0.9.0 user configuration file. Don't replace when updating library.
+// snes_spc 0.9.0
+#pragma once
+
+// Uncomment if automatic byte-order determination doesn't work
+//#define BLARGG_BIG_ENDIAN 1
+
+// Uncomment if you get errors in the bool section of blargg_common.h
+//#define BLARGG_COMPILER_HAS_BOOL 1
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/dsp/blargg_endian.h
@@ -1,1 +1,76 @@
+// CPU Byte Order Utilities
+// snes_spc 0.9.0
+#pragma once
+
+#include "blargg_common.h"
+
+// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
+#if defined(_M_IX86) || defined(_M_IA64) || defined(__i486__) || defined(__x86_64__) || defined(__ia64__) || defined(__i386__)
+# define BLARGG_CPU_X86 1
+# define BLARGG_CPU_CISC 1
+#else
+# define BLARGG_CPU_X86 0
+# define BLARGG_CPU_CISC 0
+#endif
+
+#if defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__powerc)
+# define BLARGG_CPU_POWERPC 1
+# define BLARGG_CPU_RISC 1
+#else
+# define BLARGG_CPU_POWERPC 0
+# define BLARGG_CPU_RISC 0
+#endif
+
+// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
+// one may be #defined to 1. Only needed if something actually depends on byte order.
+#if !defined(BLARGG_BIG_ENDIAN) && !defined(BLARGG_LITTLE_ENDIAN)
+# ifdef __GLIBC__
+// GCC handles this for us
+# include <endian.h>
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+# define BLARGG_LITTLE_ENDIAN 1
+# define BLARGG_BIG_ENDIAN 0
+# elif __BYTE_ORDER == __BIG_ENDIAN
+# define BLARGG_BIG_ENDIAN 1
+# define BLARGG_LITTLE_ENDIAN 0
+# endif
+# else
+# if defined(LSB_FIRST) || defined(__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || (defined(LITTLE_ENDIAN) && LITTLE_ENDIAN + 0 != 1234)
+# define BLARGG_LITTLE_ENDIAN 1
+# define BLARGG_BIG_ENDIAN 0
+# elif defined(MSB_FIRST) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) || defined(__sparc__) || BLARGG_CPU_POWERPC || (defined(BIG_ENDIAN) && BIG_ENDIAN + 0 != 4321)
+# define BLARGG_BIG_ENDIAN 1
+# define BLARGG_LITTLE_ENDIAN 0
+# else
+// No endian specified; assume little-endian, since it's most common
+# define BLARGG_LITTLE_ENDIAN 1
+# define BLARGG_BIG_ENDIAN 0
+# endif
+# endif
+#endif
+
+#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN
+# undef BLARGG_LITTLE_ENDIAN
+# undef BLARGG_BIG_ENDIAN
+#endif
+
+inline void blargg_verify_byte_order()
+{
+#ifndef NDEBUG
+ volatile int i = 1;
+ assert(*reinterpret_cast<volatile char *>(&i));
+#endif
+}
+
+inline unsigned get_le16(const uint8_t *p)
+{
+ return static_cast<unsigned>(p[1] << 8) | static_cast<unsigned>(p[0]);
+}
+
+inline void set_le16(uint8_t *p, unsigned n)
+{
+ p[1] = static_cast<unsigned char>(n >> 8);
+ p[0] = static_cast<unsigned char>(n);
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/dsp/sdsp.cpp
@@ -1,1 +1,28 @@
+#include "../snes/snes.hpp"
+#include "sdsp.hpp"
+#include "SPC_DSP.h"
+#include "../smp/smp.hpp"
+namespace SNES
+{
+ DSP dsp;
+
+ void DSP::power()
+ {
+ this->spc_dsp.init(smp.apuram.get());
+ this->spc_dsp.reset();
+ this->clock = 0;
+ }
+
+ void DSP::reset()
+ {
+ this->spc_dsp.soft_reset();
+ this->clock = 0;
+ }
+
+ DSP::DSP()
+ {
+ this->clock = 0;
+ }
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/dsp/sdsp.hpp
@@ -1,1 +1,42 @@
+#pragma once
+#include "../snes/snes.hpp"
+#include "SPC_DSP.h"
+
+namespace SNES
+{
+ class DSP : public Processor
+ {
+ public:
+ uint8_t read(uint8_t addr)
+ {
+ this->synchronize();
+ return this->spc_dsp.read(addr);
+ }
+
+ void synchronize()
+ {
+ if (this->clock)
+ {
+ this->spc_dsp.run(this->clock);
+ this->clock = 0;
+ }
+ }
+
+ void write(uint8_t addr, uint8_t data)
+ {
+ this->synchronize();
+ this->spc_dsp.write(addr, data);
+ }
+
+ void power();
+ void reset();
+
+ DSP();
+
+ SPC_DSP spc_dsp;
+ };
+
+ extern DSP dsp;
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/smp/algorithms.cpp
@@ -1,1 +1,141 @@
+#include "smp.hpp"
+namespace SNES
+{
+ uint8_t SMP::op_adc(uint8_t x, uint8_t y)
+ {
+ int r = x + y + this->regs.p.c;
+ this->regs.p.n = r & 0x80;
+ this->regs.p.v = ~(x ^ y) & (x ^ r) & 0x80;
+ this->regs.p.h = (x ^ y ^ r) & 0x10;
+ this->regs.p.z = static_cast<uint8_t>(r) == 0;
+ this->regs.p.c = r > 0xff;
+ return r;
+ }
+
+ uint16_t SMP::op_addw(uint16_t x, uint16_t y)
+ {
+ this->regs.p.c = 0;
+ uint16_t r = this->op_adc(x, y);
+ r |= this->op_adc(x >> 8, y >> 8) << 8;
+ regs.p.z = r == 0;
+ return r;
+ }
+
+ uint8_t SMP::op_and(uint8_t x, uint8_t y)
+ {
+ x &= y;
+ regs.p.n = x & 0x80;
+ regs.p.z = x == 0;
+ return x;
+ }
+
+ uint8_t SMP::op_cmp(uint8_t x, uint8_t y)
+ {
+ int r = x - y;
+ regs.p.n = r & 0x80;
+ regs.p.z = static_cast<uint8_t>(r) == 0;
+ regs.p.c = r >= 0;
+ return x;
+ }
+
+ uint16_t SMP::op_cmpw(uint16_t x, uint16_t y)
+ {
+ int r = x - y;
+ regs.p.n = r & 0x8000;
+ regs.p.z = static_cast<uint16_t>(r) == 0;
+ regs.p.c = r >= 0;
+ return x;
+ }
+
+ uint8_t SMP::op_eor(uint8_t x, uint8_t y)
+ {
+ x ^= y;
+ regs.p.n = x & 0x80;
+ regs.p.z = x == 0;
+ return x;
+ }
+
+ uint8_t SMP::op_or(uint8_t x, uint8_t y)
+ {
+ x |= y;
+ regs.p.n = x & 0x80;
+ regs.p.z = x == 0;
+ return x;
+ }
+
+ uint8_t SMP::op_sbc(uint8_t x, uint8_t y)
+ {
+ int r = x - y - !regs.p.c;
+ regs.p.n = r & 0x80;
+ regs.p.v = (x ^ y) & (x ^ r) & 0x80;
+ regs.p.h = !((x ^ y ^ r) & 0x10);
+ regs.p.z = static_cast<uint8_t>(r) == 0;
+ regs.p.c = r >= 0;
+ return r;
+ }
+
+ uint16_t SMP::op_subw(uint16_t x, uint16_t y)
+ {
+ regs.p.c = 1;
+ uint16_t r = this->op_sbc(x, y);
+ r |= this->op_sbc(x >> 8, y >> 8) << 8;
+ regs.p.z = r == 0;
+ return r;
+ }
+
+ uint8_t SMP::op_inc(uint8_t x)
+ {
+ ++x;
+ regs.p.n = x & 0x80;
+ regs.p.z = x == 0;
+ return x;
+ }
+
+ uint8_t SMP::op_dec(uint8_t x)
+ {
+ --x;
+ regs.p.n = x & 0x80;
+ regs.p.z = x == 0;
+ return x;
+ }
+
+ uint8_t SMP::op_asl(uint8_t x)
+ {
+ regs.p.c = x & 0x80;
+ x <<= 1;
+ regs.p.n = x & 0x80;
+ regs.p.z = x == 0;
+ return x;
+ }
+
+ uint8_t SMP::op_lsr(uint8_t x)
+ {
+ regs.p.c = x & 0x01;
+ x >>= 1;
+ regs.p.n = x & 0x80;
+ regs.p.z = x == 0;
+ return x;
+ }
+
+ uint8_t SMP::op_rol(uint8_t x)
+ {
+ unsigned carry = static_cast<unsigned>(regs.p.c);
+ regs.p.c = x & 0x80;
+ x = (x << 1) | carry;
+ regs.p.n = x & 0x80;
+ regs.p.z = x == 0;
+ return x;
+ }
+
+ uint8_t SMP::op_ror(uint8_t x)
+ {
+ unsigned carry = static_cast<unsigned>(regs.p.c) << 7;
+ regs.p.c = x & 0x01;
+ x = carry | (x >> 1);
+ regs.p.n = x & 0x80;
+ regs.p.z = x == 0;
+ return x;
+ }
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/smp/core.cpp
@@ -1,1 +1,2111 @@
-
+#include "smp.hpp"
+#include "../dsp/sdsp.hpp"
+
+namespace SNES
+{
+ void SMP::tick()
+ {
+ this->timer0.tick();
+ this->timer1.tick();
+ this->timer2.tick();
+
+ ++this->clock;
+ ++dsp.clock;
+ }
+
+ void SMP::tick(unsigned clocks)
+ {
+ this->timer0.tick(clocks);
+ this->timer1.tick(clocks);
+ this->timer2.tick(clocks);
+
+ this->clock += clocks;
+ dsp.clock += clocks;
+ }
+
+ void SMP::op_io()
+ {
+ this->tick();
+ }
+
+ void SMP::op_io(unsigned clocks)
+ {
+ this->tick(clocks);
+ }
+
+ uint8_t SMP::op_read(uint16_t addr)
+ {
+ this->tick();
+ if ((addr & 0xfff0) == 0x00f0)
+ return this->mmio_read(addr);
+ if (addr >= 0xffc0 && this->status.iplrom_enable)
+ return SMP::iplrom[addr & 0x3f];
+ return this->apuram[addr];
+ }
+
+ void SMP::op_write(uint16_t addr, uint8_t data)
+ {
+ this->tick();
+ if ((addr & 0xfff0) == 0x00f0)
+ this->mmio_write(addr, data);
+ this->apuram[addr] = data; // all writes go to RAM, even MMIO writes
+ }
+
+ uint8_t SMP::op_readstack()
+ {
+ this->tick();
+ return this->apuram[0x0100 | ++this->regs.sp];
+ }
+
+ void SMP::op_writestack(uint8_t data)
+ {
+ this->tick();
+ this->apuram[0x0100 | this->regs.sp--] = data;
+ }
+
+ void SMP::op_step()
+ {
+ const auto op_readpc = [&]() { return this->op_read(this->regs.pc++); };
+ const auto op_readdp = [&](uint16_t addr) { return this->op_read((this->regs.p.p << 8) + (addr & 0xff)); };
+ const auto op_writedp = [&](uint16_t addr, uint8_t data) { this->op_write((this->regs.p.p << 8) + (addr & 0xff), data); };
+ const auto op_readaddr = [&](uint16_t addr) { return this->op_read(addr); };
+ const auto op_writeaddr = [&](uint16_t addr, uint8_t data) { this->op_write(addr, data); };
+
+ if (!this->opcode_cycle)
+ this->opcode_number = op_readpc();
+
+ switch (opcode_number)
+ {
+ // Start of core/oppseudo_misc.cpp
+
+ case 0x00:
+ this->op_io();
+ break;
+
+ case 0xef:
+ case 0xff:
+ this->op_io(2);
+ --this->regs.pc;
+ break;
+
+ case 0x9f:
+ this->op_io(4);
+ this->regs.B.a = (this->regs.B.a >> 4) | (this->regs.B.a << 4);
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ break;
+
+ case 0xdf:
+ this->op_io(2);
+ if (this->regs.p.c || this->regs.B.a > 0x99)
+ {
+ this->regs.B.a += 0x60;
+ this->regs.p.c = 1;
+ }
+ if (this->regs.p.h || (this->regs.B.a & 15) > 0x09)
+ this->regs.B.a += 0x06;
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ break;
+
+ case 0xbe:
+ this->op_io(2);
+ if (!this->regs.p.c || this->regs.B.a > 0x99)
+ {
+ this->regs.B.a -= 0x60;
+ this->regs.p.c = 0;
+ }
+ if (!this->regs.p.h || (this->regs.B.a & 15) > 0x09)
+ this->regs.B.a -= 0x06;
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ break;
+
+ case 0x60:
+ case 0x80:
+ this->op_io();
+ this->regs.p.c = opcode_number == 0x80;
+ break;
+
+ case 0x20:
+ case 0x40:
+ this->op_io();
+ this->regs.p.p = opcode_number == 0x40;
+ break;
+
+ case 0xe0:
+ this->op_io();
+ this->regs.p.v = 0;
+ this->regs.p.h = 0;
+ break;
+
+ case 0xed:
+ this->op_io(2);
+ this->regs.p.c = !this->regs.p.c;
+ break;
+
+ case 0xa0:
+ case 0xc0:
+ this->op_io(2);
+ this->regs.p.i = opcode_number == 0xa0;
+ break;
+
+ case 0x02:
+ case 0x22:
+ case 0x42:
+ case 0x62:
+ case 0x82:
+ case 0xa2:
+ case 0xc2:
+ case 0xe2:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->rd |= 0x01 << ((opcode_number & 0xE0) >> 5);
+ op_writedp(this->dp, this->rd);
+ break;
+
+ case 0x12:
+ case 0x32:
+ case 0x52:
+ case 0x72:
+ case 0x92:
+ case 0xb2:
+ case 0xd2:
+ case 0xf2:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->rd &= ~(0x01 << ((opcode_number & 0xE0) >> 5));
+ op_writedp(this->dp, this->rd);
+ break;
+
+ case 0x2d:
+ this->op_io(2);
+ this->op_writestack(this->regs.B.a);
+ break;
+
+ case 0x4d:
+ this->op_io(2);
+ this->op_writestack(this->regs.x);
+ break;
+
+ case 0x6d:
+ this->op_io(2);
+ this->op_writestack(this->regs.B.y);
+ break;
+
+ case 0x0d:
+ this->op_io(2);
+ this->op_writestack(this->regs.p);
+ break;
+
+ case 0xae:
+ this->op_io(2);
+ this->regs.B.a = this->op_readstack();
+ break;
+
+ case 0xce:
+ this->op_io(2);
+ this->regs.x = this->op_readstack();
+ break;
+
+ case 0xee:
+ this->op_io(2);
+ this->regs.B.y = this->op_readstack();
+ break;
+
+ case 0x8e:
+ this->op_io(2);
+ this->regs.p = this->op_readstack();
+ break;
+
+ case 0xcf:
+ this->op_io(8);
+ this->ya = this->regs.B.y * this->regs.B.a;
+ this->regs.B.a = this->ya;
+ this->regs.B.y = this->ya >> 8;
+ // result is set based on y (high-byte) only
+ this->regs.p.n = !!(this->regs.B.y & 0x80);
+ this->regs.p.z = !this->regs.B.y;
+ break;
+
+ case 0x9e:
+ this->op_io(11);
+ this->ya = this->regs.ya;
+ // overflow set if quotient >= 256
+ this->regs.p.v = !!(this->regs.B.y >= this->regs.x);
+ this->regs.p.h = !!((this->regs.B.y & 15) >= (this->regs.x & 15));
+ if (this->regs.B.y < (this->regs.x << 1))
+ {
+ // if quotient is <= 511 (will fit into 9-bit result)
+ this->regs.B.a = this->ya / this->regs.x;
+ this->regs.B.y = this->ya % this->regs.x;
+ }
+ else
+ {
+ // otherwise, the quotient won't fit into regs.p.v + regs.B.a
+ // this emulates the odd behavior of the S-SMP in this case
+ this->regs.B.a = 255 - (this->ya - (this->regs.x << 9)) / (256 - this->regs.x);
+ this->regs.B.y = this->regs.x + (this->ya - (this->regs.x << 9)) % (256 - this->regs.x);
+ }
+ // result is set based on a (quotient) only
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ break;
+
+ // End of core/oppseudo_misc.cpp
+
+ // Start of core/oppseudo_mov.cpp
+
+ case 0x7d:
+ this->op_io();
+ this->regs.B.a = this->regs.x;
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ break;
+
+ case 0xdd:
+ this->op_io();
+ this->regs.B.a = this->regs.B.y;
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ break;
+
+ case 0x5d:
+ this->op_io();
+ this->regs.x = this->regs.B.a;
+ this->regs.p.n = !!(this->regs.x & 0x80);
+ this->regs.p.z = !this->regs.x;
+ break;
+
+ case 0xfd:
+ this->op_io();
+ this->regs.B.y = this->regs.B.a;
+ this->regs.p.n = !!(this->regs.B.y & 0x80);
+ this->regs.p.z = !this->regs.B.y;
+ break;
+
+ case 0x9d:
+ this->op_io();
+ this->regs.x = this->regs.sp;
+ this->regs.p.n = !!(this->regs.x & 0x80);
+ this->regs.p.z = !this->regs.x;
+ break;
+
+ case 0xbd:
+ this->op_io();
+ this->regs.sp = this->regs.x;
+ break;
+
+ case 0xe8:
+ this->regs.B.a = op_readpc();
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ break;
+
+ case 0xcd:
+ this->regs.x = op_readpc();
+ this->regs.p.n = !!(this->regs.x & 0x80);
+ this->regs.p.z = !this->regs.x;
+ break;
+
+ case 0x8d:
+ this->regs.B.y = op_readpc();
+ this->regs.p.n = !!(this->regs.B.y & 0x80);
+ this->regs.p.z = !this->regs.B.y;
+ break;
+
+ case 0xe6:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->op_io();
+ break;
+ case 2:
+ this->regs.B.a = op_readdp(this->regs.x);
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xbf:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->op_io();
+ break;
+ case 2:
+ this->regs.B.a = op_readdp(this->regs.x++);
+ this->op_io();
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xe4:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ break;
+ case 2:
+ this->regs.B.a = op_readdp(this->sp);
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xf8:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ break;
+ case 2:
+ this->regs.x = op_readdp(this->sp);
+ this->regs.p.n = !!(this->regs.x & 0x80);
+ this->regs.p.z = !this->regs.x;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xeb:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ break;
+ case 2:
+ this->regs.B.y = op_readdp(this->sp);
+ this->regs.p.n = !!(this->regs.B.y & 0x80);
+ this->regs.p.z = !this->regs.B.y;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xf4:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ this->op_io();
+ break;
+ case 2:
+ this->regs.B.a = op_readdp(this->sp + this->regs.x);
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xf9:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ this->op_io();
+ break;
+ case 2:
+ this->regs.x = op_readdp(this->sp + this->regs.B.y);
+ this->regs.p.n = !!(this->regs.x & 0x80);
+ this->regs.p.z = !this->regs.x;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xfb:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ this->op_io();
+ break;
+ case 2:
+ this->regs.B.y = op_readdp(this->sp + this->regs.x);
+ this->regs.p.n = !!(this->regs.B.y & 0x80);
+ this->regs.p.z = !this->regs.B.y;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xe5:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ break;
+ case 2:
+ this->sp |= op_readpc() << 8;
+ break;
+ case 3:
+ this->regs.B.a = op_readaddr(this->sp);
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xe9:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ this->sp |= op_readpc() << 8;
+ break;
+ case 2:
+ this->regs.x = op_readaddr(this->sp);
+ this->regs.p.n = !!(this->regs.x & 0x80);
+ this->regs.p.z = !this->regs.x;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xec:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ this->sp |= op_readpc() << 8;
+ break;
+ case 2:
+ this->regs.B.y = op_readaddr(this->sp);
+ this->regs.p.n = !!(this->regs.B.y & 0x80);
+ this->regs.p.z = !this->regs.B.y;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xf5:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ this->sp |= op_readpc() << 8;
+ this->op_io();
+ break;
+ case 2:
+ this->regs.B.a = op_readaddr(this->sp + this->regs.x);
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xf6:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ this->sp |= op_readpc() << 8;
+ this->op_io();
+ break;
+ case 2:
+ this->regs.B.a = op_readaddr(this->sp + this->regs.B.y);
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xe7:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc() + this->regs.x;
+ this->op_io();
+ break;
+ case 2:
+ this->sp = op_readdp(this->dp);
+ break;
+ case 3:
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ break;
+ case 4:
+ this->regs.B.a = op_readaddr(this->sp);
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xf7:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ this->op_io();
+ break;
+ case 2:
+ this->sp = op_readdp(this->dp);
+ break;
+ case 3:
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ break;
+ case 4:
+ this->regs.B.a = op_readaddr(this->sp + this->regs.B.y);
+ this->regs.p.n = !!(this->regs.B.a & 0x80);
+ this->regs.p.z = !this->regs.B.a;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xfa:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ break;
+ case 2:
+ this->rd = op_readdp(this->sp);
+ break;
+ case 3:
+ this->dp = op_readpc();
+ break;
+ case 4:
+ op_writedp(this->dp, this->rd);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0x8f:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->rd = op_readpc();
+ this->dp = op_readpc();
+ break;
+ case 2:
+ op_readdp(this->dp);
+ break;
+ case 3:
+ op_writedp(this->dp, this->rd);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xc6:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->op_io();
+ break;
+ case 2:
+ op_readdp(this->regs.x);
+ break;
+ case 3:
+ op_writedp(this->regs.x, this->regs.B.a);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xaf:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->op_io(2);
+ break;
+ case 2:
+ op_writedp(this->regs.x++, this->regs.B.a);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xc4:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ break;
+ case 2:
+ op_readdp(this->dp);
+ break;
+ case 3:
+ op_writedp(this->dp, this->regs.B.a);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xd8:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ break;
+ case 2:
+ op_readdp(this->dp);
+ break;
+ case 3:
+ op_writedp(this->dp, this->regs.x);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xcb:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ break;
+ case 2:
+ op_readdp(this->dp);
+ break;
+ case 3:
+ op_writedp(this->dp, this->regs.B.y);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xd4:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ this->op_io();
+ this->dp += this->regs.x;
+ break;
+ case 2:
+ op_readdp(this->dp);
+ break;
+ case 3:
+ op_writedp(this->dp, this->regs.B.a);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xd9:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ this->op_io();
+ this->dp += this->regs.B.y;
+ break;
+ case 2:
+ op_readdp(this->dp);
+ break;
+ case 3:
+ op_writedp(this->dp, this->regs.x);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xdb:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ this->op_io();
+ this->dp += this->regs.x;
+ break;
+ case 2:
+ op_readdp(this->dp);
+ break;
+ case 3:
+ op_writedp(this->dp, this->regs.B.y);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xc5:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ break;
+ case 2:
+ this->dp |= op_readpc() << 8;
+ break;
+ case 3:
+ op_readaddr(this->dp);
+ break;
+ case 4:
+ op_writeaddr(this->dp, this->regs.B.a);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xc9:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ break;
+ case 2:
+ this->dp |= op_readpc() << 8;
+ break;
+ case 3:
+ op_readaddr(this->dp);
+ break;
+ case 4:
+ op_writeaddr(this->dp, this->regs.x);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xcc:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ break;
+ case 2:
+ this->dp |= op_readpc() << 8;
+ break;
+ case 3:
+ op_readaddr(this->dp);
+ break;
+ case 4:
+ op_writeaddr(this->dp, this->regs.B.y);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xd5:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->dp += this->regs.x;
+ break;
+ case 2:
+ op_readaddr(this->dp);
+ break;
+ case 3:
+ op_writeaddr(this->dp, this->regs.B.a);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xd6:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->dp += this->regs.B.y;
+ break;
+ case 2:
+ op_readaddr(this->dp);
+ break;
+ case 3:
+ op_writeaddr(this->dp, this->regs.B.a);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xc7:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ this->op_io();
+ this->sp += this->regs.x;
+ break;
+ case 2:
+ this->dp = op_readdp(this->sp);
+ break;
+ case 3:
+ this->dp |= op_readdp(this->sp + 1) << 8;
+ break;
+ case 4:
+ op_readaddr(this->dp);
+ break;
+ case 5:
+ op_writeaddr(this->dp, this->regs.B.a);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xd7:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ break;
+ case 2:
+ this->dp = op_readdp(this->sp);
+ break;
+ case 3:
+ this->dp |= op_readdp(this->sp + 1) << 8;
+ this->op_io();
+ this->dp += this->regs.B.y;
+ break;
+ case 4:
+ op_readaddr(this->dp);
+ break;
+ case 5:
+ op_writeaddr(this->dp, this->regs.B.a);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xba:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ break;
+ case 2:
+ this->regs.B.a = op_readdp(this->sp);
+ this->op_io();
+ break;
+ case 3:
+ this->regs.B.y = op_readdp(this->sp + 1);
+ this->regs.p.n = !!(this->regs.ya & 0x8000);
+ this->regs.p.z = !this->regs.ya;
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xda:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ break;
+ case 2:
+ op_readdp(this->dp);
+ break;
+ case 3:
+ op_writedp(this->dp, this->regs.B.a);
+ break;
+ case 4:
+ op_writedp(this->dp + 1, this->regs.B.y);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xaa:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->sp = op_readpc();
+ this->sp |= op_readpc() << 8;
+ break;
+ case 2:
+ this->bit = this->sp >> 13;
+ this->sp &= 0x1fff;
+ this->rd = op_readaddr(this->sp);
+ this->regs.p.c = !!(this->rd & (1 << this->bit));
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0xca:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ break;
+ case 2:
+ this->bit = this->dp >> 13;
+ this->dp &= 0x1fff;
+ this->rd = op_readaddr(this->dp);
+ if (this->regs.p.c)
+ this->rd |= (1 << this->bit);
+ else
+ this->rd &= ~(1 << this->bit);
+ this->op_io();
+ break;
+ case 3:
+ op_writeaddr(this->dp, this->rd);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ // End of core/oppseudo_mov.cpp
+
+ // Start of core/oppseudo_pc.cpp
+
+ case 0x2f:
+ this->rd = op_readpc();
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0xf0:
+ this->rd = op_readpc();
+ if (!this->regs.p.z)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0xd0:
+ this->rd = op_readpc();
+ if (this->regs.p.z)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0xb0:
+ this->rd = op_readpc();
+ if (!this->regs.p.c)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0x90:
+ this->rd = op_readpc();
+ if (this->regs.p.c)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0x70:
+ this->rd = op_readpc();
+ if (!this->regs.p.v)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0x50:
+ this->rd = op_readpc();
+ if (this->regs.p.v)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0x30:
+ this->rd = op_readpc();
+ if (!this->regs.p.n)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0x10:
+ this->rd = op_readpc();
+ if (this->regs.p.n)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(rd);
+ break;
+
+ case 0x03:
+ case 0x23:
+ case 0x43:
+ case 0x63:
+ case 0x83:
+ case 0xa3:
+ case 0xc3:
+ case 0xe3:
+ {
+ this->dp = op_readpc();
+ this->sp = op_readdp(this->dp);
+ this->rd = op_readpc();
+ this->op_io();
+ uint8_t mask = 1 << ((opcode_number & 0xE0) >> 5);
+ if ((sp & mask) != mask)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+ }
+
+ case 0x13:
+ case 0x33:
+ case 0x53:
+ case 0x73:
+ case 0x93:
+ case 0xb3:
+ case 0xd3:
+ case 0xf3:
+ {
+ this->dp = op_readpc();
+ this->sp = op_readdp(this->dp);
+ this->rd = op_readpc();
+ this->op_io();
+ uint8_t mask = 1 << ((opcode_number & 0xE0) >> 5);
+ if ((sp & mask) == mask)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+ }
+
+ case 0x2e:
+ this->dp = op_readpc();
+ this->sp = op_readdp(this->dp);
+ this->rd = op_readpc();
+ this->op_io();
+ if (this->regs.B.a == this->sp)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0xde:
+ this->dp = op_readpc();
+ this->op_io();
+ this->sp = op_readdp(this->dp + this->regs.x);
+ this->rd = op_readpc();
+ this->op_io();
+ if (this->regs.B.a == this->sp)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0x6e:
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ op_writedp(this->dp, --this->wr);
+ this->rd = op_readpc();
+ if (!this->wr)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0xfe:
+ this->rd = op_readpc();
+ this->op_io();
+ --this->regs.B.y;
+ this->op_io();
+ if (!this->regs.B.y)
+ break;
+ this->op_io(2);
+ this->regs.pc += static_cast<int8_t>(this->rd);
+ break;
+
+ case 0x5f:
+ this->rd = op_readpc();
+ this->rd |= op_readpc() << 8;
+ this->regs.pc = this->rd;
+ break;
+
+ case 0x1f:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->dp += this->regs.x;
+ this->rd = op_readaddr(this->dp);
+ this->rd |= op_readaddr(this->dp + 1) << 8;
+ this->regs.pc = this->rd;
+ break;
+
+ case 0x3f:
+ this->rd = op_readpc();
+ this->rd |= op_readpc() << 8;
+ this->op_io(3);
+ this->op_writestack(this->regs.pc >> 8);
+ this->op_writestack(this->regs.pc);
+ this->regs.pc = this->rd;
+ break;
+
+ case 0x4f:
+ this->rd = op_readpc();
+ this->op_io(2);
+ this->op_writestack(this->regs.pc >> 8);
+ this->op_writestack(this->regs.pc);
+ this->regs.pc = 0xff00 | this->rd;
+ break;
+
+ case 0x01:
+ case 0x11:
+ case 0x21:
+ case 0x31:
+ case 0x41:
+ case 0x51:
+ case 0x61:
+ case 0x71:
+ case 0x81:
+ case 0x91:
+ case 0xa1:
+ case 0xb1:
+ case 0xc1:
+ case 0xd1:
+ case 0xe1:
+ case 0xf1:
+ this->dp = 0xffde - (((opcode_number & 0xF0) >> 4) << 1);
+ this->rd = op_readaddr(this->dp);
+ this->rd |= op_readaddr(this->dp + 1) << 8;
+ this->op_io(3);
+ this->op_writestack(this->regs.pc >> 8);
+ this->op_writestack(this->regs.pc);
+ this->regs.pc = this->rd;
+ break;
+
+ case 0x0f:
+ this->rd = op_readaddr(0xffde);
+ this->rd |= op_readaddr(0xffdf) << 8;
+ this->op_io(2);
+ this->op_writestack(this->regs.pc >> 8);
+ this->op_writestack(this->regs.pc);
+ this->op_writestack(this->regs.p);
+ this->regs.pc = this->rd;
+ this->regs.p.b = 1;
+ this->regs.p.i = 0;
+ break;
+
+ case 0x6f:
+ this->rd = this->op_readstack();
+ this->rd |= this->op_readstack() << 8;
+ this->op_io(2);
+ this->regs.pc = this->rd;
+ break;
+
+ case 0x7f:
+ this->regs.p = this->op_readstack();
+ this->rd = this->op_readstack();
+ this->rd |= this->op_readstack() << 8;
+ this->op_io(2);
+ this->regs.pc = this->rd;
+ break;
+
+ // End of core/oppseudo_pc.cpp
+
+ // Start of core/oppseudo_read.cpp
+
+ case 0x88:
+ this->rd = op_readpc();
+ this->regs.B.a = this->op_adc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x28:
+ this->rd = op_readpc();
+ this->regs.B.a = this->op_and(this->regs.B.a, this->rd);
+ break;
+
+ case 0x68:
+ this->rd = op_readpc();
+ this->regs.B.a = this->op_cmp(this->regs.B.a, this->rd);
+ break;
+
+ case 0xc8:
+ this->rd = op_readpc();
+ this->regs.x = this->op_cmp(this->regs.x, this->rd);
+ break;
+
+ case 0xad:
+ this->rd = op_readpc();
+ this->regs.B.y = this->op_cmp(this->regs.B.y, this->rd);
+ break;
+
+ case 0x48:
+ this->rd = op_readpc();
+ this->regs.B.a = this->op_eor(this->regs.B.a, this->rd);
+ break;
+
+ case 0x08:
+ this->rd = op_readpc();
+ this->regs.B.a = this->op_or(this->regs.B.a, this->rd);
+ break;
+
+ case 0xa8:
+ this->rd = op_readpc();
+ this->regs.B.a = this->op_sbc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x86:
+ this->op_io();
+ this->rd = op_readdp(this->regs.x);
+ this->regs.B.a = this->op_adc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x26:
+ this->op_io();
+ this->rd = op_readdp(this->regs.x);
+ this->regs.B.a = this->op_and(this->regs.B.a, this->rd);
+ break;
+
+ case 0x66:
+ this->op_io();
+ this->rd = op_readdp(this->regs.x);
+ this->regs.B.a = this->op_cmp(this->regs.B.a, this->rd);
+ break;
+
+ case 0x46:
+ this->op_io();
+ this->rd = op_readdp(this->regs.x);
+ this->regs.B.a = this->op_eor(this->regs.B.a, this->rd);
+ break;
+
+ case 0x06:
+ this->op_io();
+ this->rd = op_readdp(this->regs.x);
+ this->regs.B.a = this->op_or(this->regs.B.a, this->rd);
+ break;
+
+ case 0xa6:
+ this->op_io();
+ this->rd = op_readdp(this->regs.x);
+ this->regs.B.a = this->op_sbc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x84:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->regs.B.a = this->op_adc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x24:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->regs.B.a = this->op_and(this->regs.B.a, this->rd);
+ break;
+
+ case 0x64:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->regs.B.a = this->op_cmp(this->regs.B.a, this->rd);
+ break;
+
+ case 0x3e:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->regs.x = this->op_cmp(this->regs.x, this->rd);
+ break;
+
+ case 0x7e:
+ switch (++this->opcode_cycle)
+ {
+ case 1:
+ this->dp = op_readpc();
+ break;
+ case 2:
+ this->rd = op_readdp(this->dp);
+ this->regs.B.y = this->op_cmp(this->regs.B.y, this->rd);
+ this->opcode_cycle = 0;
+ break;
+ }
+ break;
+
+ case 0x44:
+ this->dp = op_readpc();
+ this->rd = op_readdp(dp);
+ this->regs.B.a = this->op_eor(this->regs.B.a, this->rd);
+ break;
+
+ case 0x04:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->regs.B.a = this->op_or(this->regs.B.a, this->rd);
+ break;
+
+ case 0xa4:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->regs.B.a = this->op_sbc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x94:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->regs.B.a = this->op_adc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x34:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->regs.B.a = this->op_and(this->regs.B.a, this->rd);
+ break;
+
+ case 0x74:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->regs.B.a = this->op_cmp(this->regs.B.a, this->rd);
+ break;
+
+ case 0x54:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->regs.B.a = this->op_eor(this->regs.B.a, this->rd);
+ break;
+
+ case 0x14:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->regs.B.a = this->op_or(this->regs.B.a, this->rd);
+ break;
+
+ case 0xb4:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->regs.B.a = this->op_sbc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x85:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->regs.B.a = this->op_adc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x25:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->regs.B.a = this->op_and(this->regs.B.a, this->rd);
+ break;
+
+ case 0x65:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->regs.B.a = this->op_cmp(this->regs.B.a, this->rd);
+ break;
+
+ case 0x1e:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->regs.x = this->op_cmp(this->regs.x, this->rd);
+ break;
+
+ case 0x5e:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->regs.B.y = this->op_cmp(this->regs.B.y, this->rd);
+ break;
+
+ case 0x45:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->regs.B.a = this->op_eor(this->regs.B.a, this->rd);
+ break;
+
+ case 0x05:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->regs.B.a = this->op_or(this->regs.B.a, this->rd);
+ break;
+
+ case 0xa5:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->regs.B.a = this->op_sbc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x95:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.x);
+ this->regs.B.a = this->op_adc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x96:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.B.y);
+ this->regs.B.a = this->op_adc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x35:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.x);
+ this->regs.B.a = this->op_and(this->regs.B.a, this->rd);
+ break;
+
+ case 0x36:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.B.y);
+ this->regs.B.a = this->op_and(this->regs.B.a, this->rd);
+ break;
+
+ case 0x75:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.x);
+ this->regs.B.a = this->op_cmp(this->regs.B.a, this->rd);
+ break;
+
+ case 0x76:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.B.y);
+ this->regs.B.a = this->op_cmp(this->regs.B.a, this->rd);
+ break;
+
+ case 0x55:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.x);
+ this->regs.B.a = this->op_eor(this->regs.B.a, this->rd);
+ break;
+
+ case 0x56:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.B.y);
+ this->regs.B.a = this->op_eor(this->regs.B.a, this->rd);
+ break;
+
+ case 0x15:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.x);
+ this->regs.B.a = this->op_or(this->regs.B.a, this->rd);
+ break;
+
+ case 0x16:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.B.y);
+ this->regs.B.a = this->op_or(this->regs.B.a, this->rd);
+ break;
+
+ case 0xb5:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.x);
+ this->regs.B.a = this->op_sbc(this->regs.B.a, this->rd);
+ break;
+
+ case 0xb6:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->op_io();
+ this->rd = op_readaddr(this->dp + this->regs.B.y);
+ this->regs.B.a = this->op_sbc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x87:
+ this->dp = op_readpc() + this->regs.x;
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp);
+ this->regs.B.a = this->op_adc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x27:
+ this->dp = op_readpc() + this->regs.x;
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp);
+ this->regs.B.a = this->op_and(this->regs.B.a, this->rd);
+ break;
+
+ case 0x67:
+ this->dp = op_readpc() + this->regs.x;
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp);
+ this->regs.B.a = this->op_cmp(this->regs.B.a, this->rd);
+ break;
+
+ case 0x47:
+ this->dp = op_readpc() + this->regs.x;
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp);
+ this->regs.B.a = this->op_eor(this->regs.B.a, this->rd);
+ break;
+
+ case 0x07:
+ this->dp = op_readpc() + this->regs.x;
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp);
+ this->regs.B.a = this->op_or(this->regs.B.a, this->rd);
+ break;
+
+ case 0xa7:
+ this->dp = op_readpc() + this->regs.x;
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp);
+ this->regs.B.a = this->op_sbc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x97:
+ this->dp = op_readpc();
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp + this->regs.B.y);
+ this->regs.B.a = this->op_adc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x37:
+ this->dp = op_readpc();
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp + this->regs.B.y);
+ this->regs.B.a = this->op_and(this->regs.B.a, this->rd);
+ break;
+
+ case 0x77:
+ this->dp = op_readpc();
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp + this->regs.B.y);
+ this->regs.B.a = this->op_cmp(this->regs.B.a, this->rd);
+ break;
+
+ case 0x57:
+ this->dp = op_readpc();
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp + this->regs.B.y);
+ this->regs.B.a = this->op_eor(this->regs.B.a, this->rd);
+ break;
+
+ case 0x17:
+ this->dp = op_readpc();
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp + this->regs.B.y);
+ this->regs.B.a = this->op_or(this->regs.B.a, this->rd);
+ break;
+
+ case 0xb7:
+ this->dp = op_readpc();
+ this->op_io();
+ this->sp = op_readdp(this->dp);
+ this->sp |= op_readdp(this->dp + 1) << 8;
+ this->rd = op_readaddr(this->sp + this->regs.B.y);
+ this->regs.B.a = this->op_sbc(this->regs.B.a, this->rd);
+ break;
+
+ case 0x99:
+ this->op_io();
+ this->rd = op_readdp(this->regs.B.y);
+ this->wr = op_readdp(this->regs.x);
+ this->wr = this->op_adc(this->wr, this->rd);
+ op_writedp(this->regs.x, this->wr);
+ break;
+
+ case 0x39:
+ this->op_io();
+ this->rd = op_readdp(this->regs.B.y);
+ this->wr = op_readdp(this->regs.x);
+ this->wr = this->op_and(this->wr, this->rd);
+ op_writedp(this->regs.x, this->wr);
+ break;
+
+ case 0x79:
+ this->op_io();
+ this->rd = op_readdp(this->regs.B.y);
+ this->wr = op_readdp(this->regs.x);
+ this->wr = this->op_cmp(wr, rd);
+ this->op_io();
+ break;
+
+ case 0x59:
+ this->op_io();
+ this->rd = op_readdp(this->regs.B.y);
+ this->wr = op_readdp(this->regs.x);
+ this->wr = this->op_eor(this->wr, this->rd);
+ op_writedp(this->regs.x, this->wr);
+ break;
+
+ case 0x19:
+ this->op_io();
+ this->rd = op_readdp(this->regs.B.y);
+ this->wr = op_readdp(this->regs.x);
+ this->wr = this->op_or(this->wr, this->rd);
+ op_writedp(this->regs.x, this->wr);
+ break;
+
+ case 0xb9:
+ this->op_io();
+ this->rd = op_readdp(this->regs.B.y);
+ this->wr = op_readdp(this->regs.x);
+ this->wr = this->op_sbc(this->wr, this->rd);
+ op_writedp(this->regs.x, this->wr);
+ break;
+
+ case 0x89:
+ this->sp = op_readpc();
+ this->rd = op_readdp(this->sp);
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_adc(this->wr, this->rd);
+ op_writedp(this->dp, this->wr);
+ break;
+
+ case 0x29:
+ this->sp = op_readpc();
+ this->rd = op_readdp(this->sp);
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_and(this->wr, this->rd);
+ op_writedp(this->dp, this->wr);
+ break;
+
+ case 0x69:
+ this->sp = op_readpc();
+ this->rd = op_readdp(this->sp);
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_cmp(this->wr, this->rd);
+ this->op_io();
+ break;
+
+ case 0x49:
+ this->sp = op_readpc();
+ this->rd = op_readdp(this->sp);
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_eor(this->wr, this->rd);
+ op_writedp(this->dp, this->wr);
+ break;
+
+ case 0x09:
+ this->sp = op_readpc();
+ this->rd = op_readdp(this->sp);
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_or(this->wr, this->rd);
+ op_writedp(this->dp, this->wr);
+ break;
+
+ case 0xa9:
+ this->sp = op_readpc();
+ this->rd = op_readdp(this->sp);
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_sbc(this->wr, this->rd);
+ op_writedp(this->dp, this->wr);
+ break;
+
+ case 0x98:
+ this->rd = op_readpc();
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_adc(this->wr, this->rd);
+ op_writedp(this->dp, this->wr);
+ break;
+
+ case 0x38:
+ this->rd = op_readpc();
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_and(this->wr, this->rd);
+ op_writedp(this->dp, this->wr);
+ break;
+
+ case 0x78:
+ this->rd = op_readpc();
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_cmp(this->wr, this->rd);
+ this->op_io();
+ break;
+
+ case 0x58:
+ this->rd = op_readpc();
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_eor(this->wr, this->rd);
+ op_writedp(this->dp, this->wr);
+ break;
+
+ case 0x18:
+ this->rd = op_readpc();
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_or(this->wr, this->rd);
+ op_writedp(this->dp, this->wr);
+ break;
+
+ case 0xb8:
+ this->rd = op_readpc();
+ this->dp = op_readpc();
+ this->wr = op_readdp(this->dp);
+ this->wr = this->op_sbc(this->wr, this->rd);
+ op_writedp(this->dp, this->wr);
+ break;
+
+ case 0x7a:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->op_io();
+ this->rd |= op_readdp(this->dp + 1) << 8;
+ this->regs.ya = this->op_addw(this->regs.ya, this->rd);
+ break;
+
+ case 0x9a:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->op_io();
+ this->rd |= op_readdp(this->dp + 1) << 8;
+ this->regs.ya = this->op_subw(this->regs.ya, this->rd);
+ break;
+
+ case 0x5a:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->rd |= op_readdp(this->dp + 1) << 8;
+ this->op_cmpw(this->regs.ya, this->rd);
+ break;
+
+ case 0x4a:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->bit = this->dp >> 13;
+ this->dp &= 0x1fff;
+ this->rd = op_readaddr(this->dp);
+ this->regs.p.c = this->regs.p.c & !!(this->rd & (1 << this->bit));
+ break;
+
+ case 0x6a:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->bit = this->dp >> 13;
+ this->dp &= 0x1fff;
+ this->rd = op_readaddr(this->dp);
+ this->regs.p.c = this->regs.p.c & !(this->rd & (1 << this->bit));
+ break;
+
+ case 0x8a:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->bit = this->dp >> 13;
+ this->dp &= 0x1fff;
+ this->rd = op_readaddr(this->dp);
+ this->op_io();
+ this->regs.p.c = this->regs.p.c ^ !!(this->rd & (1 << this->bit));
+ break;
+
+ case 0xea:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->bit = this->dp >> 13;
+ this->dp &= 0x1fff;
+ this->rd = op_readaddr(this->dp);
+ this->rd ^= 1 << this->bit;
+ op_writeaddr(this->dp, this->rd);
+ break;
+
+ case 0x0a:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->bit = this->dp >> 13;
+ this->dp &= 0x1fff;
+ this->rd = op_readaddr(this->dp);
+ this->op_io();
+ this->regs.p.c = this->regs.p.c | !!(this->rd & (1 << this->bit));
+ break;
+
+ case 0x2a:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->bit = this->dp >> 13;
+ this->dp &= 0x1fff;
+ this->rd = op_readaddr(this->dp);
+ this->op_io();
+ this->regs.p.c = this->regs.p.c | !(this->rd & (1 << this->bit));
+ break;
+
+ // End of core/oppseudo_read.cpp
+
+ // Start of core/oppseudo_rmw.cpp
+
+ case 0xbc:
+ this->op_io();
+ this->regs.B.a = this->op_inc(this->regs.B.a);
+ break;
+
+ case 0x3d:
+ this->op_io();
+ this->regs.x = this->op_inc(this->regs.x);
+ break;
+
+ case 0xfc:
+ this->op_io();
+ this->regs.B.y = this->op_inc(this->regs.B.y);
+ break;
+
+ case 0x9c:
+ this->op_io();
+ this->regs.B.a = this->op_dec(this->regs.B.a);
+ break;
+
+ case 0x1d:
+ this->op_io();
+ this->regs.x = this->op_dec(this->regs.x);
+ break;
+
+ case 0xdc:
+ this->op_io();
+ this->regs.B.y = this->op_dec(this->regs.B.y);
+ break;
+
+ case 0x1c:
+ this->op_io();
+ this->regs.B.a = this->op_asl(this->regs.B.a);
+ break;
+
+ case 0x5c:
+ this->op_io();
+ this->regs.B.a = this->op_lsr(this->regs.B.a);
+ break;
+
+ case 0x3c:
+ this->op_io();
+ this->regs.B.a = this->op_rol(this->regs.B.a);
+ break;
+
+ case 0x7c:
+ this->op_io();
+ this->regs.B.a = this->op_ror(this->regs.B.a);
+ break;
+
+ case 0xab:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->rd = this->op_inc(this->rd);
+ op_writedp(this->dp, this->rd);
+ break;
+
+ case 0x8b:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->rd = this->op_dec(this->rd);
+ op_writedp(this->dp, this->rd);
+ break;
+
+ case 0x0b:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->rd = this->op_asl(this->rd);
+ op_writedp(this->dp, this->rd);
+ break;
+
+ case 0x4b:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->rd = this->op_lsr(this->rd);
+ op_writedp(this->dp, this->rd);
+ break;
+
+ case 0x2b:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->rd = this->op_rol(this->rd);
+ op_writedp(this->dp, this->rd);
+ break;
+
+ case 0x6b:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ this->rd = this->op_ror(this->rd);
+ op_writedp(this->dp, this->rd);
+ break;
+
+ case 0xbb:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->rd = this->op_inc(this->rd);
+ op_writedp(this->dp + this->regs.x, this->rd);
+ break;
+
+ case 0x9b:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->rd = this->op_dec(this->rd);
+ op_writedp(this->dp + this->regs.x, this->rd);
+ break;
+
+ case 0x1b:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->rd = this->op_asl(this->rd);
+ op_writedp(this->dp + this->regs.x, this->rd);
+ break;
+
+ case 0x5b:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->rd = this->op_lsr(this->rd);
+ op_writedp(this->dp + this->regs.x, this->rd);
+ break;
+
+ case 0x3b:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->rd = this->op_rol(this->rd);
+ op_writedp(this->dp + this->regs.x, this->rd);
+ break;
+
+ case 0x7b:
+ this->dp = op_readpc();
+ this->op_io();
+ this->rd = op_readdp(this->dp + this->regs.x);
+ this->rd = this->op_ror(this->rd);
+ op_writedp(this->dp + this->regs.x, this->rd);
+ break;
+
+ case 0xac:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->rd = this->op_inc(this->rd);
+ op_writeaddr(this->dp, this->rd);
+ break;
+
+ case 0x8c:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->rd = this->op_dec(this->rd);
+ op_writeaddr(this->dp, this->rd);
+ break;
+
+ case 0x0c:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->rd = this->op_asl(this->rd);
+ op_writeaddr(this->dp, this->rd);
+ break;
+
+ case 0x4c:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->rd = this->op_lsr(this->rd);
+ op_writeaddr(this->dp, this->rd);
+ break;
+
+ case 0x2c:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->rd = this->op_rol(this->rd);
+ op_writeaddr(this->dp, this->rd);
+ break;
+
+ case 0x6c:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->rd = this->op_ror(this->rd);
+ op_writeaddr(this->dp, this->rd);
+ break;
+
+ case 0x0e:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->regs.p.n = !!((this->regs.B.a - this->rd) & 0x80);
+ this->regs.p.z = !(this->regs.B.a - this->rd);
+ op_readaddr(this->dp);
+ op_writeaddr(this->dp, this->rd | this->regs.B.a);
+ break;
+
+ case 0x4e:
+ this->dp = op_readpc();
+ this->dp |= op_readpc() << 8;
+ this->rd = op_readaddr(this->dp);
+ this->regs.p.n = !!((this->regs.B.a - this->rd) & 0x80);
+ this->regs.p.z = !(this->regs.B.a - this->rd);
+ op_readaddr(this->dp);
+ op_writeaddr(this->dp, this->rd & ~this->regs.B.a);
+ break;
+
+ case 0x3a:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ ++this->rd;
+ op_writedp(this->dp++, this->rd);
+ this->rd += op_readdp(this->dp) << 8;
+ op_writedp(this->dp, this->rd >> 8);
+ this->regs.p.n = !!(this->rd & 0x8000);
+ this->regs.p.z = !this->rd;
+ break;
+
+ case 0x1a:
+ this->dp = op_readpc();
+ this->rd = op_readdp(this->dp);
+ --this->rd;
+ op_writedp(this->dp++, this->rd);
+ this->rd += op_readdp(this->dp) << 8;
+ op_writedp(this->dp, this->rd >> 8);
+ this->regs.p.n = !!(this->rd & 0x8000);
+ this->regs.p.z = !this->rd;
+ break;
+
+ // End of core/oppseudo_rmw.cpp
+ }
+ }
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/smp/iplrom.cpp
@@ -1,1 +1,47 @@
+#include "smp.hpp"
+namespace SNES
+{
+ // this is the IPLROM for the S-SMP coprocessor.
+ // the S-SMP does not allow writing to the IPLROM.
+ // all writes are instead mapped to the extended
+ // RAM region, accessible when $f1.d7 is clear.
+
+ const uint8_t SMP::iplrom[64] =
+ {
+ /*ffc0*/ 0xcd, 0xef, //mov x,#$ef
+ /*ffc2*/ 0xbd, //mov sp,x
+ /*ffc3*/ 0xe8, 0x00, //mov a,#$00
+ /*ffc5*/ 0xc6, //mov (x),a
+ /*ffc6*/ 0x1d, //dec x
+ /*ffc7*/ 0xd0, 0xfc, //bne $ffc5
+ /*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa
+ /*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb
+ /*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc
+ /*ffd2*/ 0xd0, 0xfb, //bne $ffcf
+ /*ffd4*/ 0x2f, 0x19, //bra $ffef
+ /*ffd6*/ 0xeb, 0xf4, //mov y,$f4
+ /*ffd8*/ 0xd0, 0xfc, //bne $ffd6
+ /*ffda*/ 0x7e, 0xf4, //cmp y,$f4
+ /*ffdc*/ 0xd0, 0x0b, //bne $ffe9
+ /*ffde*/ 0xe4, 0xf5, //mov a,$f5
+ /*ffe0*/ 0xcb, 0xf4, //mov $f4,y
+ /*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a
+ /*ffe4*/ 0xfc, //inc y
+ /*ffe5*/ 0xd0, 0xf3, //bne $ffda
+ /*ffe7*/ 0xab, 0x01, //inc $01
+ /*ffe9*/ 0x10, 0xef, //bpl $ffda
+ /*ffeb*/ 0x7e, 0xf4, //cmp y,$f4
+ /*ffed*/ 0x10, 0xeb, //bpl $ffda
+ /*ffef*/ 0xba, 0xf6, //movw ya,$f6
+ /*fff1*/ 0xda, 0x00, //movw $00,ya
+ /*fff3*/ 0xba, 0xf4, //movw ya,$f4
+ /*fff5*/ 0xc4, 0xf4, //mov $f4,a
+ /*fff7*/ 0xdd, //mov a,y
+ /*fff8*/ 0x5d, //mov x,a
+ /*fff9*/ 0xd0, 0xdb, //bne $ffd6
+ /*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x)
+ /*fffe*/ 0xc0, 0xff //reset vector location ($ffc0)
+ };
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/smp/memory.cpp
@@ -1,1 +1,146 @@
+#include "smp.hpp"
+#include "../dsp/sdsp.hpp"
+namespace SNES
+{
+ unsigned SMP::port_read(unsigned addr)
+ {
+ return this->apuram[0xf4 + (addr & 3)];
+ }
+
+ void SMP::port_write(unsigned addr, unsigned data)
+ {
+ this->apuram[0xf4 + (addr & 3)] = data;
+ }
+
+ unsigned SMP::mmio_read(unsigned addr)
+ {
+ switch (addr)
+ {
+ case 0xf2:
+ return this->status.dsp_addr;
+
+ case 0xf3:
+ return dsp.read(this->status.dsp_addr & 0x7f);
+
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ return cpu.port_read(addr);
+
+ case 0xf8:
+ return this->status.ram00f8;
+
+ case 0xf9:
+ return this->status.ram00f9;
+
+ case 0xfd:
+ {
+ unsigned result = this->timer0.stage3_ticks & 15;
+ this->timer0.stage3_ticks = 0;
+ return result;
+ }
+
+ case 0xfe:
+ {
+ unsigned result = this->timer1.stage3_ticks & 15;
+ this->timer1.stage3_ticks = 0;
+ return result;
+ }
+
+ case 0xff:
+ {
+ unsigned result = this->timer2.stage3_ticks & 15;
+ this->timer2.stage3_ticks = 0;
+ return result;
+ }
+ }
+
+ return 0x00;
+ }
+
+ void SMP::mmio_write(unsigned addr, unsigned data)
+ {
+ switch (addr)
+ {
+ case 0xf1:
+ status.iplrom_enable = !!(data & 0x80);
+
+ if (data & 0x30)
+ {
+ if (data & 0x20)
+ {
+ cpu.port_write(3, 0x00);
+ cpu.port_write(2, 0x00);
+ }
+ if (data & 0x10)
+ {
+ cpu.port_write(1, 0x00);
+ cpu.port_write(0, 0x00);
+ }
+ }
+
+ if (!this->timer2.enable && !!(data & 0x04))
+ {
+ this->timer2.stage2_ticks = 0;
+ this->timer2.stage3_ticks = 0;
+ }
+ this->timer2.enable = !!(data & 0x04);
+
+ if (!this->timer1.enable && !!(data & 0x02))
+ {
+ this->timer1.stage2_ticks = 0;
+ this->timer1.stage3_ticks = 0;
+ }
+ this->timer1.enable = !!(data & 0x02);
+
+ if (!this->timer0.enable && !!(data & 0x01))
+ {
+ this->timer0.stage2_ticks = 0;
+ this->timer0.stage3_ticks = 0;
+ }
+ this->timer0.enable = !!(data & 0x01);
+
+ break;
+
+ case 0xf2:
+ this->status.dsp_addr = data;
+ break;
+
+ case 0xf3:
+ if (this->status.dsp_addr & 0x80)
+ break;
+ dsp.write(this->status.dsp_addr, data);
+ break;
+
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ this->port_write(addr, data);
+ break;
+
+ case 0xf8:
+ this->status.ram00f8 = data;
+ break;
+
+ case 0xf9:
+ this->status.ram00f9 = data;
+ break;
+
+ case 0xfa:
+ this->timer0.target = data;
+ break;
+
+ case 0xfb:
+ this->timer1.target = data;
+ break;
+
+ case 0xfc:
+ this->timer2.target = data;
+ break;
+ }
+ }
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/smp/smp.cpp
@@ -1,1 +1,65 @@
+#include "smp.hpp"
+namespace SNES
+{
+ SMP smp;
+
+ void SMP::enter()
+ {
+ while (this->clock < 0)
+ this->op_step();
+ }
+
+ void SMP::power()
+ {
+ Processor::clock = 0;
+
+ this->timer0.target = 0;
+ this->timer1.target = 0;
+ this->timer2.target = 0;
+
+ this->reset();
+ }
+
+ void SMP::reset()
+ {
+ for (unsigned n = 0x0000; n <= 0xffff; ++n)
+ this->apuram[n] = 0x00;
+
+ this->opcode_number = 0;
+ this->opcode_cycle = 0;
+
+ this->regs.pc = 0xffc0;
+ this->regs.sp = 0xef;
+ this->regs.B.a = 0x00;
+ this->regs.x = 0x00;
+ this->regs.B.y = 0x00;
+ this->regs.p = 0x02;
+
+ // $00f1
+ this->status.iplrom_enable = true;
+
+ // $00f2
+ this->status.dsp_addr = 0x00;
+
+ // $00f8,$00f9
+ this->status.ram00f8 = 0x00;
+ this->status.ram00f9 = 0x00;
+
+ // timers
+ this->timer0.enable = this->timer1.enable = this->timer2.enable = false;
+ this->timer0.stage1_ticks = this->timer1.stage1_ticks = this->timer2.stage1_ticks = 0;
+ this->timer0.stage2_ticks = this->timer1.stage2_ticks = this->timer2.stage2_ticks = 0;
+ this->timer0.stage3_ticks = this->timer1.stage3_ticks = this->timer2.stage3_ticks = 0;
+ }
+
+ SMP::SMP()
+ {
+ this->apuram.reset(new uint8_t[64 * 1024]);
+ }
+
+ SMP::~SMP()
+ {
+ }
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/smp/smp.hpp
@@ -1,1 +1,149 @@
+#pragma once
+#include <memory>
+#include "../snes/snes.hpp"
+
+namespace SNES
+{
+ class SMP : public Processor
+ {
+ public:
+ static const uint8_t iplrom[64];
+ std::unique_ptr<uint8_t[]> apuram;
+
+ unsigned port_read(unsigned port);
+ void port_write(unsigned port, unsigned data);
+
+ unsigned mmio_read(unsigned addr);
+ void mmio_write(unsigned addr, unsigned data);
+
+ void enter();
+ void power();
+ void reset();
+
+ SMP();
+ ~SMP();
+
+ //private:
+ struct Flags
+ {
+ bool n, v, p, b, h, i, z, c;
+
+ operator unsigned() const
+ {
+ return (this->n << 7) | (this->v << 6) | (this->p << 5) | (this->b << 4) | (this->h << 3) | (this->i << 2) | (this->z << 1) | (this->c << 0);
+ }
+
+ unsigned operator=(unsigned data)
+ {
+ this->n = !!(data & 0x80);
+ this->v = !!(data & 0x40);
+ this->p = !!(data & 0x20);
+ this->b = !!(data & 0x10);
+ this->h = !!(data & 0x08);
+ this->i = !!(data & 0x04);
+ this->z = !!(data & 0x02);
+ this->c = !!(data & 0x01);
+ return data;
+ }
+
+ unsigned operator|=(unsigned data)
+ {
+ return this->operator=(this->operator unsigned() | data);
+ }
+
+ unsigned operator^=(unsigned data)
+ {
+ return this->operator=(this->operator unsigned() ^ data);
+ }
+
+ unsigned operator&=(unsigned data)
+ {
+ return this->operator=(this->operator unsigned() & data);
+ }
+ };
+
+ unsigned opcode_number;
+ unsigned opcode_cycle;
+
+ uint16_t rd, wr, dp, sp, ya, bit;
+
+ struct Regs
+ {
+ uint16_t pc;
+ uint8_t sp;
+ union
+ {
+ uint16_t ya;
+#ifdef __BIG_ENDIAN__
+ struct { uint8_t y, a; } B;
+#else
+ struct { uint8_t a, y; } B;
+#endif
+ };
+ uint8_t x;
+ Flags p;
+ } regs;
+
+ struct Status
+ {
+ // $00f1
+ bool iplrom_enable;
+
+ // $00f2
+ unsigned dsp_addr;
+
+ // $00f8,$00f9
+ unsigned ram00f8;
+ unsigned ram00f9;
+ } status;
+
+ template<unsigned frequency> struct Timer
+ {
+ bool enable;
+ uint8_t target;
+ uint8_t stage1_ticks;
+ uint8_t stage2_ticks;
+ uint8_t stage3_ticks;
+
+ void tick();
+ void tick(unsigned clocks);
+ };
+
+ Timer<128> timer0;
+ Timer<128> timer1;
+ Timer<16> timer2;
+
+ inline void tick();
+ inline void tick(unsigned clocks);
+ inline void op_io();
+ inline void op_io(unsigned clocks);
+ inline uint8_t op_read(uint16_t addr);
+ inline void op_write(uint16_t addr, uint8_t data);
+ void op_step();
+ void op_writestack(uint8_t data);
+ uint8_t op_readstack();
+ uint64_t cycle_table_cpu[256];
+ unsigned cycle_table_dsp[256];
+ uint64_t cycle_step_cpu;
+
+ uint8_t op_adc(uint8_t x, uint8_t y);
+ uint16_t op_addw(uint16_t x, uint16_t y);
+ uint8_t op_and(uint8_t x, uint8_t y);
+ uint8_t op_cmp(uint8_t x, uint8_t y);
+ uint16_t op_cmpw(uint16_t x, uint16_t y);
+ uint8_t op_eor(uint8_t x, uint8_t y);
+ uint8_t op_inc(uint8_t x);
+ uint8_t op_dec(uint8_t x);
+ uint8_t op_or(uint8_t x, uint8_t y);
+ uint8_t op_sbc(uint8_t x, uint8_t y);
+ uint16_t op_subw(uint16_t x, uint16_t y);
+ uint8_t op_asl(uint8_t x);
+ uint8_t op_lsr(uint8_t x);
+ uint8_t op_rol(uint8_t x);
+ uint8_t op_ror(uint8_t x);
+ };
+
+ extern SMP smp;
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/smp/timing.cpp
@@ -1,1 +1,43 @@
+#include "smp.hpp"
+namespace SNES
+{
+ template<unsigned cycle_frequency> void SMP::Timer<cycle_frequency>::tick()
+ {
+ if (++this->stage1_ticks < cycle_frequency)
+ return;
+
+ this->stage1_ticks = 0;
+ if (!this->enable)
+ return;
+
+ if (++this->stage2_ticks != this->target)
+ return;
+
+ this->stage2_ticks = 0;
+ this->stage3_ticks = (this->stage3_ticks + 1) & 15;
+ }
+
+ template<unsigned cycle_frequency> void SMP::Timer<cycle_frequency>::tick(unsigned clocks)
+ {
+ this->stage1_ticks += clocks;
+ if (this->stage1_ticks < cycle_frequency)
+ return;
+
+ this->stage1_ticks -= cycle_frequency;
+ if (!this->enable)
+ return;
+
+ if (++this->stage2_ticks != this->target)
+ return;
+
+ this->stage2_ticks = 0;
+ this->stage3_ticks = (this->stage3_ticks + 1) & 15;
+ }
+
+ template void SMP::Timer<128>::tick();
+ template void SMP::Timer<128>::tick(unsigned);
+ template void SMP::Timer<16>::tick();
+ template void SMP::Timer<16>::tick(unsigned);
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/bapu/snes/snes.hpp
@@ -1,1 +1,38 @@
+#pragma once
+#include "../../../snes9x.h"
+
+namespace SNES
+{
+ struct Processor
+ {
+ unsigned frequency;
+ int32_t clock;
+ };
+
+ class CPU
+ {
+ public:
+ enum { Threaded = false };
+ int frequency;
+ uint8_t registers[4];
+
+ void reset()
+ {
+ this->registers[0] = this->registers[1] = this->registers[2] = this->registers[3] = 0;
+ }
+
+ void port_write(uint8_t port, uint8_t data)
+ {
+ this->registers[port & 3] = data;
+ }
+
+ uint8_t port_read(uint8_t port)
+ {
+ return this->registers[port & 3];
+ }
+ };
+
+ extern CPU cpu;
+}
+
--- a/src/in_snsf/snes9x/apu/blargg_common.h
+++ /dev/null
@@ -1,39 +1,1 @@
-// Sets up common environment for Shay Green's libraries.
-// To change configuration options, modify blargg_config.h, not this file.
-// snes_spc 0.9.0
-#pragma once
-
-#include <cstddef>
-#include <cstdlib>
-#include <cassert>
-#include <climits>
-
-#include "blargg_config.h"
-
-// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1,
-// compiler is assumed to support bool. If undefined, availability is determined.
-#ifndef BLARGG_COMPILER_HAS_BOOL
-# if defined(__MWERKS__)
-# if !__option(bool)
-# define BLARGG_COMPILER_HAS_BOOL 0
-# endif
-# elif defined(_MSC_VER)
-# if _MSC_VER < 1100
-# define BLARGG_COMPILER_HAS_BOOL 0
-# endif
-# elif defined(__GNUC__)
-// supports bool
-# elif __cplusplus < 199711
-# define BLARGG_COMPILER_HAS_BOOL 0
-# endif
-#endif
-#if defined(BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
-// If you get errors here, modify your blargg_config.h file
-typedef int bool;
-const bool true = 1;
-const bool false = 0;
-#endif
-
-#include <cstdint>
-
--- a/src/in_snsf/snes9x/apu/blargg_config.h
+++ /dev/null
@@ -1,11 +1,1 @@
-// snes_spc 0.9.0 user configuration file. Don't replace when updating library.
-// snes_spc 0.9.0
-#pragma once
-
-// Uncomment if automatic byte-order determination doesn't work
-//#define BLARGG_BIG_ENDIAN 1
-
-// Uncomment if you get errors in the bool section of blargg_common.h
-//#define BLARGG_COMPILER_HAS_BOOL 1
-
--- a/src/in_snsf/snes9x/apu/blargg_endian.h
+++ /dev/null
@@ -1,76 +1,1 @@
-// CPU Byte Order Utilities
-// snes_spc 0.9.0
-#pragma once
-
-#include "blargg_common.h"
-
-// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
-#if defined(_M_IX86) || defined(_M_IA64) || defined(__i486__) || defined(__x86_64__) || defined(__ia64__) || defined(__i386__)
-# define BLARGG_CPU_X86 1
-# define BLARGG_CPU_CISC 1
-#else
-# define BLARGG_CPU_X86 0
-# define BLARGG_CPU_CISC 0
-#endif
-
-#if defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__powerc)
-# define BLARGG_CPU_POWERPC 1
-# define BLARGG_CPU_RISC 1
-#else
-# define BLARGG_CPU_POWERPC 0
-# define BLARGG_CPU_RISC 0
-#endif
-
-// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
-// one may be #defined to 1. Only needed if something actually depends on byte order.
-#if !defined(BLARGG_BIG_ENDIAN) && !defined(BLARGG_LITTLE_ENDIAN)
-# ifdef __GLIBC__
-// GCC handles this for us
-# include <endian.h>
-# if __BYTE_ORDER == __LITTLE_ENDIAN
-# define BLARGG_LITTLE_ENDIAN 1
-# define BLARGG_BIG_ENDIAN 0
-# elif __BYTE_ORDER == __BIG_ENDIAN
-# define BLARGG_BIG_ENDIAN 1
-# define BLARGG_LITTLE_ENDIAN 0
-# endif
-# else
-# if defined(LSB_FIRST) || defined(__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || (defined(LITTLE_ENDIAN) && LITTLE_ENDIAN + 0 != 1234)
-# define BLARGG_LITTLE_ENDIAN 1
-# define BLARGG_BIG_ENDIAN 0
-# elif defined(MSB_FIRST) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) || defined(__sparc__) || BLARGG_CPU_POWERPC || (defined(BIG_ENDIAN) && BIG_ENDIAN + 0 != 4321)
-# define BLARGG_BIG_ENDIAN 1
-# define BLARGG_LITTLE_ENDIAN 0
-# else
-// No endian specified; assume little-endian, since it's most common
-# define BLARGG_LITTLE_ENDIAN 1
-# define BLARGG_BIG_ENDIAN 0
-# endif
-# endif
-#endif
-
-#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN
-# undef BLARGG_LITTLE_ENDIAN
-# undef BLARGG_BIG_ENDIAN
-#endif
-
-inline void blargg_verify_byte_order()
-{
-#ifndef NDEBUG
- volatile int i = 1;
- assert(*reinterpret_cast<volatile char *>(&i));
-#endif
-}
-
-inline unsigned get_le16(const uint8_t *p)
-{
- return static_cast<unsigned>(p[1] << 8) | static_cast<unsigned>(p[0]);
-}
-
-inline void set_le16(uint8_t *p, unsigned n)
-{
- p[1] = static_cast<unsigned char>(n >> 8);
- p[0] = static_cast<unsigned char>(n);
-}
-
--- a/src/in_snsf/snes9x/apu/bspline_resampler.h
+++ /dev/null
@@ -1,126 +1,1 @@
-/* Simple resampler based on bsnes's ruby audio library */
-#pragma once
-
-#include <cmath>
-#include "resampler.h"
-
-class BsplineResampler : public Resampler
-{
-protected:
- double r_step;
- double r_frac;
- int r_left[6], r_right[6];
-
- template<typename T1, typename T2> static T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
- template<typename T> static short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
-
- double bspline(double x, double a, double b, double c, double d, double e, double f)
- {
- float ym2py2 = a + e, ym1py1 = b + d;
- float y2mym2 = e - a, y1mym1 = d - b;
- float sixthym1py1 = 1 / 6.0 * ym1py1;
- float c0 = 1 / 120.0 * ym2py2 + 13 / 60.0 * ym1py1 + 0.55 * c;
- float c1 = 1 / 24.0 * y2mym2 + 5 / 12.0 * y1mym1;
- float c2 = 1 / 12.0 * ym2py2 + sixthym1py1 - 0.5 * c;
- float c3 = 1 / 12.0 * y2mym2 - 1 / 6.0 * y1mym1;
- float c4 = 1 / 24.0 * ym2py2 - sixthym1py1 + 0.25 * c;
- float c5 = 1 / 120.0 * (f - a) + 1 / 24.0 * (b - e) + 1 / 12.0 * (d - c);
- return ((((c5 * x + c4) * x + c3) * x + c2) * x + c1) * x + c0;
- }
-
-public:
- BsplineResampler(int num_samples) : Resampler(num_samples)
- {
- this->clear();
- }
-
- void time_ratio(double ratio)
- {
- this->r_step = ratio;
- this->clear();
- }
-
- void clear()
- {
- ring_buffer::clear();
- this->r_frac = 1.0;
- this->r_left[0] = this->r_left[1] = this->r_left[2] = this->r_left[3] = this->r_left[4] = this->r_left[5] = 0;
- this->r_right[0] = this->r_right[1] = this->r_right[2] = this->r_right[3] = this->r_right[4] = this->r_right[5] = 0;
- }
-
- void read(short *data, int num_samples)
- {
- int i_position = this->start >> 1;
- short *internal_buffer = reinterpret_cast<short *>(&this->buffer[0]);
- int o_position = 0;
- int consumed = 0;
-
- while (o_position < num_samples && consumed < this->buffer_size)
- {
- int s_left = internal_buffer[i_position];
- int s_right = internal_buffer[i_position + 1];
- int max_samples = this->buffer_size >> 1;
- static const double margin_of_error = 1.0e-10;
-
- if (std::abs(this->r_step - 1.0) < margin_of_error)
- {
- data[o_position] = static_cast<short>(s_left);
- data[o_position + 1] = static_cast<short>(s_right);
-
- o_position += 2;
- i_position += 2;
- if (i_position >= max_samples)
- i_position -= max_samples;
- consumed += 2;
-
- continue;
- }
-
- while (this->r_frac <= 1.0 && o_position < num_samples)
- {
- data[o_position] = SHORT_CLAMP(bspline(this->r_frac, this->r_left[0], this->r_left[1], this->r_left[2], this->r_left[3], this->r_left[4], this->r_left[5]));
- data[o_position + 1] = SHORT_CLAMP(bspline(this->r_frac, this->r_right[0], this->r_right[1], this->r_right[2], this->r_right[3], this->r_right[4], this->r_right[5]));
-
- o_position += 2;
-
- this->r_frac += this->r_step;
- }
-
- if (this->r_frac > 1.0)
- {
- this->r_left[0] = this->r_left[1];
- this->r_left[1] = this->r_left[2];
- this->r_left[2] = this->r_left[3];
- this->r_left[3] = this->r_left[4];
- this->r_left[4] = this->r_left[5];
- this->r_left[5] = s_left;
-
- this->r_right[0] = this->r_right[1];
- this->r_right[1] = this->r_right[2];
- this->r_right[2] = this->r_right[3];
- this->r_right[3] = this->r_right[4];
- this->r_right[4] = this->r_right[5];
- this->r_right[5] = s_right;
-
- this->r_frac -= 1.0;
-
- i_position += 2;
- if (i_position >= max_samples)
- i_position -= max_samples;
- consumed += 2;
- }
- }
-
- this->size -= consumed << 1;
- this->start += consumed << 1;
- if (this->start >= this->buffer_size)
- this->start -= this->buffer_size;
- }
-
- int avail()
- {
- return static_cast<int>(std::floor(((this->size >> 2) - this->r_frac) / this->r_step) * 2);
- }
-};
-
--- a/src/in_snsf/snes9x/apu/hermite_resampler.h
+++ /dev/null
@@ -1,131 +1,1 @@
-/* Simple resampler based on bsnes's ruby audio library */
-#pragma once
-
-#include <cmath>
-#include "resampler.h"
-
-class HermiteResampler : public Resampler
-{
-protected:
- double r_step;
- double r_frac;
- int r_left[4], r_right[4];
-
- template<typename T1, typename T2> static T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
- template<typename T> static short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
-
- double hermite(double mu1, double a, double b, double c, double d)
- {
- static const double tension = 0.0; //-1 = low, 0 = normal, 1 = high
- static const double bias = 0.0; //-1 = left, 0 = even, 1 = right
-
- double mu2, mu3, m0, m1, a0, a1, a2, a3;
-
- mu2 = mu1 * mu1;
- mu3 = mu2 * mu1;
-
- m0 = (b - a) * (1 + bias) * (1 - tension) / 2;
- m0 += (c - b) * (1 - bias) * (1 - tension) / 2;
- m1 = (c - b) * (1 + bias) * (1 - tension) / 2;
- m1 += (d - c) * (1 - bias) * (1 - tension) / 2;
-
- a0 = 2 * mu3 - 3 * mu2 + 1;
- a1 = mu3 - 2 * mu2 + mu1;
- a2 = mu3 - mu2;
- a3 = -2 * mu3 + 3 * mu2;
-
- return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c);
- }
-
-public:
- HermiteResampler(int num_samples) : Resampler(num_samples)
- {
- this->clear();
- }
-
- void time_ratio(double ratio)
- {
- this->r_step = ratio;
- this->clear();
- }
-
- void clear()
- {
- ring_buffer::clear();
- this->r_frac = 1.0;
- this->r_left[0] = this->r_left[1] = this->r_left[2] = this->r_left[3] = 0;
- this->r_right[0] = this->r_right[1] = this->r_right[2] = this->r_right[3] = 0;
- }
-
- void read(short *data, int num_samples)
- {
- int i_position = this->start >> 1;
- short *internal_buffer = reinterpret_cast<short *>(&this->buffer[0]);
- int o_position = 0;
- int consumed = 0;
-
- while (o_position < num_samples && consumed < this->buffer_size)
- {
- int s_left = internal_buffer[i_position];
- int s_right = internal_buffer[i_position + 1];
- int max_samples = this->buffer_size >> 1;
- static const double margin_of_error = 1.0e-10;
-
- if (std::abs(this->r_step - 1.0) < margin_of_error)
- {
- data[o_position] = static_cast<short>(s_left);
- data[o_position + 1] = static_cast<short>(s_right);
-
- o_position += 2;
- i_position += 2;
- if (i_position >= max_samples)
- i_position -= max_samples;
- consumed += 2;
-
- continue;
- }
-
- while (this->r_frac <= 1.0 && o_position < num_samples)
- {
- data[o_position] = SHORT_CLAMP(hermite(this->r_frac, this->r_left[0], this->r_left[1], this->r_left[2], this->r_left[3]));
- data[o_position + 1] = SHORT_CLAMP(hermite(this->r_frac, this->r_right[0], this->r_right[1], this->r_right[2], this->r_right[3]));
-
- o_position += 2;
-
- this->r_frac += this->r_step;
- }
-
- if (this->r_frac > 1.0)
- {
- this->r_left[0] = this->r_left[1];
- this->r_left[1] = this->r_left[2];
- this->r_left[2] = this->r_left[3];
- this->r_left[3] = s_left;
-
- this->r_right[0] = this->r_right[1];
- this->r_right[1] = this->r_right[2];
- this->r_right[2] = this->r_right[3];
- this->r_right[3] = s_right;
-
- this->r_frac -= 1.0;
-
- i_position += 2;
- if (i_position >= max_samples)
- i_position -= max_samples;
- consumed += 2;
- }
- }
-
- this->size -= consumed << 1;
- this->start += consumed << 1;
- if (this->start >= this->buffer_size)
- this->start -= this->buffer_size;
- }
-
- int avail()
- {
- return static_cast<int>(std::floor(((this->size >> 2) - this->r_frac) / this->r_step) * 2);
- }
-};
-
--- a/src/in_snsf/snes9x/apu/linear_resampler.h
+++ /dev/null
@@ -1,101 +1,1 @@
-/* Simple fixed-point linear resampler by BearOso*/
-#pragma once
-
-#include "resampler.h"
-#include "XSFCommon.h"
-
-class LinearResampler : public Resampler
-{
- static const int f_prec = 15;
- static const uint32_t f__one = 1 << f_prec;
-
-protected:
- uint32_t f__r_step;
- uint32_t f__inv_r_step;
- uint32_t f__r_frac;
- int r_left, r_right;
-
- static short lerp(uint32_t t, int a, short b) { return (((b - a) * t) >> f_prec) + a; }
-
-public:
- LinearResampler(int num_samples) : Resampler(num_samples)
- {
- this->f__r_frac = 0;
- }
-
- void time_ratio(double ratio)
- {
- if (fEqual(ratio, 0.0))
- ratio = 1.0;
- this->f__r_step = static_cast<uint32_t>(ratio * f__one);
- this->f__inv_r_step = static_cast<uint32_t>(f__one / ratio);
- this->clear();
- }
-
- void clear()
- {
- ring_buffer::clear();
- this->f__r_frac = 0;
- this->r_left = 0;
- this->r_right = 0;
- }
-
- void read(short *data, int num_samples)
- {
- int i_position = this->start >> 1;
- short *internal_buffer = reinterpret_cast<short *>(&this->buffer[0]);
- int o_position = 0;
- int consumed = 0;
- int max_samples = this->buffer_size >> 1;
-
- while (o_position < num_samples && consumed < this->buffer_size)
- {
- if (this->f__r_step == f__one)
- {
- data[o_position] = internal_buffer[i_position];
- data[o_position + 1] = internal_buffer[i_position + 1];
-
- o_position += 2;
- i_position += 2;
- if (i_position >= max_samples)
- i_position -= max_samples;
- consumed += 2;
-
- continue;
- }
-
- while (this->f__r_frac <= f__one && o_position < num_samples)
- {
- data[o_position] = lerp(this->f__r_frac, this->r_left, internal_buffer[i_position]);
- data[o_position + 1] = lerp(this->f__r_frac, this->r_right, internal_buffer[i_position + 1]);
-
- o_position += 2;
-
- this->f__r_frac += this->f__r_step;
- }
-
- if (this->f__r_frac > f__one)
- {
- this->f__r_frac -= f__one;
- this->r_left = internal_buffer[i_position];
- this->r_right = internal_buffer[i_position + 1];
- i_position += 2;
- if (i_position >= max_samples)
- i_position -= max_samples;
- consumed += 2;
- }
- }
-
- this->size -= consumed << 1;
- this->start += consumed << 1;
- if (this->start >= this->buffer_size)
- this->start -= this->buffer_size;
- }
-
- int avail()
- {
- return (((this->size >> 2) * this->f__inv_r_step) - ((this->f__r_frac * this->f__inv_r_step) >> f_prec)) >> (f_prec - 1);
- }
-};
-
--- a/src/in_snsf/snes9x/apu/osculating_resampler.h
+++ /dev/null
@@ -1,127 +1,1 @@
-/* Simple resampler based on bsnes's ruby audio library */
-#pragma once
-
-#include <cmath>
-#include "resampler.h"
-
-class OsculatingResampler : public Resampler
-{
-protected:
- double r_step;
- double r_frac;
- int r_left[6], r_right[6];
-
- template<typename T1, typename T2> static T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
- template<typename T> static short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
-
- double osculating(double x, double a, double b, double c, double d, double e, double f)
- {
- double z = x - 0.5;
- double even1 = a + f, odd1 = a - f;
- double even2 = b + e, odd2 = b - e;
- double even3 = c + d, odd3 = c - d;
- double c0 = 0.01171875 * even1 - 0.09765625 * even2 + 0.5859375 * even3;
- double c1 = 0.2109375 * odd2 - 281 / 192.0 * odd3 - 13 / 384.0 * odd1;
- double c2 = 0.40625 * even2 - 17 / 48.0 * even3 - 5 / 96.0 * even1;
- double c3 = 0.1875 * odd1 - 53 / 48.0 * odd2 + 2.375 * odd3;
- double c4 = 1 / 48.0*even1 - 0.0625 * even2 + 1 / 24.0 * even3;
- double c5 = 25 / 24.0 * odd2 - 25 / 12.0 * odd3 - 5 / 24.0 * odd1;
- return ((((c5 * z + c4) * z + c3) * z + c2) * z + c1) * z + c0;
- }
-
-public:
- OsculatingResampler(int num_samples) : Resampler(num_samples)
- {
- this->clear();
- }
-
- void time_ratio(double ratio)
- {
- this->r_step = ratio;
- this->clear();
- }
-
- void clear()
- {
- ring_buffer::clear();
- this->r_frac = 1.0;
- this->r_left[0] = this->r_left[1] = this->r_left[2] = this->r_left[3] = this->r_left[4] = this->r_left[5] = 0;
- this->r_right[0] = this->r_right[1] = this->r_right[2] = this->r_right[3] = this->r_right[4] = this->r_right[5] = 0;
- }
-
- void read(short *data, int num_samples)
- {
- int i_position = this->start >> 1;
- short *internal_buffer = reinterpret_cast<short *>(&this->buffer[0]);
- int o_position = 0;
- int consumed = 0;
-
- while (o_position < num_samples && consumed < this->buffer_size)
- {
- int s_left = internal_buffer[i_position];
- int s_right = internal_buffer[i_position + 1];
- int max_samples = this->buffer_size >> 1;
- static const double margin_of_error = 1.0e-10;
-
- if (std::abs(this->r_step - 1.0) < margin_of_error)
- {
- data[o_position] = static_cast<short>(s_left);
- data[o_position + 1] = static_cast<short>(s_right);
-
- o_position += 2;
- i_position += 2;
- if (i_position >= max_samples)
- i_position -= max_samples;
- consumed += 2;
-
- continue;
- }
-
- while (this->r_frac <= 1.0 && o_position < num_samples)
- {
- data[o_position] = SHORT_CLAMP(osculating(this->r_frac, this->r_left[0], this->r_left[1], this->r_left[2], this->r_left[3], this->r_left[4], this->r_left[5]));
- data[o_position + 1] = SHORT_CLAMP(osculating(this->r_frac, this->r_right[0], this->r_right[1], this->r_right[2], this->r_right[3], this->r_right[4], this->r_right[5]));
-
- o_position += 2;
-
- this->r_frac += this->r_step;
- }
-
- if (this->r_frac > 1.0)
- {
- this->r_left[0] = this->r_left[1];
- this->r_left[1] = this->r_left[2];
- this->r_left[2] = this->r_left[3];
- this->r_left[3] = this->r_left[4];
- this->r_left[4] = this->r_left[5];
- this->r_left[5] = s_left;
-
- this->r_right[0] = this->r_right[1];
- this->r_right[1] = this->r_right[2];
- this->r_right[2] = this->r_right[3];
- this->r_right[3] = this->r_right[4];
- this->r_right[4] = this->r_right[5];
- this->r_right[5] = s_right;
-
- this->r_frac -= 1.0;
-
- i_position += 2;
- if (i_position >= max_samples)
- i_position -= max_samples;
- consumed += 2;
- }
- }
-
- this->size -= consumed << 1;
- this->start += consumed << 1;
- if (this->start >= this->buffer_size)
- this->start -= this->buffer_size;
- }
-
- int avail()
- {
- return static_cast<int>(std::floor(((this->size >> 2) - this->r_frac) / this->r_step) * 2);
- }
-};
-
--- a/src/in_snsf/snes9x/apu/resampler.h
+++ b/src/in_snsf/snes9x/apu/resampler.h
@@ -1,43 +1,194 @@
-/* Simple resampler based on bsnes's ruby audio library */
+/*****************************************************************************\
+ 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
-#include "ring_buffer.h"
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <cstdint>
+#include <cmath>
+#include "XSFCommon.h"
-class Resampler : public ring_buffer
+class Resampler
{
public:
- virtual void clear() = 0;
- virtual void time_ratio(double) = 0;
- virtual void read(short *, int) = 0;
- virtual int avail() = 0;
+ int size;
+ int buffer_size;
+ int start;
+ std::unique_ptr<int16_t[]> buffer;
- Resampler(int num_samples) : ring_buffer(num_samples << 1)
+ float r_step;
+ float r_frac;
+ int r_left[4], r_right[4];
+
+ static float hermite(float mu1, float a, float b, float c, float d)
{
+ float mu2 = mu1 * mu1;
+ float mu3 = mu2 * mu1;
+
+ float m0 = (c - a) * 0.5;
+ float m1 = (d - b) * 0.5;
+
+ float a0 = +2 * mu3 - 3 * mu2 + 1;
+ float a1 = mu3 - 2 * mu2 + mu1;
+ float a2 = mu3 - mu2;
+ float a3 = -2 * mu3 + 3 * mu2;
+
+ return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c);
}
- virtual ~Resampler()
+ Resampler(int num_samples)
{
+ this->buffer_size = num_samples;
+ this->buffer.reset(new int16_t[this->buffer_size]);
+ this->r_step = 1.0;
+ this->clear();
}
- bool push(short *src, int num_samples)
+ void time_ratio(double ratio)
{
- if (this->max_write() < num_samples)
+ this->r_step = ratio;
+ }
+
+ void clear()
+ {
+ this->start = 0;
+ this->size = 0;
+ std::fill_n(&this->buffer[0], this->buffer_size, 0);
+
+ this->r_frac = 0.0;
+ this->r_left[0] = this->r_left[1] = this->r_left[2] = this->r_left[3] = 0;
+ this->r_right[0] = this->r_right[1] = this->r_right[2] = this->r_right[3] = 0;
+ }
+
+ bool pull(int16_t *dst, int num_samples)
+ {
+ if (this->space_filled() < num_samples)
return false;
- !num_samples || ring_buffer::push(reinterpret_cast<unsigned char *>(src), num_samples << 1);
+ std::copy_n(&this->buffer[start], std::min(num_samples, this->buffer_size - this->start), &dst[0]);
+
+ if (num_samples > this->buffer_size - this->start)
+ std::copy_n(&this->buffer[0], num_samples - (this->buffer_size - this->start), &dst[this->buffer_size - this->start]);
+
+ this->start = (this->start + num_samples) % this->buffer_size;
+ this->size -= num_samples;
return true;
}
- int max_write()
+ void push_sample(int16_t l, int16_t r)
{
- return this->space_empty () >> 1;
+ if (this->space_empty() >= 2)
+ {
+ int end = this->start + this->size;
+ if (end >= this->buffer_size)
+ end -= this->buffer_size;
+ this->buffer[end] = l;
+ this->buffer[end + 1] = r;
+ this->size += 2;
+ }
+ }
+
+ bool push(int16_t *src, int num_samples)
+ {
+ if (this->space_empty() < num_samples)
+ return false;
+
+ int end = this->start + this->size;
+ if (end > this->buffer_size)
+ end -= this->buffer_size;
+ int first_write_size = std::min(num_samples, this->buffer_size - end);
+
+ std::copy_n(&src[0], first_write_size, &this->buffer[end]);
+
+ if (num_samples > first_write_size)
+ std::copy_n(&src[first_write_size], num_samples - first_write_size, &this->buffer[0]);
+
+ this->size += num_samples;
+
+ return true;
+ }
+
+ void read(int16_t *data, int num_samples)
+ {
+ // If we are outputting the exact same ratio as the input, pull directly from the input buffer
+ if (fEqual(this->r_step, 1.0f))
+ {
+ this->pull(data, num_samples);
+ return;
+ }
+
+ int o_position = 0;
+
+ while (o_position < num_samples && this->size > 0)
+ {
+ int s_left = this->buffer[start];
+ int s_right = this->buffer[start + 1];
+ int hermite_val[2];
+
+ while (this->r_frac <= 1.0 && o_position < num_samples)
+ {
+ hermite_val[0] = static_cast<int>(hermite(this->r_frac, this->r_left[0], this->r_left[1], this->r_left[2], this->r_left[3]));
+ hermite_val[1] = static_cast<int>(hermite(this->r_frac, this->r_right[0], this->r_right[1], this->r_right[2], this->r_right[3]));
+ data[o_position] = static_cast<int16_t>(std::clamp<int>(hermite_val[0], std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max()));
+ data[o_position + 1] = static_cast<int16_t>(std::clamp<int>(hermite_val[1], std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max()));
+
+ o_position += 2;
+
+ this->r_frac += this->r_step;
+ }
+
+ if (this->r_frac > 1.0)
+ {
+ this->r_left[0] = this->r_left[1];
+ this->r_left[1] = this->r_left[2];
+ this->r_left[2] = this->r_left[3];
+ this->r_left[3] = s_left;
+
+ this->r_right[0] = this->r_right[1];
+ this->r_right[1] = this->r_right[2];
+ this->r_right[2] = this->r_right[3];
+ this->r_right[3] = s_right;
+
+ --this->r_frac;
+
+ this->start += 2;
+ if (this->start >= this->buffer_size)
+ this->start -= this->buffer_size;
+ this->size -= 2;
+ }
+ }
+ }
+
+ int space_empty() const
+ {
+ return this->buffer_size - this->size;
+ }
+
+ int space_filled() const
+ {
+ return this->size;
+ }
+
+ int avail()
+ {
+ // If we are outputting the exact same ratio as the input, find out directly from the input buffer
+ if (fEqual(this->r_step, 1.0f))
+ return this->size;
+
+ return static_cast<int>(std::trunc(((this->size >> 1) - this->r_frac) / this->r_step)) * 2;
}
void resize(int num_samples)
{
- ring_buffer::resize(num_samples << 1);
+ this->buffer_size = num_samples;
+ this->buffer.reset(new int16_t[this->buffer_size]);
+ this->clear();
}
};
--- a/src/in_snsf/snes9x/apu/ring_buffer.h
+++ /dev/null
@@ -1,66 +1,1 @@
-/* Simple byte-based ring buffer. Licensed under public domain (C) BearOso. */
-#pragma once
-
-#include <memory>
-#include <algorithm>
-#include <cstring>
-
-class ring_buffer
-{
-protected:
- int size;
- int buffer_size;
- int start;
- std::unique_ptr<unsigned char[]> buffer;
-
-public:
- ring_buffer(int buf_size)
- {
- this->buffer_size = buf_size;
- this->buffer.reset(new unsigned char[this->buffer_size]);
- this->clear();
- }
-
- bool push(unsigned char *src, int bytes)
- {
- if (this->space_empty() < bytes)
- return false;
-
- int end = (this->start + this->size) % this->buffer_size;
- int first_write_size = std::min(bytes, this->buffer_size - end);
-
- std::copy_n(&src[0], first_write_size, &this->buffer[end]);
-
- if (bytes > first_write_size)
- std::copy(&src[first_write_size], &src[bytes], &this->buffer[0]);
-
- this->size += bytes;
-
- return true;
- }
-
- int space_empty()
- {
- return this->buffer_size - this->size;
- }
-
- int space_filled()
- {
- return this->size;
- }
-
- void clear()
- {
- this->start = this->size = 0;
- std::fill_n(&this->buffer[0], this->buffer_size, 0);
- }
-
- void resize(int new_size)
- {
- this->buffer_size = new_size;
- this->buffer.reset(new unsigned char[this->buffer_size]);
- this->clear();
- }
-};
-
--- a/src/in_snsf/snes9x/apu/sinc_resampler.h
+++ /dev/null
@@ -1,146 +1,1 @@
-/* Simple resampler based on bsnes's ruby audio library */
-#pragma once
-
-#include <algorithm>
-#define _USE_MATH_DEFINES
-#include <cmath>
-#include "resampler.h"
-#include "XSFCommon.h"
-
-#ifndef M_PI
-const double M_PI = 3.14159265358979323846;
-#endif
-
-class SincResampler : public Resampler
-{
-protected:
- static bool initializedLUTs;
- static const unsigned SINC_RESOLUTION = 8192;
- static const unsigned SINC_WIDTH = 8;
- static const unsigned SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH;
- static double sinc_lut[SINC_SAMPLES + 1];
-
- double r_step;
- double r_frac;
- int r_left[SINC_WIDTH * 2], r_right[SINC_WIDTH * 2];
-
- template<typename T1, typename T2> static T1 CLAMP(T1 x, T2 low, T2 high) { return x > high ? high : (x < low ? low : x); }
- template<typename T> static short SHORT_CLAMP(T n) { return static_cast<short>(CLAMP(n, -32768, 32767)); }
-
- static inline double sinc(double x)
- {
- return fEqual(x, 0.0) ? 1.0 : std::sin(x * M_PI) / (x * M_PI);
- }
-
- double sinc(const int *data)
- {
- double kernel[SINC_WIDTH * 2], kernel_sum = 0.0;
- int i = SINC_WIDTH, shift = static_cast<int>(std::floor(this->r_frac * SINC_RESOLUTION));
- int step = this->r_step > 1.0 ? static_cast<int>(SINC_RESOLUTION / this->r_step) : SINC_RESOLUTION;
- int shift_adj = shift * step / SINC_RESOLUTION;
- for (; i >= -static_cast<int>(SINC_WIDTH - 1); --i)
- {
- int pos = i * step;
- kernel_sum += kernel[i + SINC_WIDTH - 1] = this->sinc_lut[std::abs(shift_adj - pos)];
- }
- double sum = 0.0;
- for (i = 0; i < static_cast<int>(SINC_WIDTH * 2); ++i)
- sum += data[i] * kernel[i];
- return sum / kernel_sum;
- }
-
-public:
- SincResampler(int num_samples) : Resampler(num_samples)
- {
- if (!this->initializedLUTs)
- {
- double dx = static_cast<double>(SINC_WIDTH) / SINC_SAMPLES, x = 0.0;
- for (unsigned i = 0; i <= SINC_SAMPLES; ++i, x += dx)
- this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) * sinc(x / SINC_WIDTH) : 0.0;
- this->initializedLUTs = true;
- }
- this->clear();
- }
-
- void time_ratio(double ratio)
- {
- this->r_step = ratio;
- this->clear();
- }
-
- void clear()
- {
- ring_buffer::clear();
- this->r_frac = 1.0;
- std::fill_n(&this->r_left[0], SINC_WIDTH * 2, 0);
- std::fill_n(&this->r_right[0], SINC_WIDTH * 2, 0);
- }
-
- void read(short *data, int num_samples)
- {
- int i_position = this->start >> 1;
- short *internal_buffer = reinterpret_cast<short *>(&this->buffer[0]);
- int o_position = 0;
- int consumed = 0;
-
- while (o_position < num_samples && consumed < this->buffer_size)
- {
- int s_left = internal_buffer[i_position];
- int s_right = internal_buffer[i_position + 1];
- int max_samples = this->buffer_size >> 1;
- static const double margin_of_error = 1.0e-10;
-
- if (std::abs(this->r_step - 1.0) < margin_of_error)
- {
- data[o_position] = static_cast<short>(s_left);
- data[o_position + 1] = static_cast<short>(s_right);
-
- o_position += 2;
- i_position += 2;
- if (i_position >= max_samples)
- i_position -= max_samples;
- consumed += 2;
-
- continue;
- }
-
- while (this->r_frac <= 1.0 && o_position < num_samples)
- {
- data[o_position] = SHORT_CLAMP(sinc(this->r_left));
- data[o_position + 1] = SHORT_CLAMP(sinc(this->r_right));
-
- o_position += 2;
-
- this->r_frac += this->r_step;
- }
-
- if (this->r_frac > 1.0)
- {
- std::copy_n(&this->r_left[1], SINC_WIDTH * 2 - 1, &this->r_left[0]);
- this->r_left[SINC_WIDTH * 2 - 1] = s_left;
-
- std::copy_n(&this->r_right[1], SINC_WIDTH * 2 - 1, &this->r_right[0]);
- this->r_right[SINC_WIDTH * 2 - 1] = s_right;
-
- this->r_frac -= 1.0;
-
- i_position += 2;
- if (i_position >= max_samples)
- i_position -= max_samples;
- consumed += 2;
- }
- }
-
- this->size -= consumed << 1;
- this->start += consumed << 1;
- if (this->start >= this->buffer_size)
- this->start -= this->buffer_size;
- }
-
- int avail()
- {
- return static_cast<int>(std::floor(((this->size >> 2) - this->r_frac) / this->r_step) * 2);
- }
-};
-
--- a/src/in_snsf/snes9x/cpu.cpp
+++ b/src/in_snsf/snes9x/cpu.cpp
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#include <algorithm>
#include "snes9x.h"
@@ -188,8 +17,7 @@
CPU.V_Counter = 0;
CPU.Flags &= DEBUG_MODE_FLAG | TRACE_FLAG;
CPU.PCBase = nullptr;
- CPU.NMILine = CPU.IRQLine = CPU.IRQTransition = CPU.IRQLastState = false;
- CPU.IRQPending = Timings.IRQPendCount;
+ CPU.NMIPending = CPU.IRQLine = CPU.IRQTransition = false;
CPU.MemSpeed = SLOW_ONE_CYCLE;
CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
CPU.FastROMSpeed = SLOW_ONE_CYCLE;
@@ -218,6 +46,9 @@
Timings.H_Max = Timings.H_Max_Master;
Timings.V_Max = Timings.V_Max_Master;
Timings.NMITriggerPos = 0xffff;
+ Timings.NextIRQTimer = 0x0fffffff;
+ Timings.IRQFlagChanging = IRQ_NONE;
+
Timings.WRAMRefreshPos = Model->_5A22 == 2 ? SNES_WRAM_REFRESH_HC_v2 : SNES_WRAM_REFRESH_HC_v1;
S9xSetPCBase(Registers.PC.xPBPC);
--- a/src/in_snsf/snes9x/cpuaddr.h
+++ b/src/in_snsf/snes9x/cpuaddr.h
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
@@ -286,6 +115,8 @@
inline uint32_t AbsoluteIndexedIndirect(AccessMode) // (a,X)
{
uint16_t addr = Immediate16Slow(READ);
+
+ AddCycles(ONE_CYCLE);
addr += Registers.X.W;
// Address load wraps within the bank
--- a/src/in_snsf/snes9x/cpuexec.cpp
+++ b/src/in_snsf/snes9x/cpuexec.cpp
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#include "snes9x.h"
#include "memmap.h"
@@ -216,45 +45,76 @@
}
}
+static void CHECK_FOR_IRQ_CHANGE()
+{
+ if (Timings.IRQFlagChanging)
+ {
+ if (Timings.IRQFlagChanging & IRQ_TRIGGER_NMI)
+ {
+ CPU.NMIPending = true;
+ Timings.NMITriggerPos = CPU.Cycles + 6;
+ }
+ if (Timings.IRQFlagChanging & IRQ_CLEAR_FLAG)
+ ClearIRQ();
+ else if (Timings.IRQFlagChanging & IRQ_SET_FLAG)
+ SetIRQ();
+ Timings.IRQFlagChanging = IRQ_NONE;
+ }
+}
+
void S9xMainLoop()
{
+ if (CPU.Flags & SCAN_KEYS_FLAG)
+ CPU.Flags &= ~SCAN_KEYS_FLAG;
+
for (;;)
{
- if (CPU.NMILine)
+ if (CPU.NMIPending)
{
if (Timings.NMITriggerPos <= CPU.Cycles)
{
- CPU.NMILine = false;
+ CPU.NMIPending = false;
Timings.NMITriggerPos = 0xffff;
if (CPU.WaitingForInterrupt)
{
CPU.WaitingForInterrupt = false;
++Registers.PC.W.xPC;
- }
-
+ CPU.Cycles += TWO_CYCLES + ONE_DOT_CYCLE / 2;
+ while (CPU.Cycles >= CPU.NextEvent)
+ S9xDoHEventProcessing();
+ }
+
+ CHECK_FOR_IRQ_CHANGE();
S9xOpcode_NMI();
}
}
- if (CPU.IRQTransition)
- {
- if (CPU.IRQPending)
- --CPU.IRQPending;
- else
- {
- if (CPU.WaitingForInterrupt)
- {
- CPU.WaitingForInterrupt = false;
- ++Registers.PC.W.xPC;
- }
-
- CPU.IRQTransition = false;
- CPU.IRQPending = Timings.IRQPendCount;
-
- if (!CheckFlag(IRQ))
- S9xOpcode_IRQ();
- }
- }
+ if (CPU.Cycles >= Timings.NextIRQTimer)
+ {
+ S9xUpdateIRQPositions(false);
+ CPU.IRQLine = true;
+ }
+
+ if (CPU.IRQLine)
+ {
+ if (CPU.WaitingForInterrupt)
+ {
+ CPU.WaitingForInterrupt = false;
+ ++Registers.PC.W.xPC;
+ CPU.Cycles += TWO_CYCLES + ONE_DOT_CYCLE / 2;
+ while (CPU.Cycles >= CPU.NextEvent)
+ S9xDoHEventProcessing();
+ }
+
+ if (!CheckFlag(IRQ))
+ {
+ /* The flag pushed onto the stack is the new value */
+ CHECK_FOR_IRQ_CHANGE();
+ S9xOpcode_IRQ();
+ }
+ }
+
+ CHECK_FOR_IRQ_CHANGE();
if (CPU.Flags & SCAN_KEYS_FLAG)
break;
@@ -265,9 +125,7 @@
if (CPU.PCBase)
{
Op = CPU.PCBase[Registers.PC.W.xPC];
- CPU.PrevCycles = CPU.Cycles;
CPU.Cycles += CPU.MemSpeed;
- S9xCheckInterrupts();
Opcodes = ICPU.S9xOpcodes;
}
else
@@ -281,7 +139,7 @@
{
uint8_t *oldPCBase = CPU.PCBase;
- CPU.PCBase = S9xGetBasePointer(ICPU.ShiftedPB + (static_cast<uint16_t>(Registers.PC.W.xPC + 4)));
+ CPU.PCBase = S9xGetBasePointer(ICPU.ShiftedPB + static_cast<uint16_t>(Registers.PC.W.xPC + 4));
if (oldPCBase != CPU.PCBase || (Registers.PC.W.xPC & ~MEMMAP_MASK) == (0xffff & ~MEMMAP_MASK))
Opcodes = S9xOpcodesSlow;
}
@@ -291,9 +149,6 @@
}
S9xPackStatus();
-
- if (CPU.Flags & SCAN_KEYS_FLAG)
- CPU.Flags &= ~SCAN_KEYS_FLAG;
}
void S9xDoHEventProcessing()
@@ -315,11 +170,11 @@
case HC_HCOUNTER_MAX_EVENT:
S9xAPUEndScanline();
CPU.Cycles -= Timings.H_Max;
- CPU.PrevCycles -= Timings.H_Max;
+ if (Timings.NMITriggerPos != 0xffff)
+ Timings.NMITriggerPos -= Timings.H_Max;
+ if (Timings.NextIRQTimer != 0x0fffffff)
+ Timings.NextIRQTimer -= Timings.H_Max;
S9xAPUSetReferenceTime(CPU.Cycles);
-
- if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max))
- Timings.NMITriggerPos -= Timings.H_Max;
++CPU.V_Counter;
if (CPU.V_Counter >= Timings.V_Max) // V ranges from 0 to Timings.V_Max - 1
@@ -343,10 +198,6 @@
// FIXME: reading $4210 will wait 2 cycles, then perform reading, then wait 4 more cycles.
Memory.FillRAM[0x4210] = Model->_5A22;
- CPU.NMILine = false;
- Timings.NMITriggerPos = 0xffff;
-
- CPU.Flags |= SCAN_KEYS_FLAG;
}
// From byuu:
@@ -375,6 +226,8 @@
if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240).
{
+ CPU.Flags |= SCAN_KEYS_FLAG;
+
PPU.HDMA = 0;
// Bits 7 and 6 of $4212 are computed when read in S9xGetPPU.
PPU.ForcedBlanking = !!((Memory.FillRAM[0x2100] >> 7) & 1);
@@ -399,7 +252,7 @@
{
// FIXME: triggered at HC=6, checked just before the final CPU cycle,
// then, when to call S9xOpcode_NMI()?
- CPU.NMILine = true;
+ CPU.NMIPending = true;
Timings.NMITriggerPos = 6 + 6;
}
}
@@ -422,11 +275,9 @@
break;
case HC_WRAM_REFRESH_EVENT:
- CPU.PrevCycles = CPU.Cycles;
CPU.Cycles += SNES_WRAM_REFRESH_CYCLES;
- S9xCheckInterrupts();
-
- S9xReschedule();
- }
-}
-
+
+ S9xReschedule();
+ }
+}
+
--- a/src/in_snsf/snes9x/cpuexec.h
+++ b/src/in_snsf/snes9x/cpuexec.h
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
@@ -264,36 +93,3 @@
}
}
-inline void S9xCheckInterrupts()
-{
- bool thisIRQ = PPU.HTimerEnabled || PPU.VTimerEnabled;
-
- if (CPU.IRQLine && thisIRQ)
- CPU.IRQTransition = true;
-
- if (PPU.HTimerEnabled)
- {
- int32_t htimepos = PPU.HTimerPosition;
- if (CPU.Cycles >= Timings.H_Max)
- htimepos += Timings.H_Max;
-
- if (CPU.PrevCycles >= htimepos || CPU.Cycles < htimepos)
- thisIRQ = false;
- }
-
- if (PPU.VTimerEnabled)
- {
- int32_t vcounter = CPU.V_Counter;
- if (CPU.Cycles >= Timings.H_Max)
- ++vcounter;
-
- if (vcounter != PPU.VTimerPosition)
- thisIRQ = false;
- }
-
- if (!CPU.IRQLastState && thisIRQ)
- CPU.IRQLine = true;
-
- CPU.IRQLastState = thisIRQ;
-}
-
--- a/src/in_snsf/snes9x/cpumacro.h
+++ b/src/in_snsf/snes9x/cpumacro.h
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
@@ -291,57 +120,39 @@
{
if (CheckDecimal())
{
- uint16_t A1 = Registers.A.W & 0x000F;
- uint16_t A2 = Registers.A.W & 0x00F0;
- uint16_t A3 = Registers.A.W & 0x0F00;
- uint32_t A4 = Registers.A.W & 0xF000;
- uint16_t W1 = Work16 & 0x000F;
- uint16_t W2 = Work16 & 0x00F0;
- uint16_t W3 = Work16 & 0x0F00;
- uint16_t W4 = Work16 & 0xF000;
-
- A1 += W1 + CheckCarry();
- if (A1 > 0x0009)
- {
- A1 -= 0x000A;
- A1 &= 0x000F;
- A2 += 0x0010;
- }
-
- A2 += W2;
- if (A2 > 0x0090)
- {
- A2 -= 0x00A0;
- A2 &= 0x00F0;
- A3 += 0x0100;
- }
-
- A3 += W3;
- if (A3 > 0x0900)
- {
- A3 -= 0x0A00;
- A3 &= 0x0F00;
- A4 += 0x1000;
- }
-
- A4 += W4;
- if (A4 > 0x9000)
- {
- A4 -= 0xA000;
- A4 &= 0xF000;
+ uint32_t carry = CheckCarry();
+
+ uint32_t result = (Registers.A.W & 0x000F) + (Work16 & 0x000F) + carry;
+ if (result > 0x0009)
+ result += 0x0006;
+ carry = result > 0x000F;
+
+ result = (Registers.A.W & 0x00F0) + (Work16 & 0x00F0) + (result & 0x000F) + carry * 0x10;
+ if (result > 0x009F)
+ result += 0x0060;
+ carry = result > 0x00FF;
+
+ result = (Registers.A.W & 0x0F00) + (Work16 & 0x0F00) + (result & 0x00FF) + carry * 0x100;
+ if (result > 0x09FF)
+ result += 0x0600;
+ carry = result > 0x0FFF;
+
+ result = (Registers.A.W & 0xF000) + (Work16 & 0xF000) + (result & 0x0FFF) + carry * 0x1000;
+
+ if ((Registers.A.W & 0x8000) == (Work16 & 0x8000) && (Registers.A.W & 0x8000) != (result & 0x8000))
+ SetOverflow();
+ else
+ ClearOverflow();
+
+ if (result > 0x9FFF)
+ result += 0x6000;
+
+ if (result > 0xFFFF)
SetCarry();
- }
else
ClearCarry();
- uint16_t Ans16 = A4 | A3 | A2 | A1;
-
- if (~(Registers.A.W ^ Work16) & (Work16 ^ Ans16) & 0x8000)
- SetOverflow();
- else
- ClearOverflow();
-
- Registers.A.W = Ans16;
+ Registers.A.W = result & 0xFFFF;
SetZN(Registers.A.W);
}
else
@@ -364,37 +175,29 @@
{
if (CheckDecimal())
{
- uint8_t A1 = Registers.A.W & 0x0F;
- uint16_t A2 = Registers.A.W & 0xF0;
- uint8_t W1 = Work8 & 0x0F;
- uint8_t W2 = Work8 & 0xF0;
-
- A1 += W1 + CheckCarry();
- if (A1 > 0x09)
- {
- A1 -= 0x0A;
- A1 &= 0x0F;
- A2 += 0x10;
- }
-
- A2 += W2;
- if (A2 > 0x90)
- {
- A2 -= 0xA0;
- A2 &= 0xF0;
+ uint32_t carry = CheckCarry();
+
+ uint32_t result = (Registers.A.B.l & 0x0F) + (Work8 & 0x0F) + carry;
+ if (result > 0x09)
+ result += 0x06;
+ carry = result > 0x0F;
+
+ result = (Registers.A.B.l & 0xF0) + (Work8 & 0xF0) + (result & 0x0F) + (carry * 0x10);
+
+ if ((Registers.A.B.l & 0x80) == (Work8 & 0x80) && (Registers.A.B.l & 0x80) != (result & 0x80))
+ SetOverflow();
+ else
+ ClearOverflow();
+
+ if (result > 0x9F)
+ result += 0x60;
+
+ if (result > 0xFF)
SetCarry();
- }
else
ClearCarry();
- uint8_t Ans8 = A2 | A1;
-
- if (~(Registers.A.B.l ^ Work8) & (Work8 ^ Ans8) & 0x80)
- SetOverflow();
- else
- ClearOverflow();
-
- Registers.A.B.l = Ans8;
+ Registers.A.B.l = result & 0xFF;
SetZN(Registers.A.B.l);
}
else
@@ -667,58 +470,41 @@
{
if (CheckDecimal())
{
- uint16_t A1 = Registers.A.W & 0x000F;
- uint16_t A2 = Registers.A.W & 0x00F0;
- uint16_t A3 = Registers.A.W & 0x0F00;
- uint32_t A4 = Registers.A.W & 0xF000;
- uint16_t W1 = Work16 & 0x000F;
- uint16_t W2 = Work16 & 0x00F0;
- uint16_t W3 = Work16 & 0x0F00;
- uint16_t W4 = Work16 & 0xF000;
-
- A1 -= W1 + !CheckCarry();
- A2 -= W2;
- A3 -= W3;
- A4 -= W4;
-
- if (A1 > 0x000F)
- {
- A1 += 0x000A;
- A1 &= 0x000F;
- A2 -= 0x0010;
- }
-
- if (A2 > 0x00F0)
- {
- A2 += 0x00A0;
- A2 &= 0x00F0;
- A3 -= 0x0100;
- }
-
- if (A3 > 0x0F00)
- {
- A3 += 0x0A00;
- A3 &= 0x0F00;
- A4 -= 0x1000;
- }
-
- if (A4 > 0xF000)
- {
- A4 += 0xA000;
- A4 &= 0xF000;
+ int carry = CheckCarry();
+
+ Work16 ^= 0xFFFF;
+
+ int result = (Registers.A.W & 0x000F) + (Work16 & 0x000F) + carry;
+ if (result < 0x0010)
+ result -= 0x0006;
+ carry = result > 0x000F;
+
+ result = (Registers.A.W & 0x00F0) + (Work16 & 0x00F0) + (result & 0x000F) + carry * 0x10;
+ if (result < 0x0100)
+ result -= 0x0060;
+ carry = result > 0x00FF;
+
+ result = (Registers.A.W & 0x0F00) + (Work16 & 0x0F00) + (result & 0x00FF) + carry * 0x100;
+ if (result < 0x1000)
+ result -= 0x0600;
+ carry = result > 0x0FFF;
+
+ result = (Registers.A.W & 0xF000) + (Work16 & 0xF000) + (result & 0x0FFF) + carry * 0x1000;
+
+ if (!((Registers.A.W ^ Work16) & 0x8000) && ((Registers.A.W ^ result) & 0x8000))
+ SetOverflow();
+ else
+ ClearOverflow();
+
+ if (result < 0x10000)
+ result -= 0x6000;
+
+ if (result > 0xFFFF)
+ SetCarry();
+ else
ClearCarry();
- }
- else
- SetCarry();
-
- uint16_t Ans16 = A4 | A3 | A2 | A1;
-
- if ((Registers.A.W ^ Work16) & (Registers.A.W ^ Ans16) & 0x8000)
- SetOverflow();
- else
- ClearOverflow();
-
- Registers.A.W = Ans16;
+
+ Registers.A.W = result & 0xFFFF;
SetZN(Registers.A.W);
}
else
@@ -741,38 +527,31 @@
{
if (CheckDecimal())
{
- uint8_t A1 = Registers.A.W & 0x0F;
- uint16_t A2 = Registers.A.W & 0xF0;
- uint8_t W1 = Work8 & 0x0F;
- uint8_t W2 = Work8 & 0xF0;
-
- A1 -= W1 + !CheckCarry();
- A2 -= W2;
-
- if (A1 > 0x0F)
- {
- A1 += 0x0A;
- A1 &= 0x0F;
- A2 -= 0x10;
- }
-
- if (A2 > 0xF0)
- {
- A2 += 0xA0;
- A2 &= 0xF0;
+ int carry = CheckCarry();
+
+ Work8 ^= 0xFF;
+
+ int result = (Registers.A.B.l & 0x0F) + (Work8 & 0x0F) + carry;
+ if (result < 0x10)
+ result -= 0x06;
+ carry = (result > 0x0F);
+
+ result = (Registers.A.B.l & 0xF0) + (Work8 & 0xF0) + (result & 0x0F) + carry * 0x10;
+
+ if ((Registers.A.B.l & 0x80) == (Work8 & 0x80) && (Registers.A.B.l & 0x80) != (result & 0x80))
+ SetOverflow();
+ else
+ ClearOverflow();
+
+ if (result < 0x100)
+ result -= 0x60;
+
+ if (result > 0xFF)
+ SetCarry();
+ else
ClearCarry();
- }
- else
- SetCarry();
-
- uint8_t Ans8 = A2 | A1;
-
- if ((Registers.A.B.l ^ Work8) & (Registers.A.B.l ^ Ans8) & 0x80)
- SetOverflow();
- else
- ClearOverflow();
-
- Registers.A.B.l = Ans8;
+
+ Registers.A.B.l = result & 0xFF;
SetZN(Registers.A.B.l);
}
else
--- a/src/in_snsf/snes9x/cpuops.cpp
+++ b/src/in_snsf/snes9x/cpuops.cpp
@@ -1,185 +1,14 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#include "snes9x.h"
#include "memmap.h"
#include "apu/apu.h"
-static inline void AddCycles(int32_t n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += n; S9xCheckInterrupts(); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); }
+static inline void AddCycles(int32_t n) { CPU.Cycles += n; while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); }
#include "cpuaddr.h"
#include "cpuops.h"
@@ -1537,15 +1366,17 @@
// CLI
static void Op58()
{
- ClearIRQ();
- AddCycles(ONE_CYCLE);
+ AddCycles(ONE_CYCLE);
+
+ Timings.IRQFlagChanging |= IRQ_CLEAR_FLAG;
}
// SEI
static void Op78()
{
- SetIRQ();
- AddCycles(ONE_CYCLE);
+ AddCycles(ONE_CYCLE);
+
+ Timings.IRQFlagChanging |= IRQ_SET_FLAG;
}
// CLV
@@ -2843,8 +2674,9 @@
static void OpCB()
{
CPU.WaitingForInterrupt = true;
+
--Registers.PC.W.xPC;
- AddCycles(TWO_CYCLES);
+ AddCycles(ONE_CYCLE);
}
// STP
--- a/src/in_snsf/snes9x/dma.cpp
+++ b/src/in_snsf/snes9x/dma.cpp
@@ -1,186 +1,15 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#include "snes9x.h"
#include "memmap.h"
#include "dma.h"
#include "apu/apu.h"
-static inline void ADD_CYCLES(int32_t n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += n; S9xCheckInterrupts(); }
+static inline void ADD_CYCLES(int32_t n) { CPU.Cycles += n; }
extern uint8_t *HDMAMemPointers[8];
extern int HDMA_ModeByteCounts[8];
@@ -365,7 +194,7 @@
if (!UPDATE_COUNTERS())
return false;
--count;
-
+ // Fall through
case 1:
Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2101 + d->BAddress);
@@ -402,7 +231,7 @@
b = 1;
break;
}
-
+ // Fall through
case 1:
Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2100 + d->BAddress);
@@ -413,7 +242,7 @@
b = 2;
break;
}
-
+ // Fall through
case 2:
Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2101 + d->BAddress);
@@ -424,7 +253,7 @@
b = 3;
break;
}
-
+ // Fall through
case 3:
Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2101 + d->BAddress);
@@ -454,7 +283,7 @@
b = 1;
break;
}
-
+ // Fall through
case 1:
Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2101 + d->BAddress);
@@ -465,7 +294,7 @@
b = 2;
break;
}
-
+ // Fall through
case 2:
Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2102 + d->BAddress);
@@ -476,7 +305,7 @@
b = 3;
break;
}
-
+ // Fall through
case 3:
Work = S9xGetByte((d->ABank << 16) + p);
S9xSetPPU(Work, 0x2103 + d->BAddress);
@@ -618,10 +447,10 @@
if (!UPDATE_COUNTERS())
return false;
--count;
-
+ // Fall through
case 1:
- Work = *(base + p);
- REGISTER_2119_linear(Work);
+ OpenBus = *(base + p);
+ REGISTER_2119_linear(OpenBus);
if (!UPDATE_COUNTERS())
return false;
--count;
@@ -651,7 +480,7 @@
if (!UPDATE_COUNTERS())
return false;
--count;
-
+ // Fall through
case 1:
Work = *(base + p);
REGISTER_2119_tile(Work);
@@ -686,7 +515,7 @@
if (!UPDATE_COUNTERS())
return false;
--count;
-
+ // Fall through
case 1:
Work = *(base + p);
S9xSetPPU(Work, 0x2101 + d->BAddress);
@@ -724,7 +553,7 @@
b = 1;
break;
}
-
+ // Fall through
case 1:
Work = *(base + p);
S9xSetPPU(Work, 0x2100 + d->BAddress);
@@ -735,7 +564,7 @@
b = 2;
break;
}
-
+ // Fall through
case 2:
Work = *(base + p);
S9xSetPPU(Work, 0x2101 + d->BAddress);
@@ -746,7 +575,7 @@
b = 3;
break;
}
-
+ // Fall through
case 3:
Work = *(base + p);
S9xSetPPU(Work, 0x2101 + d->BAddress);
@@ -776,7 +605,7 @@
b = 1;
break;
}
-
+ // Fall through
case 1:
Work = *(base + p);
S9xSetPPU(Work, 0x2101 + d->BAddress);
@@ -787,7 +616,7 @@
b = 2;
break;
}
-
+ // Fall through
case 2:
Work = *(base + p);
S9xSetPPU(Work, 0x2102 + d->BAddress);
@@ -798,7 +627,7 @@
b = 3;
break;
}
-
+ // Fall through
case 3:
Work = *(base + p);
S9xSetPPU(Work, 0x2103 + d->BAddress);
@@ -1066,12 +895,8 @@
}
}
- if (CPU.NMILine && (Timings.NMITriggerPos != 0xffff))
- {
+ if (CPU.NMIPending && Timings.NMITriggerPos != 0xffff)
Timings.NMITriggerPos = CPU.Cycles + Timings.NMIDMADelay;
- if (Timings.NMITriggerPos >= Timings.H_Max)
- Timings.NMITriggerPos -= Timings.H_Max;
- }
CPU.InDMA = CPU.InDMAorHDMA = CPU.InWRAMDMAorHDMA = false;
CPU.CurrentDMAorHDMAChannel = -1;
@@ -1176,9 +1001,10 @@
uint8_t S9xDoHDMA(uint8_t byte)
{
- SDMA *p = &DMA[0];
-
- int d = 0;
+ SDMA *p;
+
+ int d;
+ uint8_t mask;
CPU.InHDMA = CPU.InDMAorHDMA = true;
CPU.HDMARanInDMA = CPU.InDMA ? byte : 0;
@@ -1188,7 +1014,7 @@
// XXX: Not quite right...
ADD_CYCLES(Timings.DMACPUSync);
- for (uint8_t mask = 1; mask; mask <<= 1, ++p, ++d)
+ for (mask = 1, p = &DMA[0], d = 0; mask; mask <<= 1, ++p, ++d)
{
if (byte & mask)
{
@@ -1374,7 +1200,10 @@
case 1:
S9xSetPPU(*HDMAMemPointers[d], 0x2100 + p->BAddress);
ADD_CYCLES(SLOW_ONE_CYCLE);
- S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress);
+ // XXX: All HDMA should read to MDR first. This one just
+ // happens to fix Speedy Gonzales.
+ OpenBus = *(HDMAMemPointers[d] + 1);
+ S9xSetPPU(OpenBus, 0x2101 + p->BAddress);
ADD_CYCLES(SLOW_ONE_CYCLE);
HDMAMemPointers[d] += 2;
break;
@@ -1484,7 +1313,16 @@
ADD_CYCLES(SLOW_ONE_CYCLE);
}
}
-
+ }
+ }
+ }
+
+ for (mask = 1, p = &DMA[0], d = 0; mask; mask <<= 1, ++p, ++d)
+ {
+ if (byte & mask)
+ {
+ if (p->DoTransfer)
+ {
if (p->HDMAIndirectAddressing)
p->DMACount_Or_HDMAIndirectAddress += HDMA_ModeByteCounts[p->TransferMode];
else
@@ -1500,7 +1338,6 @@
byte &= ~mask;
PPU.HDMAEnded |= mask;
p->DoTransfer = false;
- continue;
}
}
else
--- a/src/in_snsf/snes9x/dma.h
+++ b/src/in_snsf/snes9x/dma.h
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
--- a/src/in_snsf/snes9x/docs/snes9x-license.txt
+++ /dev/null
@@ -1,174 +1,1 @@
- Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
- zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2010 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2010 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2010 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2010 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
-
--- a/src/in_snsf/snes9x/getset.h
+++ b/src/in_snsf/snes9x/getset.h
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
@@ -183,9 +12,7 @@
{
if (!CPU.InDMAorHDMA)
{
- CPU.PrevCycles = CPU.Cycles;
CPU.Cycles += speed;
- S9xCheckInterrupts();
while (CPU.Cycles >= CPU.NextEvent)
S9xDoHEventProcessing();
}
@@ -195,9 +22,7 @@
{
if (!CPU.InDMAorHDMA)
{
- CPU.PrevCycles = CPU.Cycles;
CPU.Cycles += speed << 1;
- S9xCheckInterrupts();
while (CPU.Cycles >= CPU.NextEvent)
S9xDoHEventProcessing();
}
@@ -278,34 +103,35 @@
inline uint16_t S9xGetWord(uint32_t Address, s9xwrap_t w = WRAP_NONE)
{
+ uint16_t word;
+
uint32_t mask = MEMMAP_MASK & (w == WRAP_PAGE ? 0xff : (w == WRAP_BANK ? 0xffff : 0xffffff));
if ((Address & mask) == mask)
{
PC_t a;
- OpenBus = S9xGetByte(Address);
+ word = OpenBus = S9xGetByte(Address);
switch (w)
{
case WRAP_PAGE:
a.xPBPC = Address;
++a.B.xPCl;
- return OpenBus | (S9xGetByte(a.xPBPC) << 8);
+ return word | (S9xGetByte(a.xPBPC) << 8);
case WRAP_BANK:
a.xPBPC = Address;
++a.W.xPC;
- return OpenBus | (S9xGetByte(a.xPBPC) << 8);
+ return word | (S9xGetByte(a.xPBPC) << 8);
default:
- return OpenBus | (S9xGetByte(Address + 1) << 8);
+ return word | (S9xGetByte(Address + 1) << 8);
}
}
int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
uint8_t *GetAddress = Memory.Map[block];
int32_t speed = memory_speed(Address);
- uint16_t word;
if (GetAddress >= reinterpret_cast<uint8_t *>(CMemory::MAP_LAST))
{
@@ -326,8 +152,8 @@
case CMemory::MAP_PPU:
if (CPU.InDMAorHDMA)
{
- OpenBus = S9xGetByte(Address);
- return OpenBus | (S9xGetByte(Address + 1) << 8);
+ word = OpenBus = S9xGetByte(Address);
+ return word | (S9xGetByte(Address + 1) << 8);
}
word = S9xGetPPU(Address & 0xffff);
@@ -550,8 +376,7 @@
Registers.PC.xPBPC = Address & 0xffffff;
ICPU.ShiftedPB = Address & 0xff0000;
- int block;
- uint8_t *GetAddress = Memory.Map[block = ((Address & 0xffffff) >> MEMMAP_SHIFT)];
+ uint8_t *GetAddress = Memory.Map[static_cast<int>((Address & 0xffffff) >> MEMMAP_SHIFT)];
CPU.MemSpeed = memory_speed(Address);
CPU.MemSpeedx2 = CPU.MemSpeed << 1;
--- a/src/in_snsf/snes9x/globals.cpp
+++ b/src/in_snsf/snes9x/globals.cpp
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#include "snes9x.h"
#include "memmap.h"
--- a/src/in_snsf/snes9x/memmap.cpp
+++ b/src/in_snsf/snes9x/memmap.cpp
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#include <vector>
#include <algorithm>
@@ -358,13 +187,20 @@
return score;
}
+int CMemory::First512BytesCountZeroes() const
+{
+ const uint8_t *buf = ROM;
+ int zeroCount = 0;
+ for (int i = 0; i < 512; ++i)
+ if (buf[i] == 0)
+ ++zeroCount;
+ return zeroCount;
+}
+
bool CMemory::LoadROMSNSF(const uint8_t *lrombuf, int32_t lromsize, const uint8_t *srambuf, int32_t sramsize)
{
- int retry_count = 0;
-
std::fill_n(&this->ROM[0], static_cast<int>(MAX_ROM_SIZE), 0);
-again:
this->CalculatedSize = 0;
this->ExtendedFormat = NOPE;
@@ -378,8 +214,22 @@
int hi_score = this->ScoreHiROM(false);
int lo_score = this->ScoreLoROM(false);
-
- if (((hi_score > lo_score && this->ScoreHiROM(true) > hi_score) || (hi_score <= lo_score && this->ScoreLoROM(true) > lo_score)))
+ int score_nonheadered = std::max(hi_score, lo_score);
+ int score_headered = std::max(this->ScoreHiROM(TRUE), this->ScoreLoROM(TRUE));
+
+ bool size_is_likely_headered = !((totalFileSize - 512) & 0xFFFF);
+ if (size_is_likely_headered)
+ score_headered += 2;
+ else
+ score_headered -= 2;
+ if (this->First512BytesCountZeroes() >= 0x1E0)
+ score_headered += 2;
+ else
+ score_headered -= 2;
+
+ bool headered_score_highest = score_headered > score_nonheadered;
+
+ if (headered_score_highest)
{
std::copy_n(&this->ROM[512], totalFileSize - 512, &this->ROM[0]);
totalFileSize -= 512;
@@ -388,9 +238,11 @@
lo_score = this->ScoreLoROM(false);
}
- this->CalculatedSize = (totalFileSize / 0x2000) * 0x2000;
+ this->CalculatedSize = ((totalFileSize + 0x1fff) / 0x2000) * 0x2000;
if (this->CalculatedSize > 0x400000 &&
+ this->ROM[0x7fd5] + (this->ROM[0x7fd6] << 8) != 0x3423 && // exclude SA-1
+ this->ROM[0x7fd5] + (this->ROM[0x7fd6] << 8) != 0x3523 &&
this->ROM[0x7fd5] + (this->ROM[0x7fd6] << 8) != 0x4332 && // exclude S-DD1
this->ROM[0x7fd5] + (this->ROM[0x7fd6] << 8) != 0x4532 &&
this->ROM[0xffd5] + (this->ROM[0xffd6] << 8) != 0xF93a && // exclude SPC7110
@@ -496,11 +348,10 @@
hi_score = this->ScoreHiROM(false);
lo_score = this->ScoreLoROM(false);
- if (((this->HiROM && (lo_score >= hi_score || hi_score < 0)) || (this->LoROM && (hi_score > lo_score || lo_score < 0))) && !retry_count)
+ if ((this->HiROM && (lo_score >= hi_score || hi_score < 0)) || (this->LoROM && (hi_score > lo_score || lo_score < 0)))
{
Settings.ForceNotInterleaved = true;
- ++retry_count;
- goto again;
+ return false;
}
}
@@ -661,7 +512,6 @@
and the NMI handler, time enough for an instruction or two. */
// Wild Guns, Mighty Morphin Power Rangers - The Fighting Edition
Timings.NMIDMADelay = 24;
- Timings.IRQPendCount = 0;
//// Hack games
@@ -765,7 +615,7 @@
for (uint32_t i = addr_s; i <= addr_e; i += 0x1000)
{
uint32_t p = (c << 4) | (i >> 12);
- this->Map[p] = reinterpret_cast<uint8_t *>(index);
+ this->Map[p] = reinterpret_cast<uint8_t *>(static_cast<intptr_t>(index));
this->BlockIsROM[p] = false;
this->BlockIsRAM[p] = isRAM;
}
@@ -791,8 +641,13 @@
void CMemory::map_LoROMSRAM()
{
- this->map_index(0x70, 0x7f, 0x0000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
- this->map_index(0xf0, 0xff, 0x0000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
+ if (!this->SRAMSize)
+ return;
+
+ uint32_t hi = this->SRAMSize > 5 ? 0x7fff : 0xffff;
+
+ this->map_index(0x70, 0x7d, 0x0000, hi, MAP_LOROM_SRAM, MAP_TYPE_RAM);
+ this->map_index(0xf0, 0xff, 0x0000, hi, MAP_LOROM_SRAM, MAP_TYPE_RAM);
}
void CMemory::map_HiROMSRAM()
@@ -857,7 +712,7 @@
this->map_System();
this->map_lorom_offset(0x00, 0x3f, 0x8000, 0xffff, this->CalculatedSize - 0x400000, 0x400000);
- this->map_lorom_offset(0x40, 0x7f, 0x0000, 0xffff, this->CalculatedSize - 0x400000, 0x400000);
+ this->map_lorom_offset(0x40, 0x7f, 0x0000, 0xffff, this->CalculatedSize - 0x600000, 0x600000);
this->map_lorom_offset(0x80, 0xbf, 0x8000, 0xffff, 0x400000, 0);
this->map_lorom_offset(0xc0, 0xff, 0x0000, 0xffff, 0x400000, 0x200000);
@@ -909,10 +764,11 @@
this->map_lorom(0x00, 0x3f, 0x8000, 0xffff, this->CalculatedSize);
this->map_lorom(0x80, 0xbf, 0x8000, 0xffff, this->CalculatedSize);
- this->map_hirom_offset(0x40, 0x7f, 0x0000, 0xffff, this->CalculatedSize, 0);
+ this->map_hirom_offset(0x60, 0x7f, 0x0000, 0xffff, this->CalculatedSize, 0);
this->map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, this->CalculatedSize, 0); // will be overwritten dynamically
this->map_index(0x70, 0x7f, 0x0000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
+ this->map_index(0xa0, 0xbf, 0x6000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
this->map_WRAM();
@@ -973,66 +829,22 @@
//// APU timing hacks :(
Timings.APUSpeedup = 0;
- Timings.APUAllowTimeOverflow = false;
if (!Settings.DisableGameSpecificHacks)
{
- if (this->match_id("AVCJ")) // Rendering Ranger R2
- Timings.APUSpeedup = 4;
-
- if (this->match_na("GAIA GENSOUKI 1 JPN") || // Gaia Gensouki
- this->match_id("JG ") || // Illusion of Gaia
- this->match_id("CQ ") || // Stunt Race FX
- this->match_na("SOULBLADER - 1") || // Soul Blader
- this->match_na("SOULBLAZER - 1 USA") || // Soul Blazer
- this->match_na("SLAP STICK 1 JPN") || // Slap Stick
- this->match_id("E9 ") || // Robotrek
- this->match_nn("ACTRAISER") || // Actraiser
- this->match_nn("ActRaiser-2") || // Actraiser 2
- this->match_id("AQT") || // Tenchi Souzou, Terranigma
- this->match_id("ATV") || // Tales of Phantasia
- this->match_id("ARF") || // Star Ocean
- this->match_id("APR") || // Zen-Nippon Pro Wrestling 2 - 3-4 Budoukan
- this->match_id("A4B") || // Super Bomberman 4
- this->match_id("Y7 ") || // U.F.O. Kamen Yakisoban - Present Ban
- this->match_id("Y9 ") || // U.F.O. Kamen Yakisoban - Shihan Ban
- this->match_id("APB") || // Super Bomberman - Panic Bomber W
- this->match_na("DARK KINGDOM") || // Dark Kingdom
- this->match_na("ZAN3 SFC") || // Zan III Spirits
- this->match_na("HIOUDEN") || // Hiouden - Mamono-tachi Tono Chikai
- this->match_na("\xC3\xDD\xBC\xC9\xB3\xC0") || // Tenshi no Uta
- this->match_na("FORTUNE QUEST") || // Fortune Quest - Dice wo Korogase
- this->match_na("FISHING TO BASSING") || // Shimono Masaki no Fishing To Bassing
- this->match_na("OHMONO BLACKBASS") || // Oomono Black Bass Fishing - Jinzouko Hen
- this->match_na("MASTERS") || // Harukanaru Augusta 2 - Masters
- this->match_na("SFC \xB6\xD2\xDD\xD7\xB2\xC0\xDE\xB0") || // Kamen Rider
- this->match_na("ZENKI TENCHIMEIDOU") || // Kishin Douji Zenki - Tenchi Meidou
- this->match_nn("TokyoDome '95Battle 7") || // Shin Nippon Pro Wrestling Kounin '95 - Tokyo Dome Battle 7
- this->match_nn("SWORD WORLD SFC") || // Sword World SFC/2
- this->match_nn("LETs PACHINKO(") || // BS Lets Pachinko Nante Gindama 1/2/3/4
- this->match_nn("THE FISHING MASTER") || // Mark Davis The Fishing Master
- this->match_nn("Parlor") || // Parlor mini/2/3/4/5/6/7, Parlor Parlor!/2/3/4/5
- this->match_na("HEIWA Parlor!Mini8") || // Parlor mini 8
- this->match_nn("SANKYO Fever! \xCC\xA8\xB0\xCA\xDE\xB0!")) // SANKYO Fever! Fever!
- Timings.APUSpeedup = 1;
-
- if (this->match_na("EARTHWORM JIM 2") || // Earthworm Jim 2
- this->match_na("NBA Hangtime") || // NBA Hang Time
- this->match_na("MSPACMAN") || // Ms Pacman
- this->match_na("THE MASK") || // The Mask
- this->match_na("PRIMAL RAGE") || // Primal Rage
- this->match_na("DOOM TROOPERS")) // Doom Troopers
- Timings.APUAllowTimeOverflow = true;
+ //if (this->match_id("AVCJ")) // Rendering Ranger R2
+ // Timings.APUSpeedup = 2;
+ if (this->match_na("CIRCUIT USA"))
+ Timings.APUSpeedup = 3;
}
S9xAPUTimingSetSpeedup(Timings.APUSpeedup);
- S9xAPUAllowTimeOverflow(Timings.APUAllowTimeOverflow);
//// Other timing hacks :(
Timings.HDMAStart = SNES_HDMA_START_HC + Settings.HDMATimingHack - 100;
Timings.HBlankStart = SNES_HBLANK_START_HC + Timings.HDMAStart - SNES_HDMA_START_HC;
- Timings.IRQTriggerCycles = 10;
+ Timings.IRQTriggerCycles = 14;
if (!Settings.DisableGameSpecificHacks)
{
@@ -1040,17 +852,10 @@
// Some games need really severe delay timing...
if (this->match_na("BATTLE GRANDPRIX")) // Battle Grandprix
Timings.DMACPUSync = 20;
-
- // An infinite loop reads $4212 and waits V-blank end, whereas VIRQ is set V=0.
- // If Snes9x succeeds to escape from the loop before jumping into the IRQ handler, the game goes further.
- // If Snes9x jumps into the IRQ handler before escaping from the loop,
- // Snes9x cannot escape from the loop permanently because the RTI is in the next V-blank.
- if (this->match_na("Aero the AcroBat 2"))
- Timings.IRQPendCount = 2;
-
- // XXX: What's happening?
- if (this->match_na("X-MEN")) // Spider-Man and the X-Men
- Settings.BlockInvalidVRAMAccess = false;
+ else if (match_na("KORYU NO MIMI ENG")) // Koryu no Mimi translation by rpgone)
+ // An infinite loop reads $4210 and checks NMI flag. This only works if LDA instruction executes before the NMI triggers,
+ // which doesn't work very well with s9x's default DMA timing.
+ Timings.DMACPUSync = 20;
//// SRAM initial value
--- a/src/in_snsf/snes9x/memmap.h
+++ b/src/in_snsf/snes9x/memmap.h
@@ -1,189 +1,18 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
#include <memory>
#include <cstdint>
-const int32_t MEMMAP_BLOCK_SIZE = 0x1000;
-const size_t MEMMAP_NUM_BLOCKS = 0x1000000 / MEMMAP_BLOCK_SIZE;
-const uint32_t MEMMAP_SHIFT = 12;
-const uint32_t MEMMAP_MASK = MEMMAP_BLOCK_SIZE - 1;
+inline constexpr int32_t MEMMAP_BLOCK_SIZE = 0x1000;
+inline constexpr size_t MEMMAP_NUM_BLOCKS = 0x1000000 / MEMMAP_BLOCK_SIZE;
+inline constexpr uint32_t MEMMAP_SHIFT = 12;
+inline constexpr uint32_t MEMMAP_MASK = MEMMAP_BLOCK_SIZE - 1;
struct CMemory
{
@@ -245,6 +74,7 @@
int ScoreHiROM(bool, int32_t romoff = 0);
int ScoreLoROM(bool, int32_t romoff = 0);
+ int First512BytesCountZeroes() const;
bool LoadROMSNSF(const uint8_t *, int32_t, const uint8_t *, int32_t);
char *Safe(const char *);
--- a/src/in_snsf/snes9x/port.h
+++ b/src/in_snsf/snes9x/port.h
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
@@ -208,7 +37,7 @@
# define strcasecmp stricmp
#endif
-#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) || defined(__alpha__) || defined(__MIPSEL__) || defined(_M_IX86) || defined(_M_X64)
+#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) || defined(__alpha__) || defined(__MIPSEL__) || defined(_M_IX86) || defined(_M_X64) || (defined(__BYTE_ORDER__) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN__)
# define LSB_FIRST
# define FAST_LSB_WORD_ACCESS
#else
--- a/src/in_snsf/snes9x/ppu.cpp
+++ b/src/in_snsf/snes9x/ppu.cpp
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#include <algorithm>
#include "snes9x.h"
@@ -184,26 +13,92 @@
extern uint8_t *HDMAMemPointers[8];
-void S9xUpdateHVTimerPosition()
+static int CyclesUntilNext(int hc, int vc)
+{
+ int32_t total = 0;
+ int vpos = CPU.V_Counter;
+
+ if (vc - vpos > 0)
+ {
+ // It's still in this frame */
+ // 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)
+ total -= ONE_DOT_CYCLE;
+ }
+ else
+ {
+ if (vc == vpos && hc > CPU.Cycles)
+ return hc;
+
+ total += (Timings.V_Max - vpos) * Timings.H_Max_Master;
+ if (vpos <= 240 && Timings.InterlaceField && !IPPU.Interlace)
+ total -= ONE_DOT_CYCLE;
+
+ total += vc * Timings.H_Max_Master;
+ if (vc > 240 && !Timings.InterlaceField && !IPPU.Interlace)
+ total -= ONE_DOT_CYCLE;
+ }
+
+ total += hc;
+
+ return total;
+}
+
+void S9xUpdateIRQPositions(bool initial)
{
PPU.HTimerPosition = PPU.IRQHBeamPos * ONE_DOT_CYCLE + Timings.IRQTriggerCycles;
- if (Timings.H_Max == Timings.H_Max_Master) // 1364
- {
- if (PPU.IRQHBeamPos > 322)
- PPU.HTimerPosition += ONE_DOT_CYCLE / 2;
- if (PPU.IRQHBeamPos > 326)
- PPU.HTimerPosition += ONE_DOT_CYCLE / 2;
- }
+ PPU.HTimerPosition -= PPU.IRQHBeamPos ? 0 : ONE_DOT_CYCLE;
+ PPU.HTimerPosition += PPU.IRQHBeamPos > 322 ? (ONE_DOT_CYCLE / 2) : 0;
+ PPU.HTimerPosition += PPU.IRQHBeamPos > 326 ? (ONE_DOT_CYCLE / 2) : 0;
PPU.VTimerPosition = PPU.IRQVBeamPos;
- if (PPU.HTimerPosition >= Timings.H_Max && PPU.IRQHBeamPos < 340)
- {
- PPU.HTimerPosition -= Timings.H_Max;
- ++PPU.VTimerPosition;
- // FIXME
- if (PPU.VTimerPosition >= Timings.V_Max)
- PPU.VTimerPosition = 0;
+ if (PPU.VTimerEnabled && PPU.VTimerPosition >= Timings.V_Max + (IPPU.Interlace ? 1 : 0))
+ Timings.NextIRQTimer = 0x0fffffff;
+ else if (!PPU.HTimerEnabled && !PPU.VTimerEnabled)
+ Timings.NextIRQTimer = 0x0fffffff;
+ else if (PPU.HTimerEnabled && !PPU.VTimerEnabled)
+ {
+ int v_pos = CPU.V_Counter;
+
+ Timings.NextIRQTimer = PPU.HTimerPosition;
+ if (CPU.Cycles > Timings.NextIRQTimer - Timings.IRQTriggerCycles)
+ {
+ Timings.NextIRQTimer += Timings.H_Max;
+ ++v_pos;
+ }
+
+ // Check for short dot scanline
+ if (v_pos == 240 && Timings.InterlaceField && !IPPU.Interlace)
+ {
+ Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 322 ? ONE_DOT_CYCLE / 2 : 0;
+ Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 326 ? ONE_DOT_CYCLE / 2 : 0;
+ }
+ }
+ else if (!PPU.HTimerEnabled && PPU.VTimerEnabled)
+ {
+ if (CPU.V_Counter == PPU.VTimerPosition && initial)
+ Timings.NextIRQTimer = CPU.Cycles + Timings.IRQTriggerCycles - ONE_DOT_CYCLE;
+ else
+ Timings.NextIRQTimer = CyclesUntilNext(Timings.IRQTriggerCycles - ONE_DOT_CYCLE, PPU.VTimerPosition);
+ }
+ else
+ {
+ Timings.NextIRQTimer = CyclesUntilNext(PPU.HTimerPosition, PPU.VTimerPosition);
+
+ // Check for short dot scanline
+ int field = Timings.InterlaceField;
+
+ if (PPU.VTimerPosition < CPU.V_Counter || (PPU.VTimerPosition == CPU.V_Counter && Timings.NextIRQTimer > Timings.H_Max))
+ field = !field;
+
+ if (PPU.VTimerPosition == 240 && field && !IPPU.Interlace)
+ {
+ Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 322 ? ONE_DOT_CYCLE / 2 : 0;
+ Timings.NextIRQTimer -= PPU.IRQHBeamPos <= 326 ? ONE_DOT_CYCLE / 2 : 0;
+ }
}
}
@@ -252,7 +147,7 @@
case 0x2102: // OAMADDL
PPU.OAMAddr = ((Memory.FillRAM[0x2103] & 1) << 8) | Byte;
- PPU.OAMFlip = 2;
+ PPU.OAMFlip = 0;
PPU.SavedOAMAddr = PPU.OAMAddr;
if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1))
PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1;
@@ -281,7 +176,7 @@
case 0x2105: // BGMODE
if (Byte != Memory.FillRAM[0x2105])
- IPPU.Interlace = !!(Memory.FillRAM[0x2133] & 1);
+ IPPU.Interlace = 0;
break;
@@ -326,15 +221,7 @@
PPU.VMA.Address &= 0xff00;
PPU.VMA.Address |= Byte;
- if (PPU.VMA.FullGraphicCount)
- {
- uint32_t addr = PPU.VMA.Address;
- uint32_t rem = addr & PPU.VMA.Mask1;
- uint32_t address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
- IPPU.VRAMReadBuffer = READ_WORD(&Memory.VRAM[(address << 1) & 0xffff]);
- }
- else
- IPPU.VRAMReadBuffer = READ_WORD(&Memory.VRAM[(PPU.VMA.Address << 1) & 0xffff]);
+ S9xUpdateVRAMReadBuffer();
break;
@@ -342,15 +229,7 @@
PPU.VMA.Address &= 0x00ff;
PPU.VMA.Address |= Byte << 8;
- if (PPU.VMA.FullGraphicCount)
- {
- uint32_t addr = PPU.VMA.Address;
- uint32_t rem = addr & PPU.VMA.Mask1;
- uint32_t address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
- IPPU.VRAMReadBuffer = READ_WORD(&Memory.VRAM[(address << 1) & 0xffff]);
- }
- else
- IPPU.VRAMReadBuffer = READ_WORD(&Memory.VRAM[(PPU.VMA.Address << 1) & 0xffff]);
+ S9xUpdateVRAMReadBuffer();
break;
@@ -499,7 +378,7 @@
return (PPU.OpenBus1 = Memory.FillRAM[Address]);
case 0x2137: // SLHV
- return OpenBus;
+ return PPU.OpenBus1;
case 0x2138: // OAMDATAREAD
if (PPU.OAMAddr & 0x100)
@@ -531,36 +410,20 @@
return (PPU.OpenBus1 = byte);
case 0x2139: // VMDATALREAD
- byte = IPPU.VRAMReadBuffer & 0xff;
+ byte = PPU.VRAMReadBuffer & 0xff;
if (!PPU.VMA.High)
{
- if (PPU.VMA.FullGraphicCount)
- {
- uint32_t addr = PPU.VMA.Address;
- uint32_t rem = addr & PPU.VMA.Mask1;
- uint32_t address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
- IPPU.VRAMReadBuffer = READ_WORD(&Memory.VRAM[(address << 1) & 0xffff]);
- }
- else
- IPPU.VRAMReadBuffer = READ_WORD(&Memory.VRAM[(PPU.VMA.Address << 1) & 0xffff]);
+ S9xUpdateVRAMReadBuffer();
PPU.VMA.Address += PPU.VMA.Increment;
}
return (PPU.OpenBus1 = byte);
case 0x213a: // VMDATAHREAD
- byte = (IPPU.VRAMReadBuffer >> 8) & 0xff;
+ byte = (PPU.VRAMReadBuffer >> 8) & 0xff;
if (PPU.VMA.High)
{
- if (PPU.VMA.FullGraphicCount)
- {
- uint32_t addr = PPU.VMA.Address;
- uint32_t rem = addr & PPU.VMA.Mask1;
- uint32_t address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
- IPPU.VRAMReadBuffer = READ_WORD(&Memory.VRAM[(address << 1) & 0xffff]);
- }
- else
- IPPU.VRAMReadBuffer = READ_WORD(&Memory.VRAM[(PPU.VMA.Address << 1) & 0xffff]);
+ S9xUpdateVRAMReadBuffer();
PPU.VMA.Address += PPU.VMA.Increment;
}
@@ -729,23 +592,24 @@
switch (Address)
{
case 0x4200: // NMITIMEN
+ if (Byte == Memory.FillRAM[0x4200])
+ break;
+
PPU.VTimerEnabled = !!(Byte & 0x20);
PPU.HTimerEnabled = !!(Byte & 0x10);
- if (CPU.IRQLine && !PPU.HTimerEnabled && PPU.VTimerEnabled)
- CPU.IRQTransition = true;
-
- if (!PPU.HTimerEnabled && !PPU.VTimerEnabled)
+ if (!(Byte & 0x10) && !(Byte & 0x20))
CPU.IRQLine = CPU.IRQTransition = false;
+
+ if ((Byte & 0x30) != (Memory.FillRAM[0x4200] & 0x30))
+ // Only allow instantaneous IRQ if turning it completely on or off
+ S9xUpdateIRQPositions(!(Byte & 0x30) || !(Memory.FillRAM[0x4200] & 0x30));
// NMI can trigger immediately during VBlank as long as NMI_read ($4210) wasn't cleard.
if ((Byte & 0x80) && !(Memory.FillRAM[0x4200] & 0x80) && CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE && (Memory.FillRAM[0x4210] & 0x80))
- {
// FIXME: triggered at HC+=6, checked just before the final CPU cycle,
// then, when to call S9xOpcode_NMI()?
- CPU.NMILine = true;
- Timings.NMITriggerPos = CPU.Cycles + 12;
- }
+ Timings.IRQFlagChanging |= IRQ_TRIGGER_NMI;
break;
@@ -779,28 +643,28 @@
pos = PPU.IRQHBeamPos;
PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff00) | Byte;
if (PPU.IRQHBeamPos != pos)
- S9xUpdateHVTimerPosition();
+ S9xUpdateIRQPositions(false);
break;
case 0x4208: // HTIMEH
pos = PPU.IRQHBeamPos;
PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff) | ((Byte & 1) << 8);
if (PPU.IRQHBeamPos != pos)
- S9xUpdateHVTimerPosition();
+ S9xUpdateIRQPositions(false);
break;
case 0x4209: // VTIMEL
pos = PPU.IRQVBeamPos;
PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff00) | Byte;
if (PPU.IRQVBeamPos != pos)
- S9xUpdateHVTimerPosition();
+ S9xUpdateIRQPositions(true);
break;
case 0x420a: // VTIMEH
pos = PPU.IRQVBeamPos;
PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff) | ((Byte & 1) << 8);
if (PPU.IRQVBeamPos != pos)
- S9xUpdateHVTimerPosition();
+ S9xUpdateIRQPositions(true);
break;
case 0x420b: // MDMAEN
@@ -837,7 +701,11 @@
case 0x420d: // MEMSEL
if ((Byte & 1) != (Memory.FillRAM[0x420d] & 1))
+ {
CPU.FastROMSpeed = Byte & 1 ? ONE_CYCLE : SLOW_ONE_CYCLE;
+ // we might currently be in FastROMSpeed region, S9xSetPCBase will update CPU.MemSpeed
+ S9xSetPCBase(Registers.PC.xPBPC);
+ }
break;
@@ -1021,7 +889,7 @@
PPU.OpenBus1 = PPU.OpenBus2 = 0;
- IPPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better?
+ PPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better?
IPPU.Interlace = false;
for (int c = 0; c < 0x8000; c += 0x100)
@@ -1033,5 +901,6 @@
std::fill_n(&Memory.FillRAM[0x1000], 0x1000, 0);
Memory.FillRAM[0x4201] = Memory.FillRAM[0x4213] = 0xff;
+ Memory.FillRAM[0x2126] = Memory.FillRAM[0x2128] = 1;
}
--- a/src/in_snsf/snes9x/ppu.h
+++ b/src/in_snsf/snes9x/ppu.h
@@ -1,183 +1,12 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
-const int32_t FIRST_VISIBLE_LINE = 1;
+inline constexpr int32_t FIRST_VISIBLE_LINE = 1;
enum
{
@@ -190,13 +19,12 @@
TILE_4BIT_ODD
};
-const size_t MAX_2BIT_TILES = 4096;
-const size_t MAX_4BIT_TILES = 2048;
-const size_t MAX_8BIT_TILES = 1024;
+inline constexpr size_t MAX_2BIT_TILES = 4096;
+inline constexpr size_t MAX_4BIT_TILES = 2048;
+inline constexpr size_t MAX_8BIT_TILES = 1024;
struct InternalPPU
{
- uint16_t VRAMReadBuffer;
bool Interlace;
uint32_t Red[256];
uint32_t Green[256];
@@ -255,6 +83,8 @@
uint8_t OpenBus1;
uint8_t OpenBus2;
+
+ uint16_t VRAMReadBuffer;
};
extern uint16_t SignExtend[2];
@@ -267,7 +97,7 @@
uint8_t S9xGetPPU(uint16_t);
void S9xSetCPU(uint8_t, uint16_t);
uint8_t S9xGetCPU(uint16_t);
-void S9xUpdateHVTimerPosition();
+void S9xUpdateIRQPositions(bool);
#include "memmap.h"
@@ -281,30 +111,34 @@
extern SnesModel *Model;
extern SnesModel M1SNES;
+inline void S9xUpdateVRAMReadBuffer()
+{
+ if (PPU.VMA.FullGraphicCount)
+ {
+ uint32_t addr = PPU.VMA.Address;
+ uint32_t rem = addr & PPU.VMA.Mask1;
+ uint32_t address = (addr & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3);
+ PPU.VRAMReadBuffer = READ_WORD(&Memory.VRAM[(address << 1) & 0xffff]);
+ }
+ else
+ PPU.VRAMReadBuffer = READ_WORD(&Memory.VRAM[(PPU.VMA.Address << 1) & 0xffff]);
+}
+
inline void REGISTER_2104(uint8_t Byt)
{
+ if (!(PPU.OAMFlip & 1))
+ {
+ PPU.OAMWriteRegister &= 0xff00;
+ PPU.OAMWriteRegister |= Byt;
+ }
+
if (PPU.OAMAddr & 0x100)
{
int addr = ((PPU.OAMAddr & 0x10f) << 1) + (PPU.OAMFlip & 1);
if (Byt != PPU.OAMData[addr])
PPU.OAMData[addr] = Byt;
-
- PPU.OAMFlip ^= 1;
- if (!(PPU.OAMFlip & 1))
- {
- ++PPU.OAMAddr;
- PPU.OAMAddr &= 0x1ff;
- if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1))
- PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1;
- }
- }
- else if (!(PPU.OAMFlip & 1))
- {
- PPU.OAMWriteRegister &= 0xff00;
- PPU.OAMWriteRegister |= Byt;
- PPU.OAMFlip |= 1;
- }
- else
+ }
+ else if (PPU.OAMFlip & 1)
{
PPU.OAMWriteRegister &= 0x00ff;
uint8_t lowbyte = static_cast<uint8_t>(PPU.OAMWriteRegister);
@@ -317,16 +151,29 @@
PPU.OAMData[addr] = lowbyte;
PPU.OAMData[addr + 1] = highbyte;
}
-
- PPU.OAMFlip &= ~1;
+ }
+
+ PPU.OAMFlip ^= 1;
+ if (!(PPU.OAMFlip & 1))
+ {
++PPU.OAMAddr;
+ PPU.OAMAddr &= 0x1ff;
if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1))
PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1;
}
}
// This code is correct, however due to Snes9x's inaccurate timings, some games might be broken by this chage. :(
-inline bool CHECK_INBLANK() { return Settings.BlockInvalidVRAMAccess && !PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE; }
+inline bool CHECK_INBLANK()
+{
+ if (Settings.BlockInvalidVRAMAccess && !PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE)
+ {
+ PPU.VMA.Address += !PPU.VMA.High ? PPU.VMA.Increment : 0;
+ return true;
+ }
+ else
+ return false;
+}
inline void REGISTER_2118(uint8_t Byt)
{
@@ -348,6 +195,33 @@
PPU.VMA.Address += PPU.VMA.Increment;
}
+inline void REGISTER_2118_tile(uint8_t Byt)
+{
+ if (CHECK_INBLANK())
+ return;
+
+ uint32_t rem = PPU.VMA.Address & PPU.VMA.Mask1;
+ uint32_t address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff;
+
+ Memory.VRAM[address] = Byt;
+
+ if (!PPU.VMA.High)
+ PPU.VMA.Address += PPU.VMA.Increment;
+}
+
+inline void REGISTER_2118_linear(uint8_t Byt)
+{
+ if (CHECK_INBLANK())
+ return;
+
+ uint32_t address;
+
+ Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xffff] = Byt;
+
+ if (!PPU.VMA.High)
+ PPU.VMA.Address += PPU.VMA.Increment;
+}
+
inline void REGISTER_2119(uint8_t Byt)
{
if (CHECK_INBLANK())
@@ -368,20 +242,6 @@
PPU.VMA.Address += PPU.VMA.Increment;
}
-inline void REGISTER_2118_tile(uint8_t Byt)
-{
- if (CHECK_INBLANK())
- return;
-
- uint32_t rem = PPU.VMA.Address & PPU.VMA.Mask1;
- uint32_t address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff;
-
- Memory.VRAM[address] = Byt;
-
- if (!PPU.VMA.High)
- PPU.VMA.Address += PPU.VMA.Increment;
-}
-
inline void REGISTER_2119_tile(uint8_t Byt)
{
if (CHECK_INBLANK())
@@ -393,19 +253,6 @@
Memory.VRAM[address] = Byt;
if (PPU.VMA.High)
- PPU.VMA.Address += PPU.VMA.Increment;
-}
-
-inline void REGISTER_2118_linear(uint8_t Byt)
-{
- if (CHECK_INBLANK())
- return;
-
- uint32_t address;
-
- Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xffff] = Byt;
-
- if (!PPU.VMA.High)
PPU.VMA.Address += PPU.VMA.Increment;
}
--- a/src/in_snsf/snes9x/sdd1.cpp
+++ b/src/in_snsf/snes9x/sdd1.cpp
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#include <algorithm>
#include "snes9x.h"
--- a/src/in_snsf/snes9x/sdd1.h
+++ b/src/in_snsf/snes9x/sdd1.h
@@ -1,179 +1,8 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
--- a/src/in_snsf/snes9x/snes9x.h
+++ b/src/in_snsf/snes9x/snes9x.h
@@ -1,219 +1,51 @@
-/***********************************************************************************
+/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
- (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
- Jerremy Koot (jkoot@snes9x.com)
-
- (c) Copyright 2002 - 2004 Matthew Kendora
-
- (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
-
- (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
-
- (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
-
- (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
- Kris Bleakley (codeviolation@hotmail.com)
-
- (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
- Nach (n-a-c-h@users.sourceforge.net),
-
- (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
-
- (c) Copyright 2006 - 2007 nitsuja
-
- (c) Copyright 2009 - 2011 BearOso,
- OV2
-
-
- BS-X C emulator code
- (c) Copyright 2005 - 2006 Dreamer Nom,
- zones
-
- C4 x86 assembler and some C emulation code
- (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
- Nach,
- zsKnight (zsknight@zsnes.com)
-
- C4 C++ code
- (c) Copyright 2003 - 2006 Brad Jorsch,
- Nach
-
- DSP-1 emulator code
- (c) Copyright 1998 - 2006 _Demo_,
- Andreas Naive (andreasnaive@gmail.com),
- Gary Henderson,
- Ivar (ivar@snes9x.com),
- John Weidman,
- Kris Bleakley,
- Matthew Kendora,
- Nach,
- neviksti (neviksti@hotmail.com)
-
- DSP-2 emulator code
- (c) Copyright 2003 John Weidman,
- Kris Bleakley,
- Lord Nightmare (lord_nightmare@users.sourceforge.net),
- Matthew Kendora,
- neviksti
-
- DSP-3 emulator code
- (c) Copyright 2003 - 2006 John Weidman,
- Kris Bleakley,
- Lancer,
- z80 gaiden
-
- DSP-4 emulator code
- (c) Copyright 2004 - 2006 Dreamer Nom,
- John Weidman,
- Kris Bleakley,
- Nach,
- z80 gaiden
-
- OBC1 emulator code
- (c) Copyright 2001 - 2004 zsKnight,
- pagefault (pagefault@zsnes.com),
- Kris Bleakley
- Ported from x86 assembler to C by sanmaiwashi
-
- SPC7110 and RTC C++ emulator code used in 1.39-1.51
- (c) Copyright 2002 Matthew Kendora with research by
- zsKnight,
- John Weidman,
- Dark Force
-
- SPC7110 and RTC C++ emulator code used in 1.52+
- (c) Copyright 2009 byuu,
- neviksti
-
- S-DD1 C emulator code
- (c) Copyright 2003 Brad Jorsch with research by
- Andreas Naive,
- John Weidman
-
- S-RTC C emulator code
- (c) Copyright 2001 - 2006 byuu,
- John Weidman
-
- ST010 C++ emulator code
- (c) Copyright 2003 Feather,
- John Weidman,
- Kris Bleakley,
- Matthew Kendora
-
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 _Demo_,
- pagefault,
- zsKnight
-
- Super FX C emulator code
- (c) Copyright 1997 - 1999 Ivar,
- Gary Henderson,
- John Weidman
-
- Sound emulator code used in 1.5-1.51
- (c) Copyright 1998 - 2003 Brad Martin
- (c) Copyright 1998 - 2006 Charles Bilyue'
-
- Sound emulator code used in 1.52+
- (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
-
- SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
-
- 2xSaI filter
- (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
-
- HQ2x, HQ3x, HQ4x filters
- (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
-
- NTSC filter
- (c) Copyright 2006 - 2007 Shay Green
-
- GTK+ GUI code
- (c) Copyright 2004 - 2011 BearOso
-
- Win32 GUI code
- (c) Copyright 2003 - 2006 blip,
- funkyass,
- Matthew Kendora,
- Nach,
- nitsuja
- (c) Copyright 2009 - 2011 OV2
-
- Mac OS GUI code
- (c) Copyright 1998 - 2001 John Stiles
- (c) Copyright 2001 - 2011 zones
-
-
- Specific ports contains the works of other authors. See headers in
- individual files.
-
-
- Snes9x homepage: http://www.snes9x.com/
-
- Permission to use, copy, modify and/or distribute Snes9x in both binary
- and source form, for non-commercial purposes, is hereby granted without
- fee, providing that this license information and copyright notice appear
- with all copies and any derived work.
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event shall the authors be held liable for any damages
- arising from the use of this software or it's derivatives.
-
- Snes9x is freeware for PERSONAL USE only. Commercial users should
- seek permission of the copyright holders first. Commercial use includes,
- but is not limited to, charging money for Snes9x or software derived from
- Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
- using Snes9x as a promotion for your commercial product.
-
- The copyright holders request that bug fixes and improvements to the code
- should be forwarded to them so everyone can benefit from the modifications
- in future versions.
-
- Super NES and Super Nintendo Entertainment System are trademarks of
- Nintendo Co., Limited and its subsidiary companies.
- ***********************************************************************************/
+ This file is licensed under the Snes9x License.
+ For further information, consult the LICENSE file in the root directory.
+\*****************************************************************************/
#pragma once
#ifndef VERSION
-#define VERSION "1.53"
+#define VERSION "1.60"
#endif
#include "port.h"
-const int SNES_WIDTH = 256;
-const int SNES_HEIGHT = 224;
-const uint16_t SNES_HEIGHT_EXTENDED = 239;
+inline constexpr int SNES_WIDTH = 256;
+inline constexpr int SNES_HEIGHT = 224;
+inline constexpr uint16_t SNES_HEIGHT_EXTENDED = 239;
-const int32_t SNES_MAX_NTSC_VCOUNTER = 262;
-const int32_t SNES_MAX_PAL_VCOUNTER = 312;
-const int32_t SNES_HCOUNTER_MAX = 341;
+inline constexpr double NTSC_MASTER_CLOCK = 21477272.727272; // 21477272 + 8/11 exact
+inline constexpr double PAL_MASTER_CLOCK = 21281370.0;
-const int32_t ONE_CYCLE = 6;
-const int32_t SLOW_ONE_CYCLE = 8;
-const int32_t TWO_CYCLES = 12;
-const int32_t ONE_DOT_CYCLE = 4;
+inline constexpr int32_t SNES_MAX_NTSC_VCOUNTER = 262;
+inline constexpr int32_t SNES_MAX_PAL_VCOUNTER = 312;
+inline constexpr int32_t SNES_HCOUNTER_MAX = 341;
-const int32_t SNES_CYCLES_PER_SCANLINE = SNES_HCOUNTER_MAX * ONE_DOT_CYCLE;
+inline constexpr int32_t ONE_CYCLE = 6;
+inline constexpr int32_t SLOW_ONE_CYCLE = 8;
+inline constexpr int32_t TWO_CYCLES = 12;
+inline constexpr int32_t ONE_DOT_CYCLE = 4;
-const int32_t SNES_WRAM_REFRESH_HC_v1 = 530;
-const int32_t SNES_WRAM_REFRESH_HC_v2 = 538;
-const int32_t SNES_WRAM_REFRESH_CYCLES = 40;
+inline constexpr int32_t SNES_CYCLES_PER_SCANLINE = SNES_HCOUNTER_MAX * ONE_DOT_CYCLE;
-const int32_t SNES_HBLANK_START_HC = 1096; // H=274
-const int32_t SNES_HDMA_START_HC = 1106; // FIXME: not true
-const int32_t SNES_HBLANK_END_HC = 4; // H=1
-const int32_t SNES_HDMA_INIT_HC = 20; // FIXME: not true
-const int32_t SNES_RENDER_START_HC = 48 * ONE_DOT_CYCLE; // FIXME: Snes9x renders a line at a time.
+inline constexpr int32_t SNES_WRAM_REFRESH_HC_v1 = 530;
+inline constexpr int32_t SNES_WRAM_REFRESH_HC_v2 = 538;
+inline constexpr int32_t SNES_WRAM_REFRESH_CYCLES = 40;
-const uint32_t DEBUG_MODE_FLAG = 1; // debugger
-const uint32_t TRACE_FLAG = 1 << 1; // debugger
-const uint32_t SCAN_KEYS_FLAG = 1 << 4; // CPU
-const uint32_t HALTED_FLAG = 1 << 12; // APU
+inline constexpr int32_t SNES_HBLANK_START_HC = 1096; // H=274
+inline constexpr int32_t SNES_HDMA_START_HC = 1106; // FIXME: not true
+inline constexpr int32_t SNES_HBLANK_END_HC = 4; // H=1
+inline constexpr int32_t SNES_HDMA_INIT_HC = 20; // FIXME: not true
+inline constexpr int32_t SNES_RENDER_START_HC = 128 * ONE_DOT_CYCLE; // FIXME: Snes9x renders a line at a time.
-const size_t ROM_NAME_LEN = 23;
+inline constexpr uint32_t DEBUG_MODE_FLAG = 1; // debugger
+inline constexpr uint32_t TRACE_FLAG = 1 << 1; // debugger
+inline constexpr uint32_t SCAN_KEYS_FLAG = 1 << 4; // CPU
+inline constexpr uint32_t HALTED_FLAG = 1 << 12; // APU
+
+inline constexpr size_t ROM_NAME_LEN = 23;
struct SCPUState
{
@@ -222,7 +54,7 @@
int32_t PrevCycles;
int32_t V_Counter;
uint8_t *PCBase;
- bool NMILine;
+ bool NMIPending;
bool IRQLine;
bool IRQTransition;
bool IRQLastState;
@@ -251,6 +83,14 @@
HC_WRAM_REFRESH_EVENT = 6
};
+enum
+{
+ IRQ_NONE = 0x0,
+ IRQ_SET_FLAG = 0x1,
+ IRQ_CLEAR_FLAG = 0x2,
+ IRQ_TRIGGER_NMI = 0x4
+};
+
struct STimings
{
int32_t H_Max_Master;
@@ -262,13 +102,14 @@
int32_t HDMAInit;
int32_t HDMAStart;
int32_t NMITriggerPos;
+ int32_t NextIRQTimer;
int32_t IRQTriggerCycles;
int32_t WRAMRefreshPos;
int32_t RenderPos;
bool InterlaceField;
int32_t DMACPUSync; // The cycles to synchronize DMA and CPU. Snes9x cannot emulate correctly.
int32_t NMIDMADelay; // The delay of NMI trigger after DMA transfers. Snes9x cannot emulate correctly.
- int32_t IRQPendCount; // This value is just a hack.
+ int32_t IRQFlagChanging; // This value is just a hack.
int32_t APUSpeedup;
bool APUAllowTimeOverflow;
};
@@ -281,12 +122,11 @@
bool PAL;
bool SoundSync;
- bool SixteenBitSound;
uint32_t SoundPlaybackRate;
uint32_t SoundInputRate;
bool Stereo;
- bool ReverseStereo;
bool Mute;
+ int32_t InterpolationMethod;
bool DisableGameSpecificHacks;
bool BlockInvalidVRAMAccessMaster;
@@ -294,6 +134,8 @@
int32_t HDMATimingHack;
bool TurboMode;
+
+ bool SeparateEchoBuffer;
};
struct SSNESGameFixes