Import actual code.
--- /dev/null
+++ b/src/.gitignore
@@ -1,1 +1,1 @@
-
+tmp.cpp
--- /dev/null
+++ b/src/Makefile
@@ -1,1 +1,67 @@
+#SOURCES= IN_XSF IN_2SF IN_GSF IN_SNSF IN_NCSF TMP
+SOURCES= IN_XSF IN_2SF IN_GSF IN_SNSF IN_NCSF
+IN_XSF_SRCS = ./in_xsf.cpp $(shell find . \! -name . -prune \( -iname \*.cpp -o -iname \*.c \) \! -iname tmp.cpp \! -iname XSFConfig_\*.cpp \! -iname XSFPlayer_\*.cpp \! -iname in_\*sf.cpp)
+IN_2SF_SRCS = ./XSFConfig_2SF.cpp ./XSFConfig_Winamp.cpp ./XSFPlayer_2SF.cpp $(shell find ./desmume \( -iname \*.cpp -o -iname \*.c \) \! -iname cpu_detect_x86_win.cpp \! -iname debug.cpp)
+IN_GSF_SRCS = ./XSFConfig_GSF.cpp ./XSFConfig_Winamp.cpp ./XSFPlayer_GSF.cpp $(shell find ./vbam \( -iname \*.cpp -o -iname \*.c \))
+IN_SNSF_SRCS = ./XSFConfig_SNSF.cpp ./XSFConfig_Winamp.cpp ./XSFPlayer_SNSF.cpp $(shell find ./snes9x \( -iname \*.cpp -o -iname \*.c \))
+IN_NCSF_SRCS = ./XSFConfig_NCSF.cpp ./XSFConfig_Winamp.cpp ./XSFPlayer_NCSF.cpp $(shell find ./SSEQPlayer \( -iname \*.cpp -o -iname \*.c \))
+#TMP_SRCS = ./tmp.cpp
+
+$(foreach SOURCE,$(SOURCES),$(eval $(SOURCE)_OBJS = $(addprefix obj/,$(patsubst %.cpp,%.o,$($(SOURCE)_SRCS:.c=.o)))))
+$(foreach SOURCE,$(SOURCES),$(eval ALL_OBJS += $($(SOURCE)_OBJS)))
+
+#DLLS = in_2sf.dll in_gsf.dll in_snsf.dll in_ncsf.dll tmp.exe
+DLLS = in_2sf.dll in_gsf.dll in_snsf.dll in_ncsf.dll
+
+$(foreach FILE,$(ALL_OBJS),$(shell mkdir -p $(dir $(FILE))))
+
+CXX ?= g++
+CFLAGS ?= -pipe -pedantic -Wall -Wextra -Winit-self -Wfloat-equal -Wshadow -Wcast-qual -Wlogical-op -Wunreachable-code -Wabi -Wno-unused-parameter -Wno-variadic-macros -Wno-strict-aliasing
+CXXFLAGS ?= -Woverloaded-virtual
+
+obj/%.o : %.c
+ @echo "Compiling $^..."
+ @$(CC) -std=gnu99 $(CFLAGS) -Wc++-compat -DWINAMP_PLUGIN -D_WINDOWS -I. $(EXTRA_INCLUDES) -I/c/Program\ Files/Winamp\ SDK -o $@ -c $^
+
+obj/%.o : %.cpp
+ @echo "Compiling $^..."
+ @$(CXX) -std=gnu++98 $(CFLAGS) $(CXXFLAGS) -DWINAMP_PLUGIN -D_WINDOWS -I. $(EXTRA_INCLUDES) -I/c/Program\ Files/Winamp\ SDK -o $@ -c $^
+
+.PHONY: clean all profile debug optimized
+
+all: $(DLLS)
+profile: CFLAGS += -g -pg
+profile: all
+debug: CFLAGS += -g
+debug: all
+optimized: CFLAGS += -O3
+optimized: all
+
+$(IN_XSF_OBJS): CXXFLAGS += -Weffc++
+$(IN_2SF_OBJS): EXTRA_INCLUDES = -Idesmume
+$(IN_2SF_OBJS): CFLAGS += -DHAVE_LIBZ
+in_2sf.dll: $(IN_XSF_OBJS) $(IN_2SF_OBJS)
+ @echo "Linking $@..."
+ @$(CXX) $(CFLAGS) -static-libgcc -static-libstdc++ -shared -o $@ $^ -lz -lgdi32
+$(IN_GSF_OBJS): EXTRA_INCLUDES = -Ivbam
+$(IN_GSF_OBJS): CFLAGS += -DNO_DEBUGGER -DFINAL_VERSION
+in_gsf.dll: $(IN_XSF_OBJS) $(IN_GSF_OBJS)
+ @echo "Linking $@..."
+ @$(CXX) $(CFLAGS) -static-libgcc -static-libstdc++ -shared -o $@ $^ -lz -lgdi32
+$(IN_SNSF_OBJS): EXTRA_INCLUDES = -Isnes9x
+in_snsf.dll: $(IN_XSF_OBJS) $(IN_SNSF_OBJS)
+ @echo "Linking $@..."
+ @$(CXX) $(CFLAGS) -static-libgcc -static-libstdc++ -shared -o $@ $^ -lz -lgdi32
+$(IN_NCSF_OBJS): EXTRA_INCLUDES = -ISSEQPlayer
+in_snsf.dll: $(IN_XSF_OBJS) $(IN_NCSF_OBJS)
+ @echo "Linking $@..."
+ @$(CXX) $(CFLAGS) -static-libgcc -static-libstdc++ -shared -o $@ $^ -lz -lgdi32
+tmp.exe: $(IN_XSF_OBJS) $(IN_2SF_OBJS) $(TMP_OBJS)
+ @echo "Linking $@..."
+ @$(CXX) $(CFLAGS) -static-libgcc -static-libstdc++ -o $@ $^ -lz -lgdi32
+
+clean:
+ @echo "Cleaning DLLs and OBJs..."
+ @-rm -f $(DLLS) $(ALL_OBJS)
+
--- /dev/null
+++ b/src/in_2sf/XSFConfig_2SF.cpp
@@ -1,1 +1,137 @@
+/*
+ * xSF - 2SF configuration
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Partially based on the vio*sf framework
+ */
+#include <bitset>
+#include "XSFPlayer.h"
+#include "XSFConfig.h"
+#include "convert.h"
+#include "BigSString.h"
+#include "desmume/NDSSystem.h"
+
+enum
+{
+ idInterpolation = 1000,
+ idMutes
+};
+
+class XSFConfig_2SF : public XSFConfig
+{
+protected:
+ static unsigned initInterpolation;
+ static std::wstring initMutes;
+
+ friend class XSFConfig;
+ unsigned interpolation;
+ std::bitset<16> mutes;
+
+ XSFConfig_2SF();
+ void LoadSpecificConfig();
+ void SaveSpecificConfig();
+ void GenerateSpecificDialogs();
+ INT_PTR CALLBACK ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void ResetSpecificConfigDefaults(HWND hwndDlg);
+ void SaveSpecificConfigDialog(HWND hwndDlg);
+ void CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
+public:
+ void About(HWND parent);
+};
+
+unsigned XSFConfig::initSampleRate = 44100;
+std::wstring XSFConfig::commonName = L"2SF Decoder";
+std::wstring XSFConfig::versionNumber = L"0.9b";
+unsigned XSFConfig_2SF::initInterpolation = 2;
+std::wstring XSFConfig_2SF::initMutes = L"0000000000000000";
+
+XSFConfig *XSFConfig::Create()
+{
+ return new XSFConfig_2SF();
+}
+
+XSFConfig_2SF::XSFConfig_2SF() : XSFConfig(), interpolation(0), mutes()
+{
+ this->supportedSampleRates.push_back(44100);
+}
+
+void XSFConfig_2SF::LoadSpecificConfig()
+{
+ this->interpolation = this->configIO->GetValue(L"Interpolation", XSFConfig_2SF::initInterpolation);
+ std::wstringstream mutesSS(this->configIO->GetValue(L"Mutes", XSFConfig_2SF::initMutes));
+ mutesSS >> this->mutes;
+}
+
+void XSFConfig_2SF::SaveSpecificConfig()
+{
+ this->configIO->SetValue(L"Interpolation", this->interpolation);
+ this->configIO->SetValue(L"Mutes", this->mutes.to_string<wchar_t>());
+}
+
+void XSFConfig_2SF::GenerateSpecificDialogs()
+{
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Interpolation").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
+ this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(78, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idInterpolation).IsDropDownList().
+ WithTabStop());
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Mute").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
+ this->configDialog.AddListBoxControl(DialogListBoxBuilder().WithSize(78, 45).WithExactHeight().InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idMutes).WithBorder().
+ WithVerticalScrollbar().WithMultipleSelect().WithTabStop());
+}
+
+INT_PTR CALLBACK XSFConfig_2SF::ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // Interpolation
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"No Interpolation"));
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Linear Interpolation"));
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Cosine Interpolation"));
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_SETCURSEL, this->interpolation, 0);
+ // Mutes
+ for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
+ {
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>((L"SPU " + wstringify(x + 1)).c_str()));
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, this->mutes[x], x);
+ }
+ break;
+ case WM_COMMAND:
+ break;
+ }
+
+ return XSFConfig::ConfigDialogProc(hwndDlg, uMsg, wParam, lParam);
+}
+
+void XSFConfig_2SF::ResetSpecificConfigDefaults(HWND hwndDlg)
+{
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_SETCURSEL, XSFConfig_2SF::initInterpolation, 0);
+ auto tmpMutes = std::bitset<16>(XSFConfig_2SF::initMutes);
+ for (int x = 0, numMutes = tmpMutes.size(); x < numMutes; ++x)
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, tmpMutes[x], x);
+}
+
+void XSFConfig_2SF::SaveSpecificConfigDialog(HWND hwndDlg)
+{
+ this->interpolation = static_cast<unsigned>(SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_GETCURSEL, 0, 0));
+ for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
+ this->mutes[x] = !!SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_GETSEL, x, 0);
+}
+
+void XSFConfig_2SF::CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad)
+{
+ if (!preLoad)
+ {
+ CommonSettings.spuInterpolationMode = static_cast<SPUInterpolationMode>(this->interpolation);
+ for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
+ CommonSettings.spu_muteChannels[x] = this->mutes[x];
+ }
+}
+
+void XSFConfig_2SF::About(HWND parent)
+{
+ MessageBox(parent, (XSFConfig::commonName + L" v" + XSFConfig::versionNumber + L", using xSF Winamp plugin framework (based on the vio*sf plugins) by Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]\n\n"
+ L"Utilizes modified DeSmuME v0.9.8 for audio playback.").c_str(), (XSFConfig::commonName + L" v" + XSFConfig::versionNumber).c_str(), MB_OK);
+}
+
--- /dev/null
+++ b/src/in_2sf/XSFPlayer_2SF.cpp
@@ -1,1 +1,735 @@
-
+/*
+ * xSF - 2SF Player
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Based on a modified vio2sf v0.22c
+ *
+ * Partially based on the vio*sf framework
+ *
+ * Utilizes a modified DeSmuME v0.9.8 for playback
+ * http://desmume.org/
+ */
+
+#include <memory>
+#include <zlib.h>
+#include "convert.h"
+#include "XSFPlayer.h"
+#include "XSFCommon.h"
+#include "desmume/armcpu.h"
+#include "desmume/saves.h"
+#include "desmume/NDSSystem.h"
+#include "desmume/cp15.h"
+
+class XSFPlayer_2SF : public XSFPlayer
+{
+public:
+ XSFPlayer_2SF(const std::string &filename);
+ XSFPlayer_2SF(const std::wstring &filename);
+ ~XSFPlayer_2SF() { this->Terminate(); }
+ bool Load();
+ void GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples);
+ void Terminate();
+};
+
+const char *XSFPlayer::WinampDescription = "2SF Decoder";
+const char *XSFPlayer::WinampExts = "2sf;mini2sf\0DS Sound Format files (*.2sf;*.mini2sf)\0";
+
+XSFPlayer *XSFPlayer::Create(const std::string &fn)
+{
+ return new XSFPlayer_2SF(fn);
+}
+
+XSFPlayer *XSFPlayer::Create(const std::wstring &fn)
+{
+ return new XSFPlayer_2SF(fn);
+}
+
+volatile bool execute = false;
+
+static struct
+{
+ std::vector<uint8_t> rom, state;
+ unsigned stateptr;
+} loaderwork;
+
+static inline uint16_t Get16BitsLE(const uint8_t *input)
+{
+ return input[0] | (input[1] << 8);
+}
+
+static void load_getstateinit(unsigned ptr)
+{
+ loaderwork.stateptr = ptr;
+}
+
+static void load_getsta(Status_Reg *ptr, unsigned l)
+{
+ unsigned s = l << 2;
+ if (loaderwork.stateptr > loaderwork.state.size() || loaderwork.stateptr + s > loaderwork.state.size())
+ return;
+ if (ptr)
+ for (unsigned i = 0; i < l; ++i)
+ {
+ uint32_t st = Get32BitsLE(&loaderwork.state[loaderwork.stateptr + (i << 2)]);
+ ptr[i].bits.N = (st >> 31) & 1;
+ ptr[i].bits.Z = (st >> 30) & 1;
+ ptr[i].bits.C = (st >> 29) & 1;
+ ptr[i].bits.V = (st >> 28) & 1;
+ ptr[i].bits.Q = (st >> 27) & 1;
+ ptr[i].bits.RAZ = (st >> 8) & ((1 << 19) - 1);
+ ptr[i].bits.I = (st >> 7) & 1;
+ ptr[i].bits.F = (st >> 6) & 1;
+ ptr[i].bits.T = (st >> 5) & 1;
+ ptr[i].bits.mode = (st >> 0) & 0x1f;
+ }
+ loaderwork.stateptr += s;
+}
+
+static void load_getbool(bool *ptr, unsigned l)
+{
+ unsigned s = l << 2;
+ if (loaderwork.stateptr > loaderwork.state.size() || loaderwork.stateptr + s > loaderwork.state.size())
+ return;
+ if (ptr)
+ for (unsigned i = 0; i < l; ++i)
+ ptr[i] = !!Get32BitsLE(&loaderwork.state[loaderwork.stateptr + (i << 2)]);
+ loaderwork.stateptr += s;
+}
+
+#ifdef SIGNED_IS_NOT_2S_COMPLEMENT
+/* 2's complement */
+static inline int32_t u32tos32(uint32_t v) { return static_cast<int32_t>((static_cast<int64_t>(v) ^ 0x8000) - 0x8000); }
+#else
+/* 2's complement */
+static inline int32_t u32tos32(uint32_t v) { return static_cast<int32_t>(v); }
+#endif
+
+static void load_gets32(int32_t *ptr, unsigned l)
+{
+ unsigned s = l << 2;
+ if (loaderwork.stateptr > loaderwork.state.size() || loaderwork.stateptr + s > loaderwork.state.size())
+ return;
+ if (ptr)
+ for (unsigned i = 0; i < l; ++i)
+ ptr[i] = u32tos32(Get32BitsLE(&loaderwork.state[loaderwork.stateptr + (i << 2)]));
+ loaderwork.stateptr += s;
+}
+
+static void load_getu32(uint32_t *ptr, unsigned l)
+{
+ unsigned s = l << 2;
+ if (loaderwork.stateptr > loaderwork.state.size() || loaderwork.stateptr + s > loaderwork.state.size())
+ return;
+ if (ptr)
+ for (unsigned i = 0; i < l; ++i)
+ ptr[i] = Get32BitsLE(&loaderwork.state[loaderwork.stateptr + (i << 2)]);
+ loaderwork.stateptr += s;
+}
+
+static void load_getu16(uint16_t *ptr, unsigned l)
+{
+ unsigned s = l << 1;
+ if (loaderwork.stateptr > loaderwork.state.size() || loaderwork.stateptr + s > loaderwork.state.size())
+ return;
+ if (ptr)
+ for (unsigned i = 0; i < l; ++i)
+ ptr[i] = Get16BitsLE(&loaderwork.state[loaderwork.stateptr + (i << 1)]);
+ loaderwork.stateptr += s;
+}
+
+static void load_getu8(uint8_t *ptr, unsigned l)
+{
+ unsigned s = l;
+ if (loaderwork.stateptr > loaderwork.state.size() || loaderwork.stateptr + s > loaderwork.state.size())
+ return;
+ if (ptr)
+ for (unsigned i = 0; i < l; ++i)
+ ptr[i] = loaderwork.state[loaderwork.stateptr + i];
+ loaderwork.stateptr += s;
+}
+
+/*static void gdb_stub_fix(armcpu_t *armcpu)
+{*/
+ /* armcpu->R[15] = armcpu->instruct_adr; */
+ /*armcpu->next_instruction = armcpu->instruct_adr;
+ if(armcpu->CPSR.bits.T == 0)
+ {
+ armcpu->instruction = MMU_read32(armcpu->proc_ID, armcpu->next_instruction);
+ armcpu->instruct_adr = armcpu->next_instruction;
+ armcpu->next_instruction += 4;
+ armcpu->R[15] = armcpu->next_instruction + 4;
+ }
+ else
+ {
+ armcpu->instruction = MMU_read16(armcpu->proc_ID, armcpu->next_instruction);
+ armcpu->instruct_adr = armcpu->next_instruction;
+ armcpu->next_instruction += 2;
+ armcpu->R[15] = armcpu->next_instruction + 2;
+ }
+}*/
+
+static void load_setstate()
+{
+ if (loaderwork.state.empty())
+ return;
+
+ //std::vector<uint8_t> savestate = std::vector<uint8_t>(&loaderwork.state[0], &loaderwork.state[loaderwork.state.size()]);
+ EMUFILE_MEMORY f(&loaderwork.state);
+ if (!savestate_load(&f))
+ {
+ //reset the emulator first to clean out the host's state
+
+ //while the series of resets below should work,
+ //we are testing the robustness of the savestate system with this full reset.
+ //the full reset wipes more things, so we can make sure that they are being restored correctly
+ //extern bool _HACK_DONT_STOPMOVIE;
+ //_HACK_DONT_STOPMOVIE = true;
+ NDS_Reset();
+ //_HACK_DONT_STOPMOVIE = false;
+
+ //reset some options to their old defaults which werent saved
+ //nds.debugConsole = false;
+
+ /* Skip over "Desmume Save File" crap */
+ load_getstateinit(0x17);
+
+ /* Read ARM7 cpu registers */
+ //load_getu32(&NDS_ARM7.proc_ID, 1);
+ load_getu32(NULL, 1);
+ load_getu32(&NDS_ARM7.instruction, 1);
+ load_getu32(&NDS_ARM7.instruct_adr, 1);
+ load_getu32(&NDS_ARM7.next_instruction, 1);
+ load_getu32(NDS_ARM7.R, 16);
+ load_getsta(&NDS_ARM7.CPSR, 1);
+ load_getsta(&NDS_ARM7.SPSR, 1);
+ load_getu32(&NDS_ARM7.R13_usr, 1);
+ load_getu32(&NDS_ARM7.R14_usr, 1);
+ load_getu32(&NDS_ARM7.R13_svc, 1);
+ load_getu32(&NDS_ARM7.R14_svc, 1);
+ load_getu32(&NDS_ARM7.R13_abt, 1);
+ load_getu32(&NDS_ARM7.R14_abt, 1);
+ load_getu32(&NDS_ARM7.R13_und, 1);
+ load_getu32(&NDS_ARM7.R14_und, 1);
+ load_getu32(&NDS_ARM7.R13_irq, 1);
+ load_getu32(&NDS_ARM7.R14_irq, 1);
+ load_getu32(&NDS_ARM7.R8_fiq, 1);
+ load_getu32(&NDS_ARM7.R9_fiq, 1);
+ load_getu32(&NDS_ARM7.R10_fiq, 1);
+ load_getu32(&NDS_ARM7.R11_fiq, 1);
+ load_getu32(&NDS_ARM7.R12_fiq, 1);
+ load_getu32(&NDS_ARM7.R13_fiq, 1);
+ load_getu32(&NDS_ARM7.R14_fiq, 1);
+ load_getsta(&NDS_ARM7.SPSR_svc, 1);
+ load_getsta(&NDS_ARM7.SPSR_abt, 1);
+ load_getsta(&NDS_ARM7.SPSR_und, 1);
+ load_getsta(&NDS_ARM7.SPSR_irq, 1);
+ load_getsta(&NDS_ARM7.SPSR_fiq, 1);
+ load_getu32(&NDS_ARM7.intVector, 1);
+ load_getu8(&NDS_ARM7.LDTBit, 1);
+ load_getbool(&NDS_ARM7.waitIRQ, 1);
+ bool tmpbool;
+ //load_getbool(&NDS_ARM7.wIRQ, 1);
+ //loaderwork.stateptr += 4;
+ load_getbool(NULL, 1);
+ //load_getbool(&NDS_ARM7.halt_IE_and_IF, 1);
+ //load_getbool(&NDS_ARM7.wirq, 1);
+ //loaderwork.stateptr += 4;
+ //load_getbool(NULL, 1);
+ //load_getbool(&NDS_ARM7.intrWaitARM_state, 1);
+ load_getbool(&tmpbool, 1);
+ //NDS_ARM7.intrWaitARM_state = tmpbool;
+
+ /* Read ARM9 cpu registers */
+ //load_getu32(&NDS_ARM9.proc_ID, 1);
+ load_getu32(NULL, 1);
+ load_getu32(&NDS_ARM9.instruction, 1);
+ load_getu32(&NDS_ARM9.instruct_adr, 1);
+ load_getu32(&NDS_ARM9.next_instruction, 1);
+ load_getu32(NDS_ARM9.R, 16);
+ load_getsta(&NDS_ARM9.CPSR, 1);
+ load_getsta(&NDS_ARM9.SPSR, 1);
+ load_getu32(&NDS_ARM9.R13_usr, 1);
+ load_getu32(&NDS_ARM9.R14_usr, 1);
+ load_getu32(&NDS_ARM9.R13_svc, 1);
+ load_getu32(&NDS_ARM9.R14_svc, 1);
+ load_getu32(&NDS_ARM9.R13_abt, 1);
+ load_getu32(&NDS_ARM9.R14_abt, 1);
+ load_getu32(&NDS_ARM9.R13_und, 1);
+ load_getu32(&NDS_ARM9.R14_und, 1);
+ load_getu32(&NDS_ARM9.R13_irq, 1);
+ load_getu32(&NDS_ARM9.R14_irq, 1);
+ load_getu32(&NDS_ARM9.R8_fiq, 1);
+ load_getu32(&NDS_ARM9.R9_fiq, 1);
+ load_getu32(&NDS_ARM9.R10_fiq, 1);
+ load_getu32(&NDS_ARM9.R11_fiq, 1);
+ load_getu32(&NDS_ARM9.R12_fiq, 1);
+ load_getu32(&NDS_ARM9.R13_fiq, 1);
+ load_getu32(&NDS_ARM9.R14_fiq, 1);
+ load_getsta(&NDS_ARM9.SPSR_svc, 1);
+ load_getsta(&NDS_ARM9.SPSR_abt, 1);
+ load_getsta(&NDS_ARM9.SPSR_und, 1);
+ load_getsta(&NDS_ARM9.SPSR_irq, 1);
+ load_getsta(&NDS_ARM9.SPSR_fiq, 1);
+ load_getu32(&NDS_ARM9.intVector, 1);
+ load_getu8(&NDS_ARM9.LDTBit, 1);
+ load_getbool(&NDS_ARM9.waitIRQ, 1);
+ //load_getbool(&NDS_ARM9.wIRQ, 1);
+ //loaderwork.stateptr += 4;
+ load_getbool(NULL, 1);
+ //load_getbool(&NDS_ARM9.halt_IE_and_IF, 1);
+ //load_getbool(&NDS_ARM9.wirq, 1);
+ //loaderwork.stateptr += 4;
+ //load_getbool(NULL, 1);
+ //load_getbool(&NDS_ARM9.intrWaitARM_state, 1);
+ load_getbool(&tmpbool, 1);
+ //NDS_ARM9.intrWaitARM_state = tmpbool;
+
+ /* Read in other internal variables that are important */
+ //int32_t tmps32;
+ //load_gets32(&nds.ARM9Cycle, 1);
+ load_gets32(NULL, 1);
+ //load_gets32(&nds.ARM7Cycle, 1);
+ load_gets32(NULL, 1);
+ load_gets32(&nds.cycles, 1);
+ int32_t tmps32_array[4];
+ //load_getu64(nds.timerCycle[0], 4);
+ load_gets32(tmps32_array, 4);
+ for (int i = 0; i < 4; ++i)
+ nds.timerCycle[0][i] = tmps32_array[i];
+ //load_getu64(nds.timerCycle[1], 4);
+ load_gets32(tmps32_array, 4);
+ for (int i = 0; i < 4; ++i)
+ nds.timerCycle[1][i] = tmps32_array[i];
+ //bool tmpbool_array[4];
+ //load_getbool(nds.timerOver[0], 4);
+ //loaderwork.stateptr += 16;
+ load_getbool(NULL, 4);
+ //load_getbool(nds.timerOver[1], 4);
+ //loaderwork.stateptr += 16;
+ load_getbool(NULL, 4);
+ //load_gets32(&nds.nextHBlank, 1);
+ //loaderwork.stateptr += 4;
+ load_gets32(NULL, 1);
+ load_getu32(&nds.VCount, 1);
+ load_getu32(&nds.old, 1);
+ //load_gets32(&nds.diff, 1);
+ //loaderwork.stateptr += 4;
+ load_gets32(NULL, 1);
+ //load_getbool(&nds.lignerendu, 1);
+ //loaderwork.stateptr += 4;
+ load_getbool(NULL, 1);
+ load_getu16(NULL, 1);
+ load_getu16(NULL, 1);
+
+ /* Read in memory/registers specific to the ARM9 */
+ //load_getu8 (MMU.ARM9_ITCM, 0x8000);
+ load_getu8(NULL, 0x8000);
+ load_getu8 (MMU.ARM9_DTCM, 0x4000);
+ //load_getu8 (MMU.MAIN_MEM, 0x1000000);
+ //load_getu8(MMU.MAIN_MEM, 0x800000);
+ //load_getu8(NULL, 0x800000);
+ //load_getu8(NULL, 0x1000000);
+ load_getu8(NULL, 0xFF8000);
+ load_getu8(MMU.ARM9_ITCM, 0x8000);
+ load_getu8 (MMU.MAIN_MEM/*+0x400000*/, 0x400000);
+ load_getu8 (MMU.ARM9_REG, 0x10000);
+ load_getu8 (MMU.ARM9_VMEM, 0x800);
+ load_getu8 (MMU.ARM9_OAM, 0x800);
+ //uint8_t tmpu8_ABG[0x80000];
+ //load_getu8 (ARM9Mem.ARM9_ABG, 0x80000);
+ //loaderwork.stateptr += 0x80000;
+ load_getu8(NULL, 0x80000);
+ //uint8_t tmpu8_BBG[0x20000];
+ //load_getu8 (ARM9Mem.ARM9_BBG, 0x20000);
+ //loaderwork.stateptr += 0x20000;
+ load_getu8(NULL, 0x20000);
+ //uint8_t tmpu8_AOBJ[0x40000];
+ //load_getu8 (ARM9Mem.ARM9_AOBJ, 0x40000);
+ //loaderwork.stateptr += 0x40000;
+ load_getu8(NULL, 0x40000);
+ //uint8_t tmpu8_BOBJ[0x20000];
+ //load_getu8 (ARM9Mem.ARM9_BOBJ, 0x20000);
+ //loaderwork.stateptr += 0x20000;
+ load_getu8(NULL, 0x20000);
+ load_getu8 (MMU.ARM9_LCD, 0xA4000);
+ //loaderwork.stateptr += 12;
+
+ /* Read in memory/registers specific to the ARM7 */
+ load_getu8 (MMU.ARM7_ERAM, 0x10000);
+ load_getu8 (MMU.ARM7_REG, 0x10000);
+ load_getu8 (MMU.ARM7_WIRAM, 0x10000);
+
+ /* Read in shared memory */
+ load_getu8 (MMU.SWIRAM, 0x8000);
+
+ //gdb_stub_fix(&NDS_ARM9);
+ //gdb_stub_fix(&NDS_ARM7);
+
+ loadstate();
+ }
+}
+
+static struct
+{
+ std::vector<uint8_t> buf;
+ unsigned filled, used;
+ uint32_t bufferbytes, cycles;
+ int xfs_load, sync_type;
+} sndifwork = {std::vector<uint8_t>(), 0, 0, 0, 0, 0, 0};
+
+static void SNDIFDeInit() { }
+
+static int SNDIFInit(int buffersize)
+{
+ uint32_t bufferbytes = buffersize * sizeof(int16_t);
+ SNDIFDeInit();
+ sndifwork.buf.resize(bufferbytes + 3);
+ sndifwork.bufferbytes = bufferbytes;
+ sndifwork.filled = sndifwork.used = 0;
+ sndifwork.cycles = 0;
+ return 0;
+}
+
+static void SNDIFMuteAudio() { }
+static void SNDIFUnMuteAudio() { }
+static void SNDIFSetVolume(int) { }
+
+static uint32_t SNDIFGetAudioSpace()
+{
+ return sndifwork.bufferbytes >> 2; // bytes to samples
+}
+
+static void SNDIFUpdateAudio(int16_t *buffer, uint32_t num_samples)
+{
+ uint32_t num_bytes = num_samples << 2;
+ if (num_bytes > sndifwork.bufferbytes)
+ num_bytes = sndifwork.bufferbytes;
+ memcpy(&sndifwork.buf[0], buffer, num_bytes);
+ sndifwork.filled = num_bytes;
+ sndifwork.used = 0;
+}
+
+static const int SNDIFID_2SF = 1;
+static SoundInterface_struct SNDIF_2SF =
+{
+ SNDIFID_2SF,
+ "2sf Sound Interface",
+ SNDIFInit,
+ SNDIFDeInit,
+ SNDIFUpdateAudio,
+ SNDIFGetAudioSpace,
+ SNDIFMuteAudio,
+ SNDIFUnMuteAudio,
+ SNDIFSetVolume,
+ NULL
+};
+
+SoundInterface_struct *SNDCoreList[] =
+{
+ &SNDIF_2SF,
+ &SNDDummy,
+ NULL
+};
+
+static void Map2SFSection(const std::vector<uint8_t> §ion, bool isSave)
+{
+ auto &data = isSave ? loaderwork.state : loaderwork.rom;
+
+ uint32_t offset = Get32BitsLE(§ion[0]), size = Get32BitsLE(§ion[4]), finalSize = size + offset;
+ if (!isSave)
+ finalSize = NextHighestPowerOf2(finalSize);
+ if (data.empty())
+ data.resize(finalSize + 10, 0);
+ else if (data.size() < size + offset)
+ data.resize(offset + finalSize + 10);
+ memcpy(&data[offset], §ion[8], size);
+}
+
+static bool Map2SF(XSFFile *xSF)
+{
+ if (!xSF->IsValidType(0x24))
+ return false;
+
+ auto &reservedSection = xSF->GetReservedSection(), &programSection = xSF->GetProgramSection();
+
+ if (!reservedSection.empty())
+ {
+ size_t reservedPosition = 0, reservedSize = reservedSection.size();
+ while (reservedPosition + 12 < reservedSize)
+ {
+ uint32_t saveSize = Get32BitsLE(&reservedSection[reservedPosition + 4]);
+ if (Get32BitsLE(&reservedSection[reservedPosition]) == 0x45564153) // "SAVE"
+ {
+ if (reservedPosition + 12 + saveSize > reservedSize)
+ return false;
+
+ uint8_t tmpSaveUncompressed[8];
+ unsigned long saveUncompressedSize = 8;
+ uncompress(tmpSaveUncompressed, &saveUncompressedSize, &reservedSection[reservedPosition + 12], saveSize);
+ saveUncompressedSize = Get32BitsLE(&tmpSaveUncompressed[4]) + 8;
+ auto saveUncompressed = std::vector<uint8_t>(saveUncompressedSize);
+ uncompress(&saveUncompressed[0], &saveUncompressedSize, &reservedSection[reservedPosition + 12], saveSize);
+
+ Map2SFSection(saveUncompressed, true);
+ }
+ reservedPosition += saveSize + 12;
+ }
+ }
+
+ if (!programSection.empty())
+ Map2SFSection(programSection, false);
+
+ return true;
+}
+
+static bool RecursiveLoad2SF(XSFFile *xSF, int level)
+{
+ if (level <= 10 && xSF->GetTagExists("_lib"))
+ {
+#ifdef _WIN32
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetWStr()) + xSF->GetTagValue("_lib").GetWStr(), 4, 8));
+#else
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetAnsi()) + xSF->GetTagValue("_lib").GetAnsi(), 4, 8));
+#endif
+ if (!RecursiveLoad2SF(libxSF.get(), level + 1))
+ return false;
+ }
+
+ if (!Map2SF(xSF))
+ return false;
+
+ unsigned n = 2;
+ bool found;
+ do
+ {
+ found = false;
+ std::string libTag = "_lib" + stringify(n++);
+ if (xSF->GetTagExists(libTag))
+ {
+ found = true;
+#ifdef _WIN32
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetWStr()) + xSF->GetTagValue(libTag).GetWStr(), 4, 8));
+#else
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetAnsi()) + xSF->GetTagValue(libTag).GetAnsi(), 4, 8));
+#endif
+ if (!RecursiveLoad2SF(libxSF.get(), level + 1))
+ return false;
+ }
+ } while (found);
+
+ return true;
+}
+
+static bool Load2SF(XSFFile *xSF)
+{
+ loaderwork.rom.clear();
+ loaderwork.state.clear();
+ loaderwork.stateptr = 0;
+
+ return RecursiveLoad2SF(xSF, 1);
+}
+
+XSFPlayer_2SF::XSFPlayer_2SF(const std::string &filename) : XSFPlayer()
+{
+ this->xSF = new XSFFile(filename, 4, 8);
+}
+
+XSFPlayer_2SF::XSFPlayer_2SF(const std::wstring &filename) : XSFPlayer()
+{
+ this->xSF = new XSFFile(filename, 4, 8);
+}
+
+bool XSFPlayer_2SF::Load()
+{
+ int frames = xSF->GetTagValue("_frames", -1);
+ sndifwork.sync_type = xSF->GetTagValue("_2sf_sync_type", 0);
+
+ sndifwork.xfs_load = false;
+ if (!Load2SF(this->xSF))
+ return false;
+
+ if (NDS_Init())
+ return false;
+
+ SPU_ChangeSoundCore(SNDIFID_2SF, 737);
+
+ execute = false;
+
+ MMU_unsetRom();
+ if (!loaderwork.rom.empty())
+ {
+ NDS_SetROM(&loaderwork.rom[0], loaderwork.rom.size() - 1);
+ gameInfo.loadData(reinterpret_cast<char *>(&loaderwork.rom[0]), loaderwork.rom.size() - 1);
+ }
+
+ NDS_Reset();
+
+ execute = true;
+
+ if (!loaderwork.state.empty())
+ {
+ armcp15_t *c9 = reinterpret_cast<armcp15_t *>(NDS_ARM9.coproc[15]);
+ //int proc;
+ if (frames == -1)
+ {
+ /* set initial ARM9 coprocessor state */
+
+ armcp15_moveARM2CP(c9, 0x00000000, 0x01, 0x00, 0, 0);
+ armcp15_moveARM2CP(c9, 0x00000000, 0x07, 0x05, 0, 0);
+ armcp15_moveARM2CP(c9, 0x00000000, 0x07, 0x06, 0, 0);
+ armcp15_moveARM2CP(c9, 0x00000000, 0x07, 0x0a, 0, 4);
+ armcp15_moveARM2CP(c9, 0x04000033, 0x06, 0x00, 0, 4);
+ armcp15_moveARM2CP(c9, 0x0200002d, 0x06, 0x01, 0, 0);
+ armcp15_moveARM2CP(c9, 0x027e0021, 0x06, 0x02, 0, 0);
+ armcp15_moveARM2CP(c9, 0x08000035, 0x06, 0x03, 0, 0);
+ armcp15_moveARM2CP(c9, 0x027e001b, 0x06, 0x04, 0, 0);
+ armcp15_moveARM2CP(c9, 0x0100002f, 0x06, 0x05, 0, 0);
+ armcp15_moveARM2CP(c9, 0xffff001d, 0x06, 0x06, 0, 0);
+ armcp15_moveARM2CP(c9, 0x027ff017, 0x06, 0x07, 0, 0);
+ armcp15_moveARM2CP(c9, 0x00000020, 0x09, 0x01, 0, 1);
+
+ armcp15_moveARM2CP(c9, 0x027e000a, 0x09, 0x01, 0, 0);
+
+ armcp15_moveARM2CP(c9, 0x00000042, 0x02, 0x00, 0, 1);
+ armcp15_moveARM2CP(c9, 0x00000042, 0x02, 0x00, 0, 0);
+ armcp15_moveARM2CP(c9, 0x00000002, 0x03, 0x00, 0, 0);
+ armcp15_moveARM2CP(c9, 0x05100011, 0x05, 0x00, 0, 3);
+ armcp15_moveARM2CP(c9, 0x15111011, 0x05, 0x00, 0, 2);
+ armcp15_moveARM2CP(c9, 0x07dd1e10, 0x01, 0x00, 0, 0);
+ armcp15_moveARM2CP(c9, 0x0005707d, 0x01, 0x00, 0, 0);
+
+ armcp15_moveARM2CP(c9, 0x00000000, 0x07, 0x0a, 0, 4);
+ armcp15_moveARM2CP(c9, 0x02004000, 0x07, 0x05, 0, 1);
+ armcp15_moveARM2CP(c9, 0x02004000, 0x07, 0x0e, 0, 1);
+
+ /* set initial timer state */
+
+ /*MMU_write16(0, REG_TM0CNTL, 0x0000);
+ MMU_write16(0, REG_TM0CNTH, 0x00C1);
+ MMU_write16(1, REG_TM0CNTL, 0x0000);
+ MMU_write16(1, REG_TM0CNTH, 0x00C1);
+ MMU_write16(1, REG_TM1CNTL, 0xf7e7);
+ MMU_write16(1, REG_TM1CNTH, 0x00C1);*/
+
+ /* set initial interrupt state */
+
+ MMU.reg_IME[0] = 0x00000001;
+ MMU.reg_IE[0] = 0x00042001;
+ MMU.reg_IME[1] = 0x00000001;
+ MMU.reg_IE[1] = 0x0104009d;
+ }
+ else if (frames > 0)
+ {
+ /* execute boot code */
+ for (int i = 0; i < frames; ++i)
+ NDS_exec<true>();
+ }
+
+ /* load state */
+
+ execute = false;
+ SPU_Reset();
+
+ load_setstate();
+ loaderwork.state.clear();
+
+ if (frames == -1)
+ armcp15_moveARM2CP(c9, (NDS_ARM9.R13_irq & 0x0fff0000) | 0x0a, 0x09, 0x01, 0, 0);
+
+ /* restore timer state */
+
+ /*for (proc = 0; proc < 2; proc++)
+ {
+ MMU_write16(proc, REG_TM0CNTH, T1ReadWord(MMU.MMU_MEM[proc][0x40], REG_TM0CNTH & 0xFFF));
+ MMU_write16(proc, REG_TM1CNTH, T1ReadWord(MMU.MMU_MEM[proc][0x40], REG_TM1CNTH & 0xFFF));
+ MMU_write16(proc, REG_TM2CNTH, T1ReadWord(MMU.MMU_MEM[proc][0x40], REG_TM2CNTH & 0xFFF));
+ MMU_write16(proc, REG_TM3CNTH, T1ReadWord(MMU.MMU_MEM[proc][0x40], REG_TM3CNTH & 0xFFF));
+ }*/
+ }
+ else if (frames > 0)
+ {
+ /* skip 1 sec */
+ for (int i = 0; i < frames; ++i)
+ NDS_exec<false>();
+ }
+ execute = true;
+ sndifwork.xfs_load = true;
+ //CommonSettings.spu_advanced = true;
+ //CommonSettings.advanced_timing = false;
+
+ return XSFPlayer::Load();
+}
+
+void XSFPlayer_2SF::GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples)
+{
+ static const double HBASE_CYCLES = 33509300.322234;
+ static const int HLINE_CYCLES = 6 * (99 + 256);
+ static const uint32_t HSAMPLES = static_cast<uint32_t>(static_cast<double>(this->sampleRate * HLINE_CYCLES) / HBASE_CYCLES);
+ static const int VDIVISION = 100;
+ static const int VLINES = 263;
+ static const double VBASE_CYCLES = HBASE_CYCLES / VDIVISION;
+ static const uint32_t VSAMPLES = static_cast<uint32_t>(static_cast<double>(this->sampleRate * HLINE_CYCLES * VLINES) / HBASE_CYCLES);
+
+ if (!sndifwork.xfs_load)
+ return;
+ unsigned bytes = samples << 2;
+ while (bytes)
+ {
+ unsigned remainbytes = sndifwork.filled - sndifwork.used;
+ if (remainbytes > 0)
+ {
+ if (remainbytes > bytes)
+ {
+ memcpy(&buf[offset], &sndifwork.buf[sndifwork.used], bytes);
+ sndifwork.used += bytes;
+ offset += bytes;
+ remainbytes -= bytes;
+ bytes = 0;
+ break;
+ }
+ else
+ {
+ memcpy(&buf[offset], &sndifwork.buf[sndifwork.used], remainbytes);
+ sndifwork.used += remainbytes;
+ offset += remainbytes;
+ bytes -= remainbytes;
+ remainbytes = 0;
+ }
+ }
+ if (!remainbytes)
+ {
+ if (sndifwork.sync_type == 1)
+ {
+ /* vsync */
+ sndifwork.cycles += (this->sampleRate / VDIVISION) * HLINE_CYCLES * VLINES;
+ if (sndifwork.cycles >= static_cast<uint32_t>(VBASE_CYCLES * (VSAMPLES + 1)))
+ sndifwork.cycles -= static_cast<uint32_t>(VBASE_CYCLES * (VSAMPLES + 1));
+ else
+ sndifwork.cycles -= static_cast<uint32_t>(VBASE_CYCLES * VSAMPLES);
+ }
+ else
+ {
+ /* hsync */
+ sndifwork.cycles += this->sampleRate * HLINE_CYCLES;
+ if (sndifwork.cycles >= static_cast<uint32_t>(HBASE_CYCLES * (HSAMPLES + 1)))
+ sndifwork.cycles -= static_cast<uint32_t>(HBASE_CYCLES * (HSAMPLES + 1));
+ else
+ sndifwork.cycles -= static_cast<uint32_t>(HBASE_CYCLES * HSAMPLES);
+ }
+ NDS_exec<false>();
+ SPU_Emulate_user();
+ }
+ }
+}
+
+void XSFPlayer_2SF::Terminate()
+{
+ MMU_unsetRom();
+ NDS_DeInit();
+
+ loaderwork.rom.clear();
+ loaderwork.state.clear();
+ loaderwork.stateptr = 0;
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/FIFO.cpp
@@ -1,1 +1,309 @@
-
+/*
+ Copyright 2006 yopyop
+ Copyright 2007 shash
+ Copyright 2007-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cstring>
+
+#include "FIFO.h"
+#include "armcpu.h"
+//#include "debug.h"
+#include "mem.h"
+#include "MMU.h"
+#include "NDSSystem.h"
+//#include "gfx3d.h"
+
+// ========================================================= IPC FIFO
+IPC_FIFO ipc_fifo[2]; // 0 - ARM9
+ // 1 - ARM7
+
+void IPC_FIFOinit(uint8_t proc)
+{
+ memset(&ipc_fifo[proc], 0, sizeof(IPC_FIFO));
+ T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, 0x00000101);
+}
+
+void IPC_FIFOsend(uint8_t proc, uint32_t val)
+{
+ uint16_t cnt_l = T1ReadWord(MMU.MMU_MEM[proc][0x40], 0x184);
+ if (!(cnt_l & IPCFIFOCNT_FIFOENABLE)) return; // FIFO disabled
+ uint8_t proc_remote = proc ^ 1;
+
+ if (ipc_fifo[proc].size > 15)
+ {
+ cnt_l |= IPCFIFOCNT_FIFOERROR;
+ T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l);
+ return;
+ }
+
+ uint16_t cnt_r = T1ReadWord(MMU.MMU_MEM[proc_remote][0x40], 0x184);
+
+ //LOG("IPC%s send FIFO 0x%08X size %03i (l 0x%X, tail %02i) (r 0x%X, tail %02i)\n",
+ // proc?"7":"9", val, ipc_fifo[proc].size, cnt_l, ipc_fifo[proc].tail, cnt_r, ipc_fifo[proc^1].tail);
+
+ cnt_l &= 0xBFFC; // clear send empty bit & full
+ cnt_r &= 0xBCFF; // set recv empty bit & full
+ ipc_fifo[proc].buf[ipc_fifo[proc].tail] = val;
+ ipc_fifo[proc].tail++;
+ ipc_fifo[proc].size++;
+ if (ipc_fifo[proc].tail > 15) ipc_fifo[proc].tail = 0;
+
+ if (ipc_fifo[proc].size > 15)
+ {
+ cnt_l |= IPCFIFOCNT_SENDFULL; // set send full bit
+ cnt_r |= IPCFIFOCNT_RECVFULL; // set recv full bit
+ }
+
+ T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l);
+ T1WriteWord(MMU.MMU_MEM[proc_remote][0x40], 0x184, cnt_r);
+
+ if (cnt_r & IPCFIFOCNT_RECVIRQEN)
+ NDS_makeIrq(proc_remote, IRQ_BIT_IPCFIFO_RECVNONEMPTY);
+
+ NDS_Reschedule();
+}
+
+uint32_t IPC_FIFOrecv(uint8_t proc)
+{
+ uint16_t cnt_l = T1ReadWord(MMU.MMU_MEM[proc][0x40], 0x184);
+ if (!(cnt_l & IPCFIFOCNT_FIFOENABLE)) return 0; // FIFO disabled
+ uint8_t proc_remote = proc ^ 1;
+
+ uint32_t val = 0;
+
+ if ( ipc_fifo[proc_remote].size == 0 ) // remote FIFO error
+ {
+ cnt_l |= IPCFIFOCNT_FIFOERROR;
+ T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l);
+ return 0;
+ }
+
+ uint16_t cnt_r = T1ReadWord(MMU.MMU_MEM[proc_remote][0x40], 0x184);
+
+ cnt_l &= 0xBCFF; // clear send full bit & empty
+ cnt_r &= 0xBFFC; // set recv full bit & empty
+
+ val = ipc_fifo[proc_remote].buf[ipc_fifo[proc_remote].head];
+ ipc_fifo[proc_remote].head++;
+ ipc_fifo[proc_remote].size--;
+ if (ipc_fifo[proc_remote].head > 15) ipc_fifo[proc_remote].head = 0;
+
+ //LOG("IPC%s recv FIFO 0x%08X size %03i (l 0x%X, tail %02i) (r 0x%X, tail %02i)\n",
+ // proc?"7":"9", val, ipc_fifo[proc].size, cnt_l, ipc_fifo[proc].tail, cnt_r, ipc_fifo[proc^1].tail);
+
+
+ if ( ipc_fifo[proc_remote].size == 0 ) // FIFO empty
+ {
+ cnt_l |= IPCFIFOCNT_RECVEMPTY;
+ cnt_r |= IPCFIFOCNT_SENDEMPTY;
+
+ if (cnt_r & IPCFIFOCNT_SENDIRQEN)
+ NDS_makeIrq(proc_remote, IRQ_BIT_IPCFIFO_SENDEMPTY);
+ }
+
+ T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l);
+ T1WriteWord(MMU.MMU_MEM[proc_remote][0x40], 0x184, cnt_r);
+
+ NDS_Reschedule();
+
+ return val;
+}
+
+void IPC_FIFOcnt(uint8_t proc, uint16_t val)
+{
+ uint16_t cnt_l = T1ReadWord(MMU.MMU_MEM[proc][0x40], 0x184);
+ uint16_t cnt_r = T1ReadWord(MMU.MMU_MEM[proc^1][0x40], 0x184);
+
+ if (val & IPCFIFOCNT_FIFOERROR)
+ {
+ //at least SPP uses this, maybe every retail game
+ cnt_l &= ~IPCFIFOCNT_FIFOERROR;
+ }
+
+ if (val & IPCFIFOCNT_SENDCLEAR)
+ {
+ ipc_fifo[proc].head = 0; ipc_fifo[proc].tail = 0; ipc_fifo[proc].size = 0;
+
+ cnt_l |= IPCFIFOCNT_SENDEMPTY;
+ cnt_r |= IPCFIFOCNT_RECVEMPTY;
+
+ cnt_l &= ~IPCFIFOCNT_SENDFULL;
+ cnt_r &= ~IPCFIFOCNT_RECVFULL;
+ }
+
+ cnt_l &= ~IPCFIFOCNT_WRITEABLE;
+ cnt_l |= val & IPCFIFOCNT_WRITEABLE;
+
+ // IPCFIFOCNT_SENDIRQEN may have been set (and/or the fifo may have been cleared) so we may need to trigger this irq
+ // (this approach is used by libnds fifo system on occasion in fifoInternalSend, and began happening frequently for value32 with r4326)
+ if (cnt_l & IPCFIFOCNT_SENDIRQEN)
+ if (cnt_l & IPCFIFOCNT_SENDEMPTY)
+ NDS_makeIrq(proc, IRQ_BIT_IPCFIFO_SENDEMPTY);
+
+ // IPCFIFOCNT_RECVIRQEN may have been set so we may need to trigger this irq
+ if(cnt_l & IPCFIFOCNT_RECVIRQEN)
+ if (!(cnt_l & IPCFIFOCNT_RECVEMPTY))
+ NDS_makeIrq(proc, IRQ_BIT_IPCFIFO_RECVNONEMPTY);
+
+ T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l);
+ T1WriteWord(MMU.MMU_MEM[proc^1][0x40], 0x184, cnt_r);
+
+ NDS_Reschedule();
+}
+
+// ========================================================= GFX FIFO
+//GFX_PIPE gxPIPE;
+//GFX_FIFO gxFIFO;
+
+/*void GFX_PIPEclear()
+{
+ gxPIPE.head = 0;
+ gxPIPE.tail = 0;
+ gxPIPE.size = 0;
+}*/
+
+/*void GFX_FIFOclear()
+{
+ gxFIFO.head = 0;
+ gxFIFO.tail = 0;
+ gxFIFO.size = 0;
+}*/
+
+/*static void GXF_FIFO_handleEvents()
+{
+ bool low = gxFIFO.size <= 127;
+ bool lowchange = MMU_new.gxstat.fifo_low ^ low;
+ MMU_new.gxstat.fifo_low = low;
+ if(low) triggerDma(EDMAMode_GXFifo);
+
+ bool empty = gxFIFO.size == 0;
+ bool emptychange = MMU_new.gxstat.fifo_empty ^ empty;
+ MMU_new.gxstat.fifo_empty = empty;
+
+ if(emptychange||lowchange) NDS_Reschedule();
+}*/
+
+/*void GFX_FIFOsend(uint8_t cmd, uint32_t param)
+{
+ if(cmd==0x41) {
+ //int zzz=9;
+ }
+
+ //INFO("gxFIFO: send 0x%02X = 0x%08X (size %03i/0x%02X) gxstat 0x%08X\n", cmd, param, gxFIFO.size, gxFIFO.size, gxstat);
+ //printf("fifo recv: %02X: %08X upto:%d\n",cmd,param,gxFIFO.size+1);
+
+ //TODO - WOAH ! NOT HANDLING A TOO-BIG FIFO RIGHT NOW!
+ //if (gxFIFO.size > 255)
+ //{
+ // GXF_FIFO_handleEvents();
+ // //NEED TO HANDLE THIS!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ // //gxstat |= 0x08000000; // busy
+ // NDS_RescheduleGXFIFO(1);
+ // //INFO("ERROR: gxFIFO is full (cmd 0x%02X = 0x%08X) (prev cmd 0x%02X = 0x%08X)\n", cmd, param, gxFIFO.cmd[255], gxFIFO.param[255]);
+ // return;
+ //}
+
+
+ gxFIFO.cmd[gxFIFO.tail] = cmd;
+ gxFIFO.param[gxFIFO.tail] = param;
+ gxFIFO.tail++;
+ gxFIFO.size++;
+ if (gxFIFO.tail > HACK_GXIFO_SIZE-1) gxFIFO.tail = 0;
+
+ if(gxFIFO.size>=HACK_GXIFO_SIZE) {
+ printf("--FIFO FULL-- : %d\n",gxFIFO.size);
+ }
+
+ //gxstat |= 0x08000000; // set busy flag
+
+ GXF_FIFO_handleEvents();
+
+ NDS_RescheduleGXFIFO(1);
+}*/
+
+// this function used ONLY in gxFIFO
+/*bool GFX_PIPErecv(uint8_t *cmd, uint32_t *param)
+{
+ //gxstat &= 0xF7FFFFFF; // clear busy flag
+
+ if (gxFIFO.size == 0)
+ {
+ GXF_FIFO_handleEvents();
+ return false;
+ }
+
+ *cmd = gxFIFO.cmd[gxFIFO.head];
+ *param = gxFIFO.param[gxFIFO.head];
+
+ gxFIFO.head++;
+ gxFIFO.size--;
+ if (gxFIFO.head > HACK_GXIFO_SIZE-1) gxFIFO.head = 0;
+
+ GXF_FIFO_handleEvents();
+
+ return true;
+}*/
+
+/*void GFX_FIFOcnt(uint32_t val)
+{
+ ////INFO("gxFIFO: write cnt 0x%08X (prev 0x%08X) FIFO size %03i PIPE size %03i\n", val, gxstat, gxFIFO.size, gxPIPE.size);
+
+ if (val & (1<<29)) // clear? (only in homebrew?)
+ {
+ GFX_PIPEclear();
+ GFX_FIFOclear();
+ return;
+ }
+
+ //zeromus says: what happened to clear stack?
+ //if (val & (1<<15)) // projection stack pointer reset
+ //{
+ // gfx3d_ClearStack();
+ // val &= 0xFFFF5FFF; // clear reset (bit15) & stack level (bit13)
+ //}
+
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x600, val);
+}*/
+
+// ========================================================= DISP FIFO
+//DISP_FIFO disp_fifo;
+
+/*void DISP_FIFOinit()
+{
+ memset(&disp_fifo, 0, sizeof(DISP_FIFO));
+}*/
+
+/*void DISP_FIFOsend(uint32_t val)
+{
+ //INFO("DISP_FIFO send value 0x%08X (head 0x%06X, tail 0x%06X)\n", val, disp_fifo.head, disp_fifo.tail);
+ disp_fifo.buf[disp_fifo.tail] = val;
+ disp_fifo.tail++;
+ if (disp_fifo.tail > 0x5FFF)
+ disp_fifo.tail = 0;
+}*/
+
+/*uint32_t DISP_FIFOrecv()
+{
+ //if (disp_fifo.tail == disp_fifo.head) return 0; // FIFO is empty
+ uint32_t val = disp_fifo.buf[disp_fifo.head];
+ disp_fifo.head++;
+ if (disp_fifo.head > 0x5FFF)
+ disp_fifo.head = 0;
+ return val;
+}*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/FIFO.h
@@ -1,1 +1,90 @@
+/*
+ Copyright 2006 yopyop
+ Copyright 2007 shash
+ Copyright 2007-2011 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef FIFO_H
+#define FIFO_H
+
+#include "types.h"
+
+//=================================================== IPC FIFO
+struct IPC_FIFO
+{
+ uint32_t buf[16];
+
+ uint8_t head;
+ uint8_t tail;
+ uint8_t size;
+};
+
+extern IPC_FIFO ipc_fifo[2];
+extern void IPC_FIFOinit(uint8_t proc);
+extern void IPC_FIFOsend(uint8_t proc, uint32_t val);
+extern uint32_t IPC_FIFOrecv(uint8_t proc);
+extern void IPC_FIFOcnt(uint8_t proc, uint16_t val);
+
+//=================================================== GFX FIFO
+
+//yeah, its oversize for now. thats a simpler solution
+//moon seems to overdrive the fifo with immediate dmas
+//i think this might be nintendo code too
+//static const uint32_t HACK_GXIFO_SIZE = 200000;
+
+/*struct GFX_FIFO
+{
+ uint8_t cmd[HACK_GXIFO_SIZE];
+ uint32_t param[HACK_GXIFO_SIZE];
+
+ uint32_t head; // start position
+ uint32_t tail; // tail
+ uint32_t size; // size FIFO buffer
+};*/
+
+/*struct GFX_PIPE
+{
+ uint8_t cmd[4];
+ uint32_t param[4];
+
+ uint8_t head;
+ uint8_t tail;
+ uint8_t size;
+};*/
+
+//extern GFX_PIPE gxPIPE;
+//extern GFX_FIFO gxFIFO;
+//extern void GFX_PIPEclear();
+//extern void GFX_FIFOclear();
+//extern void GFX_FIFOsend(uint8_t cmd, uint32_t param);
+//extern bool GFX_PIPErecv(uint8_t *cmd, uint32_t *param);
+//extern void GFX_FIFOcnt(uint32_t val);
+
+//=================================================== Display memory FIFO
+/*struct DISP_FIFO
+{
+ uint32_t buf[0x6000]; // 256x192 32K color
+ uint32_t head; // head
+ uint32_t tail; // tail
+};*/
+
+//extern DISP_FIFO disp_fifo;
+//extern void DISP_FIFOinit();
+//extern void DISP_FIFOsend(uint32_t val);
+//extern uint32_t DISP_FIFOrecv();
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/MMU.cpp
@@ -1,1 +1,4764 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2007 shash
+ Copyright (C) 2007-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <sstream>
+#include <cstdlib>
+#include <cmath>
+#include <cstring>
+#include <cassert>
+
+#include "common.h"
+//#include "debug.h"
+#include "NDSSystem.h"
+#include "cp15.h"
+//#include "wifi.h"
+#include "registers.h"
+//#include "render3D.h"
+//#include "gfx3d.h"
+//#include "rtc.h"
+#include "mc.h"
+//#include "addons.h"
+#include "slot1.h"
+//#include "mic.h"
+//#include "movie.h"
+#include "readwrite.h"
+#include "MMU_timing.h"
+
+//#undef min
+
+/*#ifdef DO_ASSERT_UNALIGNED
+#define ASSERT_UNALIGNED(x) assert(x)
+#else
+#define ASSERT_UNALIGNED(x)
+#endif*/
+
+//http://home.utah.edu/~nahaj/factoring/isqrt.c.html
+static uint64_t isqrt (uint64_t x) {
+ uint64_t squaredbit, remainder, root;
+
+ if (x<1) return 0;
+
+ /* Load the binary constant 01 00 00 ... 00, where the number
+ * of zero bits to the right of the single one bit
+ * is even, and the one bit is as far left as is consistant
+ * with that condition.)
+ */
+ squaredbit = (uint64_t) ((((uint64_t) ~0LL) >> 1) &
+ ~(((uint64_t) ~0LL) >> 2));
+ /* This portable load replaces the loop that used to be
+ * here, and was donated by legalize@xmission.com
+ */
+
+ /* Form bits of the answer. */
+ remainder = x; root = 0;
+ while (squaredbit > 0) {
+ if (remainder >= (squaredbit | root)) {
+ remainder -= (squaredbit | root);
+ root >>= 1; root |= squaredbit;
+ } else {
+ root >>= 1;
+ }
+ squaredbit >>= 2;
+ }
+
+ return root;
+}
+
+uint32_t partie = 1;
+uint32_t _MMU_MAIN_MEM_MASK = 0x3FFFFF;
+uint32_t _MMU_MAIN_MEM_MASK16 = 0x3FFFFF & ~1;
+uint32_t _MMU_MAIN_MEM_MASK32 = 0x3FFFFF & ~3;
+
+//#define _MMU_DEBUG
+
+/*#ifdef _MMU_DEBUG
+
+#include <stdarg.h>
+void mmu_log_debug_ARM9(uint32_t adr, const char *fmt, ...)
+{
+ if (adr < 0x4000000) return;
+// if (adr > 0x4100014) return;
+//#if 1
+ if (adr >= 0x4000000 && adr <= 0x400006E) return; // Display Engine A
+ if (adr >= 0x40000B0 && adr <= 0x4000134) return; // DMA, Timers and Keypad
+ if (adr >= 0x4000180 && adr <= 0x40001BC) return; // IPC/ROM
+ if (adr >= 0x4000204 && adr <= 0x400024A) return; // Memory & IRQ control
+ if (adr >= 0x4000280 && adr <= 0x4000306) return; // Maths
+ if (adr >= 0x4000320 && adr <= 0x40006A3) return; // 3D dispaly engine
+ if (adr >= 0x4001000 && adr <= 0x400106E) return; // Display Engine B
+ if (adr >= 0x4100000 && adr <= 0x4100014) return; // IPC/ROM
+//#endif
+ va_list list;
+ char msg[512];
+
+ memset(msg,0,512);
+
+ va_start(list,fmt);
+ _vsnprintf(msg,511,fmt,list);
+ va_end(list);
+
+ INFO("MMU ARM9 0x%08X: %s\n", adr, msg);
+}
+
+void mmu_log_debug_ARM7(uint32_t adr, const char *fmt, ...)
+{
+ if (adr < 0x4000004) return;
+ if (adr > 0x4808FFF) return;
+#if 1
+ if (adr >= 0x4000004 && adr < 0x4000180) return; // ARM7 I/O Map
+ if (adr >= 0x4000180 && adr <= 0x40001C4) return; // IPC/ROM
+ if (adr >= 0x4000204 && adr <= 0x400030C) return; // Memory and IRQ Control
+ if (adr >= 0x4000400 && adr <= 0x400051E) return; // Sound Registers
+ if (adr >= 0x4100000 && adr <= 0x4100014) return; // IPC/ROM
+ if (adr >= 0x4800000 && adr <= 0x4808FFF) return; // WLAN Registers
+#endif
+ va_list list;
+ char msg[512];
+
+ memset(msg,0,512);
+
+ va_start(list,fmt);
+ _vsnprintf(msg,511,fmt,list);
+ va_end(list);
+
+ INFO("MMU ARM7 0x%08X: %s\n", adr, msg);
+
+}
+#else
+#define mmu_log_debug_ARM9(...)
+#define mmu_log_debug_ARM7(...)
+#endif*/
+
+
+//#define LOG_CARD
+//#define LOG_GPU
+//#define LOG_DMA
+//#define LOG_DMA2
+//#define LOG_DIV
+
+#define DUP2(x) x, x
+#define DUP4(x) x, x, x, x
+#define DUP8(x) x, x, x, x, x, x, x, x
+#define DUP16(x) x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x
+
+MMU_struct MMU;
+MMU_struct_new MMU_new;
+MMU_struct_timing MMU_timing;
+
+uint8_t * MMU_struct::MMU_MEM[2][256] = {
+ //arm9
+ {
+ /* 0X*/ DUP16(MMU.ARM9_ITCM),
+ /* 1X*/ //DUP16(MMU.ARM9_ITCM)
+ /* 1X*/ DUP16(MMU.UNUSED_RAM),
+ /* 2X*/ DUP16(MMU.MAIN_MEM),
+ /* 3X*/ DUP16(MMU.SWIRAM),
+ /* 4X*/ DUP16(MMU.ARM9_REG),
+ /* 5X*/ DUP16(MMU.ARM9_VMEM),
+ /* 6X*/ DUP16(MMU.ARM9_LCD),
+ /* 7X*/ DUP16(MMU.ARM9_OAM),
+ /* 8X*/ DUP16(NULL),
+ /* 9X*/ DUP16(NULL),
+ /* AX*/ DUP16(MMU.UNUSED_RAM),
+ /* BX*/ DUP16(MMU.UNUSED_RAM),
+ /* CX*/ DUP16(MMU.UNUSED_RAM),
+ /* DX*/ DUP16(MMU.UNUSED_RAM),
+ /* EX*/ DUP16(MMU.UNUSED_RAM),
+ /* FX*/ DUP16(MMU.ARM9_BIOS)
+ },
+ //arm7
+ {
+ /* 0X*/ DUP16(MMU.ARM7_BIOS),
+ /* 1X*/ DUP16(MMU.UNUSED_RAM),
+ /* 2X*/ DUP16(MMU.MAIN_MEM),
+ /* 3X*/ DUP8(MMU.SWIRAM),
+ DUP8(MMU.ARM7_ERAM),
+ /* 4X*/ DUP8(MMU.ARM7_REG),
+ DUP8(MMU.ARM7_WIRAM),
+ /* 5X*/ DUP16(MMU.UNUSED_RAM),
+ /* 6X*/ DUP16(MMU.ARM9_LCD),
+ /* 7X*/ DUP16(MMU.UNUSED_RAM),
+ /* 8X*/ DUP16(NULL),
+ /* 9X*/ DUP16(NULL),
+ /* AX*/ DUP16(MMU.UNUSED_RAM),
+ /* BX*/ DUP16(MMU.UNUSED_RAM),
+ /* CX*/ DUP16(MMU.UNUSED_RAM),
+ /* DX*/ DUP16(MMU.UNUSED_RAM),
+ /* EX*/ DUP16(MMU.UNUSED_RAM),
+ /* FX*/ DUP16(MMU.UNUSED_RAM)
+ }
+};
+
+uint32_t MMU_struct::MMU_MASK[2][256] = {
+ //arm9
+ {
+ /* 0X*/ DUP16(0x00007FFF),
+ /* 1X*/ //DUP16(0x00007FFF)
+ /* 1X*/ DUP16(0x00000003),
+ /* 2X*/ DUP16(0x003FFFFF),
+ /* 3X*/ DUP16(0x00007FFF),
+ /* 4X*/ DUP16(0x00FFFFFF),
+ /* 5X*/ DUP16(0x000007FF),
+ /* 6X*/ DUP16(0x00FFFFFF),
+ /* 7X*/ DUP16(0x000007FF),
+ /* 8X*/ DUP16(0x00000003),
+ /* 9X*/ DUP16(0x00000003),
+ /* AX*/ DUP16(0x00000003),
+ /* BX*/ DUP16(0x00000003),
+ /* CX*/ DUP16(0x00000003),
+ /* DX*/ DUP16(0x00000003),
+ /* EX*/ DUP16(0x00000003),
+ /* FX*/ DUP16(0x00007FFF)
+ },
+ //arm7
+ {
+ /* 0X*/ DUP16(0x00003FFF),
+ /* 1X*/ DUP16(0x00000003),
+ /* 2X*/ DUP16(0x003FFFFF),
+ /* 3X*/ DUP8(0x00007FFF),
+ DUP8(0x0000FFFF),
+ /* 4X*/ DUP8(0x00FFFFFF),
+ DUP8(0x0000FFFF),
+ /* 5X*/ DUP16(0x00000003),
+ /* 6X*/ DUP16(0x00FFFFFF),
+ /* 7X*/ DUP16(0x00000003),
+ /* 8X*/ DUP16(0x00000003),
+ /* 9X*/ DUP16(0x00000003),
+ /* AX*/ DUP16(0x00000003),
+ /* BX*/ DUP16(0x00000003),
+ /* CX*/ DUP16(0x00000003),
+ /* DX*/ DUP16(0x00000003),
+ /* EX*/ DUP16(0x00000003),
+ /* FX*/ DUP16(0x00000003)
+ }
+};
+
+// this logic was moved to MMU_timing.h
+//CACHE_ALIGN
+//TWaitState MMU_struct::MMU_WAIT16[2][16] = {
+// { 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 1, 1, 1, 1, 1 }, //arm9
+// { 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 1, 1, 1, 1, 1 }, //arm7
+//};
+//
+//CACHE_ALIGN
+//TWaitState MMU_struct::MMU_WAIT32[2][16] = {
+// { 1, 1, 1, 1, 1, 2, 2, 1, 8, 8, 5, 1, 1, 1, 1, 1 }, //arm9
+// { 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 5, 1, 1, 1, 1, 1 }, //arm7
+//};
+
+//////////////////////////////////////////////////////////////
+
+//-------------
+//VRAM MEMORY MAPPING
+//-------------
+//(Everything is mapped through to ARM9_LCD in blocks of 16KB)
+
+//for all of the below, values = 41 indicate unmapped memory
+static const uint8_t VRAM_PAGE_UNMAPPED = 41;
+
+static const unsigned VRAM_LCDC_PAGES = 41;
+uint8_t vram_lcdc_map[VRAM_LCDC_PAGES];
+
+//in the range of 0x06000000 - 0x06800000 in 16KB pages (the ARM9 vram mappable area)
+//this maps to 16KB pages in the LCDC buffer which is what will actually contain the data
+uint8_t vram_arm9_map[VRAM_ARM9_PAGES];
+
+//this chooses which banks are mapped in the 128K banks starting at 0x06000000 in ARM7
+uint8_t vram_arm7_map[2];
+
+//----->
+//consider these later, for better recordkeeping, instead of using the uint8_t* in MMU
+
+////for each 128KB texture slot, this maps to a 16KB starting page in the LCDC buffer
+//#define VRAM_TEX_SLOTS 4
+//uint8_t vram_tex_map[VRAM_TEX_SLOTS];
+//
+////for each 16KB tex palette slot, this maps to a 16KB starting page in the LCDC buffer
+//#define VRAM_TEX_PALETTE_SLOTS 6
+//uint8_t vram_tex_palette_map[VRAM_TEX_PALETTE_SLOTS];
+
+//<---------
+
+
+//void MMU_VRAM_unmap_all();
+
+struct TVramBankInfo {
+ uint8_t page_addr, num_pages;
+};
+
+static const TVramBankInfo vram_bank_info[VRAM_BANKS] = {
+ {0,8},
+ {8,8},
+ {16,8},
+ {24,8},
+ {32,4},
+ {36,1},
+ {37,1},
+ {38,2},
+ {40,1}
+};
+
+//this is to remind you that the LCDC mapping returns a strange value (not 0x06800000) as you would expect
+//in order to play nicely with the MMU address and mask tables
+static const uint32_t LCDC_HACKY_LOCATION = 0x06000000;
+
+//maps an ARM9 BG/OBJ or LCDC address into an LCDC address, and informs the caller of whether it isn't mapped
+//TODO - in cases where this does some mapping work, we could bypass the logic at the end of the _read* and _write* routines
+//this is a good optimization to consider
+//template<int PROCNUM>
+static inline uint32_t MMU_LCDmap(uint32_t addr, bool& unmapped, bool& restricted)
+{
+ unmapped = false;
+ restricted = false; //this will track whether 8bit writes are allowed
+
+ //in case the address is entirely outside of the interesting ranges
+ if(addr < 0x06000000) return addr;
+ if(addr >= 0x07000000) return addr;
+
+ //shared wram mapping for arm7
+ /*if(PROCNUM==ARMCPU_ARM7)
+ {
+ //necessary? not sure
+ //addr &= 0x3FFFF;
+ //addr += 0x06000000;
+ uint32_t ofs = addr & 0x1FFFF;
+ uint32_t bank = (addr >> 17)&1;
+ if(vram_arm7_map[bank] == VRAM_PAGE_UNMAPPED)
+ {
+ unmapped = true;
+ return 0;
+ }
+ return LCDC_HACKY_LOCATION + (vram_arm7_map[bank]<<14) + ofs;
+ }*/
+
+ restricted = true;
+
+ //handle LCD memory mirroring
+ if(addr>=0x068A4000)
+ addr = 0x06800000 +
+ //(addr%0xA4000); //yuck!! is this even how it mirrors? but we have to keep from overrunning the buffer somehow
+ (addr&0x80000); //just as likely to be right (I have no clue how it should work) but faster.
+
+ uint32_t vram_page;
+ uint32_t ofs = addr & 0x3FFF;
+
+ //return addresses in LCDC range
+ if(addr>=0x06800000)
+ {
+ //already in LCDC range. just look it up to see whether it is unmapped
+ vram_page = (addr>>14)&63;
+ assert(vram_page<VRAM_LCDC_PAGES);
+ vram_page = vram_lcdc_map[vram_page];
+ }
+ else
+ {
+ //map addresses in BG/OBJ range to an LCDC range
+ vram_page = (addr>>14)&(VRAM_ARM9_PAGES-1);
+ assert(vram_page<VRAM_ARM9_PAGES);
+ vram_page = vram_arm9_map[vram_page];
+ }
+
+ if(vram_page == VRAM_PAGE_UNMAPPED)
+ {
+ unmapped = true;
+ return 0;
+ }
+ else
+ return LCDC_HACKY_LOCATION + (vram_page<<14) + ofs;
+}
+
+
+//#define LOG_VRAM_ERROR() LOG("No data for block %i MST %i\n", block, VRAMBankCnt & 0x07);
+
+VramConfiguration vramConfiguration;
+
+/*std::string VramConfiguration::describePurpose(Purpose p) {
+ switch(p) {
+ case OFF: return "OFF";
+ case INVALID: return "INVALID";
+ case ABG: return "ABG";
+ case BBG: return "BBG";
+ case AOBJ: return "AOBJ";
+ case BOBJ: return "BOBJ";
+ case LCDC: return "LCDC";
+ case ARM7: return "ARM7";
+ case TEX: return "TEX";
+ case TEXPAL: return "TEXPAL";
+ case ABGEXTPAL: return "ABGEXTPAL";
+ case BBGEXTPAL: return "BBGEXTPAL";
+ case AOBJEXTPAL: return "AOBJEXTPAL";
+ case BOBJEXTPAL: return "BOBJEXTPAL";
+ default: return "UNHANDLED CASE";
+ }
+}
+
+std::string VramConfiguration::describe() {
+ std::stringstream ret;
+ for(int i=0;i<VRAM_BANKS;i++) {
+ ret << (char)(i+'A') << ": " << banks[i].ofs << " " << describePurpose(banks[i].purpose) << std::endl;
+ }
+ return ret.str();
+}*/
+
+//maps the specified bank to LCDC
+static inline void MMU_vram_lcdc(const int bank)
+{
+ for(int i=0;i<vram_bank_info[bank].num_pages;i++)
+ {
+ int page = vram_bank_info[bank].page_addr+i;
+ vram_lcdc_map[page] = page;
+ }
+}
+
+//maps the specified bank to ARM9 at the provided page offset
+static inline void MMU_vram_arm9(const int bank, const int offset)
+{
+ for(int i=0;i<vram_bank_info[bank].num_pages;i++)
+ {
+ int page = vram_bank_info[bank].page_addr+i;
+
+ vram_arm9_map[i+offset] = page;
+ }
+}
+
+static inline uint8_t* MMU_vram_physical(const int page)
+{
+ return MMU.ARM9_LCD + (page/**ADDRESS_STEP_16KB*/);
+}
+
+//todo - templateize
+static inline void MMU_VRAMmapRefreshBank(const int bank)
+{
+ int block = bank;
+ if(bank >= VRAM_BANK_H) block++;
+
+ uint8_t VRAMBankCnt = T1ReadByte(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x240 + block);
+
+ //do nothing if the bank isnt enabled
+ uint8_t en = VRAMBankCnt & 0x80;
+ if(!en) return;
+
+ int mst,ofs=0;
+ switch(bank) {
+ case VRAM_BANK_A:
+ case VRAM_BANK_B:
+ mst = VRAMBankCnt & 3;
+ ofs = (VRAMBankCnt>>3) & 3;
+ switch(mst)
+ {
+ case 0: //LCDC
+ vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC;
+ MMU_vram_lcdc(bank);
+ //if(ofs != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs);
+ break;
+ case 1: //ABG
+ vramConfiguration.banks[bank].purpose = VramConfiguration::ABG;
+ MMU_vram_arm9(bank,VRAM_PAGE_ABG+ofs*8);
+ break;
+ case 2: //AOBJ
+ vramConfiguration.banks[bank].purpose = VramConfiguration::AOBJ;
+ switch(ofs) {
+ case 0:
+ case 1:
+ MMU_vram_arm9(bank,VRAM_PAGE_AOBJ+ofs*8);
+ break;
+ //default:
+ //PROGINFO("Unsupported ofs setting %d for engine A OBJ vram bank %c\n", ofs, 'A'+bank);
+ }
+ break;
+ case 3: //texture
+ vramConfiguration.banks[bank].purpose = VramConfiguration::TEX;
+ MMU.texInfo.textureSlotAddr[ofs] = MMU_vram_physical(vram_bank_info[bank].page_addr);
+ break;
+ default: goto unsupported_mst;
+ }
+ break;
+
+ case VRAM_BANK_C:
+ case VRAM_BANK_D:
+ mst = VRAMBankCnt & 7;
+ ofs = (VRAMBankCnt>>3) & 3;
+ switch(mst)
+ {
+ case 0: //LCDC
+ vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC;
+ MMU_vram_lcdc(bank);
+ //if(ofs != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs);
+ break;
+ case 1: //ABG
+ vramConfiguration.banks[bank].purpose = VramConfiguration::ABG;
+ MMU_vram_arm9(bank,VRAM_PAGE_ABG+ofs*8);
+ break;
+ case 2: //arm7
+ vramConfiguration.banks[bank].purpose = VramConfiguration::ARM7;
+ if(bank == 2) T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x240, T1ReadByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x240) | 1);
+ if(bank == 3) T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x240, T1ReadByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x240) | 2);
+ switch(ofs) {
+ case 0:
+ case 1:
+ vram_arm7_map[ofs] = vram_bank_info[bank].page_addr;
+ break;
+ //default:
+ //PROGINFO("Unsupported ofs setting %d for arm7 vram bank %c\n", ofs, 'A'+bank);
+ }
+
+ break;
+ case 3: //texture
+ vramConfiguration.banks[bank].purpose = VramConfiguration::TEX;
+ MMU.texInfo.textureSlotAddr[ofs] = MMU_vram_physical(vram_bank_info[bank].page_addr);
+ break;
+ case 4: //BGB or BOBJ
+ if(bank == VRAM_BANK_C) {
+ vramConfiguration.banks[bank].purpose = VramConfiguration::BBG;
+ MMU_vram_arm9(bank,VRAM_PAGE_BBG); //BBG
+ } else {
+ vramConfiguration.banks[bank].purpose = VramConfiguration::BOBJ;
+ MMU_vram_arm9(bank,VRAM_PAGE_BOBJ); //BOBJ
+ }
+ //if(ofs != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs);
+ break;
+ default: goto unsupported_mst;
+ }
+ break;
+
+ case VRAM_BANK_E:
+ mst = VRAMBankCnt & 7;
+ //if(((VRAMBankCnt>>3)&3) != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs);
+ switch(mst) {
+ case 0: //LCDC
+ vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC;
+ MMU_vram_lcdc(bank);
+ break;
+ case 1: //ABG
+ vramConfiguration.banks[bank].purpose = VramConfiguration::ABG;
+ MMU_vram_arm9(bank,VRAM_PAGE_ABG);
+ break;
+ case 2: //AOBJ
+ vramConfiguration.banks[bank].purpose = VramConfiguration::AOBJ;
+ MMU_vram_arm9(bank,VRAM_PAGE_AOBJ);
+ break;
+ case 3: //texture palette
+ vramConfiguration.banks[bank].purpose = VramConfiguration::TEXPAL;
+ MMU.texInfo.texPalSlot[0] = MMU_vram_physical(vram_bank_info[bank].page_addr);
+ MMU.texInfo.texPalSlot[1] = MMU_vram_physical(vram_bank_info[bank].page_addr+1);
+ MMU.texInfo.texPalSlot[2] = MMU_vram_physical(vram_bank_info[bank].page_addr+2);
+ MMU.texInfo.texPalSlot[3] = MMU_vram_physical(vram_bank_info[bank].page_addr+3);
+ break;
+ case 4: //A BG extended palette
+ vramConfiguration.banks[bank].purpose = VramConfiguration::ABGEXTPAL;
+ MMU.ExtPal[0][0] = MMU_vram_physical(vram_bank_info[bank].page_addr);
+ MMU.ExtPal[0][1] = MMU.ExtPal[0][0]/* + ADDRESS_STEP_8KB*/;
+ MMU.ExtPal[0][2] = MMU.ExtPal[0][1]/* + ADDRESS_STEP_8KB*/;
+ MMU.ExtPal[0][3] = MMU.ExtPal[0][2]/* + ADDRESS_STEP_8KB*/;
+ break;
+ default: goto unsupported_mst;
+ }
+ break;
+
+ case VRAM_BANK_F:
+ case VRAM_BANK_G: {
+ mst = VRAMBankCnt & 7;
+ ofs = (VRAMBankCnt>>3) & 3;
+ const int pageofslut[] = {0,1,4,5};
+ const int pageofs = pageofslut[ofs];
+ switch(mst)
+ {
+ case 0: //LCDC
+ vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC;
+ MMU_vram_lcdc(bank);
+ //if(ofs != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs);
+ break;
+ case 1: //ABG
+ vramConfiguration.banks[bank].purpose = VramConfiguration::ABG;
+ MMU_vram_arm9(bank,VRAM_PAGE_ABG+pageofs);
+ MMU_vram_arm9(bank,VRAM_PAGE_ABG+pageofs+2); //unexpected mirroring (required by spyro eternal night)
+ break;
+ case 2: //AOBJ
+ vramConfiguration.banks[bank].purpose = VramConfiguration::AOBJ;
+ MMU_vram_arm9(bank,VRAM_PAGE_AOBJ+pageofs);
+ MMU_vram_arm9(bank,VRAM_PAGE_AOBJ+pageofs+2); //unexpected mirroring - I have no proof, but it is inferred from the ABG above
+ break;
+ case 3: //texture palette
+ vramConfiguration.banks[bank].purpose = VramConfiguration::TEXPAL;
+ MMU.texInfo.texPalSlot[pageofs] = MMU_vram_physical(vram_bank_info[bank].page_addr);
+ break;
+ case 4: //A BG extended palette
+ switch(ofs) {
+ case 0:
+ case 1:
+ vramConfiguration.banks[bank].purpose = VramConfiguration::ABGEXTPAL;
+ MMU.ExtPal[0][ofs*2] = MMU_vram_physical(vram_bank_info[bank].page_addr);
+ MMU.ExtPal[0][ofs*2+1] = MMU.ExtPal[0][ofs*2]/* + ADDRESS_STEP_8KB*/;
+ break;
+ default:
+ vramConfiguration.banks[bank].purpose = VramConfiguration::INVALID;
+ //PROGINFO("Unsupported ofs setting %d for engine A bgextpal vram bank %c\n", ofs, 'A'+bank);
+ break;
+ }
+ break;
+ case 5: //A OBJ extended palette
+ vramConfiguration.banks[bank].purpose = VramConfiguration::AOBJEXTPAL;
+ MMU.ObjExtPal[0][0] = MMU_vram_physical(vram_bank_info[bank].page_addr);
+ MMU.ObjExtPal[0][1] = MMU.ObjExtPal[0][1]/* + ADDRESS_STEP_8KB*/;
+ //if(ofs != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs);
+ break;
+ default: goto unsupported_mst;
+ }
+ break;
+ }
+
+ case VRAM_BANK_H:
+ mst = VRAMBankCnt & 3;
+ //if(((VRAMBankCnt>>3)&3) != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs);
+ switch(mst)
+ {
+ case 0: //LCDC
+ vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC;
+ MMU_vram_lcdc(bank);
+ break;
+ case 1: //BBG
+ vramConfiguration.banks[bank].purpose = VramConfiguration::BBG;
+ MMU_vram_arm9(bank,VRAM_PAGE_BBG);
+ MMU_vram_arm9(bank,VRAM_PAGE_BBG + 4); //unexpected mirroring
+ break;
+ case 2: //B BG extended palette
+ vramConfiguration.banks[bank].purpose = VramConfiguration::BBGEXTPAL;
+ MMU.ExtPal[1][0] = MMU_vram_physical(vram_bank_info[bank].page_addr);
+ MMU.ExtPal[1][1] = MMU.ExtPal[1][0]/* + ADDRESS_STEP_8KB*/;
+ MMU.ExtPal[1][2] = MMU.ExtPal[1][1]/* + ADDRESS_STEP_8KB*/;
+ MMU.ExtPal[1][3] = MMU.ExtPal[1][2]/* + ADDRESS_STEP_8KB*/;
+ break;
+ default: goto unsupported_mst;
+ }
+ break;
+
+ case VRAM_BANK_I:
+ mst = VRAMBankCnt & 3;
+ //if(((VRAMBankCnt>>3)&3) != 0) PROGINFO("Bank %i: MST %i OFS %i\n", mst, ofs);
+ switch(mst)
+ {
+ case 0: //LCDC
+ vramConfiguration.banks[bank].purpose = VramConfiguration::LCDC;
+ MMU_vram_lcdc(bank);
+ break;
+ case 1: //BBG
+ vramConfiguration.banks[bank].purpose = VramConfiguration::BBG;
+ MMU_vram_arm9(bank,VRAM_PAGE_BBG+2);
+ MMU_vram_arm9(bank,VRAM_PAGE_BBG+3); //unexpected mirroring
+ break;
+ case 2: //BOBJ
+ vramConfiguration.banks[bank].purpose = VramConfiguration::BOBJ;
+ MMU_vram_arm9(bank,VRAM_PAGE_BOBJ);
+ MMU_vram_arm9(bank,VRAM_PAGE_BOBJ+1); //FF3 end scene (lens flare sprite) needs this as it renders a sprite off the end of the 16KB and back around
+ break;
+ case 3: //B OBJ extended palette
+ vramConfiguration.banks[bank].purpose = VramConfiguration::BOBJEXTPAL;
+ MMU.ObjExtPal[1][0] = MMU_vram_physical(vram_bank_info[bank].page_addr);
+ MMU.ObjExtPal[1][1] = MMU.ObjExtPal[1][1]/* + ADDRESS_STEP_8KB*/;
+ break;
+ default: goto unsupported_mst;
+ }
+ break;
+
+
+ } //switch(bank)
+
+ vramConfiguration.banks[bank].ofs = ofs;
+
+ return;
+
+unsupported_mst:
+ vramConfiguration.banks[bank].purpose = VramConfiguration::INVALID;
+ //PROGINFO("Unsupported mst setting %d for vram bank %c\n", mst, 'A'+bank);
+}
+
+void MMU_VRAM_unmap_all()
+{
+ vramConfiguration.clear();
+
+ vram_arm7_map[0] = VRAM_PAGE_UNMAPPED;
+ vram_arm7_map[1] = VRAM_PAGE_UNMAPPED;
+
+ for(int i=0;i<VRAM_LCDC_PAGES;i++)
+ vram_lcdc_map[i] = VRAM_PAGE_UNMAPPED;
+ for(int i=0;i<VRAM_ARM9_PAGES;i++)
+ vram_arm9_map[i] = VRAM_PAGE_UNMAPPED;
+
+ for (int i = 0; i < 4; i++)
+ {
+ MMU.ExtPal[0][i] = MMU.blank_memory;
+ MMU.ExtPal[1][i] = MMU.blank_memory;
+ }
+
+ MMU.ObjExtPal[0][0] = MMU.blank_memory;
+ MMU.ObjExtPal[0][1] = MMU.blank_memory;
+ MMU.ObjExtPal[1][0] = MMU.blank_memory;
+ MMU.ObjExtPal[1][1] = MMU.blank_memory;
+
+ for(int i=0;i<6;i++)
+ MMU.texInfo.texPalSlot[i] = MMU.blank_memory;
+
+ for(int i=0;i<4;i++)
+ MMU.texInfo.textureSlotAddr[i] = MMU.blank_memory;
+}
+
+static inline void MMU_VRAMmapControl(uint8_t block, uint8_t VRAMBankCnt)
+{
+ //dont handle wram mappings in here
+ if(block == 7) {
+ //wram
+ return;
+ }
+
+ //first, save the texture info so we can check it for changes and trigger purges of the texcache
+ MMU_struct::TextureInfo oldTexInfo = MMU.texInfo;
+
+ //unmap everything
+ MMU_VRAM_unmap_all();
+
+ //unmap VRAM_BANK_C and VRAM_BANK_D from arm7. theyll get mapped again in a moment if necessary
+ T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x240, 0);
+
+ //write the new value to the reg
+ T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x240 + block, VRAMBankCnt);
+
+ //refresh all bank settings
+ //these are enumerated so that we can tune the order they get applied
+ //in order to emulate prioritization rules for memory regions
+ //with multiple banks mapped.
+ //We're probably still not mapping things 100% correctly, but this helped us get closer:
+ //goblet of fire "care of magical creatures" maps I and D to BOBJ (the I is an accident)
+ //and requires A to override it.
+ //This may create other bugs....
+ MMU_VRAMmapRefreshBank(VRAM_BANK_I);
+ MMU_VRAMmapRefreshBank(VRAM_BANK_H);
+ MMU_VRAMmapRefreshBank(VRAM_BANK_G);
+ MMU_VRAMmapRefreshBank(VRAM_BANK_F);
+ MMU_VRAMmapRefreshBank(VRAM_BANK_E);
+ MMU_VRAMmapRefreshBank(VRAM_BANK_D);
+ MMU_VRAMmapRefreshBank(VRAM_BANK_C);
+ MMU_VRAMmapRefreshBank(VRAM_BANK_B);
+ MMU_VRAMmapRefreshBank(VRAM_BANK_A);
+
+ //printf(vramConfiguration.describe().c_str());
+ //printf("vram remapped at vcount=%d\n",nds.VCount);
+
+ //if texInfo changed, trigger notifications
+ if(memcmp(&oldTexInfo,&MMU.texInfo,sizeof(MMU_struct::TextureInfo)))
+ {
+ //if(!nds.isIn3dVblank())
+ // PROGINFO("Changing texture or texture palette mappings outside of 3d vblank\n");
+ //gpu3D->NDS_3D_VramReconfigureSignal();
+ }
+
+ //-------------------------------
+ //set up arm9 mirrorings
+ //these are probably not entirely accurate. more study will be necessary.
+ //in general, we find that it is not uncommon at all for games to accidentally do this.
+ //
+ //being able to easily do these experiments was one of the primary motivations for this remake of the vram mapping system
+
+ //see the "unexpected mirroring" comments above for some more mirroring
+ //so far "unexpected mirrorings" are tested by combining these games:
+ //despereaux - storybook subtitles
+ //NSMB - world map sub screen
+ //drill spirits EU - mission select (just for control purposes, as it doesnt use H or I)
+ //...
+ //note that the "unexpected mirroring" items above may at some point rely on being executed in a certain order.
+ //(sequentially A..I)
+
+ const int types[] = {VRAM_PAGE_ABG,VRAM_PAGE_BBG,VRAM_PAGE_AOBJ,VRAM_PAGE_BOBJ};
+ const int sizes[] = {32,8,16,8};
+ for(int t=0;t<4;t++)
+ {
+ //the idea here is to pad out the mirrored space with copies of the mappable area,
+ //without respect to what is mapped within that mappable area.
+ //we hope that this is correct in all cases
+ //required for driller spirits in mission select (mapping is simple A,B,C,D to each purpose)
+ const int size = sizes[t];
+ const int mask = size-1;
+ const int type = types[t];
+ for(int i=size;i<128;i++)
+ {
+ const int page = type + i;
+ vram_arm9_map[page] = vram_arm9_map[type+(i&mask)];
+ }
+
+ //attempt #1: screen corruption in drill spirits EU
+ //it seems like these shouldnt pad out 128K banks (space beyond those should have remained unmapped)
+ //int mirrorMask = -1;
+ //int type = types[t];
+ ////if(type==VRAM_PAGE_BOBJ) continue;
+ //if(type==VRAM_PAGE_AOBJ) continue;
+ //for(int i=0;i<128;i++)
+ //{
+ // int page = type + i;
+ // if(vram_arm9_map[page] == VRAM_PAGE_UNMAPPED)
+ // {
+ // if(i==0) break; //can't mirror anything if theres nothing mapped!
+ // if(mirrorMask == -1)
+ // mirrorMask = i-1;
+ // vram_arm9_map[page] = vram_arm9_map[type+(i&mirrorMask)];
+ // }
+ //}
+ }
+
+ //-------------------------------
+}
+
+//////////////////////////////////////////////////////////////
+//end vram
+//////////////////////////////////////////////////////////////
+
+
+
+void MMU_Init() {
+ //LOG("MMU init\n");
+
+ memset(&MMU, 0, sizeof(MMU_struct));
+
+ MMU.CART_ROM = MMU.UNUSED_RAM;
+
+ //MMU.DTCMRegion = 0x027C0000;
+ //even though apps may change dtcm immediately upon startup, this is the correct hardware starting value:
+ MMU.DTCMRegion = 0x08000000;
+ MMU.ITCMRegion = 0x00000000;
+
+ IPC_FIFOinit(ARMCPU_ARM9);
+ IPC_FIFOinit(ARMCPU_ARM7);
+ //GFX_PIPEclear();
+ //GFX_FIFOclear();
+ //DISP_FIFOinit();
+ new(&MMU_new) MMU_struct_new;
+
+ mc_init(&MMU.fw, MC_TYPE_FLASH); /* init fw device */
+ mc_alloc(&MMU.fw, NDS_FW_SIZE_V1);
+ MMU.fw.fp = NULL;
+ MMU.fw.isFirmware = true;
+
+ // Init Backup Memory device, this should really be done when the rom is loaded
+ //mc_init(&MMU.bupmem, MC_TYPE_AUTODETECT);
+ //mc_alloc(&MMU.bupmem, 1);
+ //MMU.bupmem.fp = NULL;
+ //rtcInit();
+ //addonsInit();
+ //slot1Init();
+ /*if(Mic_Init() == false)
+ INFO("Microphone init failed.\n");
+ else
+ INFO("Microphone successfully inited.\n");*/
+}
+
+void MMU_DeInit() {
+ //LOG("MMU deinit\n");
+ /*if (MMU.fw.fp)
+ fclose(MMU.fw.fp);*/
+ mc_free(&MMU.fw);
+ //if (MMU.bupmem.fp)
+ // fclose(MMU.bupmem.fp);
+ //mc_free(&MMU.bupmem);
+ //addonsClose();
+ //slot1Close();
+ //Mic_DeInit();
+}
+
+void MMU_Reset()
+{
+ memset(MMU.ARM9_DTCM, 0, sizeof(MMU.ARM9_DTCM));
+ memset(MMU.ARM9_ITCM, 0, sizeof(MMU.ARM9_ITCM));
+ memset(MMU.ARM9_LCD, 0, sizeof(MMU.ARM9_LCD));
+ memset(MMU.ARM9_OAM, 0, sizeof(MMU.ARM9_OAM));
+ memset(MMU.ARM9_REG, 0, sizeof(MMU.ARM9_REG));
+ memset(MMU.ARM9_VMEM, 0, sizeof(MMU.ARM9_VMEM));
+ memset(MMU.MAIN_MEM, 0, sizeof(MMU.MAIN_MEM));
+
+ memset(MMU.blank_memory, 0, sizeof(MMU.blank_memory));
+ memset(MMU.UNUSED_RAM, 0, sizeof(MMU.UNUSED_RAM));
+ memset(MMU.MORE_UNUSED_RAM, 0, sizeof(MMU.UNUSED_RAM));
+
+ memset(MMU.ARM7_ERAM, 0, sizeof(MMU.ARM7_ERAM));
+ memset(MMU.ARM7_REG, 0, sizeof(MMU.ARM7_REG));
+ memset(MMU.ARM7_WIRAM, 0, sizeof(MMU.ARM7_WIRAM));
+ memset(MMU.SWIRAM, 0, sizeof(MMU.SWIRAM));
+
+ IPC_FIFOinit(ARMCPU_ARM9);
+ IPC_FIFOinit(ARMCPU_ARM7);
+ //GFX_PIPEclear();
+ //GFX_FIFOclear();
+ //DISP_FIFOinit();
+
+ MMU.DTCMRegion = 0x027C0000;
+ MMU.ITCMRegion = 0x00000000;
+
+ memset(MMU.timer, 0, sizeof(uint16_t) * 2 * 4);
+ memset(MMU.timerMODE, 0, sizeof(int32_t) * 2 * 4);
+ memset(MMU.timerON, 0, sizeof(uint32_t) * 2 * 4);
+ memset(MMU.timerRUN, 0, sizeof(uint32_t) * 2 * 4);
+ memset(MMU.timerReload, 0, sizeof(uint16_t) * 2 * 4);
+
+ memset(MMU.reg_IME, 0, sizeof(uint32_t) * 2);
+ memset(MMU.reg_IE, 0, sizeof(uint32_t) * 2);
+ memset(MMU.reg_IF_bits, 0, sizeof(uint32_t) * 2);
+ memset(MMU.reg_IF_pending, 0, sizeof(uint32_t) * 2);
+
+ memset(MMU.dscard, 0, sizeof(nds_dscard) * 2);
+
+ MMU.divRunning = 0;
+ MMU.divResult = 0;
+ MMU.divMod = 0;
+ MMU.divCycles = 0;
+
+ MMU.sqrtRunning = 0;
+ MMU.sqrtResult = 0;
+ MMU.sqrtCycles = 0;
+
+ MMU.SPI_CNT = 0;
+ MMU.AUX_SPI_CNT = 0;
+
+ // Enable the sound speakers
+ T1WriteWord(MMU.ARM7_REG, 0x304, 0x0001);
+
+ //MainScreen.offset = 0;
+ //SubScreen.offset = 192;
+
+ MMU_VRAM_unmap_all();
+
+ MMU.powerMan_CntReg = 0x00;
+ MMU.powerMan_CntRegWritten = false;
+ MMU.powerMan_Reg[0] = 0x0B;
+ MMU.powerMan_Reg[1] = 0x00;
+ MMU.powerMan_Reg[2] = 0x01;
+ MMU.powerMan_Reg[3] = 0x00;
+
+ //rtcInit();
+ partie = 1;
+ //addonsReset();
+ //slot1Reset();
+ //Mic_Reset();
+ //MMU.gfx3dCycles = 0;
+
+ memset(MMU.dscard[ARMCPU_ARM9].command, 0, 8);
+ MMU.dscard[ARMCPU_ARM9].address = 0;
+ MMU.dscard[ARMCPU_ARM9].transfer_count = 0;
+ MMU.dscard[ARMCPU_ARM9].mode = CardMode_Normal;
+
+ memset(MMU.dscard[ARMCPU_ARM7].command, 0, 8);
+ MMU.dscard[ARMCPU_ARM7].address = 0;
+ MMU.dscard[ARMCPU_ARM7].transfer_count = 0;
+ MMU.dscard[ARMCPU_ARM7].mode = CardMode_Normal;
+
+ //HACK!!!
+ //until we improve all our session tracking stuff, we need to save the backup memory filename
+ std::string bleh = MMU_new.backupDevice.getFilename();
+ BackupDevice tempBackupDevice;
+ //bool bleh2 = MMU_new.backupDevice.isMovieMode;
+ //if(bleh2) tempBackupDevice = MMU_new.backupDevice;
+ reconstruct(&MMU_new);
+ /*if(bleh2) {
+ MMU_new.backupDevice = tempBackupDevice;
+ MMU_new.backupDevice.reset_hardware();
+ }
+ else*/ MMU_new.backupDevice.load_rom(bleh.c_str());
+
+ MMU_timing.arm7codeFetch.Reset();
+ MMU_timing.arm7dataFetch.Reset();
+ MMU_timing.arm9codeFetch.Reset();
+ MMU_timing.arm9dataFetch.Reset();
+ MMU_timing.arm9codeCache.Reset();
+ MMU_timing.arm9dataCache.Reset();
+}
+
+void SetupMMU(bool debugConsole, bool dsi) {
+ if(debugConsole) _MMU_MAIN_MEM_MASK = 0x7FFFFF;
+ else _MMU_MAIN_MEM_MASK = 0x3FFFFF;
+ if(dsi) _MMU_MAIN_MEM_MASK = 0xFFFFFF;
+ _MMU_MAIN_MEM_MASK16 = _MMU_MAIN_MEM_MASK & ~1;
+ _MMU_MAIN_MEM_MASK32 = _MMU_MAIN_MEM_MASK & ~3;
+}
+
+void MMU_setRom(uint8_t * rom, uint32_t)
+{
+ MMU.CART_ROM = rom;
+}
+
+void MMU_unsetRom()
+{
+ MMU.CART_ROM=MMU.UNUSED_RAM;
+}
+
+static void execsqrt() {
+ uint32_t ret;
+ uint8_t mode = MMU_new.sqrt.mode;
+ MMU_new.sqrt.busy = 1;
+
+ if (mode) {
+ uint64_t v = T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B8);
+ ret = (uint32_t)isqrt(v);
+ } else {
+ uint32_t v = T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B8);
+ ret = (uint32_t)isqrt(v);
+ }
+
+ //clear the result while the sqrt unit is busy
+ //todo - is this right? is it reasonable?
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B4, 0);
+
+ MMU.sqrtCycles = nds_timer + 26;
+ MMU.sqrtResult = ret;
+ MMU.sqrtRunning = true;
+ NDS_Reschedule();
+}
+
+static void execdiv() {
+
+ int64_t num,den;
+ int64_t res,mod;
+ uint8_t mode = MMU_new.div.mode;
+ MMU_new.div.busy = 1;
+ MMU_new.div.div0 = 0;
+
+ switch(mode)
+ {
+ case 0: // 32/32
+ num = (int64_t) (int32_t) T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290);
+ den = (int64_t) (int32_t) T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298);
+ MMU.divCycles = nds_timer + 36;
+ break;
+ case 1: // 64/32
+ case 3: //gbatek says this is same as mode 1
+ num = (int64_t) T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290);
+ den = (int64_t) (int32_t) T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298);
+ MMU.divCycles = nds_timer + 68;
+ break;
+ case 2: // 64/64
+ default:
+ num = (int64_t) T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290);
+ den = (int64_t) T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298);
+ MMU.divCycles = nds_timer + 68;
+ break;
+ }
+
+ if(den==0)
+ {
+ res = ((num < 0) ? 1 : -1);
+ mod = num;
+
+ // the DIV0 flag in DIVCNT is set only if the full 64bit DIV_DENOM value is zero, even in 32bit mode
+ if ((uint64_t)T1ReadQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298) == 0)
+ MMU_new.div.div0 = 1;
+ }
+ else
+ {
+ res = num / den;
+ mod = num % den;
+ }
+
+ /*DIVLOG("DIV %08X%08X / %08X%08X = %08X%08X\r\n", (uint32_t)(num>>32), (uint32_t)num,
+ (uint32_t)(den>>32), (uint32_t)den,
+ (uint32_t)(res>>32), (uint32_t)res);*/
+
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, 0);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, 0);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, 0);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, 0);
+
+ MMU.divResult = res;
+ MMU.divMod = mod;
+ MMU.divRunning = true;
+ NDS_Reschedule();
+}
+
+DSI_TSC::DSI_TSC()
+{
+ for(unsigned i=0;i<ARRAY_SIZE(registers);i++)
+ registers[i] = 0x00;
+ reset_command();
+}
+
+void DSI_TSC::reset_command()
+{
+ state = 0;
+ readcount = 0;
+ read_flag = 1;
+}
+
+uint16_t DSI_TSC::write16(uint16_t val)
+{
+ uint16_t ret;
+ switch(state)
+ {
+ case 0:
+ reg_selection = (val>>1)&0x7F;
+ read_flag = val&1;
+ state = 1;
+ return read16();
+ case 1:
+ if(read_flag)
+ { }
+ else
+ {
+ registers[reg_selection] = (uint8_t)val;
+ }
+ ret = read16();
+ reg_selection++;
+ reg_selection &= 0x7F;
+ return ret;
+ }
+ return 0;
+}
+
+uint16_t DSI_TSC::read16()
+{
+ uint8_t page = registers[0];
+ switch(page)
+ {
+ case 3: //page 3
+ switch(reg_selection)
+ {
+ case 9:
+ /*if(nds.isTouch)
+ return 0;
+ else */return 0x40;
+ break;
+ case 14:
+ /*if(nds.isTouch)
+ return 0;
+ else */return 0x02;
+ break;
+ }
+ break;
+
+ case 252: //page 252
+ switch(reg_selection)
+ {
+ //high byte of X:
+ /*case 1: case 3: case 5: case 7: case 9:
+ return (nds.scr_touchX>>8)&0xFF;
+
+ //low byte of X:
+ case 2: case 4: case 6: case 8: case 10:
+ return nds.scr_touchX&0xFF;
+
+ //high byte of Y:
+ case 11: case 13: case 15: case 17: case 19:
+ return (nds.scr_touchY>>8)&0xFF;
+
+ //low byte of Y:
+ case 12: case 14: case 16: case 18: case 20:
+ return nds.scr_touchY&0xFF;*/
+
+ default:
+ return 0xFF;
+ }
+ break;
+ } //switch(page)
+
+ //unknown page or register
+ return 0xFF;
+}
+
+/*bool DSI_TSC::save_state(EMUFILE* os)
+{
+ uint32_t version = 0;
+ write32le(version,os);
+
+ write8le(reg_selection,os);
+ write8le(read_flag,os);
+ write32le(state,os);
+ write32le(readcount,os);
+ for(int i=0;i<ARRAY_SIZE(registers);i++)
+ write8le(registers[i],os);
+
+ return true;
+}*/
+
+/*bool DSI_TSC::load_state(EMUFILE* is)
+{
+ uint32_t version;
+ read32le(&version,is);
+
+ read8le(®_selection,is);
+ read8le(&read_flag,is);
+ read32le(&state,is);
+ read32le(&readcount,is);
+ for(int i=0;i<ARRAY_SIZE(registers);i++)
+ read8le(®isters[i],is);
+
+ return true;
+}*/
+
+// TODO:
+// NAND flash support (used in Made in Ore/WarioWare D.I.Y.)
+template<int PROCNUM>
+void FASTCALL MMU_writeToGCControl(uint32_t val)
+{
+ const int TEST_PROCNUM = PROCNUM;
+ nds_dscard& card = MMU.dscard[TEST_PROCNUM];
+
+ memcpy(&card.command[0], &MMU.MMU_MEM[TEST_PROCNUM][0x40][0x1A8], 8);
+
+ card.blocklen = 0;
+ slot1_device.write32(PROCNUM,0xFFFFFFFF,val); //Special case for some flashcarts
+ if(card.blocklen==0x01020304) return;
+
+ if(!(val & 0x80000000))
+ {
+ card.address = 0;
+ card.transfer_count = 0;
+
+ val &= 0x7F7FFFFF;
+ T1WriteLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4, val);
+ return;
+ }
+
+ uint32_t shift = (val>>24&7);
+ if(shift == 7)
+ card.transfer_count = 1;
+ else if(shift == 0)
+ card.transfer_count = 0;
+ else
+ card.transfer_count = (0x100<<shift)/4;
+
+ switch (card.mode)
+ {
+ case CardMode_Normal:
+ break;
+
+ case CardMode_KEY1:
+ {
+ // TODO
+ //INFO("Cartridge: KEY1 mode unsupported.\n");
+
+ card.address = 0;
+ card.transfer_count = 0;
+
+ val &= 0x7F7FFFFF;
+ T1WriteLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4, val);
+ return;
+ }
+ break;
+ case CardMode_KEY2:
+ //INFO("Cartridge: KEY2 mode unsupported.\n");
+ break;
+ }
+
+ switch(card.command[0])
+ {
+ case 0x9F: //Dummy
+ card.address = 0;
+ card.transfer_count = 0x800;
+ break;
+
+ //case 0x90: //Get ROM chip ID
+ // break;
+
+ case 0x3C: //Switch to KEY1 mode
+ card.mode = CardMode_KEY1;
+ break;
+
+ default:
+ //fall through to the special slot1 handler
+ slot1_device.write32(TEST_PROCNUM, REG_GCROMCTRL,val);
+ break;
+ }
+
+ if(card.transfer_count == 0)
+ {
+ val &= 0x7F7FFFFF;
+ T1WriteLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4, val);
+ return;
+ }
+
+ val |= 0x00800000;
+ T1WriteLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4, val);
+
+ // Launch DMA if start flag was set to "DS Cart"
+ //printf("triggering card dma\n");
+ triggerDma(EDMAMode_Card);
+}
+
+
+
+template<int PROCNUM>
+uint32_t MMU_readFromGC()
+{
+ const int TEST_PROCNUM = PROCNUM;
+
+ nds_dscard& card = MMU.dscard[TEST_PROCNUM];
+ uint32_t val = 0;
+
+ if(card.transfer_count == 0)
+ return 0;
+
+ switch(card.command[0])
+ {
+ case 0x9F: //Dummy
+ val = 0xFFFFFFFF;
+ break;
+
+ case 0x3C: //Switch to KEY1 mode
+ val = 0xFFFFFFFF;
+ break;
+
+ default:
+ val = slot1_device.read32(TEST_PROCNUM, REG_GCDATAIN);
+ break;
+ }
+
+ card.address += 4; // increment address
+
+ card.transfer_count--; // update transfer counter
+ if(card.transfer_count) // if transfer is not ended
+ return val; // return data
+
+ // transfer is done
+ T1WriteLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4,
+ T1ReadLong(MMU.MMU_MEM[TEST_PROCNUM][0x40], 0x1A4) & 0x7F7FFFFF);
+
+ // if needed, throw irq for the end of transfer
+ if(MMU.AUX_SPI_CNT & 0x4000)
+ NDS_makeIrq(TEST_PROCNUM, IRQ_BIT_GC_TRANSFER_COMPLETE);
+
+ return val;
+}
+
+
+
+//does some validation on the game's choice of IF value, correcting it if necessary
+/*static void validateIF_arm9()
+{
+}*/
+
+template<int PROCNUM> static void REG_IF_WriteByte(uint32_t addr, uint8_t val)
+{
+ //the following bits are generated from logic and should not be affected here
+ //Bit 21 NDS9 only: Geometry Command FIFO
+ //arm9: IF &= ~0x00200000;
+ //arm7: IF &= ~0x00000000;
+ //UPDATE IN setIF() ALSO!!!!!!!!!!!!!!!!
+ //UPDATE IN mmu_loadstate ALSO!!!!!!!!!!!!
+ if(addr==2)
+ {
+ if(PROCNUM==ARMCPU_ARM9)
+ val &= ~0x20;
+ else
+ val &= ~0x00;
+ }
+
+ //ZERO 01-dec-2010 : I am no longer sure this approach is correct.. it proved to be wrong for IPC fifo.......
+ //it seems as if IF bits should always be cached (only the user can clear them)
+
+ MMU.reg_IF_bits[PROCNUM] &= (~(((uint32_t)val)<<(addr<<3)));
+ NDS_Reschedule();
+}
+
+template<int PROCNUM> static void REG_IF_WriteWord(uint32_t addr,uint16_t val)
+{
+ REG_IF_WriteByte<PROCNUM>(addr,val&0xFF);
+ REG_IF_WriteByte<PROCNUM>(addr+1,(val>>8)&0xFF);
+}
+
+template<int PROCNUM> static void REG_IF_WriteLong(uint32_t val)
+{
+ REG_IF_WriteByte<PROCNUM>(0,val&0xFF);
+ REG_IF_WriteByte<PROCNUM>(1,(val>>8)&0xFF);
+ REG_IF_WriteByte<PROCNUM>(2,(val>>16)&0xFF);
+ REG_IF_WriteByte<PROCNUM>(3,(val>>24)&0xFF);
+}
+
+template<int PROCNUM>
+uint32_t MMU_struct::gen_IF()
+{
+ uint32_t IF = reg_IF_bits[PROCNUM];
+
+ /*if(PROCNUM==ARMCPU_ARM9)
+ {
+ //according to gbatek, these flags are forced on until the condition is removed.
+ //no proof of this though...
+ switch(MMU_new.gxstat.gxfifo_irq)
+ {
+ case 0: //never
+ break;
+ case 1: //less than half full
+ if(MMU_new.gxstat.fifo_low)
+ IF |= IRQ_MASK_ARM9_GXFIFO;
+ break;
+ case 2: //empty
+ if(MMU_new.gxstat.fifo_empty)
+ IF |= IRQ_MASK_ARM9_GXFIFO;
+ break;
+ case 3: //reserved/unknown
+ break;
+ }
+ }*/
+
+ return IF;
+}
+
+/*static void writereg_DISP3DCNT(const int size, const uint32_t adr, const uint32_t val)
+{
+ //UGH. rewrite this shite to use individual values and reconstruct the return value instead of packing things in this !@#)ing register
+
+ //nanostray2 cutscene will test this vs old desmumes by using some kind of 32bit access for setting up this reg for cutscenes
+ switch(size)
+ {
+ case 8:
+ switch(adr)
+ {
+ case REG_DISPA_DISP3DCNT:
+ MMU.reg_DISP3DCNT_bits &= 0xFFFFFF00;
+ MMU.reg_DISP3DCNT_bits |= val;
+ //gfx3d_Control(MMU.reg_DISP3DCNT_bits);
+ break;
+ case REG_DISPA_DISP3DCNT+1:
+ {
+ uint32_t myval = (val & ~0x30) | (~val & ((MMU.reg_DISP3DCNT_bits>>8) & 0x30)); // bits 12,13 are ack bits
+ myval &= 0x7F; //top bit isnt connected
+ MMU.reg_DISP3DCNT_bits = MMU.reg_DISP3DCNT_bits&0xFFFF00FF;
+ MMU.reg_DISP3DCNT_bits |= (myval<<8);
+ //gfx3d_Control(MMU.reg_DISP3DCNT_bits);
+ }
+ break;
+ }
+ break;
+ case 16:
+ case 32:
+ writereg_DISP3DCNT(8,adr,val&0xFF);
+ writereg_DISP3DCNT(8,adr+1,(val>>8)&0xFF);
+ break;
+ }
+}*/
+
+/*static uint32_t readreg_DISP3DCNT(const int size, const uint32_t adr)
+{
+ //UGH. rewrite this shite to use individual values and reconstruct the return value instead of packing things in this !@#)ing register
+ switch(size)
+ {
+ case 8:
+ switch(adr)
+ {
+ case REG_DISPA_DISP3DCNT:
+ return MMU.reg_DISP3DCNT_bits & 0xFF;
+ case REG_DISPA_DISP3DCNT+1:
+ return ((MMU.reg_DISP3DCNT_bits)>>8)& 0xFF;
+ }
+ break;
+ case 16:
+ case 32:
+ return readreg_DISP3DCNT(8,adr)|(readreg_DISP3DCNT(8,adr+1)<<8);
+ }
+ assert(false);
+ return 0;
+}*/
+
+
+/*static uint32_t readreg_POWCNT1(const int size, const uint32_t adr) {
+ switch(size)
+ {
+ case 8:
+ switch(adr)
+ {
+ case REG_POWCNT1: {
+ uint8_t ret = 0;
+ ret |= nds.power1.lcd?BIT(0):0;
+ ret |= nds.power1.gpuMain?BIT(1):0;
+ ret |= nds.power1.gfx3d_render?BIT(2):0;
+ ret |= nds.power1.gfx3d_geometry?BIT(3):0;
+ return ret;
+ }
+ case REG_POWCNT1+1: {
+ uint8_t ret = 0;
+ ret |= nds.power1.gpuSub?BIT(1):0;
+ ret |= nds.power1.dispswap?BIT(7):0;
+ return ret;
+ }
+ }
+ case 16:
+ case 32:
+ return readreg_POWCNT1(8,adr)|(readreg_POWCNT1(8,adr+1)<<8);
+ }
+ assert(false);
+ return 0;
+}*/
+/*static void writereg_POWCNT1(const int size, const uint32_t adr, const uint32_t val) {
+ switch(size)
+ {
+ case 8:
+ switch(adr)
+ {
+ case REG_POWCNT1:
+ nds.power1.lcd = BIT0(val);
+ nds.power1.gpuMain = BIT1(val);
+ nds.power1.gfx3d_render = BIT2(val);
+ nds.power1.gfx3d_geometry = BIT3(val);
+ break;
+ case REG_POWCNT1+1:
+ nds.power1.gpuSub = BIT1(val);
+ nds.power1.dispswap = BIT7(val);
+ if(nds.power1.dispswap)
+ {
+ //printf("Main core on top (vcount=%d)\n",nds.VCount);
+ //MainScreen.offset = 0;
+ //SubScreen.offset = 192;
+ }
+ else
+ {
+ //printf("Main core on bottom (vcount=%d)\n",nds.VCount);
+ //MainScreen.offset = 192;
+ //SubScreen.offset = 0;
+ }
+ break;
+ }
+ break;
+ case 16:
+ case 32:
+ writereg_POWCNT1(8,adr,val&0xFF);
+ writereg_POWCNT1(8,adr+1,(val>>8)&0xFF);
+ break;
+ }
+}*/
+
+static inline void MMU_IPCSync(uint8_t proc, uint32_t val)
+{
+ //INFO("IPC%s sync 0x%04X (0x%02X|%02X)\n", proc?"7":"9", val, val >> 8, val & 0xFF);
+ uint32_t sync_l = T1ReadLong(MMU.MMU_MEM[proc][0x40], 0x180) & 0xFFFF;
+ uint32_t sync_r = T1ReadLong(MMU.MMU_MEM[proc^1][0x40], 0x180) & 0xFFFF;
+
+ sync_l = ( sync_l & 0x000F ) | ( val & 0x0F00 );
+ sync_r = ( sync_r & 0x6F00 ) | ( (val >> 8) & 0x000F );
+
+ sync_l |= val & 0x6000;
+
+ /*if(nds.ensataEmulation && proc==1 && nds.ensataIpcSyncCounter<9) {
+ uint32_t iteration = (val&0x0F00)>>8;*/
+
+ /*if(iteration==8-nds.ensataIpcSyncCounter)
+ nds.ensataIpcSyncCounter++;
+ else printf("ERROR: ENSATA IPC SYNC HACK FAILED; BAD THINGS MAY HAPPEN\n");*/
+
+ //for some reason, the arm9 doesn't handshake when ensata is detected.
+ //so we complete the protocol here, which is to mirror the values 8..0 back to
+ //the arm7 as they are written by the arm7
+ /*sync_r &= 0xF0FF;
+ sync_r |= (iteration<<8);
+ sync_l &= 0xFFF0;
+ sync_l |= iteration;
+ }*/
+
+ T1WriteLong(MMU.MMU_MEM[proc][0x40], 0x180, sync_l);
+ T1WriteLong(MMU.MMU_MEM[proc^1][0x40], 0x180, sync_r);
+
+ if ((sync_l & IPCSYNC_IRQ_SEND) && (sync_r & IPCSYNC_IRQ_RECV))
+ NDS_makeIrq(proc^1, IRQ_BIT_IPCSYNC);
+
+ NDS_Reschedule();
+}
+
+static inline uint16_t read_timer(int proc, int timerIndex)
+{
+ //chained timers are always up to date
+ if(MMU.timerMODE[proc][timerIndex] == 0xFFFF)
+ return MMU.timer[proc][timerIndex];
+
+ //sometimes a timer will be read when it is not enabled.
+ //we should have the value cached
+ if(!MMU.timerON[proc][timerIndex])
+ return MMU.timer[proc][timerIndex];
+
+ //for unchained timers, we do not keep the timer up to date. its value will need to be calculated here
+ int32_t diff = (int32_t)(nds.timerCycle[proc][timerIndex] - nds_timer);
+ assert(diff>=0);
+ if(diff<0)
+ printf("NEW EMULOOP BAD NEWS PLEASE REPORT: TIME READ DIFF < 0 (%d) (%d) (%d)\n",diff,timerIndex,MMU.timerMODE[proc][timerIndex]);
+
+ int32_t units = diff / (1<<MMU.timerMODE[proc][timerIndex]);
+ int32_t ret;
+
+ if(units==65536)
+ ret = 0; //I'm not sure why this is happening...
+ //whichever instruction setup this counter should advance nds_timer (I think?) and the division should truncate down to 65535 immediately
+ else if(units>65536) {
+ printf("NEW EMULOOP BAD NEWS PLEASE REPORT: UNITS %d:%d = %d\n",proc,timerIndex,units);
+ ret = 0;
+ }
+ else ret = 65535 - units;
+
+ return static_cast<uint16_t>(ret);
+}
+
+static inline void write_timer(int proc, int timerIndex, uint16_t val)
+{
+#if 0
+ int mask = ((val&0x80)>>7) << timerIndex;
+ MMU.CheckTimers = (MMU.CheckTimers & (~mask)) | mask;
+#endif
+
+ if(val&0x80)
+ MMU.timer[proc][timerIndex] = MMU.timerReload[proc][timerIndex];
+ else
+ {
+ if(MMU.timerON[proc][timerIndex])
+ //read the timer value one last time
+ MMU.timer[proc][timerIndex] = read_timer(proc,timerIndex);
+ }
+
+ MMU.timerON[proc][timerIndex] = val & 0x80;
+
+ switch(val&7)
+ {
+ case 0 :
+ MMU.timerMODE[proc][timerIndex] = 0+1;
+ break;
+ case 1 :
+ MMU.timerMODE[proc][timerIndex] = 6+1;
+ break;
+ case 2 :
+ MMU.timerMODE[proc][timerIndex] = 8+1;
+ break;
+ case 3 :
+ MMU.timerMODE[proc][timerIndex] = 10+1;
+ break;
+ default :
+ MMU.timerMODE[proc][timerIndex] = 0xFFFF;
+ break;
+ }
+
+ int remain = 65536 - MMU.timerReload[proc][timerIndex];
+ nds.timerCycle[proc][timerIndex] = nds_timer + (remain<<MMU.timerMODE[proc][timerIndex]);
+
+ T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x102+timerIndex*4, val);
+ NDS_RescheduleTimers();
+}
+
+//extern CACHE_ALIGN MatrixStack mtxStack[4];
+uint32_t TGXSTAT::read32()
+{
+ uint32_t ret = 0;
+
+ ret |= tb|(tr<<1);
+
+ //int _hack_getMatrixStackLevel(int which);
+
+ // stack position always equal zero. possible timings is wrong
+ // using in "The Wild West"
+ //ret |= ((_hack_getMatrixStackLevel(0) << 13) | (_hack_getMatrixStackLevel(1) << 8)); //matrix stack levels //no proof that these are needed yet
+
+ ret |= sb<<14; //stack busy
+ ret |= se<<15;
+ ret |= 255<<16;//(std::min(gxFIFO.size,(uint32_t)255))<<16;
+ //if(gxFIFO.size>=255) ret |= BIT(24); //fifo full
+ //if(gxFIFO.size<128) ret |= BIT(25); //fifo half
+ //if(gxFIFO.size==0) ret |= BIT(26); //fifo empty
+ //determine busy flag.
+ //if we're waiting for a flush, we're busy
+ //if(isSwapBuffers) ret |= BIT(27);
+ //if fifo is nonempty, we're busy
+ //if(gxFIFO.size!=0) ret |= BIT(27);
+
+ ret |= ((gxfifo_irq & 0x3) << 30); //user's irq flags
+
+ //printf("vc=%03d Returning gxstat read: %08X\n",nds.VCount,ret);
+
+ //ret = (2 << 8);
+ //INFO("gxSTAT 0x%08X (proj %i, pos %i)\n", ret, _hack_getMatrixStackLevel(1), _hack_getMatrixStackLevel(2));
+ return ret;
+}
+
+void TGXSTAT::write32(const uint32_t val)
+{
+ gxfifo_irq = (val>>30)&3;
+ if(BIT15(val))
+ {
+ // Writing "1" to Bit15 does reset the Error Flag (Bit15),
+ // and additionally resets the Projection Stack Pointer (Bit13)
+ //mtxStack[0].position = 0;
+ se = 0; //clear stack error flag
+ }
+ //printf("gxstat write: %08X while gxfifo.size=%d\n",val,gxFIFO.size);
+
+ //if (val & (1<<29)) // clear? (only in homebrew?)
+ //{
+ // GFX_PIPEclear();
+ // GFX_FIFOclear();
+ // return;
+ //}
+}
+
+/*void TGXSTAT::savestate(EMUFILE *f)
+{
+ write32le(1,f); //version
+ write8le(tb,f); write8le(tr,f); write8le(se,f); write8le(gxfifo_irq,f); write8le(sb,f);
+}*/
+bool TGXSTAT::loadstate(EMUFILE *f)
+{
+ uint32_t version;
+ if(read32le(&version,f) != 1) return false;
+ if(version > 1) return false;
+
+ read8le(&tb,f); read8le(&tr,f); read8le(&se,f); read8le(&gxfifo_irq,f);
+ if (version >= 1)
+ read8le(&sb,f);
+
+ return true;
+}
+
+//this could be inlined...
+void MMU_struct_new::write_dma(const int proc, const int size, const uint32_t _adr, const uint32_t val)
+{
+ //printf("%08lld -- write_dma: %d %d %08X %08X\n",nds_timer,proc,size,_adr,val);
+ const uint32_t adr = _adr - _REG_DMA_CONTROL_MIN;
+ const uint32_t chan = adr/12;
+ const uint32_t regnum = (adr - chan*12)>>2;
+
+ if(proc==0&&chan==0)
+ {
+ //int zzz=9;
+ }
+
+ if(proc==1) {
+ //int zzz=9;
+ }
+
+ MMU_new.dma[proc][chan].regs[regnum]->write(size,adr,val);
+}
+
+
+//this could be inlined...
+uint32_t MMU_struct_new::read_dma(const int proc, const int size, const uint32_t _adr)
+{
+ const uint32_t adr = _adr - _REG_DMA_CONTROL_MIN;
+ const uint32_t chan = adr/12;
+ const uint32_t regnum = (adr - chan*12)>>2;
+
+ const uint32_t temp = MMU_new.dma[proc][chan].regs[regnum]->read(size,adr);
+ //printf("%08lld -- read_dma: %d %d %08X = %08X\n",nds_timer,proc,size,_adr,temp);
+
+
+
+ if(temp == 0xAF00 && size == 16)
+ {
+ //int zzz=9;
+ }
+
+ return temp;
+}
+
+MMU_struct_new::MMU_struct_new()
+{
+ for(int i=0;i<2;i++)
+ for(int j=0;j<4;j++) {
+ dma[i][j].procnum = i;
+ dma[i][j].chan = j;
+ }
+}
+
+bool DmaController::loadstate(EMUFILE* f)
+{
+ uint32_t version;
+ if(read32le(&version,f) != 1) return false;
+ if(version >1) return false;
+
+ read8le(&enable,f); read8le(&irq,f); read8le(&repeatMode,f); read8le(&_startmode,f);
+ read8le(&userEnable,f);
+ read32le(&wordcount,f);
+ uint8_t temp;
+ read8le(&temp,f); startmode = (EDMAMode)temp;
+ read8le(&temp,f); bitWidth = (EDMABitWidth)temp;
+ read8le(&temp,f); sar = (EDMASourceUpdate)temp;
+ read8le(&temp,f); dar = (EDMADestinationUpdate)temp;
+ read32le(&saddr,f); read32le(&daddr,f);
+ read32le(reinterpret_cast<uint32_t *>(&dmaCheck),f); read32le(reinterpret_cast<uint32_t *>(&running),f); read32le(reinterpret_cast<uint32_t *>(&paused),f); read32le(reinterpret_cast<uint32_t *>(&triggered),f);
+ read64le(&nextEvent,f);
+
+ if(version==1)
+ {
+ read32le(&saddr_user,f);
+ read32le(&daddr_user,f);
+ }
+
+ return true;
+}
+
+/*void DmaController::savestate(EMUFILE *f)
+{
+ write32le(1,f); //version
+ write8le(enable,f); write8le(irq,f); write8le(repeatMode,f); write8le(_startmode,f);
+ write8le(userEnable,f);
+ write32le(wordcount,f);
+ write8le(startmode,f);
+ write8le(bitWidth,f);
+ write8le(sar,f);
+ write8le(dar,f);
+ write32le(saddr,f); write32le(daddr,f);
+ write32le(check,f); write32le(running,f); write32le(paused,f); write32le(triggered,f);
+ write64le(nextEvent,f);
+ write32le(saddr_user,f);
+ write32le(daddr_user,f);
+}*/
+
+void DmaController::write32(const uint32_t val)
+{
+ if(this->chan==0 && this->procnum==0)
+ {
+ //int zzz=9;
+ }
+ if(running)
+ {
+ //desp triggers this a lot. figure out whats going on
+ //printf("thats weird..user edited dma control while it was running\n");
+ }
+ //printf("dma %d,%d WRITE %08X\n",procnum,chan,val);
+ wordcount = val&0x1FFFFF;
+ if(wordcount==0x9FbFC || wordcount == 0x1FFFFC || wordcount == 0x1EFFFC || wordcount == 0x1FFFFF) {
+ //int zzz=9;
+ }
+ //uint8_t wasRepeatMode = repeatMode;
+ uint8_t wasEnable = enable;
+ uint32_t valhi = val>>16;
+ dar = (EDMADestinationUpdate)((valhi>>5)&3);
+ sar = (EDMASourceUpdate)((valhi>>7)&3);
+ repeatMode = static_cast<uint8_t>(BIT9(valhi));
+ bitWidth = (EDMABitWidth)BIT10(valhi);
+ _startmode = (valhi>>11)&7;
+ if(procnum==ARMCPU_ARM7) _startmode &= 6;
+ irq = static_cast<uint8_t>(BIT14(valhi));
+ enable = static_cast<uint8_t>(BIT15(valhi));
+
+ if(val==0x84400076 && saddr ==0x023BCEC4)
+ {
+ //int zzz=9;
+ }
+
+ //if(irq) printf("!!!!!!!!!!!!IRQ!!!!!!!!!!!!!\n");
+
+ //make sure we don't get any old triggers
+ if(!wasEnable && enable)
+ triggered = false;
+
+ if(enable)
+ {
+ //address registers are reloaded from user's settings whenever dma is enabled
+ //this is tested well by contra4 classic games, which use this to hdma scroll registers
+ //specifically in the fit-screen mode.
+ saddr = saddr_user;
+ daddr = daddr_user;
+ }
+
+ //printf("dma %d,%d set to startmode %d with wordcount set to: %08X\n",procnum,chan,_startmode,wordcount);
+if(_startmode==0 && wordcount==1) {
+ //int zzz=9;
+}
+ if(enable)
+ {
+ //int zzz=9;
+ }
+
+ //analyze enabling and startmode.
+ //note that we only do this if the dma was freshly enabled.
+ //we should probably also only be latching these other regs in that case too..
+ //but for now just this one will do (otherwise the dma repeat stop procedure (in this case the ff4 title menu load with gamecard dma) will fail)
+ //if(!running) enable = userEnable;
+
+ //if we were previously in a triggered mode, and were already enabled,
+ //then don't re-trigger now. this is rather confusing..
+ //we really only want to auto-trigger gxfifo and immediate modes.
+ //but we don't know what mode we're in yet.
+ //so this is our workaround
+ //(otherwise the dma repeat stop procedure (in this case the ff4 title menu load with gamecard dma) will fail)
+ bool doNotStart = false;
+ if(startmode != EDMAMode_Immediate/* && startmode != EDMAMode_GXFifo*/ && wasEnable) doNotStart = true;
+
+ //this dma may need to trigger now, so give it a chance
+ //if(!(wasRepeatMode && !repeatMode)) //this was an older test
+ if(!doNotStart)
+ doSchedule();
+
+ //driver->DEBUG_UpdateIORegView(BaseDriver::EDEBUG_IOREG_DMA);
+}
+
+void DmaController::exec()
+{
+ //this function runs when the DMA ends. the dma start actually queues this event after some kind of guess as to how long the DMA should take
+
+ //we'll need to unfreeze the arm9 bus now
+ if(procnum==ARMCPU_ARM9) nds.freezeBus &= ~(1<<(chan+1));
+
+ dmaCheck = false;
+
+ if(running)
+ {
+ switch(startmode) {
+ /*case EDMAMode_GXFifo:
+ //this dma mode won't finish always its job when it gets signalled
+ //sometimes it will have words left to transfer.
+ //if(!paused) printf("gxfifo dma ended with %d remaining\n",wordcount); //only print this once
+ if(wordcount>0) {
+ doPause();
+ break;
+ }*/
+ default:
+ doStop();
+ //driver->DEBUG_UpdateIORegView(BaseDriver::EDEBUG_IOREG_DMA);
+ return;
+ }
+ }
+
+ if(enable)
+ {
+ //analyze startmode (this only gets latched when a dma begins)
+ if(procnum==ARMCPU_ARM9) startmode = (EDMAMode)_startmode;
+ else {
+ //arm7 startmode analysis:
+ static const EDMAMode lookup[] = {EDMAMode_Immediate,EDMAMode_VBlank,EDMAMode_Card,EDMAMode7_Wifi};
+ //arm7 has a slightly different startmode encoding
+ startmode = lookup[_startmode>>1];
+ if(startmode == EDMAMode7_Wifi && (chan==1 || chan==3))
+ startmode = EDMAMode7_GBASlot;
+ }
+
+ //make it run, if it is triggered
+ //but first, scan for triggering conditions
+ switch(startmode) {
+ case EDMAMode_Immediate:
+ triggered = true;
+ break;
+ /*case EDMAMode_GXFifo:
+ if(gxFIFO.size<=127)
+ triggered = true;
+ break;*/
+ default:
+ break;
+ }
+
+ if(triggered)
+ {
+ //if(procnum==0) printf("vc=%03d %08lld trig type %d dma#%d w/words %d at src:%08X dst:%08X gxf:%d",nds.VCount,nds_timer,startmode,chan,wordcount,saddr,daddr,gxFIFO.size);
+ if(saddr ==0x023BCCEC && wordcount==118) {
+ //int zzz=9;
+ }
+ if(startmode==0 && daddr == 0x4000400) {
+ //int zzz=9;
+ }
+ running = true;
+ paused = false;
+ if(procnum == ARMCPU_ARM9) doCopy<ARMCPU_ARM9>();
+ else doCopy<ARMCPU_ARM7>();
+ //printf(";%d\n",gxFIFO.size);
+ }
+ }
+
+ //driver->DEBUG_UpdateIORegView(BaseDriver::EDEBUG_IOREG_DMA);
+}
+
+template<int PROCNUM>
+void DmaController::doCopy()
+{
+ //generate a copy count depending on various copy mode's behavior
+ uint32_t todo = wordcount;
+ if(todo == 0) todo = 0x200000; //according to gbatek.. //TODO - this should not work this way for arm7 according to gbatek
+ if(startmode == EDMAMode_MemDisplay)
+ {
+ todo = 128; //this is a hack. maybe an alright one though. it should be 4 words at a time. this is a whole scanline
+
+ //apparently this dma turns off after it finishes a frame
+ if(nds.VCount==191) enable = 0;
+ }
+ if(startmode == EDMAMode_Card) todo *= 0x80;
+ //if(startmode == EDMAMode_GXFifo) todo = std::min(todo,(uint32_t)112);
+
+ //determine how we're going to copy
+ bool bogarted = false;
+ uint32_t sz = (bitWidth==EDMABitWidth_16)?2:4;
+ uint32_t dstinc = 0,srcinc;
+ switch(dar) {
+ case EDMADestinationUpdate_Increment : dstinc = sz; break;
+ case EDMADestinationUpdate_Decrement : dstinc = (uint32_t)-(int32_t)sz; break;
+ case EDMADestinationUpdate_Fixed : dstinc = 0; break;
+ case EDMADestinationUpdate_IncrementReload : dstinc = sz; break;
+ default: bogarted = true; break;
+ }
+ switch(sar) {
+ case EDMASourceUpdate_Increment : srcinc = sz; break;
+ case EDMASourceUpdate_Decrement : srcinc = (uint32_t)-(int32_t)sz; break;
+ case EDMASourceUpdate_Fixed : srcinc = 0; break;
+ case EDMASourceUpdate_Invalid : bogarted = true; break;
+ default: bogarted = true; break;
+ }
+
+ //need to figure out what to do about this
+ if(bogarted)
+ {
+ printf("YOUR GAME IS BOGARTED!!! PLEASE REPORT!!!\n");
+ assert(false);
+ return;
+ }
+
+ uint32_t src = saddr;
+ uint32_t dst = daddr;
+
+
+ //if these do not use MMU_AT_DMA and the corresponding code in the read/write routines,
+ //then danny phantom title screen will be filled with a garbage char which is made by
+ //dmaing from 0x00000000 to 0x06000000
+ //TODO - these might be losing out a lot by not going through the templated version anymore.
+ //we might make another function to do just the raw copy op which can use them with checks
+ //outside the loop
+ int time_elapsed = 0;
+ if(sz==4) {
+ for(int32_t i=(int32_t)todo; i>0; i--)
+ {
+ time_elapsed += _MMU_accesstime<PROCNUM,MMU_AT_DMA,32,MMU_AD_READ,true>(src,true);
+ time_elapsed += _MMU_accesstime<PROCNUM,MMU_AT_DMA,32,MMU_AD_WRITE,true>(dst,true);
+ uint32_t temp = _MMU_read32(procnum,MMU_AT_DMA,src);
+ _MMU_write32(procnum,MMU_AT_DMA,dst, temp);
+ dst += dstinc;
+ src += srcinc;
+ }
+ } else {
+ for(int32_t i=(int32_t)todo; i>0; i--)
+ {
+ time_elapsed += _MMU_accesstime<PROCNUM,MMU_AT_DMA,16,MMU_AD_READ,true>(src,true);
+ time_elapsed += _MMU_accesstime<PROCNUM,MMU_AT_DMA,16,MMU_AD_WRITE,true>(dst,true);
+ uint16_t temp = _MMU_read16(procnum,MMU_AT_DMA,src);
+ _MMU_write16(procnum,MMU_AT_DMA,dst, temp);
+ dst += dstinc;
+ src += srcinc;
+ }
+ }
+
+ //reschedule an event for the end of this dma, and figure out how much it cost us
+ doSchedule();
+
+ // zeromus, check it
+ if (wordcount > todo)
+ nextEvent += todo/4; //TODO - surely this is a gross simplification
+ //apparently moon has very, very tight timing (i didnt spy it using waitbyloop swi...)
+ //so lets bump this down a bit for now,
+ //(i think this code is in nintendo libraries)
+
+ //write back the addresses
+ saddr = src;
+ if(dar != EDMADestinationUpdate_IncrementReload) //but dont write back dst if we were supposed to reload
+ daddr = dst;
+
+ //do wordcount accounting
+ if(startmode == EDMAMode_Card)
+ todo /= 0x80; //divide this funky one back down before subtracting it
+
+ if(!repeatMode)
+ wordcount -= todo;
+}
+
+void triggerDma(EDMAMode mode)
+{
+ MACRODO2(0, {
+ const int i=X;
+ MACRODO4(0, {
+ const int j=X;
+ MMU_new.dma[i][j].tryTrigger(mode);
+ });
+ });
+}
+
+void DmaController::tryTrigger(EDMAMode mode)
+{
+ if(startmode != mode) return;
+ if(!enable) return;
+
+ //hmm dont trigger it if its already running!
+ //but paused things need triggers to continue
+ if(running && !paused) return;
+ triggered = true;
+ doSchedule();
+}
+
+void DmaController::doSchedule()
+{
+ dmaCheck = true;
+ nextEvent = nds_timer;
+ NDS_RescheduleDMA();
+}
+
+
+void DmaController::doPause()
+{
+ triggered = false;
+ paused = true;
+}
+
+void DmaController::doStop()
+{
+ //if(procnum==0) printf("%08lld stop type %d dma#%d\n",nds_timer,startmode,chan);
+ running = false;
+ if(!repeatMode) enable = false;
+ if(irq) {
+ NDS_makeIrq(procnum,IRQ_BIT_DMA_0+chan);
+ }
+}
+
+
+
+uint32_t DmaController::read32()
+{
+ uint32_t ret = 0;
+ ret |= enable<<31;
+ ret |= irq<<30;
+ ret |= _startmode<<27;
+ ret |= bitWidth<<26;
+ ret |= repeatMode<<25;
+ ret |= sar<<23;
+ ret |= dar<<21;
+ ret |= wordcount;
+ //printf("dma %d,%d READ %08X\n",procnum,chan,ret);
+ if(ret == 0xAF000001) {
+ //int zzz=9;
+ }
+ return ret;
+}
+
+/*static inline void write_auxspicnt(const int, const int size, const int adr, const int val)
+{
+ //why val==0 to reset? is it a particular bit? its not bit 6...
+ switch(size) {
+ case 16:
+ MMU.AUX_SPI_CNT = val;
+ if (val == 0) MMU_new.backupDevice.reset_command();
+ break;
+ case 8:
+ switch(adr) {
+ case 0:
+ T1WriteByte((uint8_t*)&MMU.AUX_SPI_CNT,0,val);
+ if (val == 0) MMU_new.backupDevice.reset_command();
+ break;
+ case 1:
+ T1WriteByte((uint8_t*)&MMU.AUX_SPI_CNT,1,val);
+ break;
+ }
+ }
+}*/
+
+
+//================================================================================================== ARM9 *
+//=========================================================================================================
+//=========================================================================================================
+//================================================= MMU write 08
+void FASTCALL _MMU_ARM9_write08(uint32_t adr, uint8_t val)
+{
+ adr &= 0x0FFFFFFF;
+
+ //mmu_log_debug_ARM9(adr, "(write08) 0x%02X", val);
+
+ if(adr < 0x02000000)
+ {
+ T1WriteByte(MMU.ARM9_ITCM, adr&0x7FFF, val);
+ return;
+ }
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ {
+ //addon.write08(adr, val);
+ return;
+ }
+
+ //block 8bit writes to OAM and palette memory
+ if((adr&0x0F000000)==0x07000000) return;
+ if((adr&0x0F000000)==0x05000000) return;
+
+ if (adr >> 24 == 4)
+ {
+
+ // TODO: add pal reg
+ /*if (nds.power1.gpuMain == 0)
+ if ((adr >= 0x04000008) && (adr<=0x0400005F)) return;*/
+ /*if (nds.power1.gpuSub == 0)
+ if ((adr >= 0x04001008) && (adr<=0x0400105F)) return;*/
+ /*if (nds.power1.gfx3d_geometry == 0)
+ if ((adr >= 0x04000400) && (adr<=0x040006FF)) return;
+ if (nds.power1.gfx3d_render == 0)
+ if ((adr >= 0x04000320) && (adr<=0x040003FF)) return;*/
+
+ if(MMU_new.is_dma(adr)) {
+ MMU_new.write_dma(ARMCPU_ARM9,8,adr,val);
+ return;
+ }
+
+ switch(adr)
+ {
+ case REG_SQRTCNT: printf("ERROR 8bit SQRTCNT WRITE\n"); return;
+ case REG_SQRTCNT+1: printf("ERROR 8bit SQRTCNT1 WRITE\n"); return;
+ case REG_SQRTCNT+2: printf("ERROR 8bit SQRTCNT2 WRITE\n"); return;
+ case REG_SQRTCNT+3: printf("ERROR 8bit SQRTCNT3 WRITE\n"); return;
+
+#if 1
+ case REG_DIVCNT: printf("ERROR 8bit DIVCNT WRITE\n"); return;
+ case REG_DIVCNT+1: printf("ERROR 8bit DIVCNT1 WRITE\n"); return;
+ case REG_DIVCNT+2: printf("ERROR 8bit DIVCNT2 WRITE\n"); return;
+ case REG_DIVCNT+3: printf("ERROR 8bit DIVCNT3 WRITE\n"); return;
+#endif
+
+ //fog table: only write bottom 7 bits
+ /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x01: case eng_3D_FOG_TABLE+0x02: case eng_3D_FOG_TABLE+0x03:
+ case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x05: case eng_3D_FOG_TABLE+0x06: case eng_3D_FOG_TABLE+0x07:
+ case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x09: case eng_3D_FOG_TABLE+0x0A: case eng_3D_FOG_TABLE+0x0B:
+ case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x0D: case eng_3D_FOG_TABLE+0x0E: case eng_3D_FOG_TABLE+0x0F:
+ case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x11: case eng_3D_FOG_TABLE+0x12: case eng_3D_FOG_TABLE+0x13:
+ case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x15: case eng_3D_FOG_TABLE+0x16: case eng_3D_FOG_TABLE+0x17:
+ case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x19: case eng_3D_FOG_TABLE+0x1A: case eng_3D_FOG_TABLE+0x1B:
+ case eng_3D_FOG_TABLE+0x1C: case eng_3D_FOG_TABLE+0x1D: case eng_3D_FOG_TABLE+0x1E: case eng_3D_FOG_TABLE+0x1F:
+ val &= 0x7F;
+ break;*/
+
+ //ensata putchar port
+ /*case 0x04FFF000:
+ if(nds.ensataEmulation)
+ printf("%c",val);
+ break;
+
+ case eng_3D_GXSTAT:
+ MMU_new.gxstat.write(8,adr,val);
+ break;*/
+
+ /*case REG_DISPA_WIN0H:
+ GPU_setWIN0_H1(MainScreen.gpu, val);
+ break ;
+ case REG_DISPA_WIN0H+1:
+ GPU_setWIN0_H0 (MainScreen.gpu, val);
+ break ;
+ case REG_DISPA_WIN1H:
+ GPU_setWIN1_H1 (MainScreen.gpu,val);
+ break ;
+ case REG_DISPA_WIN1H+1:
+ GPU_setWIN1_H0 (MainScreen.gpu,val);
+ break ; */
+
+ /*case REG_DISPB_WIN0H:
+ GPU_setWIN0_H1(SubScreen.gpu,val);
+ break ;
+ case REG_DISPB_WIN0H+1:
+ GPU_setWIN0_H0(SubScreen.gpu,val);
+ break ;
+ case REG_DISPB_WIN1H:
+ GPU_setWIN1_H1(SubScreen.gpu,val);
+ break ;
+ case REG_DISPB_WIN1H+1:
+ GPU_setWIN1_H0(SubScreen.gpu,val);
+ break ;*/
+
+ /*case REG_DISPA_WIN0V:
+ GPU_setWIN0_V1(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_WIN0V+1:
+ GPU_setWIN0_V0(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_WIN1V:
+ GPU_setWIN1_V1(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_WIN1V+1:
+ GPU_setWIN1_V0(MainScreen.gpu,val) ;
+ break ; */
+
+ /*case REG_DISPB_WIN0V:
+ GPU_setWIN0_V1(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_WIN0V+1:
+ GPU_setWIN0_V0(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_WIN1V:
+ GPU_setWIN1_V1(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_WIN1V+1:
+ GPU_setWIN1_V0(SubScreen.gpu,val) ;
+ break ;*/
+
+ /*case REG_DISPA_WININ:
+ GPU_setWININ0(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_WININ+1:
+ GPU_setWININ1(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_WINOUT:
+ GPU_setWINOUT(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_WINOUT+1:
+ GPU_setWINOBJ(MainScreen.gpu,val);
+ break ; */
+
+ /*case REG_DISPB_WININ:
+ GPU_setWININ0(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_WININ+1:
+ GPU_setWININ1(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_WINOUT:
+ GPU_setWINOUT(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_WINOUT+1:
+ GPU_setWINOBJ(SubScreen.gpu,val) ;
+ break ;*/
+
+ /*case REG_DISPA_BLDCNT:
+ GPU_setBLDCNT_HIGH(MainScreen.gpu,val);
+ break;
+ case REG_DISPA_BLDCNT+1:
+ GPU_setBLDCNT_LOW (MainScreen.gpu,val);
+ break;*/
+
+ /*case REG_DISPB_BLDCNT:
+ GPU_setBLDCNT_HIGH (SubScreen.gpu,val);
+ break;
+ case REG_DISPB_BLDCNT+1:
+ GPU_setBLDCNT_LOW (SubScreen.gpu,val);
+ break;*/
+
+ /*case REG_DISPA_BLDALPHA:
+ MainScreen.gpu->setBLDALPHA_EVB(val);
+ break;
+ case REG_DISPA_BLDALPHA+1:
+ MainScreen.gpu->setBLDALPHA_EVA(val);
+ break;*/
+
+ /*case REG_DISPB_BLDALPHA:
+ SubScreen.gpu->setBLDALPHA_EVB(val);
+ break;
+ case REG_DISPB_BLDALPHA+1:
+ SubScreen.gpu->setBLDALPHA_EVA(val);
+ break;*/
+
+ /*case REG_DISPA_BLDY:
+ GPU_setBLDY_EVY(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_BLDY:
+ GPU_setBLDY_EVY(SubScreen.gpu,val) ;
+ break;*/
+
+ /*case REG_AUXSPICNT:
+ write_auxspicnt(9,8,0,val);
+ return;
+ case REG_AUXSPICNT+1:
+ write_auxspicnt(9,8,1,val);
+ return;
+
+ case REG_AUXSPIDATA:
+ if(val!=0) MMU.AUX_SPI_CMD = val & 0xFF;
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, MMU_new.backupDevice.data_command((uint8_t)val,ARMCPU_ARM9));
+ MMU.AUX_SPI_CNT &= ~0x80; //remove busy flag
+ return;*/
+
+ case REG_WRAMCNT:
+ /* Update WRAMSTAT at the ARM7 side */
+ T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x241, val);
+ break;
+
+ //case REG_POWCNT1: writereg_POWCNT1(8,adr,val); break;
+
+ //case REG_DISPA_DISP3DCNT: writereg_DISP3DCNT(8,adr,val); return;
+ //case REG_DISPA_DISP3DCNT+1: writereg_DISP3DCNT(8,adr,val); return;
+
+ case REG_IF: REG_IF_WriteByte<ARMCPU_ARM9>(0,val); break;
+ case REG_IF+1: REG_IF_WriteByte<ARMCPU_ARM9>(1,val); break;
+ case REG_IF+2: REG_IF_WriteByte<ARMCPU_ARM9>(2,val); break;
+ case REG_IF+3: REG_IF_WriteByte<ARMCPU_ARM9>(3,val); break;
+
+ /*case eng_3D_CLEAR_COLOR+0: case eng_3D_CLEAR_COLOR+1:
+ case eng_3D_CLEAR_COLOR+2: case eng_3D_CLEAR_COLOR+3:
+ //T1WriteByte((uint8_t*)&gfx3d.state.clearColor,adr-eng_3D_CLEAR_COLOR,val);
+ break;*/
+
+ case REG_VRAMCNTA:
+ case REG_VRAMCNTB:
+ case REG_VRAMCNTC:
+ case REG_VRAMCNTD:
+ case REG_VRAMCNTE:
+ case REG_VRAMCNTF:
+ case REG_VRAMCNTG:
+ case REG_VRAMCNTH:
+ case REG_VRAMCNTI:
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA), val);
+ break;
+ /*case REG_DISPA_DISPMMEMFIFO:
+ {
+ DISP_FIFOsend(val);
+ return;
+ }*/
+ #ifdef LOG_CARD
+ case 0x040001A0 : /* TODO (clear): ??? */
+ case 0x040001A1 :
+ case 0x040001A2 :
+ case 0x040001A8 :
+ case 0x040001A9 :
+ case 0x040001AA :
+ case 0x040001AB :
+ case 0x040001AC :
+ case 0x040001AD :
+ case 0x040001AE :
+ case 0x040001AF :
+ LOG("%08X : %02X\r\n", adr, val);
+ #endif
+
+ }
+
+ MMU.MMU_MEM[ARMCPU_ARM9][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]]=val;
+ return;
+ }
+
+ //bool unmapped = false, restricted = false;
+ //adr = MMU_LCDmap<ARMCPU_ARM9>(adr, unmapped, restricted);
+ //if(unmapped) return;
+ //if(restricted) return; //block 8bit vram writes
+
+ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash]
+ MMU.MMU_MEM[ARMCPU_ARM9][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]]=val;
+}
+
+//================================================= MMU ARM9 write 16
+void FASTCALL _MMU_ARM9_write16(uint32_t adr, uint16_t val)
+{
+ adr &= 0x0FFFFFFE;
+
+ //mmu_log_debug_ARM9(adr, "(write16) 0x%04X", val);
+
+ if (adr < 0x02000000)
+ {
+ T1WriteWord(MMU.ARM9_ITCM, adr&0x7FFF, val);
+ return;
+ }
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ {
+ //addon.write16(adr, val);
+ return;
+ }
+
+ if((adr >> 24) == 4)
+ {
+ // TODO: add pal reg
+ /*if (nds.power1.gpuMain == 0)
+ if ((adr >= 0x04000008) && (adr<=0x0400005F)) return;*/
+ /*if (nds.power1.gpuSub == 0)
+ if ((adr >= 0x04001008) && (adr<=0x0400105F)) return;*/
+ /*if (nds.power1.gfx3d_geometry == 0)
+ if ((adr >= 0x04000400) && (adr<=0x040006FF)) return;
+ if (nds.power1.gfx3d_render == 0)
+ if ((adr >= 0x04000320) && (adr<=0x040003FF)) return;*/
+
+ if(MMU_new.is_dma(adr)) {
+ if(val==0x02e9) {
+ //int zzz=9;
+ }
+ MMU_new.write_dma(ARMCPU_ARM9,16,adr,val);
+ return;
+ }
+
+ switch (adr >> 4)
+ {
+ //toon table
+ case 0x0400038:
+ case 0x0400039:
+ case 0x040003A:
+ case 0x040003B:
+ ((uint16_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[(adr & 0xFFF)>>1] = val;
+ //gfx3d_UpdateToonTable((adr & 0x3F) >> 1, val);
+ return;
+ }
+ // Address is an IO register
+ switch(adr)
+ {
+ /*case eng_3D_GXSTAT:
+ MMU_new.gxstat.write(16,adr,val);
+ break;*/
+
+ //fog table: only write bottom 7 bits
+ /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x02: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x06:
+ case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x0A: case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x0E:
+ case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x12: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x16:
+ case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x1A: case eng_3D_FOG_TABLE+0x1C: case eng_3D_FOG_TABLE+0x1E:
+ val &= 0x7F7F;
+ break;*/
+
+ /*case REG_DISPA_BG2XL: MainScreen.gpu->setAffineStartWord(2,0,val,0); break;
+ case REG_DISPA_BG2XH: MainScreen.gpu->setAffineStartWord(2,0,val,1); break;
+ case REG_DISPA_BG2YL: MainScreen.gpu->setAffineStartWord(2,1,val,0); break;
+ case REG_DISPA_BG2YH: MainScreen.gpu->setAffineStartWord(2,1,val,1); break;
+ case REG_DISPA_BG3XL: MainScreen.gpu->setAffineStartWord(3,0,val,0); break;
+ case REG_DISPA_BG3XH: MainScreen.gpu->setAffineStartWord(3,0,val,1); break;
+ case REG_DISPA_BG3YL: MainScreen.gpu->setAffineStartWord(3,1,val,0); break;
+ case REG_DISPA_BG3YH: MainScreen.gpu->setAffineStartWord(3,1,val,1); break;
+ case REG_DISPB_BG2XL: SubScreen.gpu->setAffineStartWord(2,0,val,0); break;
+ case REG_DISPB_BG2XH: SubScreen.gpu->setAffineStartWord(2,0,val,1); break;
+ case REG_DISPB_BG2YL: SubScreen.gpu->setAffineStartWord(2,1,val,0); break;
+ case REG_DISPB_BG2YH: SubScreen.gpu->setAffineStartWord(2,1,val,1); break;
+ case REG_DISPB_BG3XL: SubScreen.gpu->setAffineStartWord(3,0,val,0); break;
+ case REG_DISPB_BG3XH: SubScreen.gpu->setAffineStartWord(3,0,val,1); break;
+ case REG_DISPB_BG3YL: SubScreen.gpu->setAffineStartWord(3,1,val,0); break;
+ case REG_DISPB_BG3YH: SubScreen.gpu->setAffineStartWord(3,1,val,1); break;*/
+
+ //case REG_DISPA_DISP3DCNT: writereg_DISP3DCNT(16,adr,val); return;
+
+ // Alpha test reference value - Parameters:1
+ /*case eng_3D_ALPHA_TEST_REF:
+ {
+ ((uint16_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x340>>1] = val;
+ //gfx3d_glAlphaFunc(val);
+ return;
+ }
+
+ case eng_3D_CLEAR_COLOR:
+ case eng_3D_CLEAR_COLOR+2:
+ {
+ //T1WriteWord((uint8_t*)&gfx3d.state.clearColor,adr-eng_3D_CLEAR_COLOR,val);
+ break;
+ }
+
+ // Clear background depth setup - Parameters:2
+ case eng_3D_CLEAR_DEPTH:
+ {
+ ((uint16_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x354>>1] = val;
+ //gfx3d_glClearDepth(val);
+ return;
+ }
+ // Fog Color - Parameters:4b
+ case eng_3D_FOG_COLOR:
+ {
+ ((uint16_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x358>>1] = val;
+ //gfx3d_glFogColor(val);
+ return;
+ }
+ case eng_3D_FOG_OFFSET:
+ {
+ ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x35C>>1] = val;
+ //gfx3d_glFogOffset(val);
+ return;
+ }*/
+
+ case REG_DIVCNT:
+ MMU_new.div.write16(val);
+ execdiv();
+ return;
+#if 1
+ case REG_DIVNUMER:
+ case REG_DIVNUMER+2:
+ case REG_DIVNUMER+4:
+ printf("DIV: 16 write NUMER %08X. PLEASE REPORT! \n", val);
+ break;
+ case REG_DIVDENOM:
+ case REG_DIVDENOM+2:
+ case REG_DIVDENOM+4:
+ printf("DIV: 16 write DENOM %08X. PLEASE REPORT! \n", val);
+ break;
+#endif
+ case REG_SQRTCNT:
+ MMU_new.sqrt.write16(val);
+ execsqrt();
+ return;
+
+ /*case REG_DISPA_BLDCNT:
+ GPU_setBLDCNT(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_BLDCNT:
+ GPU_setBLDCNT(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_BLDALPHA:
+ MainScreen.gpu->setBLDALPHA(val);
+ break ;
+ case REG_DISPB_BLDALPHA:
+ SubScreen.gpu->setBLDALPHA(val);
+ break ;
+ case REG_DISPA_BLDY:
+ GPU_setBLDY_EVY(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_BLDY:
+ GPU_setBLDY_EVY(SubScreen.gpu,val) ;
+ break;
+ case REG_DISPA_MASTERBRIGHT:
+ GPU_setMasterBrightness (MainScreen.gpu, val);
+ break;*/
+ /*
+ case REG_DISPA_MOSAIC:
+ GPU_setMOSAIC(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_MOSAIC:
+ GPU_setMOSAIC(SubScreen.gpu,val) ;
+ break ;
+ */
+ //case REG_DISPA_BG0HOFS:
+ // GPU_setBGxHOFS(0, MainScreen.gpu, val);
+ // break;
+ //case REG_DISPA_BG0VOFS:
+ // GPU_setBGxVOFS(0, MainScreen.gpu, val);
+ // break;
+ //case REG_DISPA_BG1HOFS:
+ // GPU_setBGxHOFS(1, MainScreen.gpu, val);
+ // break;
+ //case REG_DISPA_BG1VOFS:
+ // GPU_setBGxVOFS(1, MainScreen.gpu, val);
+ // break;
+ //case REG_DISPA_BG2HOFS:
+ // GPU_setBGxHOFS(2, MainScreen.gpu, val);
+ // break;
+ //case REG_DISPA_BG2VOFS:
+ // GPU_setBGxVOFS(2, MainScreen.gpu, val);
+ // break;
+ //case REG_DISPA_BG3HOFS:
+ // GPU_setBGxHOFS(3, MainScreen.gpu, val);
+ // break;
+ //case REG_DISPA_BG3VOFS:
+ // GPU_setBGxVOFS(3, MainScreen.gpu, val);
+ // break;
+
+ /*case REG_DISPA_WIN0H:
+ GPU_setWIN0_H (MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_WIN1H:
+ GPU_setWIN1_H(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_WIN0H:
+ GPU_setWIN0_H(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_WIN1H:
+ GPU_setWIN1_H(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_WIN0V:
+ GPU_setWIN0_V(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_WIN1V:
+ GPU_setWIN1_V(MainScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_WIN0V:
+ GPU_setWIN0_V(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPB_WIN1V:
+ GPU_setWIN1_V(SubScreen.gpu,val) ;
+ break ;
+ case REG_DISPA_WININ:
+ GPU_setWININ(MainScreen.gpu, val) ;
+ break ;
+ case REG_DISPA_WINOUT:
+ GPU_setWINOUT16(MainScreen.gpu, val) ;
+ break ; */
+
+ /* case REG_DISPB_BG0HOFS:
+ GPU_setBGxHOFS(0, SubScreen.gpu, val);
+ break;
+ case REG_DISPB_BG0VOFS:
+ GPU_setBGxVOFS(0, SubScreen.gpu, val);
+ break;
+ case REG_DISPB_BG1HOFS:
+ GPU_setBGxHOFS(1, SubScreen.gpu, val);
+ break;
+ case REG_DISPB_BG1VOFS:
+ GPU_setBGxVOFS(1, SubScreen.gpu, val);
+ break;
+ case REG_DISPB_BG2HOFS:
+ GPU_setBGxHOFS(2, SubScreen.gpu, val);
+ break;
+ case REG_DISPB_BG2VOFS:
+ GPU_setBGxVOFS(2, SubScreen.gpu, val);
+ break;
+ case REG_DISPB_BG3HOFS:
+ GPU_setBGxHOFS(3, SubScreen.gpu, val);
+ break;
+ case REG_DISPB_BG3VOFS:
+ GPU_setBGxVOFS(3, SubScreen.gpu, val);
+ break;*/
+
+ /*case REG_DISPB_WININ:
+ GPU_setWININ(SubScreen.gpu, val) ;
+ break ;
+ case REG_DISPB_WINOUT:
+ GPU_setWINOUT16(SubScreen.gpu, val) ;
+ break ;*/
+
+ /*case REG_DISPB_MASTERBRIGHT:
+ GPU_setMasterBrightness (SubScreen.gpu, val);
+ break;*/
+
+ /*case REG_POWCNT1:
+ writereg_POWCNT1(16,adr,val);
+ return;*/
+
+ case REG_EXMEMCNT:
+ {
+ uint16_t remote_proc = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x204);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x204, val);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x204, (val & 0xFF80) | (remote_proc & 0x7F));
+ return;
+ }
+
+ /*case REG_AUXSPICNT:
+ write_auxspicnt(9,16,0,val);
+ return;
+
+ case REG_AUXSPIDATA:
+ if(val!=0)
+ MMU.AUX_SPI_CMD = val & 0xFF;
+
+ //T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, bm_transfer(&MMU.bupmem, val));
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, MMU_new.backupDevice.data_command((uint8_t)val,ARMCPU_ARM9));
+ MMU.AUX_SPI_CNT &= ~0x80; //remove busy flag
+ return;*/
+
+ /*case REG_DISPA_BG0CNT :
+ //GPULOG("MAIN BG0 SETPROP 16B %08X\r\n", val);
+ //GPU_setBGProp(MainScreen.gpu, 0, val);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x8, val);
+ return;
+ case REG_DISPA_BG1CNT :
+ //GPULOG("MAIN BG1 SETPROP 16B %08X\r\n", val);
+ //GPU_setBGProp(MainScreen.gpu, 1, val);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xA, val);
+ return;
+ case REG_DISPA_BG2CNT :
+ //GPULOG("MAIN BG2 SETPROP 16B %08X\r\n", val);
+ //GPU_setBGProp(MainScreen.gpu, 2, val);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xC, val);
+ return;
+ case REG_DISPA_BG3CNT :
+ //GPULOG("MAIN BG3 SETPROP 16B %08X\r\n", val);
+ //GPU_setBGProp(MainScreen.gpu, 3, val);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0xE, val);
+ return;
+ case REG_DISPB_BG0CNT :
+ //GPULOG("SUB BG0 SETPROP 16B %08X\r\n", val);
+ //GPU_setBGProp(SubScreen.gpu, 0, val);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1008, val);
+ return;
+ case REG_DISPB_BG1CNT :
+ //GPULOG("SUB BG1 SETPROP 16B %08X\r\n", val);
+ //GPU_setBGProp(SubScreen.gpu, 1, val);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x100A, val);
+ return;
+ case REG_DISPB_BG2CNT :
+ //GPULOG("SUB BG2 SETPROP 16B %08X\r\n", val);
+ //GPU_setBGProp(SubScreen.gpu, 2, val);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x100C, val);
+ return;
+ case REG_DISPB_BG3CNT :
+ //GPULOG("SUB BG3 SETPROP 16B %08X\r\n", val);
+ //GPU_setBGProp(SubScreen.gpu, 3, val);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x100E, val);
+ return;*/
+
+ case REG_VRAMCNTA:
+ case REG_VRAMCNTC:
+ case REG_VRAMCNTE:
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+1), val >> 8);
+ break;
+ case REG_VRAMCNTG:
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
+ /* Update WRAMSTAT at the ARM7 side */
+ T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x241, val >> 8);
+ break;
+ case REG_VRAMCNTH:
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+1), val >> 8);
+ break;
+
+ case REG_IME:
+ NDS_Reschedule();
+ MMU.reg_IME[ARMCPU_ARM9] = val & 0x01;
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x208, val);
+ return;
+ case REG_IE :
+ NDS_Reschedule();
+ MMU.reg_IE[ARMCPU_ARM9] = (MMU.reg_IE[ARMCPU_ARM9]&0xFFFF0000) | val;
+ return;
+ case REG_IE + 2 :
+ NDS_Reschedule();
+ MMU.reg_IE[ARMCPU_ARM9] = (MMU.reg_IE[ARMCPU_ARM9]&0xFFFF) | (((uint32_t)val)<<16);
+ return;
+ case REG_IF: REG_IF_WriteWord<ARMCPU_ARM9>(0,val); return;
+ case REG_IF+2: REG_IF_WriteWord<ARMCPU_ARM9>(2,val); return;
+
+ case REG_IPCSYNC :
+ MMU_IPCSync(ARMCPU_ARM9, val);
+ return;
+
+ case REG_IPCFIFOCNT :
+ IPC_FIFOcnt(ARMCPU_ARM9, val);
+ return;
+ case REG_TM0CNTL :
+ case REG_TM1CNTL :
+ case REG_TM2CNTL :
+ case REG_TM3CNTL :
+ MMU.timerReload[ARMCPU_ARM9][(adr>>2)&3] = val;
+ return;
+ case REG_TM0CNTH :
+ case REG_TM1CNTH :
+ case REG_TM2CNTH :
+ case REG_TM3CNTH :
+ {
+ int timerIndex = ((adr-2)>>2)&0x3;
+ write_timer(ARMCPU_ARM9, timerIndex, val);
+ return;
+ }
+
+ /*case REG_DISPA_DISPCNT :
+ {
+ uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0) & 0xFFFF0000) | val;
+ //GPU_setVideoProp(MainScreen.gpu, v);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0, v);
+ return;
+ }
+ case REG_DISPA_DISPCNT+2 :
+ {
+ uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0) & 0xFFFF) | ((uint32_t) val << 16);
+ //GPU_setVideoProp(MainScreen.gpu, v);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0, v);
+ }
+ return;
+ case REG_DISPA_DISPCAPCNT :
+ {
+ uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x64) & 0xFFFF0000) | val;
+ //GPU_set_DISPCAPCNT(v);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x64, v);
+ return;
+ }
+ case REG_DISPA_DISPCAPCNT + 2:
+ {
+ uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x64) & 0xFFFF) | ((uint32_t)val << 16);
+ //GPU_set_DISPCAPCNT(v);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x64, v);
+ return;
+ }
+
+ case REG_DISPB_DISPCNT :
+ {
+ uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1000) & 0xFFFF0000) | val;
+ //GPU_setVideoProp(SubScreen.gpu, v);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1000, v);
+ return;
+ }
+ case REG_DISPB_DISPCNT+2 :
+ {
+ //emu_halt();
+ uint32_t v = (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1000) & 0xFFFF) | ((uint32_t) val << 16);
+ //GPU_setVideoProp(SubScreen.gpu, v);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1000, v);
+ return;
+ }*/
+
+ /*case REG_DISPA_DISPMMEMFIFO:
+ {
+ DISP_FIFOsend(val);
+ return;
+ }*/
+
+ case REG_GCROMCTRL :
+ MMU_writeToGCControl<ARMCPU_ARM9>( (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1A4) & 0xFFFF0000) | val);
+ return;
+ case REG_GCROMCTRL+2 :
+ MMU_writeToGCControl<ARMCPU_ARM9>( (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1A4) & 0xFFFF) | ((uint32_t) val << 16));
+ return;
+ }
+
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20], val);
+ return;
+ }
+
+
+ bool unmapped, restricted;
+ adr = MMU_LCDmap/*<ARMCPU_ARM9>*/(adr, unmapped, restricted);
+ if(unmapped) return;
+
+ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash]
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20], val);
+}
+
+//================================================= MMU ARM9 write 32
+void FASTCALL _MMU_ARM9_write32(uint32_t adr, uint32_t val)
+{
+ adr &= 0x0FFFFFFC;
+
+ //mmu_log_debug_ARM9(adr, "(write32) 0x%08X", val);
+
+ if(adr<0x02000000)
+ {
+ T1WriteLong(MMU.ARM9_ITCM, adr&0x7FFF, val);
+ return ;
+ }
+
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ {
+ //addon.write32(adr, val);
+ return;
+ }
+
+ if((adr&0x0F000000)==0x05000000)
+ {
+ //int zzz=9;
+ }
+
+#if 0
+ if ((adr & 0xFF800000) == 0x04800000) {
+ // access to non regular hw registers
+ // return to not overwrite valid data
+ return ;
+ }
+#endif
+
+ if((adr>>24)==4)
+ {
+ // TODO: add pal reg
+ /*if (nds.power1.gpuMain == 0)
+ if ((adr >= 0x04000008) && (adr<=0x0400005F)) return;*/
+ /*if (nds.power1.gpuSub == 0)
+ if ((adr >= 0x04001008) && (adr<=0x0400105F)) return;*/
+ /*if (nds.power1.gfx3d_geometry == 0)
+ if ((adr >= 0x04000400) && (adr<=0x040006FF)) return;
+ if (nds.power1.gfx3d_render == 0)
+ if ((adr >= 0x04000320) && (adr<=0x040003FF)) return;*/
+
+ // MightyMax: no need to do several ifs, when only one can happen
+ // switch/case instead
+ // both comparison >=,< per if can be replaced by one bit comparison since
+ // they are 2^4 aligned and 2^4n wide
+ // this looks ugly but should reduce load on register writes, they are done as
+ // lookups by the compiler
+ /*switch (adr >> 4)
+ {
+ case 0x400033: //edge color table
+ ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[(adr & 0xFFF) >> 2] = val;
+ return;
+
+ case 0x400038:
+ case 0x400039:
+ case 0x40003A:
+ case 0x40003B: //toon table
+ ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[(adr & 0xFFF) >> 2] = val;
+ //gfx3d_UpdateToonTable((adr & 0x3F) >> 1, val);
+ return;
+
+ case 0x400040:
+ case 0x400041:
+ case 0x400042:
+ case 0x400043: // FIFO Commands
+ ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[(adr & 0xFFF) >> 2] = val;
+ //gfx3d_sendCommandToFIFO(val);
+ return;
+
+ case 0x400044:
+ case 0x400045:
+ case 0x400046:
+ case 0x400047:
+ case 0x400048:
+ case 0x400049:
+ case 0x40004A:
+ case 0x40004B:
+ case 0x40004C:
+ case 0x40004D:
+ case 0x40004E:
+ case 0x40004F:
+ case 0x400050:
+ case 0x400051:
+ case 0x400052:
+ case 0x400053:
+ case 0x400054:
+ case 0x400055:
+ case 0x400056:
+ case 0x400057:
+ case 0x400058:
+ case 0x400059:
+ case 0x40005A:
+ case 0x40005B:
+ case 0x40005C: // Individual Commands
+ if (gxFIFO.size > 254)
+ nds.freezeBus = true;
+
+ ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[(adr & 0xFFF) >> 2] = val;
+ //gfx3d_sendCommand(adr, val);
+ return;
+
+ default:
+ break;
+ }*/
+
+ if(MMU_new.is_dma(adr)) {
+ MMU_new.write_dma(ARMCPU_ARM9,32,adr,val);
+ return;
+ }
+
+ switch(adr)
+ {
+ case REG_SQRTCNT: MMU_new.sqrt.write16((uint16_t)val); return;
+ case REG_DIVCNT: MMU_new.div.write16((uint16_t)val); return;
+
+ //case REG_POWCNT1: writereg_POWCNT1(32,adr,val); break;
+
+ //fog table: only write bottom 7 bits
+ /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x0C:
+ case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x1C:
+ val &= 0x7F7F7F7F;
+ break;*/
+
+
+ //ensata handshaking port?
+ /*case 0x04FFF010:
+ if(nds.ensataEmulation && nds.ensataHandshake == ENSATA_HANDSHAKE_ack && val == 0x13579bdf)
+ nds.ensataHandshake = ENSATA_HANDSHAKE_confirm;
+ if(nds.ensataEmulation && nds.ensataHandshake == ENSATA_HANDSHAKE_confirm && val == 0xfdb97531)
+ {
+ printf("ENSATA HANDSHAKE COMPLETE\n");
+ nds.ensataHandshake = ENSATA_HANDSHAKE_complete;
+ }
+ break;*/
+
+ //todo - these are usually write only regs (these and 1000 more)
+ //shouldnt we block them from getting written? ugh
+ /*case eng_3D_CLIPMTX_RESULT:
+ if(nds.ensataEmulation && nds.ensataHandshake == ENSATA_HANDSHAKE_none && val==0x2468ace0)
+ {
+ printf("ENSATA HANDSHAKE BEGIN\n");
+ nds.ensataHandshake = ENSATA_HANDSHAKE_query;
+ }
+ break;
+
+ case eng_3D_GXSTAT:
+ MMU_new.gxstat.write32(val);
+ break;*/
+ /*case REG_DISPA_BG2XL:
+ MainScreen.gpu->setAffineStart(2,0,val);
+ return;
+ case REG_DISPA_BG2YL:
+ MainScreen.gpu->setAffineStart(2,1,val);
+ return;
+ case REG_DISPB_BG2XL:
+ SubScreen.gpu->setAffineStart(2,0,val);
+ return;
+ case REG_DISPB_BG2YL:
+ SubScreen.gpu->setAffineStart(2,1,val);
+ return;
+ case REG_DISPA_BG3XL:
+ MainScreen.gpu->setAffineStart(3,0,val);
+ return;
+ case REG_DISPA_BG3YL:
+ MainScreen.gpu->setAffineStart(3,1,val);
+ return;
+ case REG_DISPB_BG3XL:
+ SubScreen.gpu->setAffineStart(3,0,val);
+ return;
+ case REG_DISPB_BG3YL:
+ SubScreen.gpu->setAffineStart(3,1,val);
+ return;*/
+
+ // Alpha test reference value - Parameters:1
+ /*case eng_3D_ALPHA_TEST_REF:
+ {
+ ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x340>>2] = val;
+ //gfx3d_glAlphaFunc(val);
+ return;
+ }
+
+ case eng_3D_CLEAR_COLOR:
+ //T1WriteLong((uint8_t*)&gfx3d.state.clearColor,0,val);
+ break;
+
+ // Clear background depth setup - Parameters:2
+ case eng_3D_CLEAR_DEPTH:
+ {
+ ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x354>>2] = val;
+ //gfx3d_glClearDepth(val);
+ return;
+ }
+ // Fog Color - Parameters:4b
+ case 0x04000358:
+ {
+ ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x358>>2] = val;
+ //gfx3d_glFogColor(val);
+ return;
+ }
+ case 0x0400035C:
+ {
+ ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]))[0x35C>>2] = val;
+ //gfx3d_glFogOffset(val);
+ return;
+ }*/
+
+ //case REG_DISPA_BG0HOFS:
+ // GPU_setBGxHOFS(0, MainScreen.gpu, val&0xFFFF);
+ // GPU_setBGxVOFS(0, MainScreen.gpu, (val>>16));
+ // break;
+
+ /*case REG_DISPA_WININ:
+ {
+ GPU_setWININ(MainScreen.gpu, val & 0xFFFF) ;
+ GPU_setWINOUT16(MainScreen.gpu, (val >> 16) & 0xFFFF) ;
+ break;
+ }
+ case REG_DISPB_WININ:
+ {
+ GPU_setWININ(SubScreen.gpu, val & 0xFFFF) ;
+ GPU_setWINOUT16(SubScreen.gpu, (val >> 16) & 0xFFFF) ;
+ break;
+ }*/
+
+ /*case REG_DISPA_WIN0H:
+ {
+ GPU_setWIN0_H(MainScreen.gpu, val&0xFFFF);
+ GPU_setWIN1_H(MainScreen.gpu, val>>16);
+ break;
+ }
+ case REG_DISPA_WIN0V:
+ {
+ GPU_setWIN0_V(MainScreen.gpu, val&0xFFFF);
+ GPU_setWIN1_V(MainScreen.gpu, val>>16);
+ break;
+ }
+ case REG_DISPB_WIN0H:
+ {
+ GPU_setWIN0_H(SubScreen.gpu, val&0xFFFF);
+ GPU_setWIN1_H(SubScreen.gpu, val>>16);
+ break;
+ }
+ case REG_DISPB_WIN0V:
+ {
+ GPU_setWIN0_V(SubScreen.gpu, val&0xFFFF);
+ GPU_setWIN1_V(SubScreen.gpu, val>>16);
+ break;
+ }*/
+
+ /*case REG_DISPA_MASTERBRIGHT:
+ GPU_setMasterBrightness(MainScreen.gpu, val & 0xFFFF);
+ break;
+ case REG_DISPB_MASTERBRIGHT:
+ GPU_setMasterBrightness(SubScreen.gpu, val & 0xFFFF);
+ break;*/
+
+ /*case REG_DISPA_BLDCNT:
+ {
+ GPU_setBLDCNT (MainScreen.gpu,val&0xffff);
+ MainScreen.gpu->setBLDALPHA(val>>16);
+ break;
+ }
+ case REG_DISPB_BLDCNT:
+ {
+ GPU_setBLDCNT (SubScreen.gpu,val&0xffff);
+ SubScreen.gpu->setBLDALPHA(val>>16);
+ break;
+ }*/
+
+ /*case REG_DISPA_BLDY:
+ GPU_setBLDY_EVY(MainScreen.gpu,val&0xFFFF) ;
+ break ;
+ case REG_DISPB_BLDY:
+ GPU_setBLDY_EVY(SubScreen.gpu,val&0xFFFF);
+ break;*/
+
+ /*case REG_DISPA_DISPCNT :
+ //GPU_setVideoProp(MainScreen.gpu, val);
+ //GPULOG("MAIN INIT 32B %08X\r\n", val);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0, val);
+ return;
+
+ case REG_DISPB_DISPCNT :
+ //GPU_setVideoProp(SubScreen.gpu, val);
+ //GPULOG("SUB INIT 32B %08X\r\n", val);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x1000, val);
+ return;*/
+
+ case REG_VRAMCNTA:
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+1), (val >> 8) & 0xFF);
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+2), (val >> 16) & 0xFF);
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+3), (val >> 24) & 0xFF);
+ break;
+ case REG_VRAMCNTE:
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+1), (val >> 8) & 0xFF);
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+2), (val >> 16) & 0xFF);
+ /* Update WRAMSTAT at the ARM7 side */
+ T1WriteByte(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x241, (val >> 24) & 0xFF);
+ break;
+ case REG_VRAMCNTH:
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA), val & 0xFF);
+ MMU_VRAMmapControl(static_cast<uint8_t>(adr-REG_VRAMCNTA+1), (val >> 8) & 0xFF);
+ break;
+
+ case REG_IME :
+ NDS_Reschedule();
+ MMU.reg_IME[ARMCPU_ARM9] = val & 0x01;
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x208, val);
+ return;
+
+ case REG_IE :
+ NDS_Reschedule();
+ MMU.reg_IE[ARMCPU_ARM9] = val;
+ return;
+
+ case REG_IF: REG_IF_WriteLong<ARMCPU_ARM9>(val); return;
+
+ case REG_TM0CNTL:
+ case REG_TM1CNTL:
+ case REG_TM2CNTL:
+ case REG_TM3CNTL:
+ {
+ int timerIndex = (adr>>2)&0x3;
+ MMU.timerReload[ARMCPU_ARM9][timerIndex] = (uint16_t)val;
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], adr & 0xFFF, static_cast<uint16_t>(val));
+ write_timer(ARMCPU_ARM9, timerIndex, val>>16);
+ return;
+ }
+
+ case REG_DIVNUMER:
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x290, val);
+ execdiv();
+ return;
+ case REG_DIVNUMER+4:
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x294, val);
+ execdiv();
+ return;
+
+ case REG_DIVDENOM :
+ {
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x298, val);
+ execdiv();
+ return;
+ }
+ case REG_DIVDENOM+4 :
+ {
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x29C, val);
+ execdiv();
+ return;
+ }
+
+ case REG_SQRTPARAM :
+ {
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B8, val);
+ execsqrt();
+ return;
+ }
+ case REG_SQRTPARAM+4 :
+ {
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2BC, val);
+ execsqrt();
+ return;
+ }
+
+ case REG_IPCSYNC:
+ MMU_IPCSync(ARMCPU_ARM9, val);
+ return;
+ case REG_IPCFIFOCNT:
+ IPC_FIFOcnt(ARMCPU_ARM9, static_cast<uint16_t>(val));
+ return;
+ case REG_IPCFIFOSEND:
+ IPC_FIFOsend(ARMCPU_ARM9, val);
+ return;
+
+
+ case REG_GCROMCTRL :
+ MMU_writeToGCControl<ARMCPU_ARM9>(val);
+ return;
+ case REG_DISPA_DISPCAPCNT :
+ //INFO("MMU write32: REG_DISPA_DISPCAPCNT 0x%X\n", val);
+ //GPU_set_DISPCAPCNT(val);
+ T1WriteLong(MMU.ARM9_REG, 0x64, val);
+ return;
+
+ /*case REG_DISPA_BG0CNT :
+ //GPU_setBGProp(MainScreen.gpu, 0, (val&0xFFFF));
+ //GPU_setBGProp(MainScreen.gpu, 1, (val>>16));
+ //if((val>>16)==0x400) emu_halt();
+ T1WriteLong(MMU.ARM9_REG, 8, val);
+ return;
+ case REG_DISPA_BG2CNT :
+ //GPU_setBGProp(MainScreen.gpu, 2, (val&0xFFFF));
+ //GPU_setBGProp(MainScreen.gpu, 3, (val>>16));
+ T1WriteLong(MMU.ARM9_REG, 0xC, val);
+ return;
+ case REG_DISPB_BG0CNT :
+ //GPU_setBGProp(SubScreen.gpu, 0, (val&0xFFFF));
+ //GPU_setBGProp(SubScreen.gpu, 1, (val>>16));
+ T1WriteLong(MMU.ARM9_REG, 0x1008, val);
+ return;
+ case REG_DISPB_BG2CNT :
+ //GPU_setBGProp(SubScreen.gpu, 2, (val&0xFFFF));
+ //GPU_setBGProp(SubScreen.gpu, 3, (val>>16));
+ T1WriteLong(MMU.ARM9_REG, 0x100C, val);
+ return;*/
+ /*case REG_DISPA_DISPMMEMFIFO:
+ {
+ DISP_FIFOsend(val);
+ return;
+ }*/
+
+ //case REG_DISPA_DISP3DCNT: writereg_DISP3DCNT(32,adr,val); return;
+
+ case REG_GCDATAIN:
+ slot1_device.write32(ARMCPU_ARM9, REG_GCDATAIN,val);
+ return;
+ }
+
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20], val);
+ return;
+ }
+
+ bool unmapped, restricted;
+ adr = MMU_LCDmap/*<ARMCPU_ARM9>*/(adr, unmapped, restricted);
+ if(unmapped) return;
+
+ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash]
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM9][adr>>20], val);
+}
+
+//================================================= MMU ARM9 read 08
+uint8_t FASTCALL _MMU_ARM9_read08(uint32_t adr)
+{
+ adr &= 0x0FFFFFFF;
+
+ //mmu_log_debug_ARM9(adr, "(read08) 0x%02X", MMU.MMU_MEM[ARMCPU_ARM9][(adr>>20)&0xFF][adr&MMU.MMU_MASK[ARMCPU_ARM9][(adr>>20)&0xFF]]);
+
+ if(adr<0x02000000)
+ return T1ReadByte(MMU.ARM9_ITCM, adr&0x7FFF);
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ return 0/*addon.read08(adr)*/;
+
+ if (adr >> 24 == 4)
+ { //Address is an IO register
+
+ if(MMU_new.is_dma(adr)) return static_cast<uint8_t>(MMU_new.read_dma(ARMCPU_ARM9,8,adr));
+
+ switch(adr)
+ {
+ case REG_IF: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM9>());
+ case REG_IF+1: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM9>()>>8);
+ case REG_IF+2: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM9>()>>16);
+ case REG_IF+3: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM9>()>>24);
+
+ /*case REG_DISPA_DISPSTAT:
+ break;
+ case REG_DISPA_DISPSTAT+1:
+ break;
+ case REG_DISPx_VCOUNT: return nds.VCount & 0xFF;
+ case REG_DISPx_VCOUNT+1: return (nds.VCount>>8) & 0xFF;*/
+#if 0
+ case REG_SQRTCNT: printf("ERROR 8bit SQRTCNT READ\n"); return 0;
+ case REG_SQRTCNT+1: printf("ERROR 8bit SQRTCNT1 READ\n"); return 0;//(MMU_new.sqrt.read16() & 0xFF00)>>8;
+#else
+ case REG_SQRTCNT: return MMU_new.sqrt.read16() & 0xFF;
+ case REG_SQRTCNT+1: return (MMU_new.sqrt.read16()>>8) & 0xFF;
+#endif
+ case REG_SQRTCNT+2: printf("ERROR 8bit SQRTCNT2 READ\n"); return 0;
+ case REG_SQRTCNT+3: printf("ERROR 8bit SQRTCNT3 READ\n"); return 0;
+#if 1
+ case REG_DIVCNT: printf("ERROR 8bit DIVCNT READ\n"); return 0;
+ case REG_DIVCNT+1: printf("ERROR 8bit DIVCNT1 READ\n"); return 0;
+#else
+ case REG_DIVCNT: return MMU_new.div.read16() & 0xFF;
+ case REG_DIVCNT+1: return (MMU_new.div.read16()>>8) & 0xFF;
+#endif
+ case REG_DIVCNT+2: printf("ERROR 8bit DIVCNT2 READ\n"); return 0;
+ case REG_DIVCNT+3: printf("ERROR 8bit DIVCNT3 READ\n"); return 0;
+
+ //fog table: write only
+ /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x01: case eng_3D_FOG_TABLE+0x02: case eng_3D_FOG_TABLE+0x03:
+ case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x05: case eng_3D_FOG_TABLE+0x06: case eng_3D_FOG_TABLE+0x07:
+ case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x09: case eng_3D_FOG_TABLE+0x0A: case eng_3D_FOG_TABLE+0x0B:
+ case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x0D: case eng_3D_FOG_TABLE+0x0E: case eng_3D_FOG_TABLE+0x0F:
+ case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x11: case eng_3D_FOG_TABLE+0x12: case eng_3D_FOG_TABLE+0x13:
+ case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x15: case eng_3D_FOG_TABLE+0x16: case eng_3D_FOG_TABLE+0x17:
+ case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x19: case eng_3D_FOG_TABLE+0x1A: case eng_3D_FOG_TABLE+0x1B:
+ case eng_3D_FOG_TABLE+0x1C: case eng_3D_FOG_TABLE+0x1D: case eng_3D_FOG_TABLE+0x1E: case eng_3D_FOG_TABLE+0x1F:
+ return 0;*/
+
+ /*case REG_POWCNT1:
+ case REG_POWCNT1+1:
+ case REG_POWCNT1+2:
+ case REG_POWCNT1+3:
+ return readreg_POWCNT1(8,adr);*/
+
+ /*case eng_3D_GXSTAT:
+ return MMU_new.gxstat.read(8,adr);*/
+
+ //case REG_DISPA_DISP3DCNT: return readreg_DISP3DCNT(8,adr);
+ //case REG_DISPA_DISP3DCNT+1: return readreg_DISP3DCNT(8,adr);
+ //case REG_DISPA_DISP3DCNT+2: return readreg_DISP3DCNT(8,adr);
+ //case REG_DISPA_DISP3DCNT+3: return readreg_DISP3DCNT(8,adr);
+ }
+ }
+
+ bool unmapped, restricted;
+ adr = MMU_LCDmap/*<ARMCPU_ARM9>*/(adr, unmapped, restricted);
+ if(unmapped) return 0;
+
+ return MMU.MMU_MEM[ARMCPU_ARM9][(adr>>20)&0xFF][adr&MMU.MMU_MASK[ARMCPU_ARM9][(adr>>20)&0xFF]];
+}
+
+//================================================= MMU ARM9 read 16
+uint16_t FASTCALL _MMU_ARM9_read16(uint32_t adr)
+{
+ adr &= 0x0FFFFFFE;
+
+ //mmu_log_debug_ARM9(adr, "(read16) 0x%04X", T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr >> 20]));
+
+ if(adr<0x02000000)
+ return T1ReadWord_guaranteedAligned(MMU.ARM9_ITCM, adr & 0x7FFE);
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ return 0/*addon.read16(adr)*/;
+
+ if (adr >> 24 == 4)
+ {
+ if(MMU_new.is_dma(adr)) return static_cast<uint16_t>(MMU_new.read_dma(ARMCPU_ARM9,16,adr));
+
+ // Address is an IO register
+ switch(adr)
+ {
+ /*case REG_DISPA_DISPSTAT:
+ break;*/
+
+ case REG_SQRTCNT: return MMU_new.sqrt.read16();
+ case REG_DIVCNT: return MMU_new.div.read16();
+ //case eng_3D_GXSTAT: return MMU_new.gxstat.read(16,adr);
+
+ /*case REG_DISPA_VCOUNT:
+ if(nds.ensataEmulation && nds.ensataHandshake == ENSATA_HANDSHAKE_query)
+ {
+ nds.ensataHandshake = ENSATA_HANDSHAKE_ack;
+ return 270;
+ } else return nds.VCount;
+
+ // ============================================= 3D
+ case eng_3D_RAM_COUNT:
+ return 0;
+ //almost worthless for now
+ //return gfx3d_GetNumPolys();
+ case eng_3D_RAM_COUNT+2:
+ return 0;
+ //almost worthless for now
+ //return gfx3d_GetNumVertex();*/
+ // ============================================= 3D end
+ case REG_IME :
+ return (uint16_t)MMU.reg_IME[ARMCPU_ARM9];
+
+ case REG_IE :
+ return (uint16_t)MMU.reg_IE[ARMCPU_ARM9];
+ case REG_IE + 2 :
+ return (uint16_t)(MMU.reg_IE[ARMCPU_ARM9]>>16);
+
+ case REG_IF: return static_cast<uint16_t>(MMU.gen_IF<ARMCPU_ARM9>());
+ case REG_IF+2: return static_cast<uint16_t>(MMU.gen_IF<ARMCPU_ARM9>()>>16);
+
+ case REG_TM0CNTL :
+ case REG_TM1CNTL :
+ case REG_TM2CNTL :
+ case REG_TM3CNTL :
+ return read_timer(ARMCPU_ARM9,(adr&0xF)>>2);
+
+ case REG_AUXSPICNT:
+ return MMU.AUX_SPI_CNT;
+
+ /*case REG_POWCNT1:
+ case REG_POWCNT1+2:
+ return readreg_POWCNT1(16,adr);*/
+
+ //case REG_DISPA_DISP3DCNT: return readreg_DISP3DCNT(16,adr);
+ //case REG_DISPA_DISP3DCNT+2: return readreg_DISP3DCNT(16,adr);
+
+ /*case 0x04000130:
+ case 0x04000136:
+ //not sure whether these should trigger from byte reads
+ LagFrameFlag=0;
+ break;*/
+
+ //fog table: write only
+ /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x02: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x06:
+ case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x0A: case eng_3D_FOG_TABLE+0x0C: case eng_3D_FOG_TABLE+0x0E:
+ case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x12: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x16:
+ case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x1A: case eng_3D_FOG_TABLE+0x1C: case eng_3D_FOG_TABLE+0x1E:
+ return 0;*/
+ }
+
+ return T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]);
+ }
+
+ //bool unmapped = false/*, restricted*/;
+ //adr = MMU_LCDmap<ARMCPU_ARM9>(adr,unmapped, restricted);
+ //if(unmapped) return 0;
+
+ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF
+ return T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr >> 20]);
+}
+
+//================================================= MMU ARM9 read 32
+uint32_t FASTCALL _MMU_ARM9_read32(uint32_t adr)
+{
+ adr &= 0x0FFFFFFC;
+
+ //mmu_log_debug_ARM9(adr, "(read32) 0x%08X", T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]));
+
+ if(adr<0x02000000)
+ return T1ReadLong_guaranteedAligned(MMU.ARM9_ITCM, adr&0x7FFC);
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ return 0/*addon.read32(adr)*/;
+
+ // Address is an IO register
+ if((adr >> 24) == 4)
+ {
+ if(MMU_new.is_dma(adr)) return MMU_new.read_dma(ARMCPU_ARM9,32,adr);
+
+ switch(adr)
+ {
+ case REG_DSIMODE:
+ if(!nds.Is_DSI()) break;
+ return 1;
+ case 0x04004008:
+ if(!nds.Is_DSI()) break;
+ return 0x8000;
+
+ /*case REG_DISPA_DISPSTAT:
+ break;
+
+ case REG_DISPx_VCOUNT: return nds.VCount;*/
+
+ //Dolphin Island Underwater Adventures uses this amidst seemingly reasonable divs so we're going to emulate it.
+ case REG_DIVCNT: return MMU_new.div.read16();
+ //I guess we'll do this also
+ case REG_SQRTCNT: return MMU_new.sqrt.read16();
+
+ //fog table: write only
+ /*case eng_3D_FOG_TABLE+0x00: case eng_3D_FOG_TABLE+0x04: case eng_3D_FOG_TABLE+0x08: case eng_3D_FOG_TABLE+0x0C:
+ case eng_3D_FOG_TABLE+0x10: case eng_3D_FOG_TABLE+0x14: case eng_3D_FOG_TABLE+0x18: case eng_3D_FOG_TABLE+0x1C:
+ return 0;*/
+
+ /*case eng_3D_CLIPMTX_RESULT:
+ case eng_3D_CLIPMTX_RESULT+4:
+ case eng_3D_CLIPMTX_RESULT+8:
+ case eng_3D_CLIPMTX_RESULT+12:
+ case eng_3D_CLIPMTX_RESULT+16:
+ case eng_3D_CLIPMTX_RESULT+20:
+ case eng_3D_CLIPMTX_RESULT+24:
+ case eng_3D_CLIPMTX_RESULT+28:
+ case eng_3D_CLIPMTX_RESULT+32:
+ case eng_3D_CLIPMTX_RESULT+36:
+ case eng_3D_CLIPMTX_RESULT+40:
+ case eng_3D_CLIPMTX_RESULT+44:
+ case eng_3D_CLIPMTX_RESULT+48:
+ case eng_3D_CLIPMTX_RESULT+52:
+ case eng_3D_CLIPMTX_RESULT+56:
+ case eng_3D_CLIPMTX_RESULT+60:
+ {
+ //LOG("4000640h..67Fh - CLIPMTX_RESULT - Read Current Clip Coordinates Matrix (R)");
+ return gfx3d_GetClipMatrix ((adr-0x04000640)/4);
+ }*/
+ /*case eng_3D_VECMTX_RESULT:
+ case eng_3D_VECMTX_RESULT+4:
+ case eng_3D_VECMTX_RESULT+8:
+ case eng_3D_VECMTX_RESULT+12:
+ case eng_3D_VECMTX_RESULT+16:
+ case eng_3D_VECMTX_RESULT+20:
+ case eng_3D_VECMTX_RESULT+24:
+ case eng_3D_VECMTX_RESULT+28:
+ case eng_3D_VECMTX_RESULT+32:
+ {
+ //LOG("4000680h..6A3h - VECMTX_RESULT - Read Current Directional Vector Matrix (R)");
+ return gfx3d_GetDirectionalMatrix ((adr-0x04000680)/4);
+ }*/
+
+ /*case eng_3D_RAM_COUNT:
+ {
+ return gfx3d_GetNumPolys() | ((gfx3d_GetNumVertex()) << 16);
+ //LOG ("read32 - RAM_COUNT -> 0x%X", ((uint32_t *)(MMU.MMU_MEM[ARMCPU_ARM9][(adr>>20)&0xFF]))[(adr&MMU.MMU_MASK[ARMCPU_ARM9][(adr>>20)&0xFF])>>2]);
+ }*/
+
+ /*case eng_3D_POS_RESULT:
+ case eng_3D_POS_RESULT+4:
+ case eng_3D_POS_RESULT+8:
+ case eng_3D_POS_RESULT+12:
+ {
+ return gfx3d_glGetPosRes((adr & 0xF) >> 2);
+ }*/
+ /*case eng_3D_GXSTAT:
+ return MMU_new.gxstat.read(32,adr);*/
+ // ======================================== 3D end
+
+
+ case REG_IME :
+ return MMU.reg_IME[ARMCPU_ARM9];
+ case REG_IE :
+ return MMU.reg_IE[ARMCPU_ARM9];
+
+ case REG_IF: return MMU.gen_IF<ARMCPU_ARM9>();
+
+ case REG_IPCFIFORECV :
+ return IPC_FIFOrecv(ARMCPU_ARM9);
+ case REG_TM0CNTL :
+ case REG_TM1CNTL :
+ case REG_TM2CNTL :
+ case REG_TM3CNTL :
+ {
+ uint32_t val = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], (adr + 2) & 0xFFF);
+ return MMU.timer[ARMCPU_ARM9][(adr&0xF)>>2] | (val<<16);
+ }
+
+ case REG_GCDATAIN: return MMU_readFromGC<ARMCPU_ARM9>();
+ //case REG_POWCNT1: return readreg_POWCNT1(32,adr);
+ //case REG_DISPA_DISP3DCNT: return readreg_DISP3DCNT(32,adr);
+ }
+ return T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]);
+ }
+
+ //bool unmapped = false/*, restricted*/;
+ //adr = MMU_LCDmap<ARMCPU_ARM9>(adr,unmapped, restricted);
+ //if(unmapped) return 0;
+
+ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [zeromus, inspired by shash]
+ return T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM9][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM9][adr>>20]);
+}
+//================================================================================================== ARM7 *
+//=========================================================================================================
+//=========================================================================================================
+//================================================= MMU ARM7 write 08
+void FASTCALL _MMU_ARM7_write08(uint32_t adr, uint8_t val)
+{
+ adr &= 0x0FFFFFFF;
+
+ //mmu_log_debug_ARM7(adr, "(write08) 0x%02X", val);
+
+ if (adr < 0x4000) return; // PU BIOS
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ {
+ //addon.write08(adr, val);
+ return;
+ }
+
+ if ((adr>=0x04000400)&&(adr<0x04000520))
+ {
+ SPU_WriteByte(adr, val);
+ return;
+ }
+
+ if ((adr & 0xFFFF0000) == 0x04800000)
+ {
+ /* is wifi hardware, dont intermix with regular hardware registers */
+ // 8-bit writes to wifi I/O and RAM are ignored
+ // Reference: http://nocash.emubase.de/gbatek.htm#dswifiiomap
+ return;
+ }
+
+ if (adr >> 24 == 4)
+ {
+ if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM7,8,adr,val); return; }
+
+ switch(adr)
+ {
+ case REG_IF: REG_IF_WriteByte<ARMCPU_ARM7>(0,val); break;
+ case REG_IF+1: REG_IF_WriteByte<ARMCPU_ARM7>(1,val); break;
+ case REG_IF+2: REG_IF_WriteByte<ARMCPU_ARM7>(2,val); break;
+ case REG_IF+3: REG_IF_WriteByte<ARMCPU_ARM7>(3,val); break;
+
+ case REG_POSTFLG:
+ // hack for patched firmwares
+ if (val == 1)
+ {
+ if (_MMU_ARM7_read08(REG_POSTFLG) != 0)
+ break;
+ _MMU_write32<ARMCPU_ARM9>(0x27FFE24, gameInfo.header.ARM9exe);
+ _MMU_write32<ARMCPU_ARM7>(0x27FFE34, gameInfo.header.ARM7exe);
+ }
+ break;
+
+ case REG_HALTCNT:
+ //printf("halt 0x%02X\n", val);
+ switch(val)
+ {
+ case 0xC0: NDS_Sleep(); break;
+ case 0x80: armcpu_Wait4IRQ(&NDS_ARM7); break;
+ default: break;
+ }
+ break;
+
+ /*case REG_RTC:
+ rtcWrite(val);
+ return;*/
+
+ /*case REG_AUXSPICNT:
+ write_auxspicnt(9,8,0,val);
+ return;
+ case REG_AUXSPICNT+1:
+ write_auxspicnt(9,8,1,val);
+ return;
+ case REG_AUXSPIDATA:
+ if(val!=0) MMU.AUX_SPI_CMD = val & 0xFF;
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, MMU_new.backupDevice.data_command((uint8_t)val,ARMCPU_ARM7));
+ MMU.AUX_SPI_CNT &= ~0x80; //remove busy flag
+ return;*/
+ }
+ MMU.MMU_MEM[ARMCPU_ARM7][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]]=val;
+ return;
+ }
+
+ //bool unmapped = false/*, restricted*/;
+ //adr = MMU_LCDmap<ARMCPU_ARM7>(adr,unmapped, restricted);
+ //if(unmapped) return;
+
+ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash]
+ MMU.MMU_MEM[ARMCPU_ARM7][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]]=val;
+}
+
+//================================================= MMU ARM7 write 16
+void FASTCALL _MMU_ARM7_write16(uint32_t adr, uint16_t val)
+{
+ adr &= 0x0FFFFFFE;
+
+ //mmu_log_debug_ARM7(adr, "(write16) 0x%04X", val);
+
+ if (adr < 0x4000) return; // PU BIOS
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ {
+ //addon.write16(adr, val);
+ return;
+ }
+
+ //wifi mac access
+ /*if ((adr & 0xFFFF0000) == 0x04800000)
+ {
+ WIFI_write16(adr,val);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x48], adr&MMU.MMU_MASK[ARMCPU_ARM7][0x48], val);
+ return;
+ }*/
+
+ if ((adr>=0x04000400)&&(adr<0x04000520))
+ {
+ SPU_WriteWord(adr, val);
+ return;
+ }
+
+ if((adr >> 24) == 4)
+ {
+ if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM7,16,adr,val); return; }
+
+ //Address is an IO register
+ switch(adr)
+ {
+ case REG_DISPA_VCOUNT:
+ if (nds.VCount >= 202 && nds.VCount <= 212)
+ {
+ printf("VCOUNT set to %i (previous value %i)\n", val, nds.VCount);
+ nds.VCount = val;
+ }
+ else
+ printf("Attempt to set VCOUNT while not within 202-212 (%i), ignored\n", nds.VCount);
+ return;
+
+ /*case REG_RTC:
+ rtcWrite(val);
+ break;*/
+
+ case REG_EXMEMCNT:
+ {
+ uint16_t remote_proc = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x204);
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x204, (val & 0x7F) | (remote_proc & 0xFF80));
+ }
+ return;
+
+ /*case REG_EXTKEYIN: //readonly
+ return;*/
+
+
+ /*case REG_POWCNT2:
+ {
+ nds.power2.speakers = BIT0(val);
+ nds.power2.wifi = BIT0(val);
+ }
+ return;*/
+
+
+ /*case REG_AUXSPICNT:
+ write_auxspicnt(7,16,0,val);
+ return;
+
+ case REG_AUXSPIDATA:
+ if(val!=0)
+ MMU.AUX_SPI_CMD = val & 0xFF;
+
+ //T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, bm_transfer(&MMU.bupmem, val));
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_AUXSPIDATA >> 20) & 0xff], REG_AUXSPIDATA & 0xfff, MMU_new.backupDevice.data_command((uint8_t)val,ARMCPU_ARM7));
+ MMU.AUX_SPI_CNT &= ~0x80; //remove busy flag
+ return;*/
+
+ case REG_SPICNT :
+ {
+ int reset_firmware = 1;
+
+ if ( ((MMU.SPI_CNT >> 8) & 0x3) == 1)
+ {
+ if ( ((val >> 8) & 0x3) == 1)
+ {
+ if ( BIT11(MMU.SPI_CNT))
+ {
+ // select held
+ reset_firmware = 0;
+ }
+ }
+ }
+
+ //MMU.fw.com == 0; // reset fw device communication
+ if ( reset_firmware)
+ {
+ // reset fw device communication
+ fw_reset_com(&MMU.fw);
+ }
+ MMU.SPI_CNT = val;
+
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_SPICNT >> 20) & 0xff], REG_SPICNT & 0xfff, val);
+ }
+ return;
+
+ case REG_SPIDATA :
+ {
+ uint16_t spicnt;
+
+ if(val!=0)
+ MMU.SPI_CMD = val;
+
+ spicnt = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_SPICNT >> 20) & 0xff], REG_SPICNT & 0xfff);
+
+ switch((spicnt >> 8) & 0x3)
+ {
+ case 0 :
+ {
+ if(!MMU.powerMan_CntRegWritten)
+ {
+ MMU.powerMan_CntReg = (val & 0xFF);
+ MMU.powerMan_CntRegWritten = true;
+ }
+ else
+ {
+ uint16_t reg = MMU.powerMan_CntReg&0x7F;
+ reg &= 0x7;
+ if(reg==5 || reg==6 || reg==7) reg = 4;
+
+ //(let's start with emulating a DS lite, since it is the more complex case)
+ if(MMU.powerMan_CntReg & 0x80)
+ {
+ //read
+ val = MMU.powerMan_Reg[reg];
+ }
+ else
+ {
+ //write
+ MMU.powerMan_Reg[reg] = (uint8_t)val;
+
+ //enum PM_Bits //from libnds
+ //{
+ //PM_SOUND_AMP = BIT(0) , /*!< \brief Power the sound hardware (needed to hear stuff in GBA mode too) */
+ //PM_SOUND_MUTE = BIT(1), /*!< \brief Mute the main speakers, headphone output will still work. */
+ //PM_BACKLIGHT_BOTTOM = BIT(2), /*!< \brief Enable the top backlight if set */
+ //PM_BACKLIGHT_TOP = BIT(3) , /*!< \brief Enable the bottom backlight if set */
+ static const uint32_t PM_SYSTEM_PWR = BIT(6); /*!< \brief Turn the power *off* if set */
+ //};
+
+ //our totally pathetic register handling, only the one thing we've wanted so far
+ if(MMU.powerMan_Reg[0]&PM_SYSTEM_PWR) {
+ printf("SYSTEM POWERED OFF VIA ARM7 SPI POWER DEVICE\n");
+ //emu_halt();
+ execute = false;
+ }
+ }
+
+ MMU.powerMan_CntRegWritten = false;
+ }
+ }
+ break;
+
+ case 1 : /* firmware memory device */
+ if((spicnt & 0x3) != 0) /* check SPI baudrate (must be 4mhz) */
+ {
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_SPIDATA >> 20) & 0xff], REG_SPIDATA & 0xfff, 0);
+ break;
+ }
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_SPIDATA >> 20) & 0xff], REG_SPIDATA & 0xfff, fw_transfer(&MMU.fw, (uint8_t)val));
+ return;
+
+ case 2:
+ {
+ if(nds.Is_DSI())
+ {
+ //pass data to TSC
+ val = MMU_new.dsi_tsc.write16(val);
+
+ //apply reset command if appropriate
+ if(!BIT11(MMU.SPI_CNT))
+ MMU_new.dsi_tsc.reset_command();
+
+ break;
+ }
+
+ int channel = (MMU.SPI_CMD&0x70)>>4;
+ //printf("%08X\n",channel);
+ switch(channel)
+ {
+ case TSC_MEASURE_TEMP1:
+ if(spicnt & 0x800)
+ {
+ if(partie)
+ {
+ val = ((716<<3)&0x7FF);
+ partie = 0;
+ break;
+ }
+ val = (716>>5);
+ partie = 1;
+ break;
+ }
+ val = ((716<<3)&0x7FF);
+ partie = 1;
+ break;
+ case TSC_MEASURE_TEMP2:
+ if(spicnt & 0x800)
+ {
+ if(partie)
+ {
+ val = ((865<<3)&0x7FF);
+ partie = 0;
+ break;
+ }
+ val = (865>>5);
+ partie = 1;
+ break;
+ }
+ val = ((865<<3)&0x7FF);
+ partie = 1;
+ break;
+
+ case TSC_MEASURE_Y:
+ {
+ //counter the number of adc touch coord reads and jitter it after a while to simulate a shaky human hand or multiple reads
+ /*nds.adc_jitterctr++;
+ if(nds.adc_jitterctr == 25)
+ {
+ nds.adc_jitterctr = 0;
+ nds.adc_touchY ^= 16;
+ nds.adc_touchX ^= 16;
+ }*/
+ if(MMU.SPI_CNT&(1<<11))
+ {
+ if(partie)
+ {
+ //val = (nds.adc_touchY<<3) & 0xFF;
+ partie = 0;
+ break;
+ }
+
+ //val = (nds.adc_touchY>>5) & 0xFF;
+ partie = 1;
+ break;
+ }
+ //val = (nds.adc_touchY<<3)&0xFF;
+ partie = 1;
+ break;
+ }
+ case TSC_MEASURE_Z1: //Z1
+ //used for pressure calculation - must be nonzero or else some softwares will think the stylus is up.
+ //something is wrong in here and some of these LSB dont make it back to libnds... whatever.
+ /*{
+ u16 scratch;
+ CalculateTouchPressure(CommonSettings.StylusPressure,val,scratch);
+ }*/
+ if(spicnt & 0x800)
+ {
+ if(partie)
+ {
+ val = ((val<<3)&0x7FF);
+ partie = 0;
+ break;
+ }
+ val = (val>>5);
+ partie = 1;
+ break;
+ }
+ val = ((val<<3)&0x7FF);
+ partie = 1;
+ break;
+ case TSC_MEASURE_Z2: //Z2
+ //used for pressure calculation - must be nonzero or else some softwares will think the stylus is up.
+ //something is wrong in here and some of these LSB dont make it back to libnds... whatever.
+ /*{
+ u16 scratch;
+ CalculateTouchPressure(CommonSettings.StylusPressure,scratch,val);
+ }*/
+ if(spicnt & 0x800)
+ {
+ if(partie)
+ {
+ val = ((val<<3)&0x7FF);
+ partie = 0;
+ break;
+ }
+ val = (val>>5);
+ partie = 1;
+ break;
+ }
+ val = ((val<<3)&0x7FF);
+ partie = 1;
+ break;
+ case TSC_MEASURE_X:
+ if(spicnt & 0x800)
+ {
+ if(partie)
+ {
+ //val = (nds.adc_touchX << 3) & 0xFF;
+ partie = 0;
+ break;
+ }
+ //val = (nds.adc_touchX>>5) & 0xFF;
+ partie = 1;
+ break;
+ }
+ //val = (nds.adc_touchX<<3) & 0xFF;
+ partie = 1;
+ break;
+ case TSC_MEASURE_AUX:
+ /*if(!(val & 0x80))
+ val = (Mic_ReadSample() & 0xFF);
+ else*/
+ val = 0;
+ break;
+ }
+ break;
+ }
+
+ case 3 :
+ /* NOTICE: Device 3 of SPI is reserved (unused and unusable) */
+ break;
+ }
+ }
+
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][(REG_SPIDATA >> 20) & 0xff], REG_SPIDATA & 0xfff, val);
+ return;
+
+ /* NOTICE: Perhaps we have to use gbatek-like reg names instead of libnds-like ones ...*/
+
+ case REG_IME :
+ NDS_Reschedule();
+ MMU.reg_IME[ARMCPU_ARM7] = val & 0x01;
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x208, val);
+ return;
+ case REG_IE :
+ NDS_Reschedule();
+ MMU.reg_IE[ARMCPU_ARM7] = (MMU.reg_IE[ARMCPU_ARM7]&0xFFFF0000) | val;
+ return;
+ case REG_IE + 2 :
+ NDS_Reschedule();
+ //emu_halt();
+ MMU.reg_IE[ARMCPU_ARM7] = (MMU.reg_IE[ARMCPU_ARM7]&0xFFFF) | (((uint32_t)val)<<16);
+ return;
+
+ case REG_IF: REG_IF_WriteWord<ARMCPU_ARM7>(0,val); return;
+ case REG_IF+2: REG_IF_WriteWord<ARMCPU_ARM7>(2,val); return;
+
+ case REG_IPCSYNC :
+ MMU_IPCSync(ARMCPU_ARM7, val);
+ return;
+
+ case REG_IPCFIFOCNT :
+ IPC_FIFOcnt(ARMCPU_ARM7, val);
+ return;
+ case REG_TM0CNTL :
+ case REG_TM1CNTL :
+ case REG_TM2CNTL :
+ case REG_TM3CNTL :
+ MMU.timerReload[ARMCPU_ARM7][(adr>>2)&3] = val;
+ return;
+ case REG_TM0CNTH :
+ case REG_TM1CNTH :
+ case REG_TM2CNTH :
+ case REG_TM3CNTH :
+ {
+ int timerIndex = ((adr-2)>>2)&0x3;
+ write_timer(ARMCPU_ARM7, timerIndex, val);
+ return;
+ }
+
+ case REG_GCROMCTRL :
+ MMU_writeToGCControl<ARMCPU_ARM7>( (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x1A4) & 0xFFFF0000) | val);
+ return;
+ case REG_GCROMCTRL+2 :
+ MMU_writeToGCControl<ARMCPU_ARM7>( (T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x1A4) & 0xFFFF) | ((uint32_t) val << 16));
+ return;
+ }
+
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val);
+ return;
+ }
+
+ //bool unmapped = false/*, restricted*/;
+ //adr = MMU_LCDmap<ARMCPU_ARM7>(adr,unmapped, restricted);
+ //if(unmapped) return;
+
+ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash]
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val);
+}
+//================================================= MMU ARM7 write 32
+void FASTCALL _MMU_ARM7_write32(uint32_t adr, uint32_t val)
+{
+ adr &= 0x0FFFFFFC;
+
+ //mmu_log_debug_ARM7(adr, "(write32) 0x%08X", val);
+
+ if (adr < 0x4000) return; // PU BIOS
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ {
+ //addon.write32(adr, val);
+ return;
+ }
+
+ /*if ((adr & 0xFFFF0000) == 0x04800000)
+ {
+ WIFI_write16(adr, val & 0xFFFF);
+ WIFI_write16(adr+2, val >> 16);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x48], adr&MMU.MMU_MASK[ARMCPU_ARM7][0x48], val);
+ return;
+ }*/
+
+ if ((adr>=0x04000400)&&(adr<0x04000520))
+ {
+ SPU_WriteLong(adr, val);
+ return;
+ }
+
+ if((adr>>24)==4)
+ {
+ if(MMU_new.is_dma(adr)) { MMU_new.write_dma(ARMCPU_ARM7,32,adr,val); return; }
+
+ switch(adr)
+ {
+ /*case REG_RTC:
+ rtcWrite((uint16_t)val);
+ break;*/
+
+ case REG_IME :
+ NDS_Reschedule();
+ MMU.reg_IME[ARMCPU_ARM7] = val & 0x01;
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x208, val);
+ return;
+
+ case REG_IE :
+ NDS_Reschedule();
+ MMU.reg_IE[ARMCPU_ARM7] = val;
+ return;
+
+ case REG_IF: REG_IF_WriteLong<ARMCPU_ARM7>(val); return;
+
+ case REG_TM0CNTL:
+ case REG_TM1CNTL:
+ case REG_TM2CNTL:
+ case REG_TM3CNTL:
+ {
+ int timerIndex = (adr>>2)&0x3;
+ MMU.timerReload[ARMCPU_ARM7][timerIndex] = (uint16_t)val;
+ T1WriteWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], adr & 0xFFF, static_cast<uint16_t>(val));
+ write_timer(ARMCPU_ARM7, timerIndex, val>>16);
+ return;
+ }
+
+ case REG_IPCSYNC:
+ MMU_IPCSync(ARMCPU_ARM7, val);
+ return;
+ case REG_IPCFIFOCNT:
+ IPC_FIFOcnt(ARMCPU_ARM7, static_cast<uint16_t>(val));
+ return;
+ case REG_IPCFIFOSEND:
+ IPC_FIFOsend(ARMCPU_ARM7, val);
+ return;
+
+ case REG_GCROMCTRL :
+ MMU_writeToGCControl<ARMCPU_ARM7>(val);
+ return;
+
+ case REG_GCDATAIN:
+ slot1_device.write32(ARMCPU_ARM7, REG_GCDATAIN,val);
+ return;
+ }
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val);
+ return;
+ }
+
+ //bool unmapped = false/*, restricted*/;
+ //adr = MMU_LCDmap<ARMCPU_ARM7>(adr,unmapped, restricted);
+ //if(unmapped) return;
+
+ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [shash]
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val);
+}
+
+//================================================= MMU ARM7 read 08
+uint8_t FASTCALL _MMU_ARM7_read08(uint32_t adr)
+{
+ adr &= 0x0FFFFFFF;
+
+ //mmu_log_debug_ARM7(adr, "(read08) 0x%02X", MMU.MMU_MEM[ARMCPU_ARM7][(adr>>20)&0xFF][adr&MMU.MMU_MASK[ARMCPU_ARM7][(adr>>20)&0xFF]]);
+
+ if (adr < 0x4000)
+ {
+ //uint32_t prot = T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x04000308 & MMU.MMU_MASK[ARMCPU_ARM7][0x40]);
+ //if (prot) INFO("MMU7 read 08 at 0x%08X (PC 0x%08X) BIOSPROT address 0x%08X\n", adr, NDS_ARM7.R[15], prot);
+
+ //How accurate is this? our R[15] may not be exactly what the hardware uses (may use something less by up to 0x08)
+ //This may be inaccurate at the very edge cases.
+ if (NDS_ARM7.R[15] > 0x3FFF)
+ return 0xFF;
+ }
+
+ // wifi mac access
+ /*if ((adr & 0xFFFF0000) == 0x04800000)
+ {
+ if (adr & 1)
+ return (WIFI_read16(adr-1) >> 8) & 0xFF;
+ else
+ return WIFI_read16(adr) & 0xFF;
+ }*/
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ return 0/*addon.read08(adr)*/;
+
+ if ((adr>=0x04000400)&&(adr<0x04000520))
+ {
+ return SPU_ReadByte(adr);
+ }
+
+ //if (adr == REG_RTC) return (uint8_t)rtcRead();
+
+ if (adr >> 24 == 4)
+ {
+ if(MMU_new.is_dma(adr)) return static_cast<uint8_t>(MMU_new.read_dma(ARMCPU_ARM7,8,adr));
+
+ // Address is an IO register
+
+ switch(adr)
+ {
+ case REG_IF: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM7>());
+ case REG_IF+1: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM7>()>>8);
+ case REG_IF+2: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM7>()>>16);
+ case REG_IF+3: return static_cast<uint8_t>(MMU.gen_IF<ARMCPU_ARM7>()>>24);
+
+ /*case REG_DISPx_VCOUNT: return nds.VCount&0xFF;
+ case REG_DISPx_VCOUNT+1: return (nds.VCount>>8)&0xFF;*/
+ }
+
+ return MMU.MMU_MEM[ARMCPU_ARM7][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]];
+ }
+
+ //bool unmapped = false/*, restricted*/;
+ //adr = MMU_LCDmap<ARMCPU_ARM7>(adr,unmapped, restricted);
+ //if(unmapped) return 0;
+
+ return MMU.MMU_MEM[ARMCPU_ARM7][adr>>20][adr&MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]];
+}
+//================================================= MMU ARM7 read 16
+uint16_t FASTCALL _MMU_ARM7_read16(uint32_t adr)
+{
+ adr &= 0x0FFFFFFE;
+
+ //mmu_log_debug_ARM7(adr, "(read16) 0x%04X", T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][(adr>>20)&0xFF], adr & MMU.MMU_MASK[ARMCPU_ARM7][(adr>>20)&0xFF]));
+
+ if (adr < 0x4000)
+ {
+ //uint32_t prot = T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x04000308 & MMU.MMU_MASK[ARMCPU_ARM7][0x40]);
+ //if (prot) INFO("MMU7 read 16 at 0x%08X (PC 0x%08X) BIOSPROT address 0x%08X\n", adr, NDS_ARM7.R[15], prot);
+ if (NDS_ARM7.R[15] > 0x3FFF)
+ return 0xFFFF;
+ }
+
+ //wifi mac access
+ /*if ((adr & 0xFFFF0000) == 0x04800000)
+ return WIFI_read16(adr) ;*/
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ return 0/*addon.read16(adr)*/;
+
+ if ((adr>=0x04000400)&&(adr<0x04000520))
+ {
+ return SPU_ReadWord(adr);
+ }
+
+ if(adr>>24==4)
+ { //Address is an IO register
+
+ if(MMU_new.is_dma(adr)) return static_cast<uint16_t>(MMU_new.read_dma(ARMCPU_ARM7,16,adr));
+
+ switch(adr)
+ {
+ /*case REG_POWCNT2:
+ {
+ uint16_t ret = 0;
+ ret |= nds.power2.speakers?BIT(0):0;
+ ret |= nds.power2.wifi?BIT(1):0;
+ return ret;
+ }*/
+
+ //case REG_DISPx_VCOUNT: return nds.VCount;
+ //case REG_RTC: return rtcRead();
+ case REG_IME: return (uint16_t)MMU.reg_IME[ARMCPU_ARM7];
+
+ case REG_IE:
+ return (uint16_t)MMU.reg_IE[ARMCPU_ARM7];
+ case REG_IE + 2:
+ return (uint16_t)(MMU.reg_IE[ARMCPU_ARM7]>>16);
+
+ case REG_IF: return static_cast<uint16_t>(MMU.gen_IF<ARMCPU_ARM7>());
+ case REG_IF+2: return static_cast<uint16_t>(MMU.gen_IF<ARMCPU_ARM7>()>>16);
+
+ case REG_TM0CNTL :
+ case REG_TM1CNTL :
+ case REG_TM2CNTL :
+ case REG_TM3CNTL :
+ return read_timer(ARMCPU_ARM7,(adr&0xF)>>2);
+
+ /*case REG_AUXSPICNT:
+ return MMU.AUX_SPI_CNT;*/
+
+ /*case REG_KEYINPUT:
+ //here is an example of what not to do:
+ //since the arm7 polls this (and EXTKEYIN) every frame, we shouldnt count this as an input check
+ //LagFrameFlag=0;
+ break;*/
+
+ /*case REG_EXTKEYIN:
+ {
+ //this is gross. we should generate this whole reg instead of poking it in ndssystem
+ uint16_t ret = MMU.ARM7_REG[0x136];
+ if(nds.isTouch) ret &= ~64;
+ else ret |= 64;
+ return ret;
+ }*/
+ }
+ return T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]);
+ }
+
+ //bool unmapped = false/*, restricted*/;
+ //adr = MMU_LCDmap<ARMCPU_ARM7>(adr,unmapped, restricted);
+ //if(unmapped) return 0;
+
+ /* Returns data from memory */
+ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF
+ return T1ReadWord_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr >> 20]);
+}
+//================================================= MMU ARM7 read 32
+uint32_t FASTCALL _MMU_ARM7_read32(uint32_t adr)
+{
+ adr &= 0x0FFFFFFC;
+
+ //mmu_log_debug_ARM7(adr, "(read32) 0x%08X", T1ReadLong(MMU.MMU_MEM[ARMCPU_ARM7][(adr>>20)&0xFF], adr & MMU.MMU_MASK[ARMCPU_ARM7][(adr>>20)&0xFF]));
+
+ if (adr < 0x4000)
+ {
+ //uint32_t prot = T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][0x40], 0x04000308 & MMU.MMU_MASK[ARMCPU_ARM7][0x40]);
+ //if (prot) INFO("MMU7 read 32 at 0x%08X (PC 0x%08X) BIOSPROT address 0x%08X\n", adr, NDS_ARM7.R[15], prot);
+ if (NDS_ARM7.R[15] > 0x3FFF)
+ return 0xFFFFFFFF;
+ }
+
+ //wifi mac access
+ /*if ((adr & 0xFFFF0000) == 0x04800000)
+ return WIFI_read16(adr) | (WIFI_read16(adr+2) << 16);*/
+
+ if ( (adr >= 0x08000000) && (adr < 0x0A010000) )
+ return 0/*addon.read32(adr)*/;
+
+ if ((adr>=0x04000400)&&(adr<0x04000520))
+ {
+ return SPU_ReadLong(adr);
+ }
+
+ if((adr >> 24) == 4)
+ { //Address is an IO register
+
+ if(MMU_new.is_dma(adr)) return MMU_new.read_dma(ARMCPU_ARM7,32,adr);
+
+ switch(adr)
+ {
+ //case REG_RTC: return (uint32_t)rtcRead();
+ //case REG_DISPx_VCOUNT: return nds.VCount;
+
+ case REG_IME :
+ return MMU.reg_IME[ARMCPU_ARM7];
+ case REG_IE :
+ return MMU.reg_IE[ARMCPU_ARM7];
+ case REG_IF: return MMU.gen_IF<ARMCPU_ARM7>();
+ case REG_IPCFIFORECV :
+ return IPC_FIFOrecv(ARMCPU_ARM7);
+ case REG_TM0CNTL :
+ case REG_TM1CNTL :
+ case REG_TM2CNTL :
+ case REG_TM3CNTL :
+ {
+ uint32_t val = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM7][0x40], (adr + 2) & 0xFFF);
+ return MMU.timer[ARMCPU_ARM7][(adr&0xF)>>2] | (val<<16);
+ }
+ case REG_GCROMCTRL:
+ {
+ //INFO("arm7 romctrl read\n");
+ break;
+ }
+ case REG_GCDATAIN:
+ return MMU_readFromGC<ARMCPU_ARM7>();
+
+ }
+ return T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr>>20]);
+ }
+
+ //bool unmapped = false/*, restricted*/;
+ //adr = MMU_LCDmap<ARMCPU_ARM7>(adr,unmapped, restricted);
+ //if(unmapped) return 0;
+
+ //Returns data from memory
+ // Removed the &0xFF as they are implicit with the adr&0x0FFFFFFF [zeromus, inspired by shash]
+ return T1ReadLong_guaranteedAligned(MMU.MMU_MEM[ARMCPU_ARM7][adr >> 20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr >> 20]);
+}
+
+//=========================================================================================================
+
+/*uint32_t FASTCALL MMU_read32(uint32_t proc, uint32_t adr)
+{
+ ASSERT_UNALIGNED((adr&3)==0);
+
+ if(proc==0)
+ return _MMU_ARM9_read32(adr);
+ else
+ return _MMU_ARM7_read32(adr);
+}*/
+
+/*uint16_t FASTCALL MMU_read16(uint32_t proc, uint32_t adr)
+{
+ ASSERT_UNALIGNED((adr&1)==0);
+
+ if(proc==0)
+ return _MMU_ARM9_read16(adr);
+ else
+ return _MMU_ARM7_read16(adr);
+}*/
+
+/*uint8_t FASTCALL MMU_read8(uint32_t proc, uint32_t adr)
+{
+ if(proc==0)
+ return _MMU_ARM9_read08(adr);
+ else
+ return _MMU_ARM7_read08(adr);
+}*/
+
+/*void FASTCALL MMU_write32(uint32_t proc, uint32_t adr, uint32_t val)
+{
+ ASSERT_UNALIGNED((adr&3)==0);
+
+ if(proc==0)
+ _MMU_ARM9_write32(adr, val);
+ else
+ _MMU_ARM7_write32(adr,val);
+}*/
+
+/*void FASTCALL MMU_write16(uint32_t proc, uint32_t adr, uint16_t val)
+{
+ ASSERT_UNALIGNED((adr&1)==0);
+
+ if(proc==0)
+ _MMU_ARM9_write16(adr, val);
+ else
+ _MMU_ARM7_write16(adr,val);
+}*/
+
+/*void FASTCALL MMU_write8(uint32_t proc, uint32_t adr, uint8_t val)
+{
+ if(proc==0)
+ _MMU_ARM9_write08(adr, val);
+ else
+ _MMU_ARM7_write08(adr,val);
+}*/
+
+/*void FASTCALL MMU_DumpMemBlock(uint8_t proc, uint32_t address, uint32_t size, uint8_t *buffer)
+{
+ uint32_t i;
+ uint32_t curaddr;
+
+ for(i = 0, curaddr = address; i < size; i++, curaddr++)
+ {
+ buffer[i] = _MMU_read08(proc,MMU_AT_DEBUG,curaddr);
+ }
+}*/
+
+
+//these templates needed to be instantiated manually
+template uint32_t MMU_struct::gen_IF<ARMCPU_ARM9>();
+template uint32_t MMU_struct::gen_IF<ARMCPU_ARM7>();
+
+////////////////////////////////////////////////////////////
+//function pointer handlers for gdb stub stuff
+
+/*static uint16_t FASTCALL arm9_prefetch16( void *, uint32_t adr) {
+ return _MMU_read16<ARMCPU_ARM9,MMU_AT_CODE>(adr);
+}
+
+static uint32_t FASTCALL arm9_prefetch32( void *, uint32_t adr) {
+ return _MMU_read32<ARMCPU_ARM9,MMU_AT_CODE>(adr);
+}
+
+static uint8_t FASTCALL arm9_read8( void *, uint32_t adr) {
+ return _MMU_read08<ARMCPU_ARM9>(adr);
+}
+
+static uint16_t FASTCALL arm9_read16( void *, uint32_t adr) {
+ return _MMU_read16<ARMCPU_ARM9>(adr);
+}
+
+static uint32_t FASTCALL arm9_read32( void *, uint32_t adr) {
+ return _MMU_read32<ARMCPU_ARM9>(adr);
+}
+
+static void FASTCALL arm9_write8(void *, uint32_t adr, uint8_t val) {
+ _MMU_write08<ARMCPU_ARM9>(adr, val);
+}
+
+static void FASTCALL arm9_write16(void *, uint32_t adr, uint16_t val) {
+ _MMU_write16<ARMCPU_ARM9>(adr, val);
+}
+
+static void FASTCALL arm9_write32(void *, uint32_t adr, uint32_t val) {
+ _MMU_write32<ARMCPU_ARM9>(adr, val);
+}
+
+static uint16_t FASTCALL arm7_prefetch16( void *, uint32_t adr) {
+ return _MMU_read16<ARMCPU_ARM7,MMU_AT_CODE>(adr);
+}
+
+static uint32_t FASTCALL arm7_prefetch32( void *, uint32_t adr) {
+ return _MMU_read32<ARMCPU_ARM7,MMU_AT_CODE>(adr);
+}
+
+static uint8_t FASTCALL arm7_read8( void *, uint32_t adr) {
+ return _MMU_read08<ARMCPU_ARM7>(adr);
+}
+
+static uint16_t FASTCALL arm7_read16( void *, uint32_t adr) {
+ return _MMU_read16<ARMCPU_ARM7>(adr);
+}
+
+static uint32_t FASTCALL arm7_read32( void *, uint32_t adr) {
+ return _MMU_read32<ARMCPU_ARM7>(adr);
+}
+
+static void FASTCALL arm7_write8(void *, uint32_t adr, uint8_t val) {
+ _MMU_write08<ARMCPU_ARM7>(adr, val);
+}
+
+static void FASTCALL arm7_write16(void *, uint32_t adr, uint16_t val) {
+ _MMU_write16<ARMCPU_ARM7>(adr, val);
+}
+
+static void FASTCALL arm7_write32(void *, uint32_t adr, uint32_t val) {
+ _MMU_write32<ARMCPU_ARM7>(adr, val);
+}*/
+
+
+
+/*
+ * the base memory interfaces
+ */
+/*struct armcpu_memory_iface arm9_base_memory_iface = {
+ arm9_prefetch32,
+ arm9_prefetch16,
+
+ arm9_read8,
+ arm9_read16,
+ arm9_read32,
+
+ arm9_write8,
+ arm9_write16,
+ arm9_write32
+};
+
+struct armcpu_memory_iface arm7_base_memory_iface = {
+ arm7_prefetch32,
+ arm7_prefetch16,
+
+ arm7_read8,
+ arm7_read16,
+ arm7_read32,
+
+ arm7_write8,
+ arm7_write16,
+ arm7_write32
+};*/
+
+/*
+ * The direct memory interface for the ARM9.
+ * This avoids the ARM9 protection unit when accessing
+ * memory.
+ */
+/*struct armcpu_memory_iface arm9_direct_memory_iface = {
+ NULL,
+ NULL,
+
+ arm9_read8,
+ arm9_read16,
+ arm9_read32,
+
+ arm9_write8,
+ arm9_write16,
+ arm9_write32
+};*/
+
+
+/////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////
+
+//#ifdef PROFILE_MEMORY_ACCESS
+//
+//#define PROFILE_PREFETCH 0
+//#define PROFILE_READ 1
+//#define PROFILE_WRITE 2
+//
+//struct mem_access_profile {
+// uint64_t num_accesses;
+// uint32_t address_mask;
+// uint32_t masked_value;
+//};
+//
+//#define PROFILE_NUM_MEM_ACCESS_PROFILES 4
+//
+//static uint64_t profile_num_accesses[2][3];
+//static uint64_t profile_unknown_addresses[2][3];
+//static struct mem_access_profile
+//profile_memory_accesses[2][3][PROFILE_NUM_MEM_ACCESS_PROFILES];
+//
+//static void
+//setup_profiling() {
+// int i;
+//
+// for ( i = 0; i < 2; i++) {
+// int access_type;
+//
+// for ( access_type = 0; access_type < 3; access_type++) {
+// profile_num_accesses[i][access_type] = 0;
+// profile_unknown_addresses[i][access_type] = 0;
+//
+// /*
+// * Setup the access testing structures
+// */
+// profile_memory_accesses[i][access_type][0].address_mask = 0x0e000000;
+// profile_memory_accesses[i][access_type][0].masked_value = 0x00000000;
+// profile_memory_accesses[i][access_type][0].num_accesses = 0;
+//
+// /* main memory */
+// profile_memory_accesses[i][access_type][1].address_mask = 0x0f000000;
+// profile_memory_accesses[i][access_type][1].masked_value = 0x02000000;
+// profile_memory_accesses[i][access_type][1].num_accesses = 0;
+//
+// /* shared memory */
+// profile_memory_accesses[i][access_type][2].address_mask = 0x0f800000;
+// profile_memory_accesses[i][access_type][2].masked_value = 0x03000000;
+// profile_memory_accesses[i][access_type][2].num_accesses = 0;
+//
+// /* arm7 memory */
+// profile_memory_accesses[i][access_type][3].address_mask = 0x0f800000;
+// profile_memory_accesses[i][access_type][3].masked_value = 0x03800000;
+// profile_memory_accesses[i][access_type][3].num_accesses = 0;
+// }
+// }
+//}
+//
+//static void
+//profile_memory_access( int arm9, uint32_t adr, int access_type) {
+// static int first = 1;
+// int mem_profile;
+// int address_found = 0;
+//
+// if ( first) {
+// setup_profiling();
+// first = 0;
+// }
+//
+// profile_num_accesses[arm9][access_type] += 1;
+//
+// for ( mem_profile = 0;
+// mem_profile < PROFILE_NUM_MEM_ACCESS_PROFILES &&
+// !address_found;
+// mem_profile++) {
+// if ( (adr & profile_memory_accesses[arm9][access_type][mem_profile].address_mask) ==
+// profile_memory_accesses[arm9][access_type][mem_profile].masked_value) {
+// /*printf( "adr %08x mask %08x res %08x expected %08x\n",
+// adr,
+// profile_memory_accesses[arm9][access_type][mem_profile].address_mask,
+// adr & profile_memory_accesses[arm9][access_type][mem_profile].address_mask,
+// profile_memory_accesses[arm9][access_type][mem_profile].masked_value);*/
+// address_found = 1;
+// profile_memory_accesses[arm9][access_type][mem_profile].num_accesses += 1;
+// }
+// }
+//
+// if ( !address_found) {
+// profile_unknown_addresses[arm9][access_type] += 1;
+// }
+//}
+//
+//
+//static const char *access_type_strings[] = {
+// "prefetch",
+// "read ",
+// "write "
+//};
+//
+//void
+//print_memory_profiling() {
+// int arm;
+//
+// printf("------ Memory access profile ------\n");
+//
+// for ( arm = 0; arm < 2; arm++) {
+// int access_type;
+//
+// for ( access_type = 0; access_type < 3; access_type++) {
+// int mem_profile;
+// printf("ARM%c: num of %s %lld\n",
+// arm ? '9' : '7',
+// access_type_strings[access_type],
+// profile_num_accesses[arm][access_type]);
+//
+// for ( mem_profile = 0;
+// mem_profile < PROFILE_NUM_MEM_ACCESS_PROFILES;
+// mem_profile++) {
+// printf( "address %08x: %lld\n",
+// profile_memory_accesses[arm][access_type][mem_profile].masked_value,
+// profile_memory_accesses[arm][access_type][mem_profile].num_accesses);
+// }
+//
+// printf( "unknown addresses %lld\n",
+// profile_unknown_addresses[arm][access_type]);
+//
+// printf( "\n");
+// }
+// }
+//
+// printf("------ End of Memory access profile ------\n\n");
+//}
+//#else
+//void
+//print_memory_profiling() {
+//}
+//#endif /* End of PROFILE_MEMORY_ACCESS area */
+
--- /dev/null
+++ b/src/in_2sf/desmume/MMU.h
@@ -1,1 +1,941 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2007 shash
+ Copyright (C) 2007-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MMU_H
+#define MMU_H
+
+#include "FIFO.h"
+#include "mem.h"
+#include "registers.h"
+#include "mc.h"
+#include "bits.h"
+#include "readwrite.h"
+//#include "debug.h"
+
+#ifdef HAVE_LUA
+#include "lua-engine.h"
+#endif
+
+#define ARMCPU_ARM7 1
+#define ARMCPU_ARM9 0
+#define ARMPROC (PROCNUM ? NDS_ARM7:NDS_ARM9)
+
+typedef const uint8_t TWaitState;
+
+enum EDMAMode
+{
+ EDMAMode_Immediate = 0,
+ EDMAMode_VBlank = 1,
+ EDMAMode_HBlank = 2,
+ EDMAMode_HStart = 3,
+ EDMAMode_MemDisplay = 4,
+ EDMAMode_Card = 5,
+ EDMAMode_GBASlot = 6,
+ EDMAMode_GXFifo = 7,
+ EDMAMode7_Wifi = 8,
+ EDMAMode7_GBASlot = 9
+};
+
+enum EDMABitWidth
+{
+ EDMABitWidth_16 = 0,
+ EDMABitWidth_32 = 1
+};
+
+enum EDMASourceUpdate
+{
+ EDMASourceUpdate_Increment = 0,
+ EDMASourceUpdate_Decrement = 1,
+ EDMASourceUpdate_Fixed = 2,
+ EDMASourceUpdate_Invalid = 3
+};
+
+enum EDMADestinationUpdate
+{
+ EDMADestinationUpdate_Increment = 0,
+ EDMADestinationUpdate_Decrement = 1,
+ EDMADestinationUpdate_Fixed = 2,
+ EDMADestinationUpdate_IncrementReload = 3
+};
+
+//TODO
+//n.b. this may be a bad idea, for complex registers like the dma control register.
+//we need to know exactly what part was written to, instead of assuming all 32bits were written.
+class TRegister_32
+{
+public:
+ virtual uint32_t read32() = 0;
+ virtual void write32(const uint32_t val) = 0;
+ void write(const int size, const uint32_t adr, const uint32_t val) {
+ if(size==32) write32(val);
+ else {
+ const uint32_t offset = adr&3;
+ if(size==8) {
+ printf("WARNING! 8BIT DMA ACCESS\n");
+ uint32_t mask = 0xFF<<(offset<<3);
+ write32((read32()&~mask)|(val<<(offset<<3)));
+ }
+ else if(size==16) {
+ uint32_t mask = 0xFFFF<<(offset<<3);
+ write32((read32()&~mask)|(val<<(offset<<3)));
+ }
+ }
+ }
+
+ uint32_t read(const int size, const uint32_t adr)
+ {
+ if(size==32) return read32();
+ else {
+ const uint32_t offset = adr&3;
+ if(size==8) { printf("WARNING! 8BIT DMA ACCESS\n"); return (read32()>>(offset<<3))&0xFF; }
+ else return (read32()>>(offset<<3))&0xFFFF;
+ }
+ }
+};
+
+struct TGXSTAT : public TRegister_32
+{
+ TGXSTAT() {
+ gxfifo_irq = se = tr = tb = sb = 0;
+ fifo_empty = true;
+ fifo_low = false;
+ }
+ uint8_t tb; //test busy
+ uint8_t tr; //test result
+ uint8_t se; //stack error
+ uint8_t sb; //stack busy
+ uint8_t gxfifo_irq; //irq configuration
+
+ bool fifo_empty, fifo_low;
+
+ virtual uint32_t read32();
+ virtual void write32(const uint32_t val);
+
+ //void savestate(EMUFILE *f);
+ bool loadstate(EMUFILE *f);
+};
+
+void triggerDma(EDMAMode mode);
+
+class DivController
+{
+public:
+ DivController()
+ : mode(0), busy(0)
+ {}
+ void exec();
+ uint8_t mode, busy, div0;
+ uint16_t read16() { return mode|(busy<<15)|(div0<<14); }
+ void write16(uint16_t val) {
+ mode = val&3;
+ //todo - do we clear the div0 flag here or is that strictly done by the divider unit?
+ }
+ /*void savestate(EMUFILE* os)
+ {
+ write8le(&mode,os);
+ write8le(&busy,os);
+ write8le(&div0,os);
+ }*/
+ bool loadstate(EMUFILE* is, int)
+ {
+ int ret = 1;
+ ret &= read8le(&mode,is);
+ ret &= read8le(&busy,is);
+ ret &= read8le(&div0,is);
+ return ret==1;
+ }
+};
+
+class SqrtController
+{
+public:
+ SqrtController()
+ : mode(0), busy(0)
+ {}
+ void exec();
+ uint8_t mode, busy;
+ uint16_t read16() { return mode|(busy<<15); }
+ void write16(uint16_t val) { mode = val&1; }
+ /*void savestate(EMUFILE* os)
+ {
+ write8le(&mode,os);
+ write8le(&busy,os);
+ }*/
+ bool loadstate(EMUFILE* is, int)
+ {
+ int ret=1;
+ ret &= read8le(&mode,is);
+ ret &= read8le(&busy,is);
+ return ret==1;
+ }
+};
+
+class DmaController
+{
+public:
+ uint8_t enable, irq, repeatMode, _startmode;
+ uint8_t userEnable;
+ uint32_t wordcount;
+ EDMAMode startmode;
+ EDMABitWidth bitWidth;
+ EDMASourceUpdate sar;
+ EDMADestinationUpdate dar;
+ uint32_t saddr, daddr;
+ uint32_t saddr_user, daddr_user;
+
+ //indicates whether the dma needs to be checked for triggering
+ bool dmaCheck;
+
+ //indicates whether the dma right now is logically running
+ //(though for now we copy all the data when it triggers)
+ bool running;
+
+ bool paused;
+
+ //this flag will sometimes be set when a start condition is triggered
+ //other conditions may be automatically triggered based on scanning conditions
+ bool triggered;
+
+ uint64_t nextEvent;
+
+ int procnum, chan;
+
+ //void savestate(EMUFILE *f);
+ bool loadstate(EMUFILE *f);
+
+ void exec();
+ template<int PROCNUM> void doCopy();
+ void doPause();
+ void doStop();
+ void doSchedule();
+ void tryTrigger(EDMAMode mode);
+
+ DmaController() :
+ enable(0), irq(0), repeatMode(0), _startmode(0),
+ wordcount(0), startmode(EDMAMode_Immediate),
+ bitWidth(EDMABitWidth_16),
+ sar(EDMASourceUpdate_Increment), dar(EDMADestinationUpdate_Increment),
+ //if saddr isnt cleared then rings of fate will trigger copy protection
+ //by inspecting dma3 saddr when it boots
+ saddr(0), daddr(0),
+ saddr_user(0), daddr_user(0),
+ dmaCheck(false),
+ running(false),
+ paused(false),
+ triggered(false),
+ nextEvent(0),
+ sad(&saddr_user),
+ dad(&daddr_user)
+ {
+ sad.controller = this;
+ dad.controller = this;
+ ctrl.controller = this;
+ regs[0] = &sad;
+ regs[1] = &dad;
+ regs[2] = &ctrl;
+ }
+
+ class AddressRegister : public TRegister_32 {
+ public:
+ //we pass in a pointer to the controller here so we can alert it if anything changes
+ DmaController* controller;
+ uint32_t * const ptr;
+ AddressRegister(uint32_t* _ptr)
+ : ptr(_ptr)
+ {}
+ virtual uint32_t read32() {
+ return *ptr;
+ }
+ virtual void write32(const uint32_t val) {
+ *ptr = val;
+ }
+ };
+
+ class ControlRegister : public TRegister_32 {
+ public:
+ //we pass in a pointer to the controller here so we can alert it if anything changes
+ DmaController* controller;
+ ControlRegister() {}
+ virtual uint32_t read32() {
+ return controller->read32();
+ }
+ virtual void write32(const uint32_t val) {
+ return controller->write32(val);
+ }
+ };
+
+ AddressRegister sad, dad;
+ ControlRegister ctrl;
+ TRegister_32* regs[3];
+
+ void write32(const uint32_t val);
+ uint32_t read32();
+
+};
+
+enum ECardMode
+{
+ CardMode_Normal = 0,
+ CardMode_KEY1,
+ CardMode_KEY2
+};
+
+typedef struct
+{
+
+ uint8_t command[8];
+
+ uint32_t address;
+ uint32_t transfer_count;
+
+ ECardMode mode;
+
+ // NJSD stuff
+ int blocklen;
+
+} nds_dscard;
+
+struct MMU_struct
+{
+ //ARM9 mem
+ uint8_t ARM9_ITCM[0x8000];
+ uint8_t ARM9_DTCM[0x4000];
+
+ //u8 MAIN_MEM[4*1024*1024]; //expanded from 4MB to 8MB to support debug consoles
+ //u8 MAIN_MEM[8*1024*1024]; //expanded from 8MB to 16MB to support dsi
+ uint8_t MAIN_MEM[16*1024*1024]; //expanded from 8MB to 16MB to support dsi
+ uint8_t ARM9_REG[0x1000000];
+ uint8_t ARM9_BIOS[0x8000];
+ uint8_t ARM9_VMEM[0x800];
+
+ #include "PACKED.h"
+ struct {
+ uint8_t ARM9_LCD[0xA4000];
+ //an extra 128KB for blank memory, directly after arm9_lcd, so that
+ //we can easily map things to the end of arm9_lcd to represent
+ //an unmapped state
+ uint8_t blank_memory[0x20000];
+ };
+ #include "PACKED_END.h"
+
+ uint8_t ARM9_OAM[0x800];
+
+ uint8_t* ExtPal[2][4];
+ uint8_t* ObjExtPal[2][2];
+
+ struct TextureInfo {
+ uint8_t* texPalSlot[6];
+ uint8_t* textureSlotAddr[4];
+ } texInfo;
+
+ //ARM7 mem
+ uint8_t ARM7_BIOS[0x4000];
+ uint8_t ARM7_ERAM[0x10000];
+ uint8_t ARM7_REG[0x10000];
+ uint8_t ARM7_WIRAM[0x10000];
+
+ // VRAM mapping
+ uint8_t VRAM_MAP[4][32];
+ uint32_t LCD_VRAM_ADDR[10];
+ uint8_t LCDCenable[10];
+
+ //Shared ram
+ uint8_t SWIRAM[0x8000];
+
+ //Card rom & ram
+ uint8_t * CART_ROM;
+
+ //Unused ram
+ uint8_t UNUSED_RAM[4];
+
+ //this is here so that we can trap glitchy emulator code
+ //which is accessing offsets 5,6,7 of unused ram due to unaligned accesses
+ //(also since the emulator doesn't prevent unaligned accesses)
+ uint8_t MORE_UNUSED_RAM[4];
+
+ static uint8_t * MMU_MEM[2][256];
+ static uint32_t MMU_MASK[2][256];
+
+ uint8_t ARM9_RW_MODE;
+
+ uint32_t DTCMRegion;
+ uint32_t ITCMRegion;
+
+ uint16_t timer[2][4];
+ int32_t timerMODE[2][4];
+ uint32_t timerON[2][4];
+ uint32_t timerRUN[2][4];
+ uint16_t timerReload[2][4];
+
+ uint32_t reg_IME[2];
+ uint32_t reg_IE[2];
+
+ //these are the user-controlled IF bits. some IF bits are generated as necessary from hardware conditions
+ uint32_t reg_IF_bits[2];
+ //these flags are set occasionally to indicate that an irq should have entered the pipeline, and processing will be deferred a tiny bit to help emulate things
+ uint32_t reg_IF_pending[2];
+
+ //uint32_t reg_DISP3DCNT_bits;
+
+ template<int PROCNUM> uint32_t gen_IF();
+
+ bool divRunning;
+ int64_t divResult;
+ int64_t divMod;
+ uint64_t divCycles;
+
+ bool sqrtRunning;
+ uint32_t sqrtResult;
+ uint64_t sqrtCycles;
+
+ uint16_t SPI_CNT;
+ uint16_t SPI_CMD;
+ uint16_t AUX_SPI_CNT;
+ uint16_t AUX_SPI_CMD;
+
+ //uint64_t gfx3dCycles;
+
+ uint8_t powerMan_CntReg;
+ bool powerMan_CntRegWritten;
+ uint8_t powerMan_Reg[5];
+
+ memory_chip_t fw;
+
+ nds_dscard dscard[2];
+};
+
+//everything in here is derived from libnds behaviours. no hardware tests yet
+class DSI_TSC
+{
+public:
+ DSI_TSC();
+ void reset_command();
+ uint16_t write16(uint16_t val);
+ //bool save_state(EMUFILE* os);
+ //bool load_state(EMUFILE* is);
+
+private:
+ uint16_t read16();
+ uint8_t reg_selection;
+ uint8_t read_flag;
+ int32_t state;
+ int32_t readcount;
+
+ //registers[0] contains the current page.
+ //we are going to go ahead and save these out in case we want to change the way this is emulated in the future..
+ //we may want to poke registers in here at more convenient times and have the TSC dumbly pluck them out,
+ //rather than generate the values on the fly
+ uint8_t registers[0x80];
+};
+
+//this contains things which can't be memzeroed because they are smarter classes
+struct MMU_struct_new
+{
+ MMU_struct_new() ;
+ BackupDevice backupDevice;
+ DmaController dma[2][4];
+ TGXSTAT gxstat;
+ SqrtController sqrt;
+ DivController div;
+ DSI_TSC dsi_tsc;
+
+ void write_dma(const int proc, const int size, const uint32_t adr, const uint32_t val);
+ uint32_t read_dma(const int proc, const int size, const uint32_t adr);
+ bool is_dma(const uint32_t adr) { return adr >= _REG_DMA_CONTROL_MIN && adr <= _REG_DMA_CONTROL_MAX; }
+};
+
+extern MMU_struct MMU;
+extern MMU_struct_new MMU_new;
+
+
+/*struct armcpu_memory_iface {*/
+ /** the 32 bit instruction prefetch */
+ //uint32_t FASTCALL (*prefetch32)( void *data, uint32_t adr);
+
+ /** the 16 bit instruction prefetch */
+ //uint16_t FASTCALL (*prefetch16)( void *data, uint32_t adr);
+
+ /** read 8 bit data value */
+ //uint8_t FASTCALL (*read8)( void *data, uint32_t adr);
+ /** read 16 bit data value */
+ //uint16_t FASTCALL (*read16)( void *data, uint32_t adr);
+ /** read 32 bit data value */
+ //uint32_t FASTCALL (*read32)( void *data, uint32_t adr);
+
+ /** write 8 bit data value */
+ //void FASTCALL (*write8)( void *data, uint32_t adr, uint8_t val);
+ /** write 16 bit data value */
+ //void FASTCALL (*write16)( void *data, uint32_t adr, uint16_t val);
+ /** write 32 bit data value */
+ /*void FASTCALL (*write32)( void *data, uint32_t adr, uint32_t val);
+
+ void *data;
+};*/
+
+
+void MMU_Init();
+void MMU_DeInit();
+
+void MMU_Reset();
+
+void MMU_setRom(uint8_t * rom, uint32_t mask);
+void MMU_unsetRom();
+
+//void print_memory_profiling();
+
+// Memory reading/writing (old)
+//uint8_t FASTCALL MMU_read8(uint32_t proc, uint32_t adr);
+//uint16_t FASTCALL MMU_read16(uint32_t proc, uint32_t adr);
+//uint32_t FASTCALL MMU_read32(uint32_t proc, uint32_t adr);
+//void FASTCALL MMU_write8(uint32_t proc, uint32_t adr, uint8_t val);
+//void FASTCALL MMU_write16(uint32_t proc, uint32_t adr, uint16_t val);
+//void FASTCALL MMU_write32(uint32_t proc, uint32_t adr, uint32_t val);
+
+//template<int PROCNUM> void FASTCALL MMU_doDMA(uint32_t num);
+
+//The base ARM memory interfaces
+//extern struct armcpu_memory_iface arm9_base_memory_iface;
+//extern struct armcpu_memory_iface arm7_base_memory_iface;
+//extern struct armcpu_memory_iface arm9_direct_memory_iface;
+
+#define VRAM_BANKS 9
+#define VRAM_BANK_A 0
+#define VRAM_BANK_B 1
+#define VRAM_BANK_C 2
+#define VRAM_BANK_D 3
+#define VRAM_BANK_E 4
+#define VRAM_BANK_F 5
+#define VRAM_BANK_G 6
+#define VRAM_BANK_H 7
+#define VRAM_BANK_I 8
+
+#define VRAM_PAGE_ABG 0
+#define VRAM_PAGE_BBG 128
+#define VRAM_PAGE_AOBJ 256
+#define VRAM_PAGE_BOBJ 384
+
+
+struct VramConfiguration {
+
+ enum Purpose {
+ OFF, INVALID, ABG, BBG, AOBJ, BOBJ, LCDC, ARM7, TEX, TEXPAL, ABGEXTPAL, BBGEXTPAL, AOBJEXTPAL, BOBJEXTPAL
+ };
+
+ struct BankInfo {
+ Purpose purpose;
+ int ofs;
+ } banks[VRAM_BANKS];
+
+ inline void clear() {
+ for(int i=0;i<VRAM_BANKS;i++) {
+ banks[i].ofs = 0;
+ banks[i].purpose = OFF;
+ }
+ }
+
+ //std::string describePurpose(Purpose p);
+ //std::string describe();
+};
+
+extern VramConfiguration vramConfiguration;
+
+#define VRAM_ARM9_PAGES 512
+extern uint8_t vram_arm9_map[VRAM_ARM9_PAGES];
+/*inline void* MMU_gpu_map(uint32_t vram_addr)
+{
+ //this is supposed to map a single gpu vram address to emulator host memory
+ //but it returns a pointer to some zero memory in case of accesses to unmapped memory.
+ //this correctly handles the case with tile accesses to unmapped memory.
+ //it could also potentially go through a different LUT than vram_arm9_map in case we discover
+ //that it needs to be set up with different or no mirroring
+ //(I think it is a reasonable possibility that only the cpu has the nutty mirroring rules)
+ //
+ //if this system isn't used, Fantasy Aquarium displays garbage in the first ingame screen
+ //due to it storing 0x0F0F or somesuch in screen memory which points to a ridiculously big tile
+ //which should contain all 0 pixels
+
+ uint32_t vram_page = (vram_addr>>14)&(VRAM_ARM9_PAGES-1);
+ uint32_t ofs = vram_addr & 0x3FFF;
+ vram_page = vram_arm9_map[vram_page];
+ //blank pages are handled by the extra 16KB of blank memory at the end of ARM9_LCD
+ //and the fact that blank pages are mapped to appear at that location
+ return MMU.ARM9_LCD + (vram_page<<14) + ofs;
+}*/
+
+
+template<int PROCNUM, MMU_ACCESS_TYPE AT> uint8_t _MMU_read08(uint32_t addr);
+template<int PROCNUM, MMU_ACCESS_TYPE AT> uint16_t _MMU_read16(uint32_t addr);
+template<int PROCNUM, MMU_ACCESS_TYPE AT> uint32_t _MMU_read32(uint32_t addr);
+template<int PROCNUM, MMU_ACCESS_TYPE AT> void _MMU_write08(uint32_t addr, uint8_t val);
+template<int PROCNUM, MMU_ACCESS_TYPE AT> void _MMU_write16(uint32_t addr, uint16_t val);
+template<int PROCNUM, MMU_ACCESS_TYPE AT> void _MMU_write32(uint32_t addr, uint32_t val);
+
+template<int PROCNUM> inline uint8_t _MMU_read08(uint32_t addr) { return _MMU_read08<PROCNUM, MMU_AT_DATA>(addr); }
+template<int PROCNUM> inline uint16_t _MMU_read16(uint32_t addr) { return _MMU_read16<PROCNUM, MMU_AT_DATA>(addr); }
+template<int PROCNUM> inline uint32_t _MMU_read32(uint32_t addr) { return _MMU_read32<PROCNUM, MMU_AT_DATA>(addr); }
+template<int PROCNUM> inline void _MMU_write08(uint32_t addr, uint8_t val) { _MMU_write08<PROCNUM, MMU_AT_DATA>(addr,val); }
+template<int PROCNUM> inline void _MMU_write16(uint32_t addr, uint16_t val) { _MMU_write16<PROCNUM, MMU_AT_DATA>(addr,val); }
+template<int PROCNUM> inline void _MMU_write32(uint32_t addr, uint32_t val) { _MMU_write32<PROCNUM, MMU_AT_DATA>(addr,val); }
+
+void FASTCALL _MMU_ARM9_write08(uint32_t adr, uint8_t val);
+void FASTCALL _MMU_ARM9_write16(uint32_t adr, uint16_t val);
+void FASTCALL _MMU_ARM9_write32(uint32_t adr, uint32_t val);
+uint8_t FASTCALL _MMU_ARM9_read08(uint32_t adr);
+uint16_t FASTCALL _MMU_ARM9_read16(uint32_t adr);
+uint32_t FASTCALL _MMU_ARM9_read32(uint32_t adr);
+
+void FASTCALL _MMU_ARM7_write08(uint32_t adr, uint8_t val);
+void FASTCALL _MMU_ARM7_write16(uint32_t adr, uint16_t val);
+void FASTCALL _MMU_ARM7_write32(uint32_t adr, uint32_t val);
+uint8_t FASTCALL _MMU_ARM7_read08(uint32_t adr);
+uint16_t FASTCALL _MMU_ARM7_read16(uint32_t adr);
+uint32_t FASTCALL _MMU_ARM7_read32(uint32_t adr);
+
+extern uint32_t partie;
+
+extern uint32_t _MMU_MAIN_MEM_MASK;
+extern uint32_t _MMU_MAIN_MEM_MASK16;
+extern uint32_t _MMU_MAIN_MEM_MASK32;
+/*inline void SetupMMU(bool debugConsole) {
+ if(debugConsole) _MMU_MAIN_MEM_MASK = 0x7FFFFF;
+ else _MMU_MAIN_MEM_MASK = 0x3FFFFF;
+ _MMU_MAIN_MEM_MASK16 = _MMU_MAIN_MEM_MASK & ~1;
+ _MMU_MAIN_MEM_MASK32 = _MMU_MAIN_MEM_MASK & ~3;
+}*/
+void SetupMMU(bool debugConsole, bool dsi);
+
+/*inline void CheckMemoryDebugEvent(EDEBUG_EVENT event, const MMU_ACCESS_TYPE type, const uint32_t procnum, const uint32_t addr, const uint32_t size, const uint32_t val)
+{
+ //TODO - ugh work out a better prefetch event system
+ if(type == MMU_AT_CODE && event == DEBUG_EVENT_READ)
+ event = DEBUG_EVENT_EXECUTE;
+ if(CheckDebugEvent(event))
+ {
+ DebugEventData.memAccessType = type;
+ DebugEventData.procnum = procnum;
+ DebugEventData.addr = addr;
+ DebugEventData.size = size;
+ DebugEventData.val = val;
+ HandleDebugEvent(event);
+ }
+}*/
+
+
+//ALERT!!!!!!!!!!!!!!
+//the following inline functions dont do the 0x0FFFFFFF mask.
+//this may result in some unexpected behavior
+
+inline uint8_t _MMU_read08(const int PROCNUM, const MMU_ACCESS_TYPE AT, const uint32_t addr)
+{
+ //CheckMemoryDebugEvent(DEBUG_EVENT_READ,AT,PROCNUM,addr,8,0);
+
+ //special handling for DMA: read 0 from TCM
+ if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_DMA)
+ {
+ if(addr<0x02000000) return 0; //itcm
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion) return 0; //dtcm
+ }
+
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 1, /*FIXME*/ 0, LUAMEMHOOK_READ);
+#endif
+
+ if(PROCNUM==ARMCPU_ARM9)
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion)
+ {
+ //Returns data from DTCM (ARM9 only)
+ return T1ReadByte(MMU.ARM9_DTCM, addr & 0x3FFF);
+ }
+
+ if ( (addr & 0x0F000000) == 0x02000000)
+ return T1ReadByte( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK);
+
+ if(PROCNUM==ARMCPU_ARM9) return _MMU_ARM9_read08(addr);
+ else return _MMU_ARM7_read08(addr);
+}
+
+inline uint16_t _MMU_read16(const int PROCNUM, const MMU_ACCESS_TYPE AT, const uint32_t addr)
+{
+ //CheckMemoryDebugEvent(DEBUG_EVENT_READ,AT,PROCNUM,addr,16,0);
+
+ //special handling for DMA: read 0 from TCM
+ if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_DMA)
+ {
+ if(addr<0x02000000) return 0; //itcm
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion) return 0; //dtcm
+ }
+
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 2, /*FIXME*/ 0, LUAMEMHOOK_READ);
+#endif
+
+ //special handling for execution from arm9, since we spend so much time in there
+ if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_CODE)
+ {
+ if ((addr & 0x0F000000) == 0x02000000)
+ return T1ReadWord_guaranteedAligned( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK16);
+
+ if(addr<0x02000000)
+ return T1ReadWord_guaranteedAligned(MMU.ARM9_ITCM, addr&0x7FFE);
+
+ goto dunno;
+ }
+
+ if(PROCNUM==ARMCPU_ARM9)
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion)
+ {
+ //Returns data from DTCM (ARM9 only)
+ return T1ReadWord_guaranteedAligned(MMU.ARM9_DTCM, addr & 0x3FFE);
+ }
+
+ if ( (addr & 0x0F000000) == 0x02000000)
+ return T1ReadWord_guaranteedAligned( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK16);
+
+dunno:
+ if(PROCNUM==ARMCPU_ARM9) return _MMU_ARM9_read16(addr);
+ else return _MMU_ARM7_read16(addr);
+}
+
+inline uint32_t _MMU_read32(const int PROCNUM, const MMU_ACCESS_TYPE AT, const uint32_t addr)
+{
+ //CheckMemoryDebugEvent(DEBUG_EVENT_READ,AT,PROCNUM,addr,32,0);
+
+ //special handling for DMA: read 0 from TCM
+ if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_DMA)
+ {
+ if(addr<0x02000000) return 0; //itcm
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion) return 0; //dtcm
+ }
+
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 4, /*FIXME*/ 0, LUAMEMHOOK_READ);
+#endif
+
+ //special handling for execution from arm9, since we spend so much time in there
+ if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_CODE)
+ {
+ if ( (addr & 0x0F000000) == 0x02000000)
+ return T1ReadLong_guaranteedAligned( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK32);
+
+ if(addr<0x02000000)
+ return T1ReadLong_guaranteedAligned(MMU.ARM9_ITCM, addr&0x7FFC);
+
+ //what happens when we execute from DTCM? nocash makes it look like we get 0xFFFFFFFF but i can't seem to verify it
+ //historically, desmume would fall through to its old memory map struct
+ //which would return unused memory (0)
+ //it seems the hardware returns 0 or something benign because in actuality 0xFFFFFFFF is an undefined opcode
+ //and we know our handling for that is solid
+
+ goto dunno;
+ }
+
+ //special handling for execution from arm7. try reading from main memory first
+ if(PROCNUM==ARMCPU_ARM7)
+ {
+ if ( (addr & 0x0F000000) == 0x02000000)
+ return T1ReadLong_guaranteedAligned( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK32);
+ else if((addr & 0xFF800000) == 0x03800000)
+ return T1ReadLong_guaranteedAligned(MMU.ARM7_ERAM, addr&0xFFFC);
+ else if((addr & 0xFF800000) == 0x03000000)
+ return T1ReadLong_guaranteedAligned(MMU.SWIRAM, addr&0x7FFC);
+ }
+
+
+ //for other arm9 cases, we have to check from dtcm first because it is patched on top of the main memory range
+ if(PROCNUM==ARMCPU_ARM9)
+ {
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion)
+ {
+ //Returns data from DTCM (ARM9 only)
+ return T1ReadLong_guaranteedAligned(MMU.ARM9_DTCM, addr & 0x3FFC);
+ }
+
+ if ( (addr & 0x0F000000) == 0x02000000)
+ return T1ReadLong_guaranteedAligned( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK32);
+ }
+
+dunno:
+ if(PROCNUM==ARMCPU_ARM9) return _MMU_ARM9_read32(addr);
+ else return _MMU_ARM7_read32(addr);
+}
+
+inline void _MMU_write08(const int PROCNUM, const MMU_ACCESS_TYPE AT, const uint32_t addr, uint8_t val)
+{
+ //CheckMemoryDebugEvent(DEBUG_EVENT_WRITE,AT,PROCNUM,addr,8,val);
+
+ //special handling for DMA: discard writes to TCM
+ if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_DMA)
+ {
+ if(addr<0x02000000) return; //itcm
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion) return; //dtcm
+ }
+
+ if(PROCNUM==ARMCPU_ARM9)
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion)
+ {
+ T1WriteByte(MMU.ARM9_DTCM, addr & 0x3FFF, val);
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE);
+#endif
+ return;
+ }
+
+ if ( (addr & 0x0F000000) == 0x02000000) {
+ T1WriteByte( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK, val);
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE);
+#endif
+ return;
+ }
+
+ if(PROCNUM==ARMCPU_ARM9) _MMU_ARM9_write08(addr,val);
+ else _MMU_ARM7_write08(addr,val);
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE);
+#endif
+}
+
+inline void _MMU_write16(const int PROCNUM, const MMU_ACCESS_TYPE AT, const uint32_t addr, uint16_t val)
+{
+ //CheckMemoryDebugEvent(DEBUG_EVENT_WRITE,AT,PROCNUM,addr,16,val);
+
+ //special handling for DMA: discard writes to TCM
+ if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_DMA)
+ {
+ if(addr<0x02000000) return; //itcm
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion) return; //dtcm
+ }
+
+ if(PROCNUM==ARMCPU_ARM9)
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion)
+ {
+ T1WriteWord(MMU.ARM9_DTCM, addr & 0x3FFE, val);
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE);
+#endif
+ return;
+ }
+
+ if ( (addr & 0x0F000000) == 0x02000000) {
+ T1WriteWord( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK16, val);
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE);
+#endif
+ return;
+ }
+
+ if(PROCNUM==ARMCPU_ARM9) _MMU_ARM9_write16(addr,val);
+ else _MMU_ARM7_write16(addr,val);
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE);
+#endif
+}
+
+inline void _MMU_write32(const int PROCNUM, const MMU_ACCESS_TYPE AT, const uint32_t addr, uint32_t val)
+{
+ //CheckMemoryDebugEvent(DEBUG_EVENT_WRITE,AT,PROCNUM,addr,32,val);
+
+ //special handling for DMA: discard writes to TCM
+ if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_DMA)
+ {
+ if(addr<0x02000000) return; //itcm
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion) return; //dtcm
+ }
+
+ if(PROCNUM==ARMCPU_ARM9)
+ if((addr&(~0x3FFF)) == MMU.DTCMRegion)
+ {
+ T1WriteLong(MMU.ARM9_DTCM, addr & 0x3FFC, val);
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE);
+#endif
+ return;
+ }
+
+ if ( (addr & 0x0F000000) == 0x02000000) {
+ T1WriteLong( MMU.MAIN_MEM, addr & _MMU_MAIN_MEM_MASK32, val);
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE);
+#endif
+ return;
+ }
+
+ if(PROCNUM==ARMCPU_ARM9) _MMU_ARM9_write32(addr,val);
+ else _MMU_ARM7_write32(addr,val);
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE);
+#endif
+}
+
+
+//#ifdef MMU_ENABLE_ACL
+// void FASTCALL MMU_write8_acl(uint32_t proc, uint32_t adr, uint8_t val);
+// void FASTCALL MMU_write16_acl(uint32_t proc, uint32_t adr, uint16_t val);
+// void FASTCALL MMU_write32_acl(uint32_t proc, uint32_t adr, uint32_t val);
+// uint8_t FASTCALL MMU_read8_acl(uint32_t proc, uint32_t adr, uint32_t access);
+// uint16_t FASTCALL MMU_read16_acl(uint32_t proc, uint32_t adr, uint32_t access);
+// uint32_t FASTCALL MMU_read32_acl(uint32_t proc, uint32_t adr, uint32_t access);
+//#else
+// #define MMU_write8_acl(proc, adr, val) _MMU_write08<proc>(adr, val)
+// #define MMU_write16_acl(proc, adr, val) _MMU_write16<proc>(adr, val)
+// #define MMU_write32_acl(proc, adr, val) _MMU_write32<proc>(adr, val)
+// #define MMU_read8_acl(proc,adr,access) _MMU_read08<proc>(adr)
+// #define MMU_read16_acl(proc,adr,access) ((access==CP15_ACCESS_EXECUTE)?_MMU_read16<proc,MMU_AT_CODE>(adr):_MMU_read16<proc,MMU_AT_DATA>(adr))
+// #define MMU_read32_acl(proc,adr,access) ((access==CP15_ACCESS_EXECUTE)?_MMU_read32<proc,MMU_AT_CODE>(adr):_MMU_read32<proc,MMU_AT_DATA>(adr))
+//#endif
+
+// Use this macros for reading/writing, so the GDB stub isn't broken
+#ifdef GDB_STUB
+ #define READ32(a,b) cpu->mem_if->read32(a,(b) & 0xFFFFFFFC)
+ #define WRITE32(a,b,c) cpu->mem_if->write32(a,(b) & 0xFFFFFFFC,c)
+ #define READ16(a,b) cpu->mem_if->read16(a,(b) & 0xFFFFFFFE)
+ #define WRITE16(a,b,c) cpu->mem_if->write16(a,(b) & 0xFFFFFFFE,c)
+ #define READ8(a,b) cpu->mem_if->read8(a,b)
+ #define WRITE8(a,b,c) cpu->mem_if->write8(a,b,c)
+#else
+ #define READ32(a,b) _MMU_read32<PROCNUM>((b) & 0xFFFFFFFC)
+ #define WRITE32(a,b,c) _MMU_write32<PROCNUM>((b) & 0xFFFFFFFC,c)
+ #define READ16(a,b) _MMU_read16<PROCNUM>((b) & 0xFFFFFFFE)
+ #define WRITE16(a,b,c) _MMU_write16<PROCNUM>((b) & 0xFFFFFFFE,c)
+ #define READ8(a,b) _MMU_read08<PROCNUM>(b)
+ #define WRITE8(a,b,c) _MMU_write08<PROCNUM>(b, c)
+#endif
+
+template<int PROCNUM, MMU_ACCESS_TYPE AT>
+inline uint8_t _MMU_read08(uint32_t addr) { return _MMU_read08(PROCNUM, AT, addr); }
+
+template<int PROCNUM, MMU_ACCESS_TYPE AT>
+inline uint16_t _MMU_read16(uint32_t addr) { return _MMU_read16(PROCNUM, AT, addr); }
+
+template<int PROCNUM, MMU_ACCESS_TYPE AT>
+inline uint32_t _MMU_read32(uint32_t addr) { return _MMU_read32(PROCNUM, AT, addr); }
+
+template<int PROCNUM, MMU_ACCESS_TYPE AT>
+inline void _MMU_write08(uint32_t addr, uint8_t val) { _MMU_write08(PROCNUM, AT, addr, val); }
+
+template<int PROCNUM, MMU_ACCESS_TYPE AT>
+inline void _MMU_write16(uint32_t addr, uint16_t val) { _MMU_write16(PROCNUM, AT, addr, val); }
+
+template<int PROCNUM, MMU_ACCESS_TYPE AT>
+inline void _MMU_write32(uint32_t addr, uint32_t val) { _MMU_write32(PROCNUM, AT, addr, val); }
+
+//void FASTCALL MMU_DumpMemBlock(uint8_t proc, uint32_t address, uint32_t size, uint8_t *buffer);
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/MMU_timing.h
@@ -1,1 +1,452 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2007 shash
+ Copyright (C) 2007-2011 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// this file is split from MMU.h for the purpose of avoiding ridiculous recompile times
+// when changing it, because practically everything includes MMU.h.
+#ifndef MMUTIMING_H
+#define MMUTIMING_H
+
+#include <algorithm>
+#include <cmath>
+
+#include "MMU.h"
+#include "cp15.h"
+#include "readwrite.h"
+#include "NDSSystem.h"
+
+////////////////////////////////////////////////////////////////
+// MEMORY TIMING ACCURACY CONFIGURATION
+//
+// the more of these are enabled,
+// the more accurate memory access timing _should_ become.
+// they should be listed roughly in order of most to least important.
+// it's reasonable to disable some of these as a speed hack.
+// obviously, these defines don't cover all the variables or features needed,
+// and in particular, DMA or code+data access bus contention is still missing.
+
+ //disable this to prevent the advanced timing logic from ever running at all
+//#define ENABLE_ADVANCED_TIMING
+
+#ifdef ENABLE_ADVANCED_TIMING
+ // makes non-sequential accesses slower than sequential ones.
+#define ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
+ //(SOMETIMES THIS IS A BIG SPEED HIT!)
+
+ // enables emulation of code fetch waits.
+#define ACCOUNT_FOR_CODE_FETCH_CYCLES
+
+ // makes access to DTCM (arm9 only) fast.
+#define ACCOUNT_FOR_DATA_TCM_SPEED
+
+ // enables simulation of cache hits and cache misses.
+#define ENABLE_CACHE_CONTROLLER_EMULATION
+
+#endif //ENABLE_ADVANCED_TIMING
+
+//
+////////////////////////////////////////////////////////////////
+
+inline bool USE_TIMING() {
+#ifdef ENABLE_ADVANCED_TIMING
+ return CommonSettings.advanced_timing;
+#else
+ return false;
+#endif
+}
+
+
+enum MMU_ACCESS_DIRECTION
+{
+ MMU_AD_READ, MMU_AD_WRITE
+};
+
+
+// note that we don't actually emulate the cache contents here,
+// only enough to guess what would be a cache hit or a cache miss.
+// this doesn't really get used unless ENABLE_CACHE_CONTROLLER_EMULATION is defined.
+template<int SIZESHIFT, int ASSOCIATIVESHIFT, int BLOCKSIZESHIFT>
+class CacheController
+{
+public:
+ template<MMU_ACCESS_DIRECTION DIR>
+ inline bool Cached(uint32_t addr)
+ {
+ uint32_t blockMasked = addr & BLOCKMASK;
+ if(blockMasked == m_cacheCache)
+ return true;
+ else
+ return this->CachedInternal<DIR>(addr, blockMasked);
+ }
+
+ void Reset()
+ {
+ for(int blockIndex = 0; blockIndex < NUMBLOCKS; blockIndex++)
+ m_blocks[blockIndex].Reset();
+ m_cacheCache = ~0;
+ }
+ CacheController()
+ {
+ Reset();
+ }
+
+ /*void savestate(EMUFILE* os, int)
+ {
+ write32le(m_cacheCache, os);
+ for(int i = 0; i < NUMBLOCKS; i++)
+ {
+ for(int j = 0; j < ASSOCIATIVITY; j++)
+ write32le(m_blocks[i].tag[j],os);
+ write32le(m_blocks[i].nextWay,os);
+ }
+ }*/
+ bool loadstate(EMUFILE* is, int)
+ {
+ read32le(&m_cacheCache, is);
+ for(int i = 0; i < NUMBLOCKS; i++)
+ {
+ for(int j = 0; j < ASSOCIATIVITY; j++)
+ read32le(&m_blocks[i].tag[j],is);
+ read32le(&m_blocks[i].nextWay,is);
+ }
+ return true;
+ }
+
+private:
+ template<MMU_ACCESS_DIRECTION DIR>
+ bool CachedInternal(uint32_t addr, uint32_t blockMasked)
+ {
+ uint32_t blockIndex = blockMasked >> BLOCKSIZESHIFT;
+ CacheBlock& block = m_blocks[blockIndex];
+ addr &= TAGMASK;
+
+ for(int way = 0; way < ASSOCIATIVITY; way++)
+ if(addr == block.tag[way])
+ {
+ // found it, already allocated
+ m_cacheCache = blockMasked;
+ return true;
+ }
+ if(DIR == MMU_AD_READ)
+ {
+ // TODO: support other allocation orders?
+ block.tag[block.nextWay++] = addr;
+ block.nextWay %= ASSOCIATIVITY;
+ m_cacheCache = blockMasked;
+ }
+ return false;
+ }
+
+ enum { SIZE = 1 << SIZESHIFT };
+ enum { ASSOCIATIVITY = 1 << ASSOCIATIVESHIFT };
+ enum { BLOCKSIZE = 1 << BLOCKSIZESHIFT };
+ enum { TAGSHIFT = SIZESHIFT - ASSOCIATIVESHIFT };
+ enum { TAGMASK = (uint32_t)(~0 << TAGSHIFT) };
+ enum { BLOCKMASK = ((uint32_t)~0 >> (32 - TAGSHIFT)) & (uint32_t)(~0 << BLOCKSIZESHIFT) };
+ enum { WORDSIZE = sizeof(uint32_t) };
+ enum { WORDSPERBLOCK = (1 << BLOCKSIZESHIFT) / WORDSIZE };
+ enum { DATAPERWORD = WORDSIZE * ASSOCIATIVITY };
+ enum { DATAPERBLOCK = DATAPERWORD * WORDSPERBLOCK };
+ enum { NUMBLOCKS = SIZE / DATAPERBLOCK };
+
+ struct CacheBlock
+ {
+ uint32_t tag [ASSOCIATIVITY];
+ uint32_t nextWay;
+
+ void Reset()
+ {
+ nextWay = 0;
+ for(int way = 0; way < ASSOCIATIVITY; way++)
+ tag[way] = 0;
+ }
+ };
+
+ uint32_t m_cacheCache; // optimization
+
+ CacheBlock m_blocks [NUMBLOCKS];
+};
+
+
+template<int PROCNUM, MMU_ACCESS_TYPE AT, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
+inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential);
+
+
+template<int PROCNUM, MMU_ACCESS_TYPE AT>
+class FetchAccessUnit
+{
+public:
+ template<int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
+ inline uint32_t Fetch(uint32_t address)
+ {
+ #ifdef ACCOUNT_FOR_CODE_FETCH_CYCLES
+ const bool prohibit = TIMING;
+ #else
+ const bool prohibit = false;
+ #endif
+
+ if(AT == MMU_AT_CODE && !prohibit)
+ {
+ return 1;
+ }
+
+ uint32_t time = _MMU_accesstime<PROCNUM, AT, READSIZE, DIRECTION,TIMING>(address,
+#ifdef ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
+ (TIMING?
+ (address == (m_lastAddress + (READSIZE>>3)))
+ :true
+ )
+#else
+ true
+#endif
+ );
+
+#ifdef ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
+ m_lastAddress = address;
+#endif
+
+ return time;
+ }
+
+ void Reset()
+ {
+ m_lastAddress = ~0;
+ }
+ FetchAccessUnit() { this->Reset(); }
+
+ /*void savestate(EMUFILE* os, int)
+ {
+ write32le(m_lastAddress,os);
+ }*/
+ bool loadstate(EMUFILE* is, int)
+ {
+ read32le(&m_lastAddress,is);
+ return true;
+ }
+
+private:
+ uint32_t m_lastAddress;
+};
+
+
+
+
+
+struct MMU_struct_timing
+{
+ // technically part of the cp15, but I didn't want the dereferencing penalty.
+ // these template values correspond with the value of armcp15->cacheType.
+ CacheController<13,2,5> arm9codeCache; // 8192 bytes, 4-way associative, 32-byte blocks
+ CacheController<12,2,5> arm9dataCache; // 4096 bytes, 4-way associative, 32-byte blocks
+
+ // technically part of armcpu_t, but that struct isn't templated on PROCNUM
+ FetchAccessUnit<0,MMU_AT_CODE> arm9codeFetch;
+ FetchAccessUnit<0,MMU_AT_DATA> arm9dataFetch;
+ FetchAccessUnit<1,MMU_AT_CODE> arm7codeFetch;
+ FetchAccessUnit<1,MMU_AT_DATA> arm7dataFetch;
+
+ template<int PROCNUM> inline FetchAccessUnit<PROCNUM,MMU_AT_CODE>& armCodeFetch();
+ template<int PROCNUM> inline FetchAccessUnit<PROCNUM,MMU_AT_DATA>& armDataFetch();
+};
+template<> inline FetchAccessUnit<0,MMU_AT_CODE>& MMU_struct_timing::armCodeFetch<0>() { return this->arm9codeFetch; }
+template<> inline FetchAccessUnit<1,MMU_AT_CODE>& MMU_struct_timing::armCodeFetch<1>() { return this->arm7codeFetch; }
+template<> inline FetchAccessUnit<0,MMU_AT_DATA>& MMU_struct_timing::armDataFetch<0>() { return this->arm9dataFetch; }
+template<> inline FetchAccessUnit<1,MMU_AT_DATA>& MMU_struct_timing::armDataFetch<1>() { return this->arm7dataFetch; }
+
+
+extern MMU_struct_timing MMU_timing;
+
+
+
+// calculates the time a single memory access takes,
+// in units of cycles of the current processor.
+// this function replaces what used to be MMU_WAIT16 and MMU_WAIT32.
+// this may have side effects, so don't call it more than necessary.
+template<int PROCNUM, MMU_ACCESS_TYPE AT, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
+inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential)
+{
+ static const int MC = 1; // cached or tcm memory speed
+ static const int M32 = (PROCNUM==ARMCPU_ARM9) ? 2 : 1; // access through 32-bit bus
+ static const int M16 = M32 * ((READSIZE>16) ? 2 : 1); // access through 16-bit bus
+ static const int MSLW = M16 * 8; // this needs tuning
+
+ if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_CODE && addr < 0x02000000)
+ return MC; // ITCM
+
+#ifdef ACCOUNT_FOR_DATA_TCM_SPEED
+ if(TIMING && PROCNUM==ARMCPU_ARM9 && AT==MMU_AT_DATA && (addr&(~0x3FFF)) == MMU.DTCMRegion)
+ return MC; // DTCM
+#endif
+
+ // for now, assume the cache is always enabled for all of main memory
+ if(AT != MMU_AT_DMA && TIMING && PROCNUM==ARMCPU_ARM9 && (addr & 0x0F000000) == 0x02000000)
+ {
+#ifdef ENABLE_CACHE_CONTROLLER_EMULATION
+ bool cached = false;
+ if(AT==MMU_AT_CODE)
+ cached = MMU_timing.arm9codeCache.Cached<DIRECTION>(addr);
+ if(AT==MMU_AT_DATA)
+ cached = MMU_timing.arm9dataCache.Cached<DIRECTION>(addr);
+ if(cached)
+ return MC;
+ uint32_t c;
+ if(sequential && AT==MMU_AT_DATA)
+ c = M16; // bonus for sequential data access
+ else if(DIRECTION == MMU_AD_READ)
+ c = M16 * 5;
+ else
+ c = M16 * 2; // should be 4, but write buffer isn't emulated yet.
+ if(DIRECTION == MMU_AD_READ)
+ {
+ // cache miss while reading means it has to fill a whole cache line
+ // by reading 32 bytes...
+ c += 8 * M32*2;
+ }
+ return c;
+#elif defined(ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS)
+ // this is the closest approximation I could find
+ // to the with-cache-controller timing
+ // that doesn't do any actual caching logic.
+ return sequential ? MC : M16;
+#endif
+ }
+
+ static const TWaitState MMU_WAIT[16*16] = {
+ // ITCM, ITCM, MAIN, SWI, REG, VMEM, LCD, OAM, ROM, ROM, RAM, U, U, U, U, BIOS
+#define X MC, MC, M16, M32, M32, M16, M16, M32, MSLW, MSLW, MSLW, M32,M32,M32,M32, M32,
+ // duplicate it 16 times (this was somehow faster than using a mask of 0xF)
+ X X X X X X X X X X X X X X X X
+#undef X
+ };
+
+ uint32_t c = MMU_WAIT[(addr >> 24)];
+
+#ifdef ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
+ if(TIMING && !sequential)
+ {
+ //if(c != MC || PROCNUM==ARMCPU_ARM7) // check not needed anymore because ITCM/DTCM return earlier
+ {
+ c += (PROCNUM==ARMCPU_ARM9) ? 3*2 : 1;
+ }
+ }
+#endif
+
+ return c;
+}
+
+
+
+
+
+// calculates the cycle time of a single memory access in the MEM stage.
+// to be used to calculate the memCycles argument for MMU_aluMemCycles.
+// this may have side effects, so don't call it more than necessary.
+template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
+inline uint32_t MMU_memAccessCycles(uint32_t addr)
+{
+ if(TIMING)
+ return MMU_timing.armDataFetch<PROCNUM>().template Fetch<READSIZE,DIRECTION,true>((addr)&(~((READSIZE>>3)-1)));
+ else
+ return MMU_timing.armDataFetch<PROCNUM>().template Fetch<READSIZE,DIRECTION,false>((addr)&(~((READSIZE>>3)-1)));
+}
+
+template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION>
+inline uint32_t MMU_memAccessCycles(uint32_t addr)
+{
+ if(USE_TIMING())
+ return MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,true>(addr);
+ else
+ return MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,false>(addr);
+}
+
+// calculates the cycle time of a single code fetch in the FETCH stage
+// to be used to calculate the fetchCycles argument for MMU_fetchExecuteCycles.
+// this may have side effects, so don't call it more than necessary.
+template<int PROCNUM, int READSIZE>
+inline uint32_t MMU_codeFetchCycles(uint32_t addr)
+{
+ if(USE_TIMING())
+ return MMU_timing.armCodeFetch<PROCNUM>().template Fetch<READSIZE,MMU_AD_READ,true>((addr)&(~((READSIZE>>3)-1)));
+ else
+ return MMU_timing.armCodeFetch<PROCNUM>().template Fetch<READSIZE,MMU_AD_READ,false>((addr)&(~((READSIZE>>3)-1)));
+}
+
+// calculates the cycle contribution of ALU + MEM stages (= EXECUTE)
+// given ALU cycle time and the summation of multiple memory access cycle times.
+// this function might belong more in armcpu, but I don't think it matters.
+template<int PROCNUM>
+inline uint32_t MMU_aluMemCycles(uint32_t aluCycles, uint32_t memCycles)
+{
+ if(PROCNUM==ARMCPU_ARM9)
+ {
+ // ALU and MEM are different stages of the 5-stage pipeline.
+ // we approximate the pipeline throughput using max,
+ // since simply adding the cycles of each instruction together
+ // fails to take into account the parallelism of the arm pipeline
+ // and would make the emulated system unnaturally slow.
+ return std::max(aluCycles, memCycles);
+ }
+ else
+ {
+ // ALU and MEM are part of the same stage of the 3-stage pipeline,
+ // thus they occur in sequence and we can simply add the counts together.
+ return aluCycles + memCycles;
+ }
+}
+
+// calculates the cycle contribution of ALU + MEM stages (= EXECUTE)
+// given ALU cycle time and the description of a single memory access.
+// this may have side effects, so don't call it more than necessary.
+template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION>
+inline uint32_t MMU_aluMemAccessCycles(uint32_t aluCycles, uint32_t addr)
+{
+ uint32_t memCycles;
+ if(USE_TIMING())
+ memCycles = MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,true>(addr);
+ else memCycles = MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,false>(addr);
+ return MMU_aluMemCycles<PROCNUM>(aluCycles, memCycles);
+}
+
+// calculates the cycle contribution of FETCH + EXECUTE stages
+// given executeCycles = the combined ALU+MEM cycles
+// and fetchCycles = the cycle time of the FETCH stage
+// this function might belong more in armcpu, but I don't think it matters.
+template<int PROCNUM>
+inline uint32_t MMU_fetchExecuteCycles(uint32_t executeCycles, uint32_t fetchCycles)
+{
+ #ifdef ACCOUNT_FOR_CODE_FETCH_CYCLES
+ const bool allow = true;
+ #else
+ const bool allow = false;
+ #endif
+
+ if(USE_TIMING() && allow)
+ {
+ // execute and fetch are different stages of the pipeline for both arm7 and arm9.
+ // again, we approximate the pipeline throughput using max.
+ return std::max(executeCycles, fetchCycles);
+ // TODO: add an option to support conflict between MEM and FETCH cycles
+ // if they're both using the same data bus.
+ // in the case of a conflict this should be:
+ // return std::max(aluCycles, memCycles + fetchCycles);
+ }
+ return executeCycles;
+}
+
+#endif //MMUTIMING_H
+
--- /dev/null
+++ b/src/in_2sf/desmume/NDSSystem.cpp
@@ -1,1 +1,3007 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2008-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <algorithm>
+#include <cstring>
+#include <cstdlib>
+#include <cmath>
+#include <zlib.h>
+
+#include "common.h"
+#include "NDSSystem.h"
+//#include "render3D.h"
+#include "MMU.h"
+//#include "ROMReader.h"
+//#include "gfx3d.h"
+//#include "utils/decrypt/decrypt.h"
+//#include "utils/decrypt/crc.h"
+#include "bios.h"
+//#include "debug.h"
+//#include "cheatSystem.h"
+//#include "movie.h"
+//#include "Disassembler.h"
+#include "readwrite.h"
+//#include "debug.h"
+#include "firmware.h"
+#include "version.h"
+#include "slot1.h"
+
+#include "path.h"
+
+//#define LOG_ARM9
+//#define LOG_ARM7
+//bool dolog = false;
+//#define LOG_TO_FILE
+//#define LOG_TO_FILE_REGS
+
+//===============================================================
+//FILE *fp_dis7 = NULL;
+//FILE *fp_dis9 = NULL;
+
+PathInfo path;
+
+TCommonSettings CommonSettings;
+//static BaseDriver _stub_driver;
+//BaseDriver* driver = &_stub_driver;
+//std::string InputDisplayString;
+
+//static bool LidClosed = false;
+//static uint8_t countLid = 0;
+
+GameInfo gameInfo;
+NDSSystem nds;
+CFIRMWARE *firmware = NULL;
+//ADVANsCEne advsc;
+
+bool singleStep;
+//bool nds_debug_continuing[2];
+//int lagframecounter;
+//int LagFrameFlag;
+//int lastLag;
+//int TotalLagFrames;
+
+//TSCalInfo TSCal;
+
+namespace DLDI
+{
+ bool tryPatch(void* data, size_t size);
+}
+
+/*void Desmume_InitOnce()
+{
+ static bool initOnce = false;
+ if(initOnce) return;
+ initOnce = true;*/
+
+/*#ifdef HAVE_LIBAGG
+ extern void Agg_init(); //no need to include just for this
+ Agg_init();
+#endif*/
+//}
+
+#ifdef GDB_STUB
+int NDS_Init( struct armcpu_memory_iface *arm9_mem_if,
+struct armcpu_ctrl_iface **arm9_ctrl_iface,
+struct armcpu_memory_iface *arm7_mem_if,
+struct armcpu_ctrl_iface **arm7_ctrl_iface) {
+#else
+int NDS_Init() {
+#endif
+ //nds.idleFrameCounter = 0;
+ //memset(nds.runCycleCollector,0,sizeof(nds.runCycleCollector));
+ MMU_Init();
+ nds.VCount = 0;
+
+ //got to print this somewhere..
+ printf("%s\n", EMU_DESMUME_NAME_AND_VERSION());
+
+ /*if (Screen_Init(GFXCORE_DUMMY) != 0)
+ return -1;*/
+
+ //gfx3d_init();
+
+#ifdef GDB_STUB
+ armcpu_new(&NDS_ARM7,1, arm7_mem_if, arm7_ctrl_iface);
+ armcpu_new(&NDS_ARM9,0, arm9_mem_if, arm9_ctrl_iface);
+#else
+ armcpu_new(&NDS_ARM7,1);
+ armcpu_new(&NDS_ARM9,0);
+#endif
+
+ if (SPU_Init(SNDCORE_DUMMY, 740) != 0)
+ return -1;
+
+ //WIFI_Init() ;
+
+ // Init calibration info
+ //TSCal.adc.x1 = 0x0200;
+ //TSCal.adc.y1 = 0x0200;
+ //TSCal.scr.x1 = 0x20 + 1; // calibration screen coords are 1-based,
+ //TSCal.scr.y1 = 0x20 + 1; // either that or NDS_getADCTouchPosX/Y are wrong.
+ //TSCal.adc.x2 = 0x0E00;
+ //TSCal.adc.y2 = 0x0800;
+ //TSCal.scr.x2 = 0xE0 + 1;
+ //TSCal.scr.y2 = 0x80 + 1;
+ //TSCal.adc.width = (TSCal.adc.x2 - TSCal.adc.x1);
+ //TSCal.adc.height = (TSCal.adc.y2 - TSCal.adc.y1);
+ //TSCal.scr.width = (TSCal.scr.x2 - TSCal.scr.x1);
+ //TSCal.scr.height = (TSCal.scr.y2 - TSCal.scr.y1);
+
+ //cheats = new CHEATS();
+ //cheatSearch = new CHEATSEARCH();
+
+ return 0;
+}
+
+void NDS_DeInit() {
+ if(MMU.CART_ROM != MMU.UNUSED_RAM)
+ NDS_FreeROM();
+
+ SPU_DeInit();
+ //Screen_DeInit();
+ MMU_DeInit();
+ //gpu3D->NDS_3D_Close();
+
+ //WIFI_DeInit();
+ /*if (cheats)
+ delete cheats;*/
+ /*if (cheatSearch)
+ delete cheatSearch;*/
+
+#ifdef LOG_ARM7
+ if (fp_dis7 != NULL)
+ {
+ fclose(fp_dis7);
+ fp_dis7 = NULL;
+ }
+#endif
+
+#ifdef LOG_ARM9
+ if (fp_dis9 != NULL)
+ {
+ fclose(fp_dis9);
+ fp_dis9 = NULL;
+ }
+#endif
+}
+
+bool NDS_SetROM(uint8_t * rom, uint32_t mask)
+{
+ MMU_setRom(rom, mask);
+
+ return true;
+}
+
+NDS_header * NDS_getROMHeader()
+{
+ if(MMU.CART_ROM == MMU.UNUSED_RAM) return NULL;
+ NDS_header * header = new NDS_header;
+
+ memcpy(header->gameTile, MMU.CART_ROM, 12);
+ memcpy(header->gameCode, MMU.CART_ROM + 12, 4);
+ header->makerCode = T1ReadWord(MMU.CART_ROM, 16);
+ header->unitCode = MMU.CART_ROM[18];
+ header->deviceCode = MMU.CART_ROM[19];
+ header->cardSize = MMU.CART_ROM[20];
+ memcpy(header->cardInfo, MMU.CART_ROM + 21, 8);
+ header->flags = MMU.CART_ROM[29];
+ header->romversion = MMU.CART_ROM[30];
+ header->ARM9src = T1ReadLong(MMU.CART_ROM, 32);
+ header->ARM9exe = T1ReadLong(MMU.CART_ROM, 36);
+ header->ARM9cpy = T1ReadLong(MMU.CART_ROM, 40);
+ header->ARM9binSize = T1ReadLong(MMU.CART_ROM, 44);
+ header->ARM7src = T1ReadLong(MMU.CART_ROM, 48);
+ header->ARM7exe = T1ReadLong(MMU.CART_ROM, 52);
+ header->ARM7cpy = T1ReadLong(MMU.CART_ROM, 56);
+ header->ARM7binSize = T1ReadLong(MMU.CART_ROM, 60);
+ header->FNameTblOff = T1ReadLong(MMU.CART_ROM, 64);
+ header->FNameTblSize = T1ReadLong(MMU.CART_ROM, 68);
+ header->FATOff = T1ReadLong(MMU.CART_ROM, 72);
+ header->FATSize = T1ReadLong(MMU.CART_ROM, 76);
+ header->ARM9OverlayOff = T1ReadLong(MMU.CART_ROM, 80);
+ header->ARM9OverlaySize = T1ReadLong(MMU.CART_ROM, 84);
+ header->ARM7OverlayOff = T1ReadLong(MMU.CART_ROM, 88);
+ header->ARM7OverlaySize = T1ReadLong(MMU.CART_ROM, 92);
+ header->unknown2a = T1ReadLong(MMU.CART_ROM, 96);
+ header->unknown2b = T1ReadLong(MMU.CART_ROM, 100);
+ header->IconOff = T1ReadLong(MMU.CART_ROM, 104);
+ header->CRC16 = T1ReadWord(MMU.CART_ROM, 108);
+ header->ROMtimeout = T1ReadWord(MMU.CART_ROM, 110);
+ header->ARM9unk = T1ReadLong(MMU.CART_ROM, 112);
+ header->ARM7unk = T1ReadLong(MMU.CART_ROM, 116);
+ memcpy(header->unknown3c, MMU.CART_ROM + 120, 8);
+ header->ROMSize = T1ReadLong(MMU.CART_ROM, 128);
+ header->HeaderSize = T1ReadLong(MMU.CART_ROM, 132);
+ memcpy(header->unknown5, MMU.CART_ROM + 136, 56);
+ memcpy(header->logo, MMU.CART_ROM + 192, 156);
+ header->logoCRC16 = T1ReadWord(MMU.CART_ROM, 348);
+ header->headerCRC16 = T1ReadWord(MMU.CART_ROM, 350);
+ memcpy(header->reserved, MMU.CART_ROM + 352, std::min(160, (int)gameInfo.romsize - 352));
+
+ return header;
+}
+
+
+
+
+/*void debug()
+{
+ //if(NDS_ARM9.R[15]==0x020520DC) emu_halt();
+ //DSLinux
+ //if(NDS_ARM9.CPSR.bits.mode == 0) emu_halt();
+ //if((NDS_ARM9.R[15]&0xFFFFF000)==0) emu_halt();
+ //if((NDS_ARM9.R[15]==0x0201B4F4)&&(NDS_ARM9.R[1]==0x0)) emu_halt();
+ //AOE
+ //if((NDS_ARM9.R[15]==0x01FFE194)&&(NDS_ARM9.R[0]==0)) emu_halt();
+ //if((NDS_ARM9.R[15]==0x01FFE134)&&(NDS_ARM9.R[0]==0)) emu_halt();
+
+ //BBMAN
+ //if(NDS_ARM9.R[15]==0x02098B4C) emu_halt();
+ //if(NDS_ARM9.R[15]==0x02004924) emu_halt();
+ //if(NDS_ARM9.R[15]==0x02004890) emu_halt();
+
+ //if(NDS_ARM9.R[15]==0x0202B800) emu_halt();
+ //if(NDS_ARM9.R[15]==0x0202B3DC) emu_halt();
+ //if((NDS_ARM9.R[1]==0x9AC29AC1)&&(!fait)) {emu_halt();fait = true;}
+ //if(NDS_ARM9.R[1]==0x0400004A) {emu_halt();fait = true;}
+ if(NDS_ARM9.R[4]==0x2E33373C) emu_halt();
+ if(NDS_ARM9.R[15]==0x02036668) //emu_halt();
+ {
+ nds.logcount++;
+ sprintf(logbuf, "%d %08X", nds.logcount, NDS_ARM9.R[13]);
+ log::ajouter(logbuf);
+ if(nds.logcount==89) execute=false;
+ }
+ //if(NDS_ARM9.instruction==0) emu_halt();
+ //if((NDS_ARM9.R[15]>>28)) emu_halt();
+}*/
+
+//#define DSGBA_LOADER_SIZE 512
+/*enum
+{
+ ROM_NDS = 0,
+ ROM_DSGBA
+};*/
+
+#if 0 /* not used */
+//http://www.aggregate.org/MAGIC/#Population%20Count%20(Ones%20Count)
+static uint32_t ones32(uint32_t x)
+{
+ /* 32-bit recursive reduction using SWAR...
+ but first step is mapping 2-bit values
+ into sum of 2 1-bit values in sneaky way
+ */
+ x -= ((x >> 1) & 0x55555555);
+ x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
+ x = (((x >> 4) + x) & 0x0f0f0f0f);
+ x += (x >> 8);
+ x += (x >> 16);
+ return x & 0x0000003f;
+}
+#endif
+
+RomBanner::RomBanner(bool defaultInit)
+{
+ if(!defaultInit) return;
+ version = 1; //Version (0001h)
+ crc16 = 0; //CRC16 across entries 020h..83Fh
+ memset(reserved,0,sizeof(reserved));
+ memset(bitmap,0,sizeof(bitmap));
+ memset(palette,0,sizeof(palette));
+ memset(titles,0,sizeof(titles));
+ memset(end0xFF,0,sizeof(end0xFF));
+}
+
+/*bool GameInfo::hasRomBanner()
+{
+ if(header.IconOff + sizeof(RomBanner) > romsize)
+ return false;
+ else return true;
+}*/
+
+/*const RomBanner& GameInfo::getRomBanner()
+{
+ //we may not have a valid banner. return a default one
+ if(!hasRomBanner())
+ {
+ static RomBanner defaultBanner(true);
+ return defaultBanner;
+ }
+
+ return *(RomBanner*)(romdata+header.IconOff);
+}*/
+
+/*void GameInfo::populate()
+{
+ const char *regions[] = { "JPFSEDIRKH",
+ "JPN",
+ "EUR",
+ "FRA",
+ "ESP",
+ "USA",
+ "NOE",
+ "ITA",
+ "RUS",
+ "KOR",
+ "HOL",
+
+ };
+
+ NDS_header * _header = NDS_getROMHeader();
+ header = *_header;
+ delete _header;
+
+ memset(ROMserial, 0, sizeof(ROMserial));
+ memset(ROMname, 0, sizeof(ROMname));
+
+ if (
+ //Option 1. - look for this instruction in the game title
+ //(did this ever work?)
+ //(header->gameTile[0] == 0x2E) &&
+ //(header->gameTile[1] == 0x00) &&
+ //(header->gameTile[2] == 0x00) &&
+ //(header->gameTile[3] == 0xEA)
+ //) &&
+ //option 2. - look for gamecode #### (default for ndstool)
+ //or an invalid gamecode
+ (
+ ((header.gameCode[0] == 0x23) &&
+ (header.gameCode[1] == 0x23) &&
+ (header.gameCode[2] == 0x23) &&
+ (header.gameCode[3] == 0x23)
+ ) ||
+ (header.gameCode[0] == 0x00)
+ )
+ &&
+ header.makerCode == 0x0
+ )
+ {
+ //we can't really make a serial for a homebrew game that hasnt set a game code
+ strcpy(ROMserial, "Homebrew");
+ }
+ else
+ {
+ strcpy(ROMserial,"NTR- -");
+ memcpy(ROMserial+4, header.gameCode, 4);
+
+ uint32_t region = (uint32_t)(std::max<int32_t>(strchr(regions[0],header.gameCode[3]) - regions[0] + 1, 0));
+ if (region != 0)
+ strcat(ROMserial, regions[region]);
+ else
+ strcat(ROMserial, "Unknown");
+ }
+
+ //rom name is probably set even in homebrew
+ memset(ROMname, 0, sizeof(ROMname));
+ memcpy(ROMname, header.gameTile, 12);
+ trim(ROMname,20);
+
+ if(header.IconOff < romsize)
+ {
+ uint8_t num = (T1ReadByte((uint8_t*)romdata, header.IconOff) == 1)?6:7;
+ for (int i = 0; i < num; i++)
+ {
+ wcstombs(ROMfullName[i], (wchar_t *)(romdata+header.IconOff+0x240+(i*0x100)), 0x100);
+ trim(ROMfullName[i]);
+ }
+ }
+
+ //this may look like a poor heuristic for detecting homebrew, but it is actually pretty good.
+ //setting your own game code is stupid, so homebrew should just leave it.
+ //however, non-devkitARM-default makefiles may not have set this.
+ isHomebrew = !memcmp(header.gameCode,"####",4);
+}*/
+
+/*#ifdef _WINDOWS
+
+//static std::vector<char> buffer;
+//static std::vector<char> v;
+
+static void loadrom(std::string fname) {
+
+ FILE* inf = fopen(fname.c_str(),"rb");
+ if(!inf) return;
+
+ fseek(inf,0,SEEK_END);
+ int size = ftell(inf);
+ fseek(inf,0,SEEK_SET);
+
+ gameInfo.resize(size);
+ fread(gameInfo.romdata,1,size,inf);
+ gameInfo.fillGap();
+
+ fclose(inf);
+}
+
+static int rom_init_path(const char *filename, const char *logicalFilename)
+{
+ int type = ROM_NDS;
+
+ path.init(logicalFilename);
+
+ if ( path.isdsgba(path.path)) {
+ type = ROM_DSGBA;
+ loadrom(path.path);
+ }
+ else if ( !strcasecmp(path.extension().c_str(), "nds")) {
+ type = ROM_NDS;
+ loadrom(path.path); //n.b. this does nothing if the file can't be found (i.e. if it was an extracted tempfile)...
+ //...but since the data was extracted to gameInfo then it is ok
+ }
+ //ds.gba in archives, it's already been loaded into memory at this point
+ else if (path.isdsgba(std::string(logicalFilename))) {
+ type = ROM_DSGBA;
+ } else {
+ //well, try to load it as an nds rom anyway
+ type = ROM_NDS;
+ loadrom(path.path);
+ }
+
+ if(type == ROM_DSGBA)
+ {
+ std::vector<char> v(gameInfo.romdata + DSGBA_LOADER_SIZE, gameInfo.romdata + gameInfo.romsize);
+ gameInfo.loadData(&v[0],gameInfo.romsize - DSGBA_LOADER_SIZE);
+ }
+
+ //check that size is at least the size of the header
+ if (gameInfo.romsize < 352) {
+ return -1;
+ }
+
+ return 1;
+}
+#else
+static int rom_init_path(const char *filename, const char *logicalFilename)
+{
+ int ret;
+ int type;
+ ROMReader_struct *reader;
+ void *file;
+ uint32_t size;
+ char *noext;
+
+ noext = strdup(filename);
+ reader = ROMReaderInit(&noext);
+ free(noext);
+
+ if (logicalFilename)
+ path.init(logicalFilename);
+ else
+ path.init(filename);
+
+ if (!strcasecmp(path.extension().c_str(), "zip"))
+ type = ROM_NDS;
+ else if (!strcasecmp(path.extension().c_str(), "nds"))
+ type = ROM_NDS;
+ else if (path.isdsgba(path.path))
+ type = ROM_DSGBA;
+ else
+ type = ROM_NDS;
+
+ file = reader->Init(filename);
+ if (!file)
+ {
+ reader->DeInit(file);
+ return -1;
+ }
+
+ size = reader->Size(file);
+
+ if(type == ROM_DSGBA)
+ {
+ reader->Seek(file, DSGBA_LOADER_SIZE, SEEK_SET);
+ size -= DSGBA_LOADER_SIZE;
+ }
+
+ //check that size is at least the size of the header
+ if (size < 352) {
+ reader->DeInit(file);
+ return -1;
+ }
+
+ // Make sure old ROM is freed first(at least this way we won't be eating
+ // up a ton of ram before the old ROM is freed)
+ if(MMU.CART_ROM != MMU.UNUSED_RAM)
+ NDS_FreeROM();
+
+ gameInfo.resize(size);
+ ret = reader->Read(file, gameInfo.romdata, size);
+ gameInfo.fillGap();
+ reader->DeInit(file);
+
+ return ret;
+}
+#endif*/
+
+/*int NDS_LoadROM(const char *filename, const char *logicalFilename)
+{
+ int ret;
+ char buf[MAX_PATH];
+
+ if (filename == NULL)
+ return -1;
+
+ ret = rom_init_path(filename, logicalFilename);
+ if (ret < 1)
+ return ret;
+
+ //decrypt if necessary..
+ //but this is untested and suspected to fail on big endian, so lets not support this on big endian
+#ifndef WORDS_BIGENDIAN
+ bool okRom = DecryptSecureArea((uint8_t*)gameInfo.romdata,gameInfo.romsize);
+
+ if(!okRom) {
+ printf("Specified file is not a valid rom\n");
+ return -1;
+ }
+#endif
+
+ if (cheatSearch)
+ cheatSearch->close();
+ FCEUI_StopMovie();
+
+ MMU_unsetRom();
+ NDS_SetROM((uint8_t*)gameInfo.romdata, gameInfo.mask);
+
+ gameInfo.populate();
+ gameInfo.crc = crc32(0,(uint8_t*)gameInfo.romdata,gameInfo.romsize);
+ //INFO("\nROM game code: %c%c%c%c\n", gameInfo.header.gameCode[0], gameInfo.header.gameCode[1], gameInfo.header.gameCode[2], gameInfo.header.gameCode[3]);
+ //INFO("ROM crc: %08X\n", gameInfo.crc);
+ //INFO("ROM serial: %s\n", gameInfo.ROMserial);
+ //INFO("ROM internal name: %s\n", gameInfo.ROMname);
+
+ memset(buf, 0, MAX_PATH);
+ strcpy(buf, path.pathToModule);
+ strcat(buf, "desmume.ddb"); // DeSmuME database :)
+ advsc.setDatabase(buf);
+ buf[0] = gameInfo.header.gameCode[0];
+ buf[1] = gameInfo.header.gameCode[1];
+ buf[2] = gameInfo.header.gameCode[2];
+ buf[3] = gameInfo.header.gameCode[3];
+ buf[4] = 0;
+ if (advsc.checkDB(buf))
+ {
+ u8 sv = advsc.getSaveType();
+ printf("ADVANsCEne database:\n");
+ printf("\t* ROM save type: ");
+ if (sv == 0xFF)
+ printf("Unknown");
+ else
+ if (sv == 0xFE)
+ printf("None");
+ else
+ {
+ printf("%s", save_names[sv]);
+ if (CommonSettings.autodetectBackupMethod == 1)
+ backup_setManualBackupType(sv+1);
+ }
+ printf("\n\t* ROM crc: %08X\n", advsc.getCRC32());
+ }
+ printf("\n");
+
+ //for homebrew, try auto-patching DLDI. should be benign if there is no DLDI or if it fails
+ if(gameInfo.isHomebrew)
+ DLDI::tryPatch((void*)gameInfo.romdata, gameInfo.romsize);
+
+ memset(buf, 0, MAX_PATH);
+ path.getpathnoext(path.BATTERY, buf);
+ strcat(buf, ".dsv"); // DeSmuME memory card :)
+ MMU_new.backupDevice.load_rom(buf);
+
+ memset(buf, 0, MAX_PATH);
+ path.getpathnoext(path.CHEATS, buf);
+ strcat(buf, ".dct"); // DeSmuME cheat :)
+ cheats->init(buf);
+
+ NDS_Reset();
+
+ return ret;
+}*/
+
+void NDS_FreeROM()
+{
+ //FCEUI_StopMovie();
+ if ((uint8_t*)MMU.CART_ROM == (uint8_t*)gameInfo.romdata)
+ gameInfo.romdata = NULL;
+ if (MMU.CART_ROM != MMU.UNUSED_RAM)
+ delete [] MMU.CART_ROM;
+ MMU_unsetRom();
+}
+
+
+
+/*int NDS_ImportSave(const char *filename)
+{
+ if (strlen(filename) < 4)
+ return 0;
+
+ if (memcmp(filename+strlen(filename)-4, ".duc", 4) == 0)
+ return MMU_new.backupDevice.load_duc(filename);
+ else
+ if (MMU_new.backupDevice.load_no_gba(filename))
+ return 1;
+ else
+ return MMU_new.backupDevice.load_raw(filename);
+
+ //return 0;
+}*/
+
+/*bool NDS_ExportSave(const char *filename)
+{
+ if (strlen(filename) < 4)
+ return false;
+
+ if (memcmp(filename+strlen(filename)-5, ".sav*", 5) == 0)
+ {
+ char tmp[MAX_PATH];
+ memset(tmp, 0, MAX_PATH);
+ strcpy(tmp, filename);
+ tmp[strlen(tmp)-1] = 0;
+ return MMU_new.backupDevice.save_no_gba(tmp);
+ }
+
+ if (memcmp(filename+strlen(filename)-4, ".sav", 4) == 0)
+ return MMU_new.backupDevice.save_raw(filename);
+
+ return false;
+}*/
+
+/*static int WritePNGChunk(FILE *fp, uint32 size, const char *type, const uint8 *data)
+{
+ uint32 crc;
+
+ uint8 tempo[4];
+
+ tempo[0]=size>>24;
+ tempo[1]=size>>16;
+ tempo[2]=size>>8;
+ tempo[3]=size;
+
+ if(fwrite(tempo,4,1,fp)!=1)
+ return 0;
+ if(fwrite(type,4,1,fp)!=1)
+ return 0;
+
+ if(size)
+ if(fwrite(data,1,size,fp)!=size)
+ return 0;
+
+ crc = crc32(0,(uint8 *)type,4);
+ if(size)
+ crc = crc32(crc,data,size);
+
+ tempo[0]=crc>>24;
+ tempo[1]=crc>>16;
+ tempo[2]=crc>>8;
+ tempo[3]=crc;
+
+ if(fwrite(tempo,4,1,fp)!=1)
+ return 0;
+ return 1;
+}*/
+/*int NDS_WritePNG(const char *fname)
+{
+ int x, y;
+ int width=256;
+ int height=192*2;
+ uint16_t * bmp = (uint16_t *)GPU_screen;
+ FILE *pp=NULL;
+ uint8 *compmem = NULL;
+ uLongf compmemsize = (uLongf)( (height * (width + 1) * 3 * 1.001 + 1) + 12 );
+
+ if(!(compmem=(uint8 *)malloc(compmemsize)))
+ return 0;
+
+ if(!(pp=fopen(fname, "wb")))
+ {
+ goto PNGerr;
+ }
+ {
+ const uint8 header[8]={137,80,78,71,13,10,26,10};
+ if(fwrite(header,8,1,pp)!=1)
+ goto PNGerr;
+ }
+
+ {
+ uint8 chunko[13];
+
+ chunko[0] = width >> 24; // Width
+ chunko[1] = width >> 16;
+ chunko[2] = width >> 8;
+ chunko[3] = width;
+
+ chunko[4] = height >> 24; // Height
+ chunko[5] = height >> 16;
+ chunko[6] = height >> 8;
+ chunko[7] = height;
+
+ chunko[8]=8; // 8 bits per sample(24 bits per pixel)
+ chunko[9]=2; // Color type; RGB triplet
+ chunko[10]=0; // compression: deflate
+ chunko[11]=0; // Basic adapative filter set(though none are used).
+ chunko[12]=0; // No interlace.
+
+ if(!WritePNGChunk(pp,13,"IHDR",chunko))
+ goto PNGerr;
+ }
+
+ {
+ uint8 *tmp_buffer;
+ uint8 *tmp_inc;
+ tmp_inc = tmp_buffer = (uint8 *)malloc((width * 3 + 1) * height);
+
+ for(y=0;y<height;y++)
+ {
+ *tmp_inc = 0;
+ tmp_inc++;
+ for(x=0;x<width;x++)
+ {
+ int r,g,b;
+ uint16_t pixel = bmp[y*256+x];
+ r = pixel>>10;
+ pixel-=r<<10;
+ g = pixel>>5;
+ pixel-=g<<5;
+ b = pixel;
+ r*=255/31;
+ g*=255/31;
+ b*=255/31;
+ tmp_inc[0] = b;
+ tmp_inc[1] = g;
+ tmp_inc[2] = r;
+ tmp_inc += 3;
+ }
+ }
+
+ if(compress(compmem, &compmemsize, tmp_buffer, height * (width * 3 + 1))!=Z_OK)
+ {
+ if(tmp_buffer) free(tmp_buffer);
+ goto PNGerr;
+ }
+ if(tmp_buffer) free(tmp_buffer);
+ if(!WritePNGChunk(pp,compmemsize,"IDAT",compmem))
+ goto PNGerr;
+ }
+ if(!WritePNGChunk(pp,0,"IEND",0))
+ goto PNGerr;
+
+ free(compmem);
+ fclose(pp);
+
+ return 1;
+
+PNGerr:
+ if(compmem)
+ free(compmem);
+ if(pp)
+ fclose(pp);
+ return 0;
+}*/
+
+/*typedef struct
+{
+ uint32_t size;
+ int32_t width;
+ int32_t height;
+ uint16_t planes;
+ uint16_t bpp;
+ uint32_t cmptype;
+ uint32_t imgsize;
+ int32_t hppm;
+ int32_t vppm;
+ uint32_t numcol;
+ uint32_t numimpcol;
+} bmpimgheader_struct;
+
+#include "PACKED.h"
+typedef struct
+{
+ uint16_t id __PACKED;
+ uint32_t size __PACKED;
+ uint16_t reserved1 __PACKED;
+ uint16_t reserved2 __PACKED;
+ uint32_t imgoffset __PACKED;
+} bmpfileheader_struct;
+#include "PACKED_END.h"*/
+
+/*int NDS_WriteBMP(const char *filename)
+{
+ bmpfileheader_struct fileheader;
+ bmpimgheader_struct imageheader;
+ FILE *file;
+ int i,j;
+ uint16_t * bmp = (uint16_t *)GPU_screen;
+ size_t elems_written = 0;
+
+ memset(&fileheader, 0, sizeof(fileheader));
+ fileheader.size = sizeof(fileheader);
+ fileheader.id = 'B' | ('M' << 8);
+ fileheader.imgoffset = sizeof(fileheader)+sizeof(imageheader);
+
+ memset(&imageheader, 0, sizeof(imageheader));
+ imageheader.size = sizeof(imageheader);
+ imageheader.width = 256;
+ imageheader.height = 192*2;
+ imageheader.planes = 1;
+ imageheader.bpp = 24;
+ imageheader.cmptype = 0; // None
+ imageheader.imgsize = imageheader.width * imageheader.height * 3;
+
+ if ((file = fopen(filename,"wb")) == NULL)
+ return 0;
+
+ elems_written += fwrite(&fileheader, 1, sizeof(fileheader), file);
+ elems_written += fwrite(&imageheader, 1, sizeof(imageheader), file);
+
+ for(j=0;j<192*2;j++)
+ {
+ for(i=0;i<256;i++)
+ {
+ uint8_t r,g,b;
+ uint16_t pixel = bmp[(192*2-j-1)*256+i];
+ r = pixel>>10;
+ pixel-=r<<10;
+ g = pixel>>5;
+ pixel-=g<<5;
+ b = (uint8_t)pixel;
+ r*=255/31;
+ g*=255/31;
+ b*=255/31;
+ elems_written += fwrite(&r, 1, sizeof(uint8_t), file);
+ elems_written += fwrite(&g, 1, sizeof(uint8_t), file);
+ elems_written += fwrite(&b, 1, sizeof(uint8_t), file);
+ }
+ }
+ fclose(file);
+
+ return 1;
+}*/
+
+/*int NDS_WriteBMP_32bppBuffer(int width, int height, const void* buf, const char *filename)
+{
+ bmpfileheader_struct fileheader;
+ bmpimgheader_struct imageheader;
+ FILE *file;
+ size_t elems_written = 0;
+ memset(&fileheader, 0, sizeof(fileheader));
+ fileheader.size = sizeof(fileheader);
+ fileheader.id = 'B' | ('M' << 8);
+ fileheader.imgoffset = sizeof(fileheader)+sizeof(imageheader);
+
+ memset(&imageheader, 0, sizeof(imageheader));
+ imageheader.size = sizeof(imageheader);
+ imageheader.width = width;
+ imageheader.height = height;
+ imageheader.planes = 1;
+ imageheader.bpp = 32;
+ imageheader.cmptype = 0; // None
+ imageheader.imgsize = imageheader.width * imageheader.height * 4;
+
+ if ((file = fopen(filename,"wb")) == NULL)
+ return 0;
+
+ elems_written += fwrite(&fileheader, 1, sizeof(fileheader), file);
+ elems_written += fwrite(&imageheader, 1, sizeof(imageheader), file);
+
+ for(int i=0;i<height;i++)
+ for(int x=0;x<width;x++)
+ {
+ uint8_t* pixel = (uint8_t*)buf + (height-i-1)*width*4;
+ pixel += (x*4);
+ elems_written += fwrite(pixel+2,1,1,file);
+ elems_written += fwrite(pixel+1,1,1,file);
+ elems_written += fwrite(pixel+0,1,1,file);
+ elems_written += fwrite(pixel+3,1,1,file);
+ }
+ fclose(file);
+
+ return 1;
+}*/
+
+void NDS_Sleep() { nds.sleeping = true; }
+/*void NDS_ToggleCardEject()
+{
+ if(!nds.cardEjected)
+ {
+ //staff of kings will test this (it also uses the arm9 0xB8 poll)
+ NDS_makeIrq(ARMCPU_ARM7, IRQ_BIT_GC_IREQ_MC);
+ }
+ nds.cardEjected ^= true;
+}*/
+
+
+/*class FrameSkipper
+{
+public:
+ void RequestSkip()
+ {
+ nextSkip = true;
+ }
+ void OmitSkip(bool force, bool forceEvenIfCapturing=false)
+ {
+ nextSkip = false;
+ if((force && consecutiveNonCaptures > 30) || forceEvenIfCapturing)
+ {
+ SkipCur2DFrame = false;
+ SkipCur3DFrame = false;
+ SkipNext2DFrame = false;
+ if(forceEvenIfCapturing)
+ consecutiveNonCaptures = 0;
+ }
+ }
+ void Advance()
+ {
+ bool capturing = false*//*(MainScreen.gpu->dispCapCnt.enabled || (MainScreen.gpu->dispCapCnt.val & 0x80000000))*//*;
+
+ if(capturing && consecutiveNonCaptures > 30)
+ {
+ // the worst-looking graphics corruption problems from frameskip
+ // are the result of skipping the capture on first frame it turns on.
+ // so we do this to handle the capture immediately,
+ // despite the risk of 1 frame of 2d/3d mismatch or wrong screen display.
+ SkipNext2DFrame = false;
+ nextSkip = false;
+ }
+ else if(*//*lastOffset != MainScreen.offset && *//*lastSkip && !skipped)
+ {
+ // if we're switching from not skipping to skipping
+ // and the screens are also switching around this frame,
+ // go for 1 extra frame without skipping.
+ // this avoids the scenario where we only draw one of the two screens
+ // when a game is switching screens every frame.
+ nextSkip = false;
+ }
+
+ if(capturing)
+ consecutiveNonCaptures = 0;
+ else if(!(consecutiveNonCaptures > 9000)) // arbitrary cap to avoid eventual wrap
+ consecutiveNonCaptures++;
+ lastLastOffset = lastOffset;
+ //lastOffset = MainScreen.offset;
+ lastSkip = skipped;
+ skipped = nextSkip;
+ nextSkip = false;
+
+ SkipCur2DFrame = SkipNext2DFrame;
+ SkipCur3DFrame = skipped;
+ SkipNext2DFrame = skipped;
+ }
+ inline bool ShouldSkip2D()
+ {
+ return SkipCur2DFrame;
+ }
+ inline bool ShouldSkip3D()
+ {
+ return SkipCur3DFrame;
+ }
+ FrameSkipper()
+ {
+ nextSkip = false;
+ skipped = false;
+ lastSkip = false;
+ lastOffset = 0;
+ SkipCur2DFrame = false;
+ SkipCur3DFrame = false;
+ SkipNext2DFrame = false;
+ consecutiveNonCaptures = 0;
+ }
+private:
+ bool nextSkip;
+ bool skipped;
+ bool lastSkip;
+ int lastOffset;
+ int lastLastOffset;
+ int consecutiveNonCaptures;
+ bool SkipCur2DFrame;
+ bool SkipCur3DFrame;
+ bool SkipNext2DFrame;
+};*/
+//static FrameSkipper frameSkipper;
+
+
+/*void NDS_SkipNextFrame() {
+ //if (!driver->AVI_IsRecording()) {
+ //frameSkipper.RequestSkip();
+ //}
+}*/
+/*void NDS_OmitFrameSkip(int force) {
+ //frameSkipper.OmitSkip(force > 0, force > 1);
+}*/
+
+//#define INDEX(i) ((((i)>>16)&0xFF0)|(((i)>>4)&0xF))
+
+
+enum ESI_DISPCNT
+{
+ ESI_DISPCNT_HStart, ESI_DISPCNT_HStartIRQ, ESI_DISPCNT_HDraw, ESI_DISPCNT_HBlank
+};
+
+uint64_t nds_timer;
+uint64_t nds_arm9_timer, nds_arm7_timer;
+
+static const uint64_t kNever = 0xFFFFFFFFFFFFFFFFULL;
+
+struct TSequenceItem
+{
+ uint64_t timestamp;
+ uint32_t param;
+ bool enabled;
+
+ /*virtual void save(EMUFILE* os)
+ {
+ write64le(timestamp,os);
+ write32le(param,os);
+ writebool(enabled,os);
+ }*/
+
+ virtual bool load(EMUFILE* is)
+ {
+ if(read64le(×tamp,is) != 1) return false;
+ if(read32le(¶m,is) != 1) return false;
+ if(readbool(&enabled,is) != 1) return false;
+ return true;
+ }
+
+ inline bool isTriggered()
+ {
+ return enabled && nds_timer >= timestamp;
+ }
+
+ inline uint64_t next()
+ {
+ return timestamp;
+ }
+};
+
+/*struct TSequenceItem_GXFIFO : public TSequenceItem
+{
+ inline bool isTriggered()
+ {
+ return enabled && nds_timer >= MMU.gfx3dCycles;
+ }
+
+ inline void exec()
+ {
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[4]++);
+ while(isTriggered()) {
+ enabled = false;
+ //gfx3d_execute3D();
+ }
+ }
+
+ inline uint64_t next()
+ {
+ if(enabled) return MMU.gfx3dCycles;
+ else return kNever;
+ }
+};*/
+
+template<int procnum, int num> struct TSequenceItem_Timer : public TSequenceItem
+{
+ inline bool isTriggered()
+ {
+ return enabled && nds_timer >= nds.timerCycle[procnum][num];
+ }
+
+ inline void schedule()
+ {
+ enabled = MMU.timerON[procnum][num] && MMU.timerMODE[procnum][num] != 0xFFFF;
+ }
+
+ inline uint64_t next()
+ {
+ return nds.timerCycle[procnum][num];
+ }
+
+ inline void exec()
+ {
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[13+procnum*4+num]++);
+ uint8_t* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG;
+ bool first = true, over;
+ //we'll need to check chained timers..
+ for(int i=num;i<4;i++)
+ {
+ //maybe too many checks if this is here, but we need it here for now
+ if(!MMU.timerON[procnum][i]) return;
+
+ if(MMU.timerMODE[procnum][i] == 0xFFFF)
+ {
+ ++(MMU.timer[procnum][i]);
+ over = !MMU.timer[procnum][i];
+ }
+ else
+ {
+ if(!first) break; //this timer isn't chained. break the chain
+ first = false;
+
+ over = true;
+ int remain = 65536 - MMU.timerReload[procnum][i];
+ int ctr=0;
+ while(nds.timerCycle[procnum][i] <= nds_timer) {
+ nds.timerCycle[procnum][i] += (remain << MMU.timerMODE[procnum][i]);
+ ctr++;
+ }
+#ifndef NDEBUG
+ if(ctr>1) {
+ printf("yikes!!!!! please report!\n");
+ }
+#endif
+ }
+
+ if(over)
+ {
+ MMU.timer[procnum][i] = MMU.timerReload[procnum][i];
+ if(T1ReadWord(regs, 0x102 + i*4) & 0x40)
+ {
+ NDS_makeIrq(procnum, IRQ_BIT_TIMER_0 + i);
+ }
+ }
+ else
+ break; //no more chained timers to trigger. we're done here
+ }
+ }
+};
+
+template<int procnum, int chan> struct TSequenceItem_DMA : public TSequenceItem
+{
+ DmaController* controller;
+
+ inline bool isTriggered()
+ {
+ return controller->dmaCheck && nds_timer>= controller->nextEvent;
+ }
+
+ inline bool isEnabled() {
+ return controller->dmaCheck?true:false;
+ }
+
+ inline uint64_t next()
+ {
+ return controller->nextEvent;
+ }
+
+ inline void exec()
+ {
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[5+procnum*4+chan]++);
+
+ //if (nds.freezeBus) return;
+
+ //printf("exec from TSequenceItem_DMA: %d %d\n",procnum,chan);
+ controller->exec();
+// //give gxfifo dmas a chance to re-trigger
+// if(MMU.DMAStartTime[procnum][chan] == EDMAMode_GXFifo) {
+// MMU.DMAing[procnum][chan] = false;
+// if (gxFIFO.size <= 127)
+// {
+// execHardware_doDma(procnum,chan,EDMAMode_GXFifo);
+// if (MMU.DMACompleted[procnum][chan])
+// goto docomplete;
+// else return;
+// }
+// }
+//
+//docomplete:
+// if (MMU.DMACompleted[procnum][chan])
+// {
+// uint8_t* regs = procnum==0?MMU.ARM9_REG:MMU.ARM7_REG;
+//
+// //disable the channel
+// if(MMU.DMAStartTime[procnum][chan] != EDMAMode_GXFifo) {
+// T1WriteLong(regs, 0xB8 + (0xC*chan), T1ReadLong(regs, 0xB8 + (0xC*chan)) & 0x7FFFFFFF);
+// MMU.DMACrt[procnum][chan] &= 0x7FFFFFFF; //blehhh i hate this shit being mirrored in memory
+// }
+//
+// if((MMU.DMACrt[procnum][chan])&(1<<30)) {
+// if(procnum==0) NDS_makeARM9Int(8+chan);
+// else NDS_makeARM7Int(8+chan);
+// }
+//
+// MMU.DMAing[procnum][chan] = false;
+// }
+
+ }
+};
+
+struct TSequenceItem_divider : public TSequenceItem
+{
+ inline bool isTriggered()
+ {
+ return MMU.divRunning && nds_timer >= MMU.divCycles;
+ }
+
+ bool isEnabled() { return MMU.divRunning!=0; }
+
+ inline uint64_t next()
+ {
+ return MMU.divCycles;
+ }
+
+ void exec()
+ {
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[2]++);
+ MMU_new.div.busy = 0;
+#ifdef _WIN64
+ T1WriteQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, MMU.divResult);
+ T1WriteQuad(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, MMU.divMod);
+#else
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A0, (uint32_t)MMU.divResult);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A4, (uint32_t)(MMU.divResult >> 32));
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2A8, (uint32_t)MMU.divMod);
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2AC, (uint32_t)(MMU.divMod >> 32));
+#endif
+ MMU.divRunning = false;
+ }
+
+};
+
+struct TSequenceItem_sqrtunit : public TSequenceItem
+{
+ inline bool isTriggered()
+ {
+ return MMU.sqrtRunning && nds_timer >= MMU.sqrtCycles;
+ }
+
+ bool isEnabled() { return MMU.sqrtRunning!=0; }
+
+ inline uint64_t next()
+ {
+ return MMU.sqrtCycles;
+ }
+
+ inline void exec()
+ {
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[3]++);
+ MMU_new.sqrt.busy = 0;
+ T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x2B4, MMU.sqrtResult);
+ MMU.sqrtRunning = false;
+ }
+
+};
+
+struct Sequencer
+{
+ bool nds_vblankEnded;
+ bool reschedule;
+ TSequenceItem dispcnt;
+ TSequenceItem wifi;
+ TSequenceItem_divider divider;
+ TSequenceItem_sqrtunit sqrtunit;
+ TSequenceItem/*_GXFIFO*/ gxfifo;
+ TSequenceItem_DMA<0,0> dma_0_0; TSequenceItem_DMA<0,1> dma_0_1;
+ TSequenceItem_DMA<0,2> dma_0_2; TSequenceItem_DMA<0,3> dma_0_3;
+ TSequenceItem_DMA<1,0> dma_1_0; TSequenceItem_DMA<1,1> dma_1_1;
+ TSequenceItem_DMA<1,2> dma_1_2; TSequenceItem_DMA<1,3> dma_1_3;
+ TSequenceItem_Timer<0,0> timer_0_0; TSequenceItem_Timer<0,1> timer_0_1;
+ TSequenceItem_Timer<0,2> timer_0_2; TSequenceItem_Timer<0,3> timer_0_3;
+ TSequenceItem_Timer<1,0> timer_1_0; TSequenceItem_Timer<1,1> timer_1_1;
+ TSequenceItem_Timer<1,2> timer_1_2; TSequenceItem_Timer<1,3> timer_1_3;
+
+ void init();
+
+ void execHardware();
+ uint64_t findNext();
+
+ /*void save(EMUFILE* os)
+ {
+ write64le(nds_timer,os);
+ write64le(nds_arm9_timer,os);
+ write64le(nds_arm7_timer,os);
+ dispcnt.save(os);
+ divider.save(os);
+ sqrtunit.save(os);
+ gxfifo.save(os);
+ wifi.save(os);
+#define SAVE(I,X,Y) I##_##X##_##Y .save(os);
+ SAVE(timer,0,0); SAVE(timer,0,1); SAVE(timer,0,2); SAVE(timer,0,3);
+ SAVE(timer,1,0); SAVE(timer,1,1); SAVE(timer,1,2); SAVE(timer,1,3);
+ SAVE(dma,0,0); SAVE(dma,0,1); SAVE(dma,0,2); SAVE(dma,0,3);
+ SAVE(dma,1,0); SAVE(dma,1,1); SAVE(dma,1,2); SAVE(dma,1,3);
+#undef SAVE
+ }*/
+
+ bool load(EMUFILE* is, int version)
+ {
+ if(read64le(&nds_timer,is) != 1) return false;
+ if(read64le(&nds_arm9_timer,is) != 1) return false;
+ if(read64le(&nds_arm7_timer,is) != 1) return false;
+ if(!dispcnt.load(is)) return false;
+ if(!divider.load(is)) return false;
+ if(!sqrtunit.load(is)) return false;
+ if(!gxfifo.load(is)) return false;
+ if(version >= 1) if(!wifi.load(is)) return false;
+#define LOAD(I,X,Y) if(!I##_##X##_##Y .load(is)) return false;
+ LOAD(timer,0,0); LOAD(timer,0,1); LOAD(timer,0,2); LOAD(timer,0,3);
+ LOAD(timer,1,0); LOAD(timer,1,1); LOAD(timer,1,2); LOAD(timer,1,3);
+ LOAD(dma,0,0); LOAD(dma,0,1); LOAD(dma,0,2); LOAD(dma,0,3);
+ LOAD(dma,1,0); LOAD(dma,1,1); LOAD(dma,1,2); LOAD(dma,1,3);
+#undef LOAD
+
+ return true;
+ }
+
+} sequencer;
+
+/*void NDS_RescheduleGXFIFO(uint32_t cost)
+{
+ //if(!sequencer.gxfifo.enabled) {
+ //MMU.gfx3dCycles = nds_timer;
+ //sequencer.gxfifo.enabled = true;
+ //}
+ //MMU.gfx3dCycles += cost;
+ NDS_Reschedule();
+}*/
+
+void NDS_RescheduleTimers()
+{
+#define check(X,Y) sequencer.timer_##X##_##Y .schedule();
+ check(0,0); check(0,1); check(0,2); check(0,3);
+ check(1,0); check(1,1); check(1,2); check(1,3);
+#undef check
+
+ NDS_Reschedule();
+}
+
+void NDS_RescheduleDMA()
+{
+ //TBD
+ NDS_Reschedule();
+
+}
+
+static void initSchedule()
+{
+ sequencer.init();
+
+ //begin at the very end of the last scanline
+ //so that at t=0 we can increment to scanline=0
+ nds.VCount = 262;
+
+ sequencer.nds_vblankEnded = false;
+}
+
+
+// 2196372 ~= (ARM7_CLOCK << 16) / 1000000
+// This value makes more sense to me, because:
+// ARM7_CLOCK = 33.51 mhz
+// = 33513982 cycles per second
+// = 33.513982 cycles per microsecond
+//const uint64_t kWifiCycles = 34*2;
+//(this isn't very precise. I don't think it needs to be)
+
+void Sequencer::init()
+{
+ NDS_RescheduleTimers();
+ NDS_RescheduleDMA();
+
+ reschedule = false;
+ nds_timer = 0;
+ nds_arm9_timer = 0;
+ nds_arm7_timer = 0;
+
+ dispcnt.enabled = true;
+ dispcnt.param = ESI_DISPCNT_HStart;
+ dispcnt.timestamp = 0;
+
+ //gxfifo.enabled = false;
+
+ dma_0_0.controller = &MMU_new.dma[0][0];
+ dma_0_1.controller = &MMU_new.dma[0][1];
+ dma_0_2.controller = &MMU_new.dma[0][2];
+ dma_0_3.controller = &MMU_new.dma[0][3];
+ dma_1_0.controller = &MMU_new.dma[1][0];
+ dma_1_1.controller = &MMU_new.dma[1][1];
+ dma_1_2.controller = &MMU_new.dma[1][2];
+ dma_1_3.controller = &MMU_new.dma[1][3];
+
+
+ /*#ifdef EXPERIMENTAL_WIFI_COMM
+ wifi.enabled = true;
+ wifi.timestamp = kWifiCycles;
+ #else
+ wifi.enabled = false;
+ #endif*/
+}
+
+//this isnt helping much right now. work on it later
+//#include "utils/task.h"
+//Task taskSubGpu(true);
+//void* renderSubScreen(void*)
+//{
+// GPU_RenderLine(&SubScreen, nds.VCount, SkipCur2DFrame);
+// return NULL;
+//}
+
+static void execHardware_hblank()
+{
+ //this logic keeps moving around.
+ //now, we try and give the game as much time as possible to finish doing its work for the scanline,
+ //by drawing scanline N at the end of drawing time (but before subsequent interrupt or hdma-driven events happen)
+ //don't try to do this at the end of the scanline, because some games (sonic classics) may use hblank IRQ to set
+ //scroll regs for the next scanline
+ if(nds.VCount<192)
+ {
+ //taskSubGpu.execute(renderSubScreen,NULL);
+ //GPU_RenderLine(&MainScreen, nds.VCount, frameSkipper.ShouldSkip2D());
+ //GPU_RenderLine(&SubScreen, nds.VCount, frameSkipper.ShouldSkip2D());
+ //taskSubGpu.finish();
+
+ //trigger hblank dmas
+ //but notice, we do that just after we finished drawing the line
+ //(values copied by this hdma should not be used until the next scanline)
+ triggerDma(EDMAMode_HBlank);
+ }
+
+ if(nds.VCount==262)
+ {
+ //we need to trigger one last hblank dma since
+ //a. we're sort of lagged behind by one scanline
+ //b. i think that 193 hblanks actually fire (one for the hblank in scanline 262)
+ //this is demonstrated by NSMB splot-parallaxing clouds
+ //for some reason the game will setup two hdma scroll register buffers
+ //to be run consecutively, and unless we do this, the second buffer will be offset by one scanline
+ //causing a glitch in the 0th scanline
+ //triggerDma(EDMAMode_HBlank);
+
+ //BUT! this was removed in order to make glitches in megaman zero collection (mmz 4 1st level) work.
+ //and, it seems that it is no longer necessary in nsmb. perhaps something else fixed it
+ }
+
+
+ //turn on hblank status bit
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 2);
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 2);
+
+ //fire hblank interrupts if necessary
+ if(T1ReadWord(MMU.ARM9_REG, 4) & 0x10) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_HBLANK);
+ if(T1ReadWord(MMU.ARM7_REG, 4) & 0x10) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_HBLANK);
+
+ //emulation housekeeping. for some reason we always do this at hblank,
+ //even though it sounds more reasonable to do it at hstart
+ SPU_Emulate_core();
+ //driver->AVI_SoundUpdate(SPU_core->outbuf,spu_core_samples);
+ //WAV_WavSoundUpdate(SPU_core->outbuf,spu_core_samples);
+}
+
+static void execHardware_hstart_vblankEnd()
+{
+ sequencer.nds_vblankEnded = true;
+ sequencer.reschedule = true;
+
+ //turn off vblank status bit
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & ~1);
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & ~1);
+
+ //some emulation housekeeping
+ //frameSkipper.Advance();
+}
+
+static void execHardware_hstart_vblankStart()
+{
+ //printf("--------VBLANK!!!--------\n");
+
+ //fire vblank interrupts if necessary
+ for(int i=0;i<2;i++)
+ if(MMU.reg_IF_pending[i] & (1<<IRQ_BIT_LCD_VBLANK))
+ {
+ MMU.reg_IF_pending[i] &= ~(1<<IRQ_BIT_LCD_VBLANK);
+ NDS_makeIrq(i,IRQ_BIT_LCD_VBLANK);
+ }
+
+ //trigger vblank dmas
+ triggerDma(EDMAMode_VBlank);
+
+ //tracking for arm9 load average
+ //nds.runCycleCollector[0][nds.idleFrameCounter] = 1120380-nds.idleCycles[0];
+ //nds.runCycleCollector[1][nds.idleFrameCounter] = 1120380-nds.idleCycles[1];
+ //nds.idleFrameCounter++;
+ //nds.idleFrameCounter &= 15;
+ //nds.idleCycles[0] = 0;
+ //nds.idleCycles[1] = 0;
+}
+
+static uint16_t execHardware_gen_vmatch_goal()
+{
+ uint16_t vmatch = T1ReadWord(MMU.ARM9_REG, 4);
+ vmatch = ((vmatch>>8)|((vmatch<<1)&(1<<8)));
+ return vmatch;
+}
+
+static void execHardware_hstart_vcount_irq()
+{
+ //trigger pending VMATCH irqs
+ if(MMU.reg_IF_pending[ARMCPU_ARM9] & (1<<IRQ_BIT_LCD_VMATCH))
+ {
+ MMU.reg_IF_pending[ARMCPU_ARM9] &= ~(1<<IRQ_BIT_LCD_VMATCH);
+ NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_VMATCH);
+ }
+ if(MMU.reg_IF_pending[ARMCPU_ARM7] & (1<<IRQ_BIT_LCD_VMATCH))
+ {
+ MMU.reg_IF_pending[ARMCPU_ARM7] &= ~(1<<IRQ_BIT_LCD_VMATCH);
+ NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_VMATCH);
+ }
+}
+
+static void execHardware_hstart_vcount()
+{
+ uint16_t vmatch = execHardware_gen_vmatch_goal();
+ if(nds.VCount==vmatch)
+ {
+ //arm9 vmatch
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 4);
+ if(T1ReadWord(MMU.ARM9_REG, 4) & 32) {
+ MMU.reg_IF_pending[ARMCPU_ARM9] |= (1<<IRQ_BIT_LCD_VMATCH);
+ }
+ }
+ else
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & 0xFFFB);
+
+ vmatch = T1ReadWord(MMU.ARM7_REG, 4);
+ vmatch = ((vmatch>>8)|((vmatch<<1)&(1<<8)));
+ if(nds.VCount==vmatch)
+ {
+ //arm7 vmatch
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 4);
+ if(T1ReadWord(MMU.ARM7_REG, 4) & 32)
+ MMU.reg_IF_pending[ARMCPU_ARM7] |= (1<<IRQ_BIT_LCD_VMATCH);
+ }
+ else
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFB);
+}
+
+static void execHardware_hdraw()
+{
+ //due to hacks in our selection of rendering time, we do not actually render here as intended.
+ //consider changing this if there is some problem with raster fx timing but check the documentation near the gpu rendering calls
+ //to make sure you check for regressions (nsmb, sonic classics, et al)
+}
+
+static void execHardware_hstart_irq()
+{
+ //this function very soon after the registers get updated to trigger IRQs
+ //this is necessary to fix "egokoro kyoushitsu" which idles waiting for vcount=192, which never happens due to a long vblank irq
+ //100% accurate emulation would require the read of VCOUNT to be in the pipeline already with the irq coming in behind it, thus
+ //allowing the vcount to register as 192 occasionally (maybe about 1 out of 28 frames)
+ //the actual length of the delay is in execHardware() where the events are scheduled
+ sequencer.reschedule = true;
+ if(nds.VCount==192)
+ {
+ //when the vcount hits 192, vblank begins
+ execHardware_hstart_vblankStart();
+ }
+
+ execHardware_hstart_vcount_irq();
+}
+
+static void execHardware_hstart()
+{
+ nds.VCount++;
+
+ //end of 3d vblank
+ //this should be 214, but we are going to be generous for games with tight timing
+ //they shouldnt be changing any textures at 262 but they might accidentally still be at 214
+ //so..
+ /*if((CommonSettings.rigorous_timing && nds.VCount==214) || (!CommonSettings.rigorous_timing && nds.VCount==262))
+ {
+ gfx3d_VBlankEndSignal(frameSkipper.ShouldSkip3D());
+ }*/
+
+ if(nds.VCount==263)
+ {
+ //when the vcount hits 263 it rolls over to 0
+ nds.VCount=0;
+ }
+ if(nds.VCount==262)
+ {
+ //when the vcount hits 262, vblank ends (oam pre-renders by one scanline)
+ execHardware_hstart_vblankEnd();
+ }
+ /*else if(nds.VCount==191)
+ {
+ //when the vcount hits 191, the 3d vblank occurs (maybe because OAM doesnt need to run anymore, so we can power it down, and give the 3d as much time as possible?)
+ gfx3d_VBlankSignal();
+ }*/
+ else if(nds.VCount==192)
+ {
+ //turn on vblank status bit
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 1);
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 1);
+
+ //check whether we'll need to fire vblank irqs
+ if(T1ReadWord(MMU.ARM9_REG, 4) & 0x8) MMU.reg_IF_pending[ARMCPU_ARM9] |= (1<<IRQ_BIT_LCD_VBLANK);
+ if(T1ReadWord(MMU.ARM7_REG, 4) & 0x8) MMU.reg_IF_pending[ARMCPU_ARM7] |= (1<<IRQ_BIT_LCD_VBLANK);
+ }
+
+ //write the new vcount
+ T1WriteWord(MMU.ARM9_REG, 6, static_cast<uint16_t>(nds.VCount));
+ T1WriteWord(MMU.ARM9_REG, 0x1006, static_cast<uint16_t>(nds.VCount));
+ T1WriteWord(MMU.ARM7_REG, 6, static_cast<uint16_t>(nds.VCount));
+ T1WriteWord(MMU.ARM7_REG, 0x1006, static_cast<uint16_t>(nds.VCount));
+
+ //turn off hblank status bit
+ T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & 0xFFFD);
+ T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFD);
+
+ //handle vcount status
+ execHardware_hstart_vcount();
+
+ //trigger hstart dmas
+ triggerDma(EDMAMode_HStart);
+
+ if(nds.VCount<192)
+ {
+ //this is hacky.
+ //there is a corresponding hack in doDMA.
+ //it should be driven by a fifo (and generate just in time as the scanline is displayed)
+ //but that isnt even possible until we have some sort of sub-scanline timing.
+ //it may not be necessary.
+ triggerDma(EDMAMode_MemDisplay);
+ }
+}
+
+void NDS_Reschedule()
+{
+ IF_DEVELOPER(if(!sequencer.reschedule) DEBUG_statistics.sequencerExecutionCounters[0]++;);
+ sequencer.reschedule = true;
+}
+
+/*inline uint32_t _fast_min32(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
+{
+ return (( ((int32_t)(a-b)) >> (32-1)) & (c^d)) ^ d;
+}*/
+
+inline uint64_t _fast_min(uint64_t a, uint64_t b)
+{
+ //you might find that this is faster on a 64bit system; someone should try it
+ //http://aggregate.org/MAGIC/#Integer%20Selection
+ //uint64_t ret = (((((s64)(a-b)) >> (64-1)) & (a^b)) ^ b);
+ //assert(ret==min(a,b));
+ //return ret;
+
+ //but this ends up being the fastest on 32bits
+ return a<b?a:b;
+
+ //just for the record, I tried to do the 64bit math on a 32bit proc
+ //using sse2 and it was really slow
+ //__m128i __a; __a.m128i_u64[0] = a;
+ //__m128i __b; __b.m128i_u64[0] = b;
+ //__m128i xorval = _mm_xor_si128(__a,__b);
+ //__m128i temp = _mm_sub_epi64(__a,__b);
+ //temp.m128i_i64[0] >>= 63; //no 64bit shra in sse2, what a disappointment
+ //temp = _mm_and_si128(temp,xorval);
+ //temp = _mm_xor_si128(temp,__b);
+ //return temp.m128i_u64[0];
+}
+
+
+
+uint64_t Sequencer::findNext()
+{
+ //this one is always enabled so dont bother to check it
+ uint64_t next = dispcnt.next();
+
+ if(divider.isEnabled()) next = _fast_min(next,divider.next());
+ if(sqrtunit.isEnabled()) next = _fast_min(next,sqrtunit.next());
+ //if(gxfifo.enabled) next = _fast_min(next,gxfifo.next());
+
+#ifdef EXPERIMENTAL_WIFI_COMM
+ next = _fast_min(next,wifi.next());
+#endif
+
+#define test(X,Y) if(dma_##X##_##Y .isEnabled()) next = _fast_min(next,dma_##X##_##Y .next());
+ test(0,0); test(0,1); test(0,2); test(0,3);
+ test(1,0); test(1,1); test(1,2); test(1,3);
+#undef test
+#define test(X,Y) if(timer_##X##_##Y .enabled) next = _fast_min(next,timer_##X##_##Y .next());
+ test(0,0); test(0,1); test(0,2); test(0,3);
+ test(1,0); test(1,1); test(1,2); test(1,3);
+#undef test
+
+ return next;
+}
+
+void Sequencer::execHardware()
+{
+ if(dispcnt.isTriggered())
+ {
+
+ IF_DEVELOPER(DEBUG_statistics.sequencerExecutionCounters[1]++);
+
+ switch(dispcnt.param)
+ {
+ case ESI_DISPCNT_HStart:
+ execHardware_hstart();
+ //(used to be 3168)
+ //hstart is actually 8 dots before the visible drawing begins
+ //we're going to run 1 here and then run 7 in the next case
+ dispcnt.timestamp += 1*6*2;
+ dispcnt.param = ESI_DISPCNT_HStartIRQ;
+ break;
+ case ESI_DISPCNT_HStartIRQ:
+ execHardware_hstart_irq();
+ dispcnt.timestamp += 7*6*2;
+ dispcnt.param = ESI_DISPCNT_HDraw;
+ break;
+
+ case ESI_DISPCNT_HDraw:
+ execHardware_hdraw();
+ //duration of non-blanking period is ~1606 clocks (gbatek agrees) [but says its different on arm7]
+ //im gonna call this 267 dots = 267*6=1602
+ //so, this event lasts 267 dots minus the 8 dot preroll
+ dispcnt.timestamp += (267-8)*6*2;
+ dispcnt.param = ESI_DISPCNT_HBlank;
+ break;
+
+ case ESI_DISPCNT_HBlank:
+ execHardware_hblank();
+ //(once this was 1092 or 1092/12=91 dots.)
+ //there are surely 355 dots per scanline, less 267 for non-blanking period. the rest is hblank and then after that is hstart
+ dispcnt.timestamp += (355-267)*6*2;
+ dispcnt.param = ESI_DISPCNT_HStart;
+ break;
+ }
+ }
+
+#ifdef EXPERIMENTAL_WIFI_COMM
+ if(wifi.isTriggered())
+ {
+ WIFI_usTrigger();
+ wifi.timestamp += kWifiCycles;
+ }
+#endif
+
+ if(divider.isTriggered()) divider.exec();
+ if(sqrtunit.isTriggered()) sqrtunit.exec();
+ //if(gxfifo.isTriggered()) gxfifo.exec();
+
+
+#define test(X,Y) if(dma_##X##_##Y .isTriggered()) dma_##X##_##Y .exec();
+ test(0,0); test(0,1); test(0,2); test(0,3);
+ test(1,0); test(1,1); test(1,2); test(1,3);
+#undef test
+#define test(X,Y) if(timer_##X##_##Y .enabled) if(timer_##X##_##Y .isTriggered()) timer_##X##_##Y .exec();
+ test(0,0); test(0,1); test(0,2); test(0,3);
+ test(1,0); test(1,1); test(1,2); test(1,3);
+#undef test
+}
+
+void execHardware_interrupts();
+
+//static void saveUserInput(EMUFILE* os);
+static bool loadUserInput(EMUFILE* is, int version);
+
+/*void nds_savestate(EMUFILE* os)
+{
+ //version
+ write32le(3,os);
+
+ //sequencer.save(os);
+
+ saveUserInput(os);
+
+ write32le(LidClosed,os);
+ write8le(countLid,os);
+}*/
+
+bool nds_loadstate(EMUFILE* is, int)
+{
+ // this isn't part of the savestate loading logic, but
+ // don't skip the next frame after loading a savestate
+ //frameSkipper.OmitSkip(true, true);
+
+ //read version
+ uint32_t version;
+ if(read32le(&version,is) != 1) return false;
+
+ if(version > 3) return false;
+
+ bool temp = true;
+ temp &= sequencer.load(is, version);
+ if(version <= 1 || !temp) return temp;
+ temp &= loadUserInput(is, version);
+
+ if(version < 3) return temp;
+
+ uint32_t tmpu32;
+ read32le(&tmpu32,is);
+ uint8_t tmpu8;
+ read8le(&tmpu8,is);
+
+ return temp;
+}
+
+/*inline void arm9log()
+{
+#ifdef LOG_ARM9
+ if(dolog)
+ {
+ char dasmbuf[4096];
+ if(NDS_ARM9.CPSR.bits.T)
+ des_thumb_instructions_set[((NDS_ARM9.instruction)>>6)&1023](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf);
+ else
+ des_arm_instructions_set[INDEX(NDS_ARM9.instruction)](NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf);
+
+#ifdef LOG_TO_FILE
+ if (!fp_dis9) return;
+#ifdef LOG_TO_FILE_REGS
+ fprintf(fp_dis9, "\t\t;R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X R6:%08X R7:%08X R8:%08X R9:%08X\n\t\t;R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X| next %08X, N:%i Z:%i C:%i V:%i\n",
+ NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7],
+ NDS_ARM9.R[8], NDS_ARM9.R[9], NDS_ARM9.R[10], NDS_ARM9.R[11], NDS_ARM9.R[12], NDS_ARM9.R[13], NDS_ARM9.R[14], NDS_ARM9.R[15],
+ NDS_ARM9.next_instruction, NDS_ARM9.CPSR.bits.N, NDS_ARM9.CPSR.bits.Z, NDS_ARM9.CPSR.bits.C, NDS_ARM9.CPSR.bits.V);
+#endif
+ fprintf(fp_dis9, "%s %08X\t%08X \t%s\n", NDS_ARM9.CPSR.bits.T?"THUMB":"ARM", NDS_ARM9.instruct_adr, NDS_ARM9.instruction, dasmbuf);*/
+ /*if (NDS_ARM9.instruction == 0)
+ {
+ dolog = false;
+ INFO("Disassembler is stopped\n");
+ }*/
+/*#else
+ printf("%05d:%03d %12lld 9:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n",
+ currFrameCounter, nds.VCount, nds_timer,
+ NDS_ARM9.instruct_adr,NDS_ARM9.instruction, dasmbuf,
+ NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7],
+ NDS_ARM9.R[8], NDS_ARM9.R[9], NDS_ARM9.R[10], NDS_ARM9.R[11], NDS_ARM9.R[12], NDS_ARM9.R[13], NDS_ARM9.R[14], NDS_ARM9.R[15]);
+#endif
+ }
+#endif
+}*/
+
+/*inline void arm7log()
+{
+#ifdef LOG_ARM7
+ if(dolog)
+ {
+ char dasmbuf[4096];
+ if(NDS_ARM7.CPSR.bits.T)
+ des_thumb_instructions_set[((NDS_ARM7.instruction)>>6)&1023](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);
+ else
+ des_arm_instructions_set[INDEX(NDS_ARM7.instruction)](NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);
+#ifdef LOG_TO_FILE
+ if (!fp_dis7) return;
+#ifdef LOG_TO_FILE_REGS
+ fprintf(fp_dis7, "\t\t;R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X R6:%08X R7:%08X R8:%08X R9:%08X\n\t\t;R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X| next %08X, N:%i Z:%i C:%i V:%i\n",
+ NDS_ARM7.R[0], NDS_ARM7.R[1], NDS_ARM7.R[2], NDS_ARM7.R[3], NDS_ARM7.R[4], NDS_ARM7.R[5], NDS_ARM7.R[6], NDS_ARM7.R[7],
+ NDS_ARM7.R[8], NDS_ARM7.R[9], NDS_ARM7.R[10], NDS_ARM7.R[11], NDS_ARM7.R[12], NDS_ARM7.R[13], NDS_ARM7.R[14], NDS_ARM7.R[15],
+ NDS_ARM7.next_instruction, NDS_ARM7.CPSR.bits.N, NDS_ARM7.CPSR.bits.Z, NDS_ARM7.CPSR.bits.C, NDS_ARM7.CPSR.bits.V);
+#endif
+ fprintf(fp_dis7, "%s %08X\t%08X \t%s\n", NDS_ARM7.CPSR.bits.T?"THUMB":"ARM", NDS_ARM7.instruct_adr, NDS_ARM7.instruction, dasmbuf);*/
+ /*if (NDS_ARM7.instruction == 0)
+ {
+ dolog = false;
+ INFO("Disassembler is stopped\n");
+ }*/
+/*#else
+ printf("%05d:%03d %12lld 7:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n",
+ currFrameCounter, nds.VCount, nds_timer,
+ NDS_ARM7.instruct_adr,NDS_ARM7.instruction, dasmbuf,
+ NDS_ARM7.R[0], NDS_ARM7.R[1], NDS_ARM7.R[2], NDS_ARM7.R[3], NDS_ARM7.R[4], NDS_ARM7.R[5], NDS_ARM7.R[6], NDS_ARM7.R[7],
+ NDS_ARM7.R[8], NDS_ARM7.R[9], NDS_ARM7.R[10], NDS_ARM7.R[11], NDS_ARM7.R[12], NDS_ARM7.R[13], NDS_ARM7.R[14], NDS_ARM7.R[15]);
+#endif
+ }
+#endif
+}*/
+
+//these have not been tuned very well yet.
+static const int kMaxWork = 4000;
+static const int kIrqWait = 4000;
+
+
+template<bool doarm9, bool doarm7>
+static inline int32_t minarmtime(int32_t arm9, int32_t arm7)
+{
+ if(doarm9)
+ {
+ if(doarm7)
+ return std::min(arm9,arm7);
+ else
+ return arm9;
+ }
+ else
+ return arm7;
+}
+
+template<bool doarm9, bool doarm7>
+static /*donotinline*/ std::pair<int32_t,int32_t> armInnerLoop(
+ const uint64_t nds_timer_base, const int32_t s32next, int32_t arm9, int32_t arm7)
+{
+ int32_t timer = minarmtime<doarm9,doarm7>(arm9,arm7);
+ while(timer < s32next && !sequencer.reschedule && execute)
+ {
+ if(doarm9 && (!doarm7 || arm9 <= timer))
+ {
+ if(!NDS_ARM9.waitIRQ&&!nds.freezeBus)
+ {
+ //arm9log();
+ arm9 += armcpu_exec<ARMCPU_ARM9>();
+ #ifdef DEVELOPER
+ nds_debug_continuing[0] = false;
+ #endif
+ }
+ else
+ {
+ //int32_t temp = arm9;
+ arm9 = std::min(s32next, arm9 + kIrqWait);
+ //nds.idleCycles[0] += arm9-temp;
+ //if (gxFIFO.size < 255) nds.freezeBus = false;
+ }
+ }
+ if(doarm7 && (!doarm9 || arm7 <= timer))
+ {
+ if(!NDS_ARM7.waitIRQ&&!nds.freezeBus)
+ {
+ //arm7log();
+ arm7 += (armcpu_exec<ARMCPU_ARM7>()<<1);
+ #ifdef DEVELOPER
+ nds_debug_continuing[1] = false;
+ #endif
+ }
+ else
+ {
+ //int32_t temp = arm7;
+ arm7 = std::min(s32next, arm7 + kIrqWait);
+ //nds.idleCycles[1] += arm7-temp;
+ if(arm7 == s32next)
+ {
+ nds_timer = nds_timer_base + minarmtime<doarm9,false>(arm9,arm7);
+ return armInnerLoop<doarm9,false>(nds_timer_base, s32next, arm9, arm7);
+ }
+ }
+ }
+
+ timer = minarmtime<doarm9,doarm7>(arm9,arm7);
+ nds_timer = nds_timer_base + timer;
+ }
+
+ return std::make_pair(arm9, arm7);
+}
+
+/*void NDS_debug_break()
+{
+ NDS_ARM9.stalled = NDS_ARM7.stalled = 1;
+
+ //triggers an immediate exit from the cpu loop
+ NDS_Reschedule();
+}*/
+
+/*void NDS_debug_continue()
+{
+ NDS_ARM9.stalled = NDS_ARM7.stalled = 0;
+}*/
+
+/*void NDS_debug_step()
+{
+ NDS_debug_continue();
+ singleStep = true;
+}*/
+
+template<bool FORCE>
+void NDS_exec(int32_t)
+{
+ //LagFrameFlag=1;
+
+ /*if((currFrameCounter&63) == 0)
+ MMU_new.backupDevice.lazy_flush();*/
+
+ sequencer.nds_vblankEnded = false;
+
+ //nds.cpuloopIterationCount = 0;
+
+ IF_DEVELOPER(for(int i=0;i<32;i++) DEBUG_statistics.sequencerExecutionCounters[i] = 0);
+
+ if(nds.sleeping)
+ {
+ //speculative code: if ANY irq happens, wake up the arm7.
+ //I think the arm7 program analyzes the system and may decide not to wake up
+ //if it is dissatisfied with the conditions
+ if((MMU.reg_IE[1] & MMU.gen_IF<1>()))
+ {
+ nds.sleeping = false;
+ }
+ }
+ else
+ {
+ for(;;)
+ {
+ //trap the debug-stalled condition
+ #ifdef DEVELOPER
+ singleStep = false;
+ //(gdb stub doesnt yet know how to trigger these immediately by calling reschedule)
+ while((NDS_ARM9.stalled || NDS_ARM7.stalled) && execute)
+ {
+ driver->EMU_DebugIdleUpdate();
+ nds_debug_continuing[0] = nds_debug_continuing[1] = true;
+ }
+ #endif
+
+ //nds.cpuloopIterationCount++;
+ sequencer.execHardware();
+
+ //break out once per frame
+ if(sequencer.nds_vblankEnded) break;
+ //it should be benign to execute execHardware in the next frame,
+ //since there won't be anything for it to do (everything should be scheduled in the future)
+
+ //bail in case the system halted
+ if(!execute) break;
+
+ execHardware_interrupts();
+
+ //find next work unit:
+ uint64_t next = sequencer.findNext();
+ next = std::min(next,nds_timer+kMaxWork); //lets set an upper limit for now
+
+ //printf("%d\n",(next-nds_timer));
+
+ sequencer.reschedule = false;
+
+ //cast these down to 32bits so that things run faster on 32bit procs
+ uint64_t nds_timer_base = nds_timer;
+ int32_t arm9 = (int32_t)(nds_arm9_timer-nds_timer);
+ int32_t arm7 = (int32_t)(nds_arm7_timer-nds_timer);
+ int32_t s32next = (int32_t)(next-nds_timer);
+
+ #ifdef DEVELOPER
+ if(singleStep)
+ {
+ s32next = 1;
+ }
+ #endif
+
+ std::pair<int32_t,int32_t> arm9arm7 = armInnerLoop<true,true>(nds_timer_base,s32next,arm9,arm7);
+
+ #ifdef DEVELOPER
+ if(singleStep)
+ {
+ NDS_ARM9.stalled = NDS_ARM7.stalled = 1;
+ }
+ #endif
+
+ arm9 = arm9arm7.first;
+ arm7 = arm9arm7.second;
+ nds_arm7_timer = nds_timer_base+arm7;
+ nds_arm9_timer = nds_timer_base+arm9;
+
+#ifndef NDEBUG
+ //what we find here is dependent on the timing constants above
+ //if(nds_timer>next && (nds_timer-next)>22)
+ // printf("curious. please report: over by %d\n",(int)(nds_timer-next));
+#endif
+
+ //if we were waiting for an irq, don't wait too long:
+ //let's re-analyze it after this hardware event (this rolls back a big burst of irq waiting which may have been interrupted by a resynch)
+ if(NDS_ARM9.waitIRQ)
+ {
+ //nds.idleCycles[0] -= (int32_t)(nds_arm9_timer-nds_timer);
+ nds_arm9_timer = nds_timer;
+ }
+ if(NDS_ARM7.waitIRQ)
+ {
+ //nds.idleCycles[1] -= (int32_t)(nds_arm7_timer-nds_timer);
+ nds_arm7_timer = nds_timer;
+ }
+ }
+ }
+
+ //DEBUG_statistics.printSequencerExecutionCounters();
+ //DEBUG_statistics.print();
+
+ //end of frame emulation housekeeping
+ /*if(LagFrameFlag)
+ {
+ lagframecounter++;
+ TotalLagFrames++;
+ }
+ else
+ {
+ lastLag = lagframecounter;
+ lagframecounter = 0;
+ }*/
+ //currFrameCounter++;
+ //DEBUG_Notify.NextFrame();
+ /*if (cheats)
+ cheats->process();*/
+}
+
+template<int PROCNUM> static void execHardware_interrupts_core()
+{
+ uint32_t IF = MMU.gen_IF<PROCNUM>();
+ uint32_t IE = MMU.reg_IE[PROCNUM];
+ uint32_t masked = IF & IE;
+ if(ARMPROC.halt_IE_and_IF && masked)
+ {
+ ARMPROC.halt_IE_and_IF = false;
+ ARMPROC.waitIRQ = false;
+ }
+
+ if(masked && MMU.reg_IME[PROCNUM] && !ARMPROC.CPSR.bits.I)
+ {
+ //printf("Executing IRQ on procnum %d with IF = %08X and IE = %08X\n",PROCNUM,IF,IE);
+ armcpu_irqException(&ARMPROC);
+ }
+}
+
+void execHardware_interrupts()
+{
+ execHardware_interrupts_core<ARMCPU_ARM9>();
+ execHardware_interrupts_core<ARMCPU_ARM7>();
+}
+
+//static void resetUserInput();
+
+//bool _HACK_DONT_STOPMOVIE = false;
+void NDS_Reset()
+{
+ singleStep = false;
+ //nds_debug_continuing[0] = nds_debug_continuing[1] = false;
+ uint32_t src = 0;
+ uint32_t dst = 0;
+ bool fw_success = false;
+ FILE* inf = NULL;
+ NDS_header * header = NDS_getROMHeader();
+
+ //DEBUG_reset();
+
+ if (!header) return ;
+
+ nds.sleeping = false;
+ nds.cardEjected = false;
+ nds.freezeBus = 0;
+ //nds.power1.lcd = nds.power1.gpuMain = nds.power1.gfx3d_render = nds.power1.gfx3d_geometry = nds.power1.gpuSub = nds.power1.dispswap = 1;
+ //nds.power2.speakers = 1;
+ //nds.power2.wifi = 0;
+
+ nds_timer = 0;
+ nds_arm9_timer = 0;
+ nds_arm7_timer = 0;
+
+ /*if(movieMode != MOVIEMODE_INACTIVE && !_HACK_DONT_STOPMOVIE)
+ movie_reset_command = true;*/
+
+ /*if(movieMode == MOVIEMODE_INACTIVE) {
+ //currFrameCounter = 0;
+ lagframecounter = 0;
+ LagFrameFlag = 0;
+ lastLag = 0;
+ TotalLagFrames = 0;
+ }*/
+
+ SPU_DeInit();
+
+ MMU_Reset();
+
+ //put random garbage in vram for homebrew games, to help mimic the situation where libnds does not clear out junk
+ //which the card's launcher may or may not have left behind
+ //1. retail games dont clear TCM, so why should we jumble it and expect homebrew to clear it?
+ //2. some retail games _dont boot_ if main memory is jumbled. wha...?
+ //3. clearing this is not as useful as tracking uninitialized reads in dev+ builds
+ //4. the vram clearing causes lots of graphical corruptions in badly coded homebrews. this reduces compatibility substantially
+ //conclusion: disable it for now and bring it back as an option
+ //if(gameInfo.isHomebrew)
+ //{
+ // uint32_t w=100000,x=99,y=117,z=19382173;
+ // CTASSERT(sizeof(MMU.ARM9_LCD) < sizeof(MMU.MAIN_MEM));
+ // CTASSERT(sizeof(MMU.ARM9_VMEM) < sizeof(MMU.MAIN_MEM));
+ // CTASSERT(sizeof(MMU.ARM9_ITCM) < sizeof(MMU.MAIN_MEM));
+ // CTASSERT(sizeof(MMU.ARM9_DTCM) < sizeof(MMU.MAIN_MEM));
+ // for(int i=0;i<sizeof(MMU.MAIN_MEM);i++)
+ // {
+ // uint32_t t= (x^(x<<11));
+ // x=y;
+ // y=z;
+ // z=w;
+ // t = (w= (w^(w>>19))^(t^(t>>8)));
+ // //MMU.MAIN_MEM[i] = t;
+ // if (i<sizeof(MMU.ARM9_LCD)) MMU.ARM9_LCD[i] = t;
+ // if (i<sizeof(MMU.ARM9_VMEM)) MMU.ARM9_VMEM[i] = t;
+ // //if (i<sizeof(MMU.ARM9_ITCM)) MMU.ARM9_ITCM[i] = t;
+ // //if (i<sizeof(MMU.ARM9_DTCM)) MMU.ARM9_DTCM[i] = t;
+ // }
+ //}
+
+ NDS_ARM7.BIOS_loaded = false;
+ NDS_ARM9.BIOS_loaded = false;
+ memset(MMU.ARM7_BIOS, 0, sizeof(MMU.ARM7_BIOS));
+ memset(MMU.ARM9_BIOS, 0, sizeof(MMU.ARM9_BIOS));
+
+ //ARM7 BIOS IRQ HANDLER
+ if(CommonSettings.UseExtBIOS == true)
+ inf = fopen(CommonSettings.ARM7BIOS,"rb");
+ else
+ inf = NULL;
+
+ if(inf)
+ {
+ if (fread(MMU.ARM7_BIOS,1,16384,inf) == 16384) NDS_ARM7.BIOS_loaded = true;
+ fclose(inf);
+
+ if((CommonSettings.SWIFromBIOS) && (NDS_ARM7.BIOS_loaded)) NDS_ARM7.swi_tab = 0;
+ else NDS_ARM7.swi_tab = ARM7_swi_tab;
+
+ if (CommonSettings.PatchSWI3)
+ _MMU_write16<ARMCPU_ARM7>(0x00002F08, 0x4770);
+
+ //INFO("ARM7 BIOS is %s.\n", NDS_ARM7.BIOS_loaded?"loaded":"failed");
+ }
+ else
+ {
+ NDS_ARM7.swi_tab = ARM7_swi_tab;
+
+#if 0
+ // TODO
+ T1WriteLong(MMU.ARM7_BIOS, 0x0000, 0xEAFFFFFE); // loop for Reset !!!
+ T1WriteLong(MMU.ARM7_BIOS, 0x0004, 0xEAFFFFFE); // loop for Undef instr expection
+ T1WriteLong(MMU.ARM7_BIOS, 0x0008, 0xEA00009C); // SWI
+ T1WriteLong(MMU.ARM7_BIOS, 0x000C, 0xEAFFFFFE); // loop for Prefetch Abort
+ T1WriteLong(MMU.ARM7_BIOS, 0x0010, 0xEAFFFFFE); // loop for Data Abort
+ T1WriteLong(MMU.ARM7_BIOS, 0x0014, 0x00000000); // Reserved
+ T1WriteLong(MMU.ARM7_BIOS, 0x001C, 0x00000000); // Fast IRQ
+#endif
+ T1WriteLong(MMU.ARM7_BIOS, 0x0000, 0xE25EF002);
+ T1WriteLong(MMU.ARM7_BIOS, 0x0018, 0xEA000000);
+ T1WriteLong(MMU.ARM7_BIOS, 0x0020, 0xE92D500F);
+ T1WriteLong(MMU.ARM7_BIOS, 0x0024, 0xE3A00301);
+ T1WriteLong(MMU.ARM7_BIOS, 0x0028, 0xE28FE000);
+ T1WriteLong(MMU.ARM7_BIOS, 0x002C, 0xE510F004);
+ T1WriteLong(MMU.ARM7_BIOS, 0x0030, 0xE8BD500F);
+ T1WriteLong(MMU.ARM7_BIOS, 0x0034, 0xE25EF004);
+ }
+
+ //ARM9 BIOS IRQ HANDLER
+ if(CommonSettings.UseExtBIOS == true)
+ inf = fopen(CommonSettings.ARM9BIOS,"rb");
+ else
+ inf = NULL;
+
+ if(inf)
+ {
+ if (fread(MMU.ARM9_BIOS,1,4096,inf) == 4096) NDS_ARM9.BIOS_loaded = true;
+ fclose(inf);
+
+ if((CommonSettings.SWIFromBIOS) && (NDS_ARM9.BIOS_loaded)) NDS_ARM9.swi_tab = 0;
+ else NDS_ARM9.swi_tab = ARM9_swi_tab;
+
+ if (CommonSettings.PatchSWI3)
+ _MMU_write16<ARMCPU_ARM9>(0xFFFF07CC, 0x4770);
+
+ //INFO("ARM9 BIOS is %s.\n", NDS_ARM9.BIOS_loaded?"loaded":"failed");
+ }
+ else
+ {
+ NDS_ARM9.swi_tab = ARM9_swi_tab;
+
+ //bios chains data abort to fast irq
+
+ //exception vectors:
+ T1WriteLong(MMU.ARM9_BIOS, 0x0000, 0xEAFFFFFE); // (infinite loop for) Reset !!!
+ //T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEAFFFFFE); // (infinite loop for) Undefined instruction
+ T1WriteLong(MMU.ARM9_BIOS, 0x0004, 0xEA000004); // Undefined instruction -> Fast IRQ (just guessing)
+ T1WriteLong(MMU.ARM9_BIOS, 0x0008, 0xEA00009C); // SWI -> ?????
+ T1WriteLong(MMU.ARM9_BIOS, 0x000C, 0xEAFFFFFE); // (infinite loop for) Prefetch Abort
+ T1WriteLong(MMU.ARM9_BIOS, 0x0010, 0xEA000001); // Data Abort -> Fast IRQ
+ T1WriteLong(MMU.ARM9_BIOS, 0x0014, 0x00000000); // Reserved
+ T1WriteLong(MMU.ARM9_BIOS, 0x0018, 0xEA000095); // Normal IRQ -> 0x0274
+ T1WriteLong(MMU.ARM9_BIOS, 0x001C, 0xEA00009D); // Fast IRQ -> 0x0298
+
+ // logo (do some games fail to boot without this? example?)
+ for (int t = 0; t < 0x9C; t++)
+ MMU.ARM9_BIOS[t + 0x20] = logo_data[t];
+
+ //...0xBC:
+
+ //(now what goes in this gap??)
+
+ //IRQ handler: get dtcm address and jump to a vector in it
+ T1WriteLong(MMU.ARM9_BIOS, 0x0274, 0xE92D500F); //STMDB SP!, {R0-R3,R12,LR}
+ T1WriteLong(MMU.ARM9_BIOS, 0x0278, 0xEE190F11); //MRC CP15, 0, R0, CR9, CR1, 0
+ T1WriteLong(MMU.ARM9_BIOS, 0x027C, 0xE1A00620); //MOV R0, R0, LSR #C
+ T1WriteLong(MMU.ARM9_BIOS, 0x0280, 0xE1A00600); //MOV R0, R0, LSL #C
+ T1WriteLong(MMU.ARM9_BIOS, 0x0284, 0xE2800C40); //ADD R0, R0, #4000
+ T1WriteLong(MMU.ARM9_BIOS, 0x0288, 0xE28FE000); //ADD LR, PC, #0
+ T1WriteLong(MMU.ARM9_BIOS, 0x028C, 0xE510F004); //LDR PC, [R0, -#4]
+
+ //????
+ T1WriteLong(MMU.ARM9_BIOS, 0x0290, 0xE8BD500F); //LDMIA SP!, {R0-R3,R12,LR}
+ T1WriteLong(MMU.ARM9_BIOS, 0x0294, 0xE25EF004); //SUBS PC, LR, #4
+
+ //-------
+ //FIQ and abort exception handler
+ //TODO - this code is copied from the bios. refactor it
+ //friendly reminder: to calculate an immediate offset: encoded = (desired_address-cur_address-8)
+
+ T1WriteLong(MMU.ARM9_BIOS, 0x0298, 0xE10FD000); //MRS SP, CPSR
+ T1WriteLong(MMU.ARM9_BIOS, 0x029C, 0xE38DD0C0); //ORR SP, SP, #C0
+
+ T1WriteLong(MMU.ARM9_BIOS, 0x02A0, 0xE12FF00D); //MSR CPSR_fsxc, SP
+ T1WriteLong(MMU.ARM9_BIOS, 0x02A4, 0xE59FD000 | (0x2D4-0x2A4-8)); //LDR SP, [FFFF02D4]
+ T1WriteLong(MMU.ARM9_BIOS, 0x02A8, 0xE28DD001); //ADD SP, SP, #1
+ T1WriteLong(MMU.ARM9_BIOS, 0x02AC, 0xE92D5000); //STMDB SP!, {R12,LR}
+
+ T1WriteLong(MMU.ARM9_BIOS, 0x02B0, 0xE14FE000); //MRS LR, SPSR
+ T1WriteLong(MMU.ARM9_BIOS, 0x02B4, 0xEE11CF10); //MRC CP15, 0, R12, CR1, CR0, 0
+ T1WriteLong(MMU.ARM9_BIOS, 0x02B8, 0xE92D5000); //STMDB SP!, {R12,LR}
+ T1WriteLong(MMU.ARM9_BIOS, 0x02BC, 0xE3CCC001); //BIC R12, R12, #1
+
+ T1WriteLong(MMU.ARM9_BIOS, 0x02C0, 0xEE01CF10); //MCR CP15, 0, R12, CR1, CR0, 0
+ T1WriteLong(MMU.ARM9_BIOS, 0x02C4, 0xE3CDC001); //BIC R12, SP, #1
+ T1WriteLong(MMU.ARM9_BIOS, 0x02C8, 0xE59CC010); //LDR R12, [R12, #10]
+ T1WriteLong(MMU.ARM9_BIOS, 0x02CC, 0xE35C0000); //CMP R12, #0
+
+ T1WriteLong(MMU.ARM9_BIOS, 0x02D0, 0x112FFF3C); //BLXNE R12
+ T1WriteLong(MMU.ARM9_BIOS, 0x02D4, 0x027FFD9C); //0x027FFD9C
+ //---------
+
+ }
+
+#ifdef LOG_ARM7
+ if (fp_dis7 != NULL)
+ {
+ fclose(fp_dis7);
+ fp_dis7 = NULL;
+ }
+ fp_dis7 = fopen("D:\\desmume_dis7.asm", "w");
+#endif
+
+#ifdef LOG_ARM9
+ if (fp_dis9 != NULL)
+ {
+ fclose(fp_dis9);
+ fp_dis9 = NULL;
+ }
+ fp_dis9 = fopen("D:\\desmume_dis9.asm", "w");
+#endif
+
+ if (firmware)
+ {
+ delete firmware;
+ firmware = NULL;
+ }
+ firmware = new CFIRMWARE();
+ fw_success = firmware->load();
+ if (NDS_ARM7.BIOS_loaded && NDS_ARM9.BIOS_loaded && CommonSettings.BootFromFirmware && fw_success)
+ {
+ // Copy secure area to memory if needed
+ if ((header->ARM9src >= 0x4000) && (header->ARM9src < 0x8000))
+ {
+ src = header->ARM9src;
+ dst = header->ARM9cpy;
+
+ uint32_t size = (0x8000 - src) >> 2;
+ //INFO("Copy secure area from 0x%08X to 0x%08X (size %i/0x%08X)\n", src, dst, size, size);
+ for (uint32_t i = 0; i < size; i++)
+ {
+ _MMU_write32<ARMCPU_ARM9>(dst, T1ReadLong(MMU.CART_ROM, src));
+ src += 4; dst += 4;
+ }
+ }
+
+ if (firmware->patched)
+ {
+ armcpu_init(&NDS_ARM7, 0x00000008);
+ armcpu_init(&NDS_ARM9, 0xFFFF0008);
+ }
+ else
+ {
+ //INFO("Booting at ARM9: 0x%08X, ARM7: 0x%08X\n", firmware->ARM9bootAddr, firmware->ARM7bootAddr);
+ // need for firmware
+ //armcpu_init(&NDS_ARM7, 0x00000008);
+ //armcpu_init(&NDS_ARM9, 0xFFFF0008);
+ armcpu_init(&NDS_ARM7, firmware->ARM7bootAddr);
+ armcpu_init(&NDS_ARM9, firmware->ARM9bootAddr);
+ }
+
+ _MMU_write08<ARMCPU_ARM9>(0x04000300, 0);
+ _MMU_write08<ARMCPU_ARM7>(0x04000300, 0);
+ }
+ else
+ {
+ src = header->ARM9src;
+ dst = header->ARM9cpy;
+
+ for(uint32_t i = 0; i < (header->ARM9binSize>>2); ++i)
+ {
+ _MMU_write32<ARMCPU_ARM9>(dst, T1ReadLong(MMU.CART_ROM, src));
+ dst += 4;
+ src += 4;
+ }
+
+ src = header->ARM7src;
+ dst = header->ARM7cpy;
+
+ for(uint32_t i = 0; i < (header->ARM7binSize>>2); ++i)
+ {
+ _MMU_write32<ARMCPU_ARM7>(dst, T1ReadLong(MMU.CART_ROM, src));
+ dst += 4;
+ src += 4;
+ }
+
+ armcpu_init(&NDS_ARM7, header->ARM7exe);
+ armcpu_init(&NDS_ARM9, header->ARM9exe);
+
+ _MMU_write08<ARMCPU_ARM9>(REG_POSTFLG, 1);
+ _MMU_write08<ARMCPU_ARM7>(REG_POSTFLG, 1);
+ }
+ //bitbox 4k demo is so stripped down it relies on default stack values
+ //otherwise the arm7 will crash before making a sound
+ //(these according to gbatek softreset bios docs)
+ NDS_ARM7.R13_svc = 0x0380FFDC;
+ NDS_ARM7.R13_irq = 0x0380FFB0;
+ NDS_ARM7.R13_usr = 0x0380FF00;
+ NDS_ARM7.R[13] = NDS_ARM7.R13_usr;
+ //and let's set these for the arm9 while we're at it, though we have no proof
+ NDS_ARM9.R13_svc = 0x00803FC0;
+ NDS_ARM9.R13_irq = 0x00803FA0;
+ NDS_ARM9.R13_usr = 0x00803EC0;
+ NDS_ARM9.R13_abt = NDS_ARM9.R13_usr; //?????
+ //I think it is wrong to take gbatek's "SYS" and put it in USR--maybe USR doesnt matter.
+ //i think SYS is all the misc modes. please verify by setting nonsensical stack values for USR here
+ NDS_ARM9.R[13] = NDS_ARM9.R13_usr;
+ //n.b.: im not sure about all these, I dont know enough about arm9 svc/irq/etc modes
+ //and how theyre named in desmume to match them up correctly. i just guessed.
+
+ //nds.wifiCycle = 0;
+ memset(nds.timerCycle, 0, sizeof(uint64_t) * 2 * 4);
+ nds.old = 0;
+ //nds.touchX = nds.touchY = 0;
+ //nds.isTouch = 0;
+ //nds.debugConsole = CommonSettings.DebugConsole;
+ //nds.ensataEmulation = CommonSettings.EnsataEmulation;
+ //nds.ensataHandshake = ENSATA_HANDSHAKE_none;
+ //nds.ensataIpcSyncCounter = 0;
+ SetupMMU(/*nds.Is_DebugConsole()*/false,nds.Is_DSI());
+
+ _MMU_write16<ARMCPU_ARM9>(REG_KEYINPUT, 0x3FF);
+ _MMU_write16<ARMCPU_ARM7>(REG_KEYINPUT, 0x3FF);
+ _MMU_write08<ARMCPU_ARM7>(REG_EXTKEYIN, 0x43);
+
+ //LidClosed = false;
+ //countLid = 0;
+
+ //resetUserInput();
+
+ //Setup a copy of the firmware user settings in memory.
+ //(this is what the DS firmware would do).
+ {
+ uint8_t temp_buffer[NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT];
+ int fw_index;
+
+ if ( copy_firmware_user_data( temp_buffer, &MMU.fw.data[0])) {
+ for ( fw_index = 0; fw_index < NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT; fw_index++)
+ _MMU_write08<ARMCPU_ARM9>(0x027FFC80 + fw_index, temp_buffer[fw_index]);
+ }
+ }
+
+ // Copy the whole header to Main RAM 0x27FFE00 on startup. (http://nocash.emubase.de/gbatek.htm#dscartridgeheader)
+ //once upon a time this copied 0x90 more. this was thought to be wrong, and changed.
+ if(nds.Is_DSI())
+ {
+ //dsi needs this copied later in memory. there are probably a number of things that get copied to a later location in memory.. thats where the NDS consoles tend to stash stuff.
+ for (int i = 0; i < ((0x170)/4); i++)
+ _MMU_write32<ARMCPU_ARM9>(0x02FFFE00+i*4, LE_TO_LOCAL_32(((uint32_t*)MMU.CART_ROM)[i]));
+ }
+ else
+ {
+ for (int i = 0; i < ((0x170)/4); i++)
+ _MMU_write32<ARMCPU_ARM9>(0x027FFE00+i*4, LE_TO_LOCAL_32(((uint32_t*)MMU.CART_ROM)[i]));
+ }
+
+ // Write the header checksum to memory (the firmware needs it to see the cart)
+ _MMU_write16<ARMCPU_ARM9>(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E));
+
+ //--------------------------------
+ //setup the homebrew argv
+ //this is useful for nitrofs apps which are emulating themselves via cflash
+ //struct __argv {
+ // int argvMagic; //!< argv magic number, set to 0x5f617267 ('_arg') if valid
+ // char *commandLine; //!< base address of command line, set of null terminated strings
+ // int length; //!< total length of command line
+ // int argc; //!< internal use, number of arguments
+ // char **argv; //!< internal use, argv pointer
+ //};
+ std::string rompath = "fat:/" + path.RomName;
+ const uint32_t kCommandline = 0x027E0000;
+ //const uint32_t kCommandline = 0x027FFF84;
+
+ //
+ _MMU_write32<ARMCPU_ARM9>(0x02FFFE70, 0x5f617267);
+ _MMU_write32<ARMCPU_ARM9>(0x02FFFE74, kCommandline); //(commandline starts here)
+ _MMU_write32<ARMCPU_ARM9>(0x02FFFE78, rompath.size()+1);
+ //0x027FFF7C (argc)
+ //0x027FFF80 (argv)
+ for(size_t i=0;i<rompath.size();i++)
+ _MMU_write08<ARMCPU_ARM9>(kCommandline+i, rompath[i]);
+ _MMU_write08<ARMCPU_ARM9>(kCommandline+rompath.size(), 0);
+ //--------------------------------
+
+ if ((firmware->patched) && (CommonSettings.UseExtBIOS == true) && (CommonSettings.BootFromFirmware == true) && (fw_success == true))
+ {
+ // HACK! for flashme
+ _MMU_write32<ARMCPU_ARM9>(0x27FFE24, firmware->ARM9bootAddr);
+ _MMU_write32<ARMCPU_ARM7>(0x27FFE34, firmware->ARM7bootAddr);
+ }
+
+ // make system think it's booted from card -- EXTREMELY IMPORTANT!!! Thanks to cReDiAr
+ _MMU_write08<ARMCPU_ARM9>(0x02FFFC40,0x1);
+ _MMU_write08<ARMCPU_ARM7>(0x02FFFC40,0x1);
+
+ // Save touchscreen calibration info in a structure
+ // so we can easily access it at any time
+ //TSCal.adc.x1 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x58);
+ //TSCal.adc.y1 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x5A);
+ //TSCal.scr.x1 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x5C);
+ //TSCal.scr.y1 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x5D);
+ //TSCal.adc.x2 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x5E);
+ //TSCal.adc.y2 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x60);
+ //TSCal.scr.x2 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x62);
+ //TSCal.scr.y2 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x63);
+
+ //TSCal.adc.width = (TSCal.adc.x2 - TSCal.adc.x1);
+ //TSCal.adc.height = (TSCal.adc.y2 - TSCal.adc.y1);
+ //TSCal.scr.width = (TSCal.scr.x2 - TSCal.scr.x1);
+ //TSCal.scr.height = (TSCal.scr.y2 - TSCal.scr.y1);
+
+ //MainScreen.offset = 0;
+ //SubScreen.offset = 192;
+
+ //_MMU_write32[ARMCPU_ARM9](0x02007FFC, 0xE92D4030);
+
+ delete header;
+
+ //Screen_Reset();
+ //gfx3d_reset();
+ //gpu3D->NDS_3D_Reset();
+ //slot1Reset();
+
+ //WIFI_Reset();
+
+ //memcpy(FW_Mac, (MMU.fw.data + 0x36), 6);
+
+ initSchedule();
+
+ SPU_ReInit();
+}
+
+/*static std::string MakeInputDisplayString(uint16_t pad, const std::string* Buttons, int count) {
+ std::string s;
+ for (int x = 0; x < count; x++) {
+ if (pad & (1 << x))
+ s.append(Buttons[x].size(), ' ');
+ else
+ s += Buttons[x];
+ }
+ return s;
+}*/
+
+/*static std::string MakeInputDisplayString(uint16_t pad, uint16_t padExt) {
+ const std::string Buttons[] = {"A", "B", "Sl", "St", "R", "L", "U", "D", "Rs", "Ls"};
+ const std::string Ext[] = {"X", "Y"};
+
+ std::string s = MakeInputDisplayString(pad, Ext, ARRAY_SIZE(Ext));
+ s += MakeInputDisplayString(padExt, Buttons, ARRAY_SIZE(Buttons));
+
+ return s;
+}*/
+
+
+//buttonstruct<bool> Turbo;
+buttonstruct<int> TurboTime;
+//buttonstruct<bool> AutoHold;
+
+/*void ClearAutoHold() {
+
+ for (uint32_t i=0; i < ARRAY_SIZE(AutoHold.array); i++) {
+ AutoHold.array[i]=false;
+ }
+}*/
+
+
+/*inline uint16_t NDS_getADCTouchPosX(uint16_t scrX)
+{
+ // this is a little iffy,
+ // we're basically adjusting the ADC results to
+ // compensate for how they will be interpreted.
+ // the actual system doesn't do this transformation.
+ int rv = (scrX - TSCal.scr.x1 + 1) * TSCal.adc.width / TSCal.scr.width + TSCal.adc.x1;
+ rv = min(0xFFF, max(0, rv));
+ return (uint16_t)rv;
+}*/
+/*inline uint16_t NDS_getADCTouchPosY(uint16_t scrY)
+{
+ int rv = (scrY - TSCal.scr.y1 + 1) * TSCal.adc.height / TSCal.scr.height + TSCal.adc.y1;
+ rv = min(0xFFF, max(0, rv));
+ return (uint16_t)rv;
+}*/
+
+//static UserInput rawUserInput = {}; // requested input, generally what the user is physically pressing
+static UserInput intermediateUserInput; // intermediate buffer for modifications (seperated from finalUserInput for safety reasons)
+static UserInput finalUserInput; // what gets sent to the game and possibly recorded
+bool validToProcessInput = false;
+
+/*const UserInput& NDS_getRawUserInput()
+{
+ return rawUserInput;
+}*/
+/*UserInput& NDS_getProcessingUserInput()
+{
+ assert(validToProcessInput);
+ return intermediateUserInput;
+}*/
+/*bool NDS_isProcessingUserInput()
+{
+ return validToProcessInput;
+}*/
+/*const UserInput& NDS_getFinalUserInput()
+{
+ return finalUserInput;
+}*/
+
+
+/*static void saveUserInput(EMUFILE* os, UserInput& input)
+{
+ os->fwrite((const char*)input.buttons.array, 14);
+ writebool(input.touch.isTouch, os);
+ write16le(input.touch.touchX, os);
+ write16le(input.touch.touchY, os);
+ write32le(input.mic.micButtonPressed, os);
+}*/
+static bool loadUserInput(EMUFILE* is, UserInput& input, int)
+{
+ is->fread((char*)input.buttons.array, 14);
+ readbool(&input.touch.isTouch, is);
+ read16le(&input.touch.touchX, is);
+ read16le(&input.touch.touchY, is);
+ read32le(&input.mic.micButtonPressed, is);
+ return true;
+}
+/*static void resetUserInput(UserInput& input)
+{
+ memset(&input, 0, sizeof(UserInput));
+}*/
+// (userinput is kind of a misnomer, e.g. finalUserInput has to mirror nds.pad, nds.touchX, etc.)
+/*static void saveUserInput(EMUFILE* os)
+{
+ saveUserInput(os, finalUserInput);
+ saveUserInput(os, intermediateUserInput); // saved in case a savestate is made during input processing (which Lua could do if nothing else)
+ writebool(validToProcessInput, os);
+ for(int i = 0; i < 14; i++)
+ write32le(TurboTime.array[i], os); // saved to make autofire more tolerable to use with re-recording
+}*/
+static bool loadUserInput(EMUFILE* is, int version)
+{
+ bool rv = true;
+ rv &= loadUserInput(is, finalUserInput, version);
+ rv &= loadUserInput(is, intermediateUserInput, version);
+ readbool(&validToProcessInput, is);
+ for(int i = 0; i < 14; i++)
+ read32le((uint32_t*)&TurboTime.array[i], is);
+ return rv;
+}
+/*static void resetUserInput()
+{
+ resetUserInput(finalUserInput);
+ resetUserInput(intermediateUserInput);
+}*/
+
+/*static inline void gotInputRequest()
+{
+ // nobody should set the raw input while we're processing the input.
+ // it might not screw anything up but it would be completely useless.
+ assert(!validToProcessInput);
+}*/
+
+/*void NDS_setPad(bool R,bool L,bool D,bool U,bool T,bool S,bool B,bool A,bool Y,bool X,bool W,bool E,bool G, bool F)
+{
+ gotInputRequest();
+ UserButtons& rawButtons = rawUserInput.buttons;
+ rawButtons.R = R;
+ rawButtons.L = L;
+ rawButtons.D = D;
+ rawButtons.U = U;
+ rawButtons.T = T;
+ rawButtons.S = S;
+ rawButtons.B = B;
+ rawButtons.A = A;
+ rawButtons.Y = Y;
+ rawButtons.X = X;
+ rawButtons.W = W;
+ rawButtons.E = E;
+ rawButtons.G = G;
+ rawButtons.F = F;
+}*/
+/*void NDS_setTouchPos(uint16_t x, uint16_t y)
+{
+ gotInputRequest();
+ rawUserInput.touch.touchX = NDS_getADCTouchPosX(x);
+ rawUserInput.touch.touchY = NDS_getADCTouchPosY(y);
+ rawUserInput.touch.isTouch = true;*/
+
+ /*if(movieMode != MOVIEMODE_INACTIVE && movieMode != MOVIEMODE_FINISHED)
+ {
+ // just in case, since the movie only stores 8 bits per touch coord
+ rawUserInput.touch.touchX &= 0x0FF0;
+ rawUserInput.touch.touchY &= 0x0FF0;
+ }*/
+/*
+#ifndef WIN32
+ // FIXME: this code should be deleted from here,
+ // other platforms should call NDS_beginProcessingInput,NDS_endProcessingInput once per frame instead
+ // (see the function called "StepRunLoop_Core" in src/windows/main.cpp),
+ // but I'm leaving this here for now since I can't test those other platforms myself.
+ nds.touchX = rawUserInput.touch.touchX;
+ nds.touchY = rawUserInput.touch.touchY;
+ nds.isTouch = 1;
+ MMU.ARM7_REG[0x136] &= 0xBF;
+#endif
+}*/
+/*void NDS_releaseTouch()
+{
+ gotInputRequest();
+ rawUserInput.touch.touchX = 0;
+ rawUserInput.touch.touchY = 0;
+ rawUserInput.touch.isTouch = false;
+
+#ifndef WIN32
+ // FIXME: this code should be deleted from here,
+ // other platforms should call NDS_beginProcessingInput,NDS_endProcessingInput once per frame instead
+ // (see the function called "StepRunLoop_Core" in src/windows/main.cpp),
+ // but I'm leaving this here for now since I can't test those other platforms myself.
+ nds.touchX = 0;
+ nds.touchY = 0;
+ nds.isTouch = 0;
+ MMU.ARM7_REG[0x136] |= 0x40;
+#endif
+}*/
+/*void NDS_setMic(bool pressed)
+{
+ gotInputRequest();
+ rawUserInput.mic.micButtonPressed = (pressed ? true : false);
+}*/
+
+
+//static void NDS_applyFinalInput();
+
+
+/*void NDS_beginProcessingInput()
+{
+ // start off from the raw input
+ intermediateUserInput = rawUserInput;
+
+ // processing is valid now
+ validToProcessInput = true;
+}*/
+
+/*void NDS_endProcessingInput()
+{
+ // transfer the processed input
+ finalUserInput = intermediateUserInput;
+
+ // processing is invalid now
+ validToProcessInput = false;
+
+ // use the final input for a few things right away
+ NDS_applyFinalInput();
+}*/
+
+
+
+
+
+
+
+
+/*static void NDS_applyFinalInput()
+{
+ const UserInput& input = NDS_getFinalUserInput();
+
+ uint16_t pad = (0 |
+ ((input.buttons.A ? 0 : 0x80) >> 7) |
+ ((input.buttons.B ? 0 : 0x80) >> 6) |
+ ((input.buttons.T ? 0 : 0x80) >> 5) |
+ ((input.buttons.S ? 0 : 0x80) >> 4) |
+ ((input.buttons.R ? 0 : 0x80) >> 3) |
+ ((input.buttons.L ? 0 : 0x80) >> 2) |
+ ((input.buttons.U ? 0 : 0x80) >> 1) |
+ ((input.buttons.D ? 0 : 0x80) ) |
+ ((input.buttons.E ? 0 : 0x80) << 1) |
+ ((input.buttons.W ? 0 : 0x80) << 2)) ;
+
+ ((uint16_t *)MMU.ARM9_REG)[0x130>>1] = (uint16_t)pad;
+ ((uint16_t *)MMU.ARM7_REG)[0x130>>1] = (uint16_t)pad;
+
+ uint16_t k_cnt = ((uint16_t *)MMU.ARM9_REG)[0x132>>1];
+ if ( k_cnt & (1<<14))
+ {
+ //INFO("ARM9: KeyPad IRQ (pad 0x%04X, cnt 0x%04X (condition %s))\n", pad, k_cnt, k_cnt&(1<<15)?"AND":"OR");
+ uint16_t k_cnt_selected = (k_cnt & 0x3F);
+ if (k_cnt&(1<<15)) // AND
+ {
+ if ((~pad & k_cnt_selected) == k_cnt_selected) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_KEYPAD);
+ }
+ else // OR
+ {
+ if (~pad & k_cnt_selected) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_KEYPAD);
+ }
+ }
+
+ k_cnt = ((uint16_t *)MMU.ARM7_REG)[0x132>>1];
+ if ( k_cnt & (1<<14))
+ {
+ //INFO("ARM7: KeyPad IRQ (pad 0x%04X, cnt 0x%04X (condition %s))\n", pad, k_cnt, k_cnt&(1<<15)?"AND":"OR");
+ uint16_t k_cnt_selected = (k_cnt & 0x3F);
+ if (k_cnt&(1<<15)) // AND
+ {
+ if ((~pad & k_cnt_selected) == k_cnt_selected) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_KEYPAD);
+ }
+ else // OR
+ {
+ if (~pad & k_cnt_selected) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_KEYPAD);
+ }
+ }
+
+
+ if(input.touch.isTouch)
+ {
+ nds.touchX = input.touch.touchX;
+ nds.touchY = input.touch.touchY;
+ nds.isTouch = 1;
+
+ MMU.ARM7_REG[0x136] &= 0xBF;
+ }
+ else
+ {
+
+ nds.touchX = 0;
+ nds.touchY = 0;
+ nds.isTouch = 0;
+
+ MMU.ARM7_REG[0x136] |= 0x40;
+ }
+
+
+ if (input.buttons.F && !countLid)
+ {
+ LidClosed = (!LidClosed) & 0x01;
+ if (!LidClosed)
+ {
+ // SPU_Pause(false);
+ NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_ARM7_FOLD);
+
+ }
+ //else
+ //SPU_Pause(true);
+
+ countLid = 30;
+ }
+ else
+ {
+ if (countLid > 0)
+ countLid--;
+ }
+
+ uint16_t padExt = (((uint16_t *)MMU.ARM7_REG)[0x136>>1] & 0x0070) |
+ ((input.buttons.X ? 0 : 0x80) >> 7) |
+ ((input.buttons.Y ? 0 : 0x80) >> 6) |
+ ((input.buttons.G ? 0 : 0x80) >> 4) |
+ ((LidClosed) << 7) |
+ 0x0034;
+
+ ((uint16_t *)MMU.ARM7_REG)[0x136>>1] = (uint16_t)padExt;
+
+ InputDisplayString=MakeInputDisplayString(padExt, pad);
+
+ //put into the format we want for the movie system
+ //fRLDUTSBAYXWEg
+ //we don't really need nds.pad anymore, but removing it would be a pain
+
+ nds.pad =
+ ((input.buttons.R ? 1 : 0) << 12)|
+ ((input.buttons.L ? 1 : 0) << 11)|
+ ((input.buttons.D ? 1 : 0) << 10)|
+ ((input.buttons.U ? 1 : 0) << 9)|
+ ((input.buttons.T ? 1 : 0) << 8)|
+ ((input.buttons.S ? 1 : 0) << 7)|
+ ((input.buttons.B ? 1 : 0) << 6)|
+ ((input.buttons.A ? 1 : 0) << 5)|
+ ((input.buttons.Y ? 1 : 0) << 4)|
+ ((input.buttons.X ? 1 : 0) << 3)|
+ ((input.buttons.W ? 1 : 0) << 2)|
+ ((input.buttons.E ? 1 : 0) << 1);
+
+ // TODO: low power IRQ
+}*/
+
+
+/*void NDS_suspendProcessingInput(bool suspend)
+{
+ static int suspendCount = 0;
+ if(suspend)
+ {
+ // enter non-processing block
+ assert(validToProcessInput);
+ validToProcessInput = false;
+ suspendCount++;
+ }
+ else if(suspendCount)
+ {
+ // exit non-processing block
+ validToProcessInput = true;
+ suspendCount--;
+ }
+ else
+ {
+ // unwound past first time -> not processing
+ validToProcessInput = false;
+ }
+}*/
+
+
+/*void emu_halt() {
+ //printf("halting emu: ARM9 PC=%08X/%08X, ARM7 PC=%08X/%08X\n", NDS_ARM9.R[15], NDS_ARM9.instruct_adr, NDS_ARM7.R[15], NDS_ARM7.instruct_adr);
+ execute = false;
+#ifdef LOG_ARM9
+ if (fp_dis9)
+ {
+ char buf[256] = { 0 };
+ sprintf(buf, "halting emu: ARM9 PC=%08X/%08X\n", NDS_ARM9.R[15], NDS_ARM9.instruct_adr);
+ fwrite(buf, 1, strlen(buf), fp_dis9);
+ INFO("ARM9 halted\n");
+ }
+#endif
+
+#ifdef LOG_ARM7
+ if (fp_dis7)
+ {
+ char buf[256] = { 0 };
+ sprintf(buf, "halting emu: ARM7 PC=%08X/%08X\n", NDS_ARM7.R[15], NDS_ARM7.instruct_adr);
+ fwrite(buf, 1, strlen(buf), fp_dis7);
+ INFO("ARM7 halted\n");
+ }
+#endif
+}*/
+
+//returns true if exmemcnt specifies satisfactory parameters for the device, which calls this function
+/*bool ValidateSlot2Access(uint32_t procnum, uint32_t demandSRAMSpeed, uint32_t demand1stROMSpeed, uint32_t demand2ndROMSpeed, int clockbits)
+{
+ static const uint32_t _sramSpeeds[] = {10,8,6,18};
+ static const uint32_t _rom1Speeds[] = {10,8,6,18};
+ static const uint32_t _rom2Speeds[] = {6,4};
+ uint16_t exmemcnt = T1ReadWord(MMU.MMU_MEM[procnum][0x40], 0x204);
+ uint16_t exmemcnt9 = T1ReadWord(MMU.MMU_MEM[ARMCPU_ARM9][0x40], 0x204);
+ uint32_t arm7access = (exmemcnt9 & EXMEMCNT_MASK_SLOT2_ARM7);
+ uint32_t sramSpeed = _sramSpeeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_SRAM_TIME)];
+ uint32_t romSpeed1 = _rom1Speeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_ROM_1ST_TIME)>>2];
+ uint32_t romSpeed2 = _rom2Speeds[(exmemcnt & EXMEMCNT_MASK_SLOT2_ROM_2ND_TIME)>>4];
+ uint32_t curclockbits = (exmemcnt & EXMEMCNT_MASK_SLOT2_CLOCKRATE)>>5;
+
+ if(procnum==ARMCPU_ARM9 && arm7access) return false;
+ if(procnum==ARMCPU_ARM7 && !arm7access) return false;
+
+ //what we're interested in here is whether the rom/ram are too low -> too fast. then accesses won't have enough time to work.
+ //i'm not sure if this gives us enough flexibility, but it is good enough for now.
+ //should make the arguments to this function bitmasks later if we need better.
+ if(sramSpeed < demandSRAMSpeed) return false;
+ if(romSpeed1 < demand1stROMSpeed) return false;
+ if(romSpeed2 < demand2ndROMSpeed) return false;
+
+ if(clockbits != -1 && clockbits != (int)curclockbits) return false;
+
+ return true;
+}*/
+
+//these templates needed to be instantiated manually
+template void NDS_exec<false>(int32_t nb);
+template void NDS_exec<true>(int32_t nb);
+
--- /dev/null
+++ b/src/in_2sf/desmume/NDSSystem.h
@@ -1,1 +1,606 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2008-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef NDSSYSTEM_H
+#define NDSSYSTEM_H
+
+#include <cstring>
+
+#include "armcpu.h"
+#include "MMU.h"
+//#include "driver.h"
+//#include "GPU.h"
+#include "SPU.h"
+#include "mem.h"
+//#include "wifi.h"
+#include "emufile.h"
+#include "firmware.h"
+
+#include <string>
+
+#if defined(_WINDOWS) && !defined(WXPORT)
+#include "pathsettings.h"
+#endif
+
+template<typename Type>
+struct buttonstruct {
+ union {
+ struct {
+ // changing the order of these fields would break stuff
+ //fRLDUTSBAYXWEg
+ Type G; // debug
+ Type E; // right shoulder
+ Type W; // left shoulder
+ Type X;
+ Type Y;
+ Type A;
+ Type B;
+ Type S; // start
+ Type T; // select
+ Type U; // up
+ Type D; // down
+ Type L; // left
+ Type R; // right
+ Type F; // lid
+ };
+ Type array[14];
+ };
+};
+
+//extern buttonstruct<bool> Turbo;
+extern buttonstruct<int> TurboTime;
+//extern buttonstruct<bool> AutoHold;
+
+//int NDS_WritePNG(const char *fname);
+
+extern volatile bool execute;
+//extern bool click;
+
+/*
+ * The firmware language values
+ */
+/*#define NDS_FW_LANG_JAP 0
+#define NDS_FW_LANG_ENG 1
+#define NDS_FW_LANG_FRE 2
+#define NDS_FW_LANG_GER 3
+#define NDS_FW_LANG_ITA 4
+#define NDS_FW_LANG_SPA 5
+#define NDS_FW_LANG_CHI 6
+#define NDS_FW_LANG_RES 7*/
+
+
+//#define LOG_ARM9
+//#define LOG_ARM7
+
+struct NDS_header
+{
+ char gameTile[12];
+ char gameCode[4];
+ uint16_t makerCode;
+ uint8_t unitCode;
+ uint8_t deviceCode;
+ uint8_t cardSize;
+ uint8_t cardInfo[8];
+ uint8_t flags;
+ uint8_t romversion;
+
+ uint32_t ARM9src;
+ uint32_t ARM9exe;
+ uint32_t ARM9cpy;
+ uint32_t ARM9binSize;
+
+ uint32_t ARM7src;
+ uint32_t ARM7exe;
+ uint32_t ARM7cpy;
+ uint32_t ARM7binSize;
+
+ uint32_t FNameTblOff;
+ uint32_t FNameTblSize;
+
+ uint32_t FATOff;
+ uint32_t FATSize;
+
+ uint32_t ARM9OverlayOff;
+ uint32_t ARM9OverlaySize;
+ uint32_t ARM7OverlayOff;
+ uint32_t ARM7OverlaySize;
+
+ uint32_t unknown2a;
+ uint32_t unknown2b;
+
+ uint32_t IconOff;
+ uint16_t CRC16;
+ uint16_t ROMtimeout;
+ uint32_t ARM9unk;
+ uint32_t ARM7unk;
+
+ uint8_t unknown3c[8];
+ uint32_t ROMSize;
+ uint32_t HeaderSize;
+ uint8_t unknown5[56];
+ uint8_t logo[156];
+ uint16_t logoCRC16;
+ uint16_t headerCRC16;
+ uint8_t reserved[160];
+};
+
+//extern void debug();
+//void emu_halt();
+
+extern uint64_t nds_timer;
+void NDS_Reschedule();
+//void NDS_RescheduleGXFIFO(uint32_t cost);
+void NDS_RescheduleDMA();
+void NDS_RescheduleTimers();
+
+/*enum ENSATA_HANDSHAKE
+{
+ ENSATA_HANDSHAKE_none = 0,
+ ENSATA_HANDSHAKE_query = 1,
+ ENSATA_HANDSHAKE_ack = 2,
+ ENSATA_HANDSHAKE_confirm = 3,
+ ENSATA_HANDSHAKE_complete = 4
+};*/
+
+enum NDS_CONSOLE_TYPE
+{
+ NDS_CONSOLE_TYPE_FAT,
+ NDS_CONSOLE_TYPE_LITE,
+ NDS_CONSOLE_TYPE_IQUE,
+ NDS_CONSOLE_TYPE_DSI
+};
+
+struct NDSSystem
+{
+ //int32_t wifiCycle;
+ int32_t cycles;
+ uint64_t timerCycle[2][4];
+ uint32_t VCount;
+ uint32_t old;
+
+ //uint16_t touchX;
+ //uint16_t touchY;
+ //bool isTouch;
+ //uint16_t pad;
+
+ uint8_t *FW_ARM9BootCode;
+ uint8_t *FW_ARM7BootCode;
+ uint32_t FW_ARM9BootCodeAddr;
+ uint32_t FW_ARM7BootCodeAddr;
+ uint32_t FW_ARM9BootCodeSize;
+ uint32_t FW_ARM7BootCodeSize;
+
+ bool sleeping;
+ bool cardEjected;
+ uint32_t freezeBus;
+
+ //this is not essential NDS runtime state.
+ //it was perhaps a mistake to put it here.
+ //it is far less important than the above.
+ //maybe I should move it.
+ //int32_t idleCycles[2];
+ //int32_t runCycleCollector[2][16];
+ //int32_t idleFrameCounter;
+ //int32_t cpuloopIterationCount; //counts the number of times during a frame that a reschedule happened
+
+ //if the game was booted on a debug console, this is set
+ //bool debugConsole;
+
+ //console type must be copied in when the system boots. it can't be changed on the fly.
+ int ConsoleType;
+ bool Is_DSI() { return ConsoleType == NDS_CONSOLE_TYPE_DSI; }
+
+ //set if the user requests ensata emulation
+ //bool ensataEmulation;
+
+ //there is a hack in the ipc sync for ensata. this tracks its state
+ //uint32_t ensataIpcSyncCounter;
+
+ //maintains the state of the ensata handshaking protocol
+ //uint32_t ensataHandshake;
+
+ /*struct {
+ uint8_t lcd, gpuMain, gfx3d_render, gfx3d_geometry, gpuSub, dispswap;
+ } power1;*/ //POWCNT1
+
+ /*struct {
+ uint8_t speakers, wifi*/ /*(initial value=0)*//*;
+ } power2;*/ //POWCNT2
+
+ bool isInVblank() const { return VCount >= 192; }
+ bool isIn3dVblank() const { return VCount >= 192 && VCount<215; }
+};
+
+/** /brief A touchscreen calibration point.
+ */
+/*struct NDS_fw_touchscreen_cal {
+ uint16_t adc_x;
+ uint16_t adc_y;
+
+ uint8_t screen_x;
+ uint8_t screen_y;
+};*/
+
+#define MAX_FW_NICKNAME_LENGTH 10
+#define MAX_FW_MESSAGE_LENGTH 26
+
+struct NDS_fw_config_data {
+ NDS_CONSOLE_TYPE ds_type;
+
+ uint8_t fav_colour;
+ uint8_t birth_month;
+ uint8_t birth_day;
+
+ uint16_t nickname[MAX_FW_NICKNAME_LENGTH];
+ uint8_t nickname_len;
+
+ uint16_t message[MAX_FW_MESSAGE_LENGTH];
+ uint8_t message_len;
+
+ uint8_t language;
+
+ /* touchscreen calibration */
+ //struct NDS_fw_touchscreen_cal touch_cal[2];
+};
+
+extern NDSSystem nds;
+
+#ifdef GDB_STUB
+int NDS_Init( struct armcpu_memory_iface *arm9_mem_if,
+ struct armcpu_ctrl_iface **arm9_ctrl_iface,
+ struct armcpu_memory_iface *arm7_mem_if,
+ struct armcpu_ctrl_iface **arm7_ctrl_iface);
+#else
+int NDS_Init ();
+#endif
+
+//void Desmume_InitOnce();
+
+void NDS_DeInit();
+
+bool NDS_SetROM(uint8_t * rom, uint32_t mask);
+NDS_header * NDS_getROMHeader();
+
+struct RomBanner
+{
+ RomBanner(bool defaultInit);
+ uint16_t version; //Version (0001h)
+ uint16_t crc16; //CRC16 across entries 020h..83Fh
+ uint8_t reserved[0x1C]; //Reserved (zero-filled)
+ uint8_t bitmap[0x200]; //Icon Bitmap (32x32 pix) (4x4 tiles, each 4x8 bytes, 4bit depth)
+ uint16_t palette[0x10]; //Icon Palette (16 colors, 16bit, range 0000h-7FFFh) (Color 0 is transparent, so the 1st palette entry is ignored)
+ enum { NUM_TITLES = 6 };
+ union {
+ struct {
+ uint16_t title_jp[0x80]; //Title 0 Japanese (128 characters, 16bit Unicode)
+ uint16_t title_en[0x80]; //Title 1 English ("")
+ uint16_t title_fr[0x80]; //Title 2 French ("")
+ uint16_t title_de[0x80]; //Title 3 German ("")
+ uint16_t title_it[0x80]; //Title 4 Italian ("")
+ uint16_t title_es[0x80]; //Title 5 Spanish ("")
+ };
+ uint16_t titles[NUM_TITLES][0x80];
+ };
+ uint8_t end0xFF[0x1C0];
+ //840h ? (Maybe newer/chinese firmware do also support chinese title?)
+ //840h - End of Icon/Title structure (next 1C0h bytes usually FFh-filled)
+};
+
+struct GameInfo
+{
+ GameInfo()
+ : romdata(NULL)
+ {}
+
+ void loadData(char* buf, int size)
+ {
+ resize(size);
+ memcpy(romdata,buf,size);
+ romsize = (uint32_t)size;
+ fillGap();
+ }
+
+ void fillGap()
+ {
+ memset(romdata+romsize,0xFF,allocatedSize-romsize);
+ }
+
+ void resize(int size) {
+ if(romdata != NULL) delete[] romdata;
+
+ //calculate the necessary mask for the requested size
+ mask = size-1;
+ mask |= (mask >>1);
+ mask |= (mask >>2);
+ mask |= (mask >>4);
+ mask |= (mask >>8);
+ mask |= (mask >>16);
+
+ //now, we actually need to over-allocate, because bytes from anywhere protected by that mask
+ //could be read from the rom
+ allocatedSize = mask+4;
+
+ romdata = new char[allocatedSize];
+ romsize = size;
+ }
+ uint32_t crc;
+ NDS_header header;
+ char ROMserial[20];
+ char ROMname[20];
+ //char ROMfullName[7][0x100];
+ //void populate();
+ char* romdata;
+ uint32_t romsize;
+ uint32_t allocatedSize;
+ uint32_t mask;
+ //const RomBanner& getRomBanner();
+ //bool hasRomBanner();
+ bool isHomebrew;
+};
+
+/*typedef struct TSCalInfo
+{
+ struct adc
+ {
+ uint16_t x1, x2;
+ uint16_t y1, y2;
+ uint16_t width;
+ uint16_t height;
+ } adc;
+
+ struct scr
+ {
+ uint8_t x1, x2;
+ uint8_t y1, y2;
+ uint16_t width;
+ uint16_t height;
+ } scr;
+
+} TSCalInfo;*/
+
+extern GameInfo gameInfo;
+
+
+struct UserButtons : buttonstruct<bool>
+{
+};
+struct UserTouch
+{
+ uint16_t touchX;
+ uint16_t touchY;
+ bool isTouch;
+};
+struct UserMicrophone
+{
+ uint32_t micButtonPressed;
+};
+struct UserInput
+{
+ UserButtons buttons;
+ UserTouch touch;
+ UserMicrophone mic;
+};
+
+// set physical user input
+// these functions merely request the input to be changed.
+// the actual change happens later at a specific time during the frame.
+// this is to minimize the risk of desyncs.
+//void NDS_setTouchPos(uint16_t x, uint16_t y);
+//void NDS_releaseTouch();
+//void NDS_setPad(bool right,bool left,bool down,bool up,bool select,bool start,bool B,bool A,bool Y,bool X,bool leftShoulder,bool rightShoulder,bool debug, bool lid);
+//void NDS_setMic(bool pressed);
+
+// get physical user input
+// not including the results of autofire/etc.
+// the effects of calls to "set physical user input" functions will be immediately reflected here though.
+//const UserInput& NDS_getRawUserInput();
+//const UserInput& NDS_getPrevRawUserInput();
+
+// get final (fully processed) user input
+// this should match whatever was or would be sent to the game
+//const UserInput& NDS_getFinalUserInput();
+
+// set/get to-be-processed or in-the-middle-of-being-processed user input
+// to process input, simply call this function and edit the return value.
+// (applying autofire is one example of processing the input.)
+// (movie playback is another example.)
+// this must be done after the raw user input is set
+// and before that input is sent to the game's memory.
+//UserInput& NDS_getProcessingUserInput();
+//bool NDS_isProcessingUserInput();
+// call once per frame to prepare input for processing
+//void NDS_beginProcessingInput();
+// call once per frame to copy the processed input to the final input
+//void NDS_endProcessingInput();
+
+// this is in case something needs reentrancy while processing input
+//void NDS_suspendProcessingInput(bool suspend);
+
+
+
+//int NDS_LoadROM(const char *filename, const char* logicalFilename=0);
+void NDS_FreeROM();
+void NDS_Reset();
+//int NDS_ImportSave(const char *filename);
+//bool NDS_ExportSave(const char *filename);
+
+//void nds_savestate(EMUFILE* os);
+bool nds_loadstate(EMUFILE* is, int size);
+
+//int NDS_WriteBMP(const char *filename);
+
+void NDS_Sleep();
+//void NDS_ToggleCardEject();
+
+//void NDS_SkipNextFrame();
+//#define NDS_SkipFrame(s) if(s) NDS_SkipNext2DFrame();
+//void NDS_OmitFrameSkip(int force=0);
+
+//void NDS_debug_break();
+//void NDS_debug_continue();
+//void NDS_debug_step();
+
+void execHardware_doAllDma(EDMAMode modeNum);
+
+template<bool FORCE> void NDS_exec(int32_t nb = 560190<<1);
+
+//extern int lagframecounter;
+
+/*static INLINE void NDS_swapScreen()
+{
+ uint16_t tmp = MainScreen.offset;
+ MainScreen.offset = SubScreen.offset;
+ SubScreen.offset = tmp;
+}*/
+
+//int NDS_WriteBMP_32bppBuffer(int width, int height, const void* buf, const char *filename);
+
+extern struct TCommonSettings {
+ TCommonSettings()
+ : //GFX3D_HighResolutionInterpolateColor(true)
+ //, GFX3D_EdgeMark(true)
+ //, GFX3D_Fog(true)
+ //, GFX3D_Texture(true)
+ //, GFX3D_Zelda_Shadow_Depth_Hack(0)
+ /*,*/ UseExtBIOS(false)
+ , SWIFromBIOS(false)
+ , PatchSWI3(false)
+ , UseExtFirmware(false)
+ , BootFromFirmware(false)
+ , ConsoleType(NDS_CONSOLE_TYPE_FAT)
+ //, DebugConsole(false)
+ //, EnsataEmulation(false)
+ //, cheatsDisable(false)
+ //, num_cores(1)
+ , rigorous_timing(false)
+ , advanced_timing(true)
+ //, micMode(InternalNoise)
+ , spuInterpolationMode(SPUInterpolation_Linear)
+ , manualBackupType(0)
+ , spu_captureMuted(false)
+ , spu_advanced(false)
+ {
+ strcpy(ARM9BIOS, "biosnds9.bin");
+ strcpy(ARM7BIOS, "biosnds7.bin");
+ strcpy(Firmware, "firmware.bin");
+ NDS_FillDefaultFirmwareConfigData(&InternalFirmConf);
+
+ /* WIFI mode: adhoc = 0, infrastructure = 1 */
+ //wifi.mode = 1;
+ //wifi.infraBridgeAdapter = 0;
+
+ for(int i=0;i<16;i++)
+ spu_muteChannels[i] = false;
+
+ /*for(int g=0;g<2;g++)
+ for(int x=0;x<5;x++)
+ dispLayers[g][x]=true;*/
+ }
+ //bool GFX3D_HighResolutionInterpolateColor;
+ //bool GFX3D_EdgeMark;
+ //bool GFX3D_Fog;
+ //bool GFX3D_Texture;
+ //int GFX3D_Zelda_Shadow_Depth_Hack;
+
+ bool UseExtBIOS;
+ char ARM9BIOS[256];
+ char ARM7BIOS[256];
+ bool SWIFromBIOS;
+ bool PatchSWI3;
+
+ bool UseExtFirmware;
+ char Firmware[256];
+ bool BootFromFirmware;
+ struct NDS_fw_config_data InternalFirmConf;
+
+ NDS_CONSOLE_TYPE ConsoleType;
+ //bool DebugConsole;
+ //bool EnsataEmulation;
+
+ //bool cheatsDisable;
+
+ //int num_cores;
+ //bool single_core() { return num_cores==1; }
+ bool rigorous_timing;
+
+ //bool dispLayers[2][5];
+
+ /*FAST_ALIGN*/ bool advanced_timing;
+
+ /*struct _Wifi {
+ int mode;
+ int infraBridgeAdapter;
+ } wifi;*/
+
+ /*enum MicMode
+ {
+ InternalNoise = 0,
+ Sample = 1,
+ Random = 2,
+ Physical = 3
+ } micMode;*/
+
+
+ SPUInterpolationMode spuInterpolationMode;
+
+ //this is a temporary hack until we straighten out the flushing logic and/or gxfifo
+ //int gfx3d_flushMode;
+
+ //this is the user's choice of manual backup type, for cases when the autodetection can't be trusted
+ int manualBackupType;
+
+ bool spu_muteChannels[16];
+ bool spu_captureMuted;
+ bool spu_advanced;
+
+ /*struct _ShowGpu {
+ _ShowGpu() : main(true), sub(true) {}
+ union {
+ struct { bool main,sub; };
+ bool screens[2];
+ };
+ } showGpu;*/
+
+ /*struct _Hud {
+ _Hud()
+ : ShowInputDisplay(false)
+ , ShowGraphicalInputDisplay(false)
+ , FpsDisplay(false)
+ , FrameCounterDisplay(false)
+ , ShowLagFrameCounter(false)
+ , ShowMicrophone(false)
+ , ShowRTC(false)
+ {}
+ bool ShowInputDisplay, ShowGraphicalInputDisplay, FpsDisplay, FrameCounterDisplay, ShowLagFrameCounter, ShowMicrophone, ShowRTC;
+ } hud;*/
+
+} CommonSettings;
+
+
+//extern std::string InputDisplayString;
+//extern int LagFrameFlag;
+//extern int lastLag, TotalLagFrames;
+
+//void MovieSRAM();
+
+//void ClearAutoHold();
+
+//bool ValidateSlot2Access(uint32_t procnum, uint32_t demandSRAMSpeed, uint32_t demand1stROMSpeed, uint32_t demand2ndROMSpeed, int clockbits);
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/PACKED.h
@@ -1,1 +1,13 @@
+#ifndef __GNUC__
+#pragma pack(push, 1)
+#pragma warning(disable : 4103)
+#endif
+#ifndef __PACKED
+ #ifdef __GNUC__
+ #define __PACKED __attribute__((__packed__))
+ #else
+ #define __PACKED
+ #endif
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/PACKED_END.h
@@ -1,1 +1,4 @@
+#ifndef __GNUC__
+#pragma pack(pop)
+#endif
--- /dev/null
+++ b/src/in_2sf/desmume/SPU.cpp
@@ -1,1 +1,1758 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2006 Theo Berkau
+ Copyright (C) 2008-2012 DeSmuME team
+
+ Ideas borrowed from Stephane Dallongeville's SCSP core
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "XSFCommon.h"
+
+#include <queue>
+#include <vector>
+#include <cstdlib>
+#include <cstring>
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+//#include "debug.h"
+#include "MMU.h"
+#include "SPU.h"
+#include "mem.h"
+#include "readwrite.h"
+#include "armcpu.h"
+#include "NDSSystem.h"
+#include "matrix.h"
+
+#include "metaspu/metaspu.h"
+
+static const int K_ADPCM_LOOPING_RECOVERY_INDEX = 99999;
+static const int COSINE_INTERPOLATION_RESOLUTION = 8192;
+
+//static ISynchronizingAudioBuffer* synchronizer = metaspu_construct(ESynchMethod_Z);
+static ISynchronizingAudioBuffer* synchronizer = metaspu_construct(ESynchMethod_N);
+
+SPU_struct *SPU_core = 0;
+SPU_struct *SPU_user = 0;
+int SPU_currentCoreNum = SNDCORE_DUMMY;
+static int volume = 100;
+
+static int buffersize = 0;
+static ESynchMode synchmode = ESynchMode_DualSynchAsynch;
+static ESynchMethod synchmethod = ESynchMethod_N;
+
+static int SNDCoreId=-1;
+static SoundInterface_struct *SNDCore=NULL;
+extern SoundInterface_struct *SNDCoreList[];
+
+//const int shift = (FORMAT == 0 ? 2 : 1);
+static const int format_shift[] = { 2, 1, 3, 0 };
+
+static const int8_t indextbl[8] =
+{
+ -1, -1, -1, -1, 2, 4, 6, 8
+};
+
+static const uint16_t adpcmtbl[89] =
+{
+ 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0010,
+ 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, 0x0022, 0x0025,
+ 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042, 0x0049, 0x0050, 0x0058,
+ 0x0061, 0x006B, 0x0076, 0x0082, 0x008F, 0x009D, 0x00AD, 0x00BE, 0x00D1,
+ 0x00E6, 0x00FD, 0x0117, 0x0133, 0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE,
+ 0x0220, 0x0256, 0x0292, 0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E,
+ 0x0502, 0x0583, 0x0610, 0x06AB, 0x0756, 0x0812, 0x08E0, 0x09C3, 0x0ABD,
+ 0x0BD0, 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954,
+ 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B, 0x3BB9,
+ 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF
+};
+
+static const int16_t wavedutytbl[8][8] = {
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF }
+};
+
+static int32_t precalcdifftbl[89][16];
+static uint8_t precalcindextbl[89][8];
+static double cos_lut[COSINE_INTERPOLATION_RESOLUTION];
+
+static const double ARM7_CLOCK = 33513982;
+
+static const double samples_per_hline = (DESMUME_SAMPLE_RATE / 59.8261f) / 263.0f;
+
+static double samples = 0;
+
+template<typename T>
+static inline T MinMax(T val, T min, T max)
+{
+ if (val < min)
+ return min;
+ else if (val > max)
+ return max;
+
+ return val;
+}
+
+//--------------external spu interface---------------
+
+int SPU_ChangeSoundCore(int coreid, int Buffersize)
+{
+ int i;
+
+ buffersize = Buffersize;
+
+ delete SPU_user; SPU_user = NULL;
+
+ // Make sure the old core is freed
+ if (SNDCore)
+ SNDCore->DeInit();
+
+ // So which core do we want?
+ if (coreid == SNDCORE_DEFAULT)
+ coreid = 0; // Assume we want the first one
+
+ SPU_currentCoreNum = coreid;
+
+ // Go through core list and find the id
+ for (i = 0; SNDCoreList[i] != NULL; i++)
+ {
+ if (SNDCoreList[i]->id == coreid)
+ {
+ // Set to current core
+ SNDCore = SNDCoreList[i];
+ break;
+ }
+ }
+
+ SNDCoreId = coreid;
+
+ //If the user picked the dummy core, disable the user spu
+ if(SNDCore == &SNDDummy)
+ return 0;
+
+ //If the core wasnt found in the list for some reason, disable the user spu
+ if (SNDCore == NULL)
+ return -1;
+
+ // Since it failed, instead of it being fatal, disable the user spu
+ if (SNDCore->Init(buffersize * 2) == -1)
+ {
+ SNDCore = 0;
+ return -1;
+ }
+
+ SNDCore->SetVolume(volume);
+
+ SPU_SetSynchMode(synchmode,synchmethod);
+
+ return 0;
+}
+
+/*SoundInterface_struct *SPU_SoundCore()
+{
+ return SNDCore;
+}*/
+
+void SPU_ReInit()
+{
+ SPU_Init(SNDCoreId, buffersize);
+}
+
+int SPU_Init(int coreid, int Buffersize)
+{
+ int i, j;
+
+ // Build the cosine interpolation LUT
+ for(i = 0; i < COSINE_INTERPOLATION_RESOLUTION; i++)
+ cos_lut[i] = (1.0 - cos(((double)i/(double)COSINE_INTERPOLATION_RESOLUTION) * M_PI)) * 0.5;
+
+ SPU_core = new SPU_struct((int)ceil(samples_per_hline));
+ SPU_Reset();
+
+ //create adpcm decode accelerator lookups
+ for(i = 0; i < 16; i++)
+ {
+ for(j = 0; j < 89; j++)
+ {
+ precalcdifftbl[j][i] = (((i & 0x7) * 2 + 1) * adpcmtbl[j] / 8);
+ if(i & 0x8) precalcdifftbl[j][i] = -precalcdifftbl[j][i];
+ }
+ }
+ for(i = 0; i < 8; i++)
+ {
+ for(j = 0; j < 89; j++)
+ {
+ precalcindextbl[j][i] = MinMax((j + indextbl[i]), 0, 88);
+ }
+ }
+
+ return SPU_ChangeSoundCore(coreid, Buffersize);
+}
+
+/*void SPU_Pause(int pause)
+{
+ if (SNDCore == NULL) return;
+
+ if(pause)
+ SNDCore->MuteAudio();
+ else
+ SNDCore->UnMuteAudio();
+}*/
+
+void SPU_CloneUser()
+{
+ if(SPU_user) {
+ memcpy(SPU_user->channels,SPU_core->channels,sizeof(SPU_core->channels));
+ SPU_user->regs = SPU_core->regs;
+ }
+}
+
+void SPU_SetSynchMode(ESynchMode mode, ESynchMethod method)
+{
+ synchmode = mode;
+ if(synchmethod != method)
+ {
+ synchmethod = method;
+ delete synchronizer;
+ //grr does this need to be locked? spu might need a lock method
+ // or maybe not, maybe the platform-specific code that calls this function can deal with it.
+ synchronizer = metaspu_construct(synchmethod);
+ }
+
+ delete SPU_user;
+ SPU_user = NULL;
+
+ if(synchmode == ESynchMode_DualSynchAsynch)
+ {
+ SPU_user = new SPU_struct(buffersize);
+ SPU_CloneUser();
+ }
+}
+
+/*void SPU_ClearOutputBuffer()
+{
+ if(SNDCore && SNDCore->ClearBuffer)
+ SNDCore->ClearBuffer();
+}*/
+
+/*void SPU_SetVolume(int vol)
+{
+ volume = vol;
+ if (SNDCore)
+ SNDCore->SetVolume(vol);
+}*/
+
+
+void SPU_Reset()
+{
+ int i;
+
+ SPU_core->reset();
+
+ if(SPU_user) {
+ if(SNDCore)
+ {
+ SNDCore->DeInit();
+ SNDCore->Init(SPU_user->bufsize*2);
+ SNDCore->SetVolume(volume);
+ }
+ SPU_user->reset();
+ }
+
+ //zero - 09-apr-2010: this concerns me, regarding savestate synch.
+ //After 0.9.6, lets experiment with removing it and just properly zapping the spu instead
+ // Reset Registers
+ for (i = 0x400; i < 0x51D; i++)
+ T1WriteByte(MMU.ARM7_REG, i, 0);
+
+ samples = 0;
+}
+
+//------------------------------------------
+
+void SPU_struct::reset()
+{
+ memset(sndbuf,0,bufsize*2*4);
+ memset(outbuf,0,bufsize*2*2);
+
+ memset((void *)channels, 0, sizeof(channel_struct) * 16);
+
+ reconstruct(®s);
+
+ for(int i = 0; i < 16; i++)
+ {
+ channels[i].num = i;
+ }
+}
+
+SPU_struct::SPU_struct(int Buffersize)
+ : bufpos(0)
+ , buflength(0)
+ , sndbuf(0)
+ , outbuf(0)
+ , bufsize(Buffersize)
+{
+ sndbuf = new int32_t[Buffersize*2];
+ outbuf = new int16_t[Buffersize*2];
+ reset();
+}
+
+SPU_struct::~SPU_struct()
+{
+ if(sndbuf) delete[] sndbuf;
+ if(outbuf) delete[] outbuf;
+}
+
+void SPU_DeInit()
+{
+ if(SNDCore)
+ SNDCore->DeInit();
+ SNDCore = 0;
+
+ delete SPU_core; SPU_core=0;
+ delete SPU_user; SPU_user=0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void SPU_struct::ShutUp()
+{
+ for(int i=0;i<16;i++)
+ channels[i].status = CHANSTAT_STOPPED;
+}
+
+static inline void adjust_channel_timer(channel_struct *chan)
+{
+ chan->sampinc = (((double)ARM7_CLOCK) / (DESMUME_SAMPLE_RATE * 2)) / (double)(0x10000 - chan->timer);
+}
+
+void SPU_struct::KeyProbe(int chan_num)
+{
+ channel_struct &thischan = channels[chan_num];
+ if(thischan.status == CHANSTAT_STOPPED)
+ {
+ if(thischan.keyon && regs.masteren)
+ KeyOn(chan_num);
+ }
+ else if(thischan.status == CHANSTAT_PLAY)
+ {
+ if(!thischan.keyon || !regs.masteren)
+ KeyOff(chan_num);
+ }
+}
+
+void SPU_struct::KeyOff(int channel)
+{
+ //printf("keyoff%d\n",channel);
+ channel_struct &thischan = channels[channel];
+ thischan.status = CHANSTAT_STOPPED;
+}
+
+void SPU_struct::KeyOn(int channel)
+{
+ channel_struct &thischan = channels[channel];
+ thischan.status = CHANSTAT_PLAY;
+
+ thischan.totlength = thischan.length + thischan.loopstart;
+ adjust_channel_timer(&thischan);
+
+ //printf("keyon %d totlength:%d\n",channel,thischan.totlength);
+
+
+ //LOG("Channel %d key on: vol = %d, datashift = %d, hold = %d, pan = %d, waveduty = %d, repeat = %d, format = %d, source address = %07X,"
+ // "timer = %04X, loop start = %04X, length = %06X, MMU.ARM7_REG[0x501] = %02X\n", channel, chan->vol, chan->datashift, chan->hold,
+ // chan->pan, chan->waveduty, chan->repeat, chan->format, chan->addr, chan->timer, chan->loopstart, chan->length, T1ReadByte(MMU.ARM7_REG, 0x501));
+
+ switch(thischan.format)
+ {
+ case 0: // 8-bit
+ thischan.buf8 = (int8_t*)&MMU.MMU_MEM[1][(thischan.addr>>20)&0xFF][(thischan.addr & MMU.MMU_MASK[1][(thischan.addr >> 20) & 0xFF])];
+ // thischan.loopstart = thischan.loopstart << 2;
+ // thischan.length = (thischan.length << 2) + thischan.loopstart;
+ thischan.sampcnt = -3;
+ break;
+ case 1: // 16-bit
+ thischan.buf16 = (int16_t *)&MMU.MMU_MEM[1][(thischan.addr>>20)&0xFF][(thischan.addr & MMU.MMU_MASK[1][(thischan.addr >> 20) & 0xFF])];
+ // thischan.loopstart = thischan.loopstart << 1;
+ // thischan.length = (thischan.length << 1) + thischan.loopstart;
+ thischan.sampcnt = -3;
+ break;
+ case 2: // ADPCM
+ {
+ thischan.buf8 = (int8_t*)&MMU.MMU_MEM[1][(thischan.addr>>20)&0xFF][(thischan.addr & MMU.MMU_MASK[1][(thischan.addr >> 20) & 0xFF])];
+ thischan.pcm16b = (int16_t)((thischan.buf8[1] << 8) | thischan.buf8[0]);
+ thischan.pcm16b_last = thischan.pcm16b;
+ thischan.index = thischan.buf8[2] & 0x7F;
+ thischan.lastsampcnt = 7;
+ thischan.sampcnt = -3;
+ thischan.loop_index = K_ADPCM_LOOPING_RECOVERY_INDEX;
+ // thischan.loopstart = thischan.loopstart << 3;
+ // thischan.length = (thischan.length << 3) + thischan.loopstart;
+ break;
+ }
+ case 3: // PSG
+ {
+ thischan.sampcnt = -1;
+ thischan.x = 0x7FFF;
+ break;
+ }
+ default: break;
+ }
+
+ thischan.double_totlength_shifted = (double)(thischan.totlength << format_shift[thischan.format]);
+
+ if(thischan.format != 3)
+ {
+ if(fEqual(thischan.double_totlength_shifted, 0.0))
+ {
+ printf("INFO: Stopping channel %d due to zero length\n",channel);
+ thischan.status = CHANSTAT_STOPPED;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+//#define SETBYTE(which,oldval,newval) oldval = (oldval & (~(0xFF<<(which*8)))) | ((newval)<<(which*8))
+template<typename T> static inline void SETBYTE(uint32_t which, T &oldval, uint8_t newval) { oldval = (oldval & (~(0xFF << (which*8)))) | (newval << (which*8)); }
+//#define GETBYTE(which,val) ((val>>(which*8))&0xFF)
+static inline uint8_t GETBYTE(uint32_t which, uint32_t val) { return (val >> (which * 8)) & 0xFF; }
+
+uint8_t SPU_ReadByte(uint32_t addr) {
+ addr &= 0xFFF;
+ return SPU_core->ReadByte(addr);
+}
+uint16_t SPU_ReadWord(uint32_t addr) {
+ addr &= 0xFFF;
+ return SPU_core->ReadWord(addr);
+}
+uint32_t SPU_ReadLong(uint32_t addr) {
+ addr &= 0xFFF;
+ return SPU_core->ReadLong(addr);
+}
+
+uint16_t SPU_struct::ReadWord(uint32_t addr)
+{
+ return ReadByte(addr)|(ReadByte(addr+1)<<8);
+}
+
+uint32_t SPU_struct::ReadLong(uint32_t addr)
+{
+ return ReadByte(addr)|(ReadByte(addr+1)<<8)|(ReadByte(addr+2)<<16)|(ReadByte(addr+3)<<24);
+}
+
+uint8_t SPU_struct::ReadByte(uint32_t addr)
+{
+ switch(addr)
+ {
+ //SOUNDCNT
+ case 0x500: return regs.mastervol;
+ case 0x501:
+ return (regs.ctl_left)|(regs.ctl_right<<2)|(regs.ctl_ch1bypass<<4)|(regs.ctl_ch3bypass<<5)|(regs.masteren<<7);
+ case 0x502: return 0;
+ case 0x503: return 0;
+
+ //SOUNDBIAS
+ case 0x504: return regs.soundbias&0xFF;
+ case 0x505: return (regs.soundbias>>8)&0xFF;
+ case 0x506: return 0;
+ case 0x507: return 0;
+
+ //SNDCAP0CNT/SNDCAP1CNT
+ case 0x508:
+ case 0x509: {
+ uint32_t which = addr-0x508;
+ return regs.cap[which].add
+ | (regs.cap[which].source<<1)
+ | (regs.cap[which].oneshot<<2)
+ | (regs.cap[which].bits8<<3)
+ //| (regs.cap[which].active<<7); //? which is right? need test
+ | (regs.cap[which].runtime.running<<7);
+ }
+
+ //SNDCAP0DAD
+ case 0x510: return GETBYTE(0,regs.cap[0].dad);
+ case 0x511: return GETBYTE(1,regs.cap[0].dad);
+ case 0x512: return GETBYTE(2,regs.cap[0].dad);
+ case 0x513: return GETBYTE(3,regs.cap[0].dad);
+
+ //SNDCAP0LEN
+ case 0x514: return GETBYTE(0,regs.cap[0].len);
+ case 0x515: return GETBYTE(1,regs.cap[0].len);
+ case 0x516: return 0; //not used
+ case 0x517: return 0; //not used
+
+ //SNDCAP1DAD
+ case 0x518: return GETBYTE(0,regs.cap[1].dad);
+ case 0x519: return GETBYTE(1,regs.cap[1].dad);
+ case 0x51A: return GETBYTE(2,regs.cap[1].dad);
+ case 0x51B: return GETBYTE(3,regs.cap[1].dad);
+
+ //SNDCAP1LEN
+ case 0x51C: return GETBYTE(0,regs.cap[1].len);
+ case 0x51D: return GETBYTE(1,regs.cap[1].len);
+ case 0x51E: return 0; //not used
+ case 0x51F: return 0; //not used
+
+ default: {
+ //individual channel regs
+
+ uint32_t chan_num = (addr >> 4) & 0xF;
+ if(chan_num>0xF) return 0;
+ channel_struct &thischan=channels[chan_num];
+
+ switch(addr & 0xF) {
+ case 0x0: return thischan.vol;
+ case 0x1: {
+ uint8_t ret = thischan.datashift;
+ if(ret==4) ret=3;
+ ret |= thischan.hold<<7;
+ return ret;
+ }
+ case 0x2: return thischan.pan;
+ case 0x3: return thischan.waveduty|(thischan.repeat<<3)|(thischan.format<<5)|((thischan.status == CHANSTAT_PLAY)?0x80:0);
+ case 0x4: return 0; //return GETBYTE(0,thischan.addr); //not readable
+ case 0x5: return 0; //return GETBYTE(1,thischan.addr); //not readable
+ case 0x6: return 0; //return GETBYTE(2,thischan.addr); //not readable
+ case 0x7: return 0; //return GETBYTE(3,thischan.addr); //not readable
+ case 0x8: return GETBYTE(0,thischan.timer);
+ case 0x9: return GETBYTE(1,thischan.timer);
+ case 0xA: return GETBYTE(0,thischan.loopstart);
+ case 0xB: return GETBYTE(1,thischan.loopstart);
+ case 0xC: return 0; //return GETBYTE(0,thischan.length); //not readable
+ case 0xD: return 0; //return GETBYTE(1,thischan.length); //not readable
+ case 0xE: return 0; //return GETBYTE(2,thischan.length); //not readable
+ case 0xF: return 0; //return GETBYTE(3,thischan.length); //not readable
+ default: return 0; //impossible
+ } //switch on individual channel regs
+ } //default case
+ } //switch on address
+}
+
+SPUFifo::SPUFifo()
+{
+ reset();
+}
+
+void SPUFifo::reset()
+{
+ head = tail = size = 0;
+}
+
+void SPUFifo::enqueue(int16_t val)
+{
+ if(size==16) return;
+ buffer[tail] = val;
+ tail++;
+ tail &= 15;
+ size++;
+}
+
+int16_t SPUFifo::dequeue()
+{
+ if(size==0) return 0;
+ head++;
+ head &= 15;
+ int16_t ret = buffer[head];
+ size--;
+ return ret;
+}
+
+/*void SPUFifo::save(EMUFILE* fp)
+{
+ uint32_t version = 1;
+ write32le(version,fp);
+ write32le(head,fp);
+ write32le(tail,fp);
+ write32le(size,fp);
+ for(int i=0;i<16;i++)
+ write16le(buffer[i],fp);
+}*/
+
+bool SPUFifo::load(EMUFILE* fp)
+{
+ uint32_t version;
+ if(read32le(&version,fp) != 1) return false;
+ read32le(&head,fp);
+ read32le(&tail,fp);
+ read32le(&size,fp);
+ for(int i=0;i<16;i++)
+ read16le(&buffer[i],fp);
+ return true;
+}
+
+void SPU_struct::ProbeCapture(int which)
+{
+ //VERY UNTESTED -- HOW MUCH OF THIS RESETS, AND WHEN?
+
+ if(!regs.cap[which].active)
+ {
+ regs.cap[which].runtime.running = 0;
+ return;
+ }
+
+ REGS::CAP &cap = regs.cap[which];
+ cap.runtime.running = 1;
+ cap.runtime.curdad = cap.dad;
+ uint32_t len = cap.len;
+ if(len==0) len=1;
+ cap.runtime.maxdad = cap.dad + len*4;
+ cap.runtime.sampcnt = 0;
+ cap.runtime.fifo.reset();
+}
+
+void SPU_struct::WriteByte(uint32_t addr, uint8_t val)
+{
+ switch(addr)
+ {
+ //SOUNDCNT
+ case 0x500:
+ regs.mastervol = val&0x7F;
+ break;
+ case 0x501:
+ regs.ctl_left = (val>>0)&3;
+ regs.ctl_right = (val>>2)&3;
+ regs.ctl_ch1bypass = (val>>4)&1;
+ regs.ctl_ch3bypass = (val>>5)&1;
+ regs.masteren = (val>>7)&1;
+ for(int i=0;i<16;i++)
+ KeyProbe(i);
+ break;
+ case 0x502: break; //not used
+ case 0x503: break; //not used
+
+ //SOUNDBIAS
+ case 0x504: SETBYTE(0,regs.soundbias, val); break;
+ case 0x505: SETBYTE(1,regs.soundbias, val&3); break;
+ case 0x506: break; //these dont answer anyway
+ case 0x507: break; //these dont answer anyway
+
+ //SNDCAP0CNT/SNDCAP1CNT
+ case 0x508:
+ case 0x509: {
+ uint32_t which = addr-0x508;
+ regs.cap[which].add = static_cast<uint8_t>(BIT0(val));
+ regs.cap[which].source = static_cast<uint8_t>(BIT1(val));
+ regs.cap[which].oneshot = static_cast<uint8_t>(BIT2(val));
+ regs.cap[which].bits8 = static_cast<uint8_t>(BIT3(val));
+ regs.cap[which].active = static_cast<uint8_t>(BIT7(val));
+ ProbeCapture(which);
+ break;
+ }
+
+ //SNDCAP0DAD
+ case 0x510: SETBYTE(0,regs.cap[0].dad,val); break;
+ case 0x511: SETBYTE(1,regs.cap[0].dad,val); break;
+ case 0x512: SETBYTE(2,regs.cap[0].dad,val); break;
+ case 0x513: SETBYTE(3,regs.cap[0].dad,val&7); break;
+
+ //SNDCAP0LEN
+ case 0x514: SETBYTE(0,regs.cap[0].len,val); break;
+ case 0x515: SETBYTE(1,regs.cap[0].len,val); break;
+ case 0x516: break; //not used
+ case 0x517: break; //not used
+
+ //SNDCAP1DAD
+ case 0x518: SETBYTE(0,regs.cap[1].dad,val); break;
+ case 0x519: SETBYTE(1,regs.cap[1].dad,val); break;
+ case 0x51A: SETBYTE(2,regs.cap[1].dad,val); break;
+ case 0x51B: SETBYTE(3,regs.cap[1].dad,val&7); break;
+
+ //SNDCAP1LEN
+ case 0x51C: SETBYTE(0,regs.cap[1].len,val); break;
+ case 0x51D: SETBYTE(1,regs.cap[1].len,val); break;
+ case 0x51E: break; //not used
+ case 0x51F: break; //not used
+
+
+
+ default: {
+ //individual channel regs
+
+ uint32_t chan_num = (addr >> 4) & 0xF;
+ if(chan_num>0xF) break;
+ channel_struct &thischan=channels[chan_num];
+
+ switch(addr & 0xF) {
+ case 0x0:
+ thischan.vol = val & 0x7F;
+ break;
+ case 0x1:
+ thischan.datashift = val & 0x3;
+ if (thischan.datashift == 3)
+ thischan.datashift = 4;
+ thischan.hold = (val >> 7) & 0x1;
+ break;
+ case 0x2:
+ thischan.pan = val & 0x7F;
+ break;
+ case 0x3:
+ thischan.waveduty = val & 0x7;
+ thischan.repeat = (val >> 3) & 0x3;
+ thischan.format = (val >> 5) & 0x3;
+ thischan.keyon = static_cast<uint8_t>(BIT7(val));
+ KeyProbe(chan_num);
+ break;
+ case 0x4: SETBYTE(0,thischan.addr,val); break;
+ case 0x5: SETBYTE(1,thischan.addr,val); break;
+ case 0x6: SETBYTE(2,thischan.addr,val); break;
+ case 0x7: SETBYTE(3,thischan.addr,val&0x7); break; //only 27 bits of this register are used
+ case 0x8:
+ SETBYTE(0,thischan.timer,val);
+ adjust_channel_timer(&thischan);
+ break;
+ case 0x9:
+ SETBYTE(1,thischan.timer,val);
+ adjust_channel_timer(&thischan);
+ break;
+ case 0xA: SETBYTE(0,thischan.loopstart,val); break;
+ case 0xB: SETBYTE(1,thischan.loopstart,val); break;
+ case 0xC: SETBYTE(0,thischan.length,val); break;
+ case 0xD: SETBYTE(1,thischan.length,val); break;
+ case 0xE: SETBYTE(2,thischan.length,val & 0x3F); break; //only 22 bits of this register are used
+ case 0xF: SETBYTE(3,thischan.length,0); break;
+ } //switch on individual channel regs
+ } //default case
+ } //switch on address
+}
+
+void SPU_WriteByte(uint32_t addr, uint8_t val)
+{
+ //printf("%08X: chan:%02X reg:%02X val:%02X\n",addr,(addr>>4)&0xF,addr&0xF,val);
+ addr &= 0xFFF;
+
+ SPU_core->WriteByte(addr,val);
+ if(SPU_user) SPU_user->WriteByte(addr,val);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void SPU_struct::WriteWord(uint32_t addr, uint16_t val)
+{
+ WriteByte(addr,val&0xFF);
+ WriteByte(addr+1,(val>>8)&0xFF);
+}
+
+void SPU_WriteWord(uint32_t addr, uint16_t val)
+{
+ //printf("%08X: chan:%02X reg:%02X val:%04X\n",addr,(addr>>4)&0xF,addr&0xF,val);
+ addr &= 0xFFF;
+
+ SPU_core->WriteWord(addr,val);
+ if(SPU_user) SPU_user->WriteWord(addr,val);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void SPU_struct::WriteLong(uint32_t addr, uint32_t val)
+{
+ WriteByte(addr,val&0xFF);
+ WriteByte(addr+1,(val>>8)&0xFF);
+ WriteByte(addr+2,(val>>16)&0xFF);
+ WriteByte(addr+3,(val>>24)&0xFF);
+}
+
+void SPU_WriteLong(uint32_t addr, uint32_t val)
+{
+ //printf("%08X: chan:%02X reg:%02X val:%08X\n",addr,(addr>>4)&0xF,addr&0xF,val);
+ addr &= 0xFFF;
+
+ SPU_core->WriteLong(addr,val);
+ if(SPU_user) SPU_user->WriteLong(addr,val);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template<SPUInterpolationMode INTERPOLATE_MODE> static inline int32_t Interpolate(int32_t a, int32_t b, double ratio)
+{
+ double sampleA = (double)a;
+ double sampleB = (double)b;
+ ratio = ratio - u32floor(ratio);
+
+ switch (INTERPOLATE_MODE)
+ {
+ case SPUInterpolation_Cosine:
+ // Cosine Interpolation Formula:
+ // ratio2 = (1 - cos(ratio * M_PI)) / 2
+ // sampleI = sampleA * (1 - ratio2) + sampleB * ratio2
+ return s32floor((cos_lut[(unsigned int)(ratio * (double)COSINE_INTERPOLATION_RESOLUTION)] * (sampleB - sampleA)) + sampleA);
+ break;
+
+ case SPUInterpolation_Linear:
+ // Linear Interpolation Formula:
+ // sampleI = sampleA * (1 - ratio) + sampleB * ratio
+ return s32floor((ratio * (sampleB - sampleA)) + sampleA);
+ break;
+
+ default:
+ break;
+ }
+
+ return a;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template<SPUInterpolationMode INTERPOLATE_MODE> static inline void Fetch8BitData(channel_struct *chan, int32_t *data)
+{
+ if (chan->sampcnt < 0)
+ {
+ *data = 0;
+ return;
+ }
+
+ uint32_t loc = u32floor(chan->sampcnt);
+ if(INTERPOLATE_MODE != SPUInterpolation_None)
+ {
+ int32_t a = (int32_t)(chan->buf8[loc] << 8);
+ if(loc < (chan->totlength << 2) - 1) {
+ int32_t b = (int32_t)(chan->buf8[loc + 1] << 8);
+ a = Interpolate<INTERPOLATE_MODE>(a, b, chan->sampcnt);
+ }
+ *data = a;
+ }
+ else
+ *data = (int32_t)chan->buf8[loc] << 8;
+}
+
+template<SPUInterpolationMode INTERPOLATE_MODE> static inline void Fetch16BitData(const channel_struct * const chan, int32_t *data)
+{
+ if (chan->sampcnt < 0)
+ {
+ *data = 0;
+ return;
+ }
+
+ if(INTERPOLATE_MODE != SPUInterpolation_None)
+ {
+ uint32_t loc = u32floor(chan->sampcnt);
+ int32_t a = (int32_t)chan->buf16[loc], b;
+ if(loc < (chan->totlength << 1) - 1)
+ {
+ b = (int32_t)chan->buf16[loc + 1];
+ a = Interpolate<INTERPOLATE_MODE>(a, b, chan->sampcnt);
+ }
+ *data = a;
+ }
+ else
+ *data = (int32_t)chan->buf16[u32floor(chan->sampcnt)];
+}
+
+template<SPUInterpolationMode INTERPOLATE_MODE> static inline void FetchADPCMData(channel_struct * const chan, int32_t * const data)
+{
+ if (chan->sampcnt < 8)
+ {
+ *data = 0;
+ return;
+ }
+
+ // No sense decoding, just return the last sample
+ if (chan->lastsampcnt != u32floor(chan->sampcnt)){
+
+ const uint32_t endExclusive = u32floor(chan->sampcnt+1);
+ for (uint32_t i = chan->lastsampcnt+1; i < endExclusive; i++)
+ {
+ const uint32_t shift = (i&1)<<2;
+ const uint32_t data4bit = (((uint32_t)chan->buf8[i >> 1]) >> shift);
+
+ const int32_t diff = precalcdifftbl[chan->index][data4bit & 0xF];
+ chan->index = precalcindextbl[chan->index][data4bit & 0x7];
+
+ chan->pcm16b_last = chan->pcm16b;
+ chan->pcm16b = static_cast<int16_t>(MinMax<int32_t>(chan->pcm16b+diff, -0x8000, 0x7FFF));
+
+ if(i == static_cast<uint32_t>(chan->loopstart<<3)) {
+ if(chan->loop_index != K_ADPCM_LOOPING_RECOVERY_INDEX) printf("over-snagging\n");
+ chan->loop_pcm16b = chan->pcm16b;
+ chan->loop_index = chan->index;
+ }
+ }
+
+ chan->lastsampcnt = u32floor(chan->sampcnt);
+ }
+
+ if(INTERPOLATE_MODE != SPUInterpolation_None)
+ *data = Interpolate<INTERPOLATE_MODE>((int32_t)chan->pcm16b_last,(int32_t)chan->pcm16b,chan->sampcnt);
+ else
+ *data = (int32_t)chan->pcm16b;
+}
+
+static inline void FetchPSGData(channel_struct *chan, int32_t *data)
+{
+ if (chan->sampcnt < 0)
+ {
+ *data = 0;
+ return;
+ }
+
+ if(chan->num < 8)
+ {
+ *data = 0;
+ }
+ else if(chan->num < 14)
+ {
+ *data = (int32_t)wavedutytbl[chan->waveduty][(u32floor(chan->sampcnt)) & 0x7];
+ }
+ else
+ {
+ if(chan->lastsampcnt == u32floor(chan->sampcnt))
+ {
+ *data = (int32_t)chan->psgnoise_last;
+ return;
+ }
+
+ uint32_t max = u32floor(chan->sampcnt);
+ for(uint32_t i = chan->lastsampcnt; i < max; i++)
+ {
+ if(chan->x & 0x1)
+ {
+ chan->x = (chan->x >> 1) ^ 0x6000;
+ chan->psgnoise_last = -0x7FFF;
+ }
+ else
+ {
+ chan->x >>= 1;
+ chan->psgnoise_last = 0x7FFF;
+ }
+ }
+
+ chan->lastsampcnt = u32floor(chan->sampcnt);
+
+ *data = (int32_t)chan->psgnoise_last;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static inline void MixL(SPU_struct* SPU, channel_struct *chan, int32_t data)
+{
+ data = spumuldiv7(data, chan->vol) >> chan->datashift;
+ SPU->sndbuf[SPU->bufpos<<1] += data;
+}
+
+static inline void MixR(SPU_struct* SPU, channel_struct *chan, int32_t data)
+{
+ data = spumuldiv7(data, chan->vol) >> chan->datashift;
+ SPU->sndbuf[(SPU->bufpos<<1)+1] += data;
+}
+
+static inline void MixLR(SPU_struct* SPU, channel_struct *chan, int32_t data)
+{
+ data = spumuldiv7(data, chan->vol) >> chan->datashift;
+ SPU->sndbuf[SPU->bufpos<<1] += spumuldiv7(data, 127 - chan->pan);
+ SPU->sndbuf[(SPU->bufpos<<1)+1] += spumuldiv7(data, chan->pan);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template<int FORMAT> static inline void TestForLoop(SPU_struct *SPU, channel_struct *chan)
+{
+ const int shift = (FORMAT == 0 ? 2 : 1);
+
+ chan->sampcnt += chan->sampinc;
+
+ if (chan->sampcnt > chan->double_totlength_shifted)
+ {
+ // Do we loop? Or are we done?
+ if (chan->repeat == 1)
+ {
+ while (chan->sampcnt > chan->double_totlength_shifted)
+ chan->sampcnt -= chan->double_totlength_shifted - (double)(chan->loopstart << shift);
+ //chan->sampcnt = (double)(chan->loopstart << shift);
+ }
+ else
+ {
+ SPU->KeyOff(chan->num);
+ SPU->bufpos = SPU->buflength;
+ }
+ }
+}
+
+static inline void TestForLoop2(SPU_struct *SPU, channel_struct *chan)
+{
+ chan->sampcnt += chan->sampinc;
+
+ if (chan->sampcnt > chan->double_totlength_shifted)
+ {
+ // Do we loop? Or are we done?
+ if (chan->repeat == 1)
+ {
+ while (chan->sampcnt > chan->double_totlength_shifted)
+ chan->sampcnt -= chan->double_totlength_shifted - (double)(chan->loopstart << 3);
+
+ if(chan->loop_index == K_ADPCM_LOOPING_RECOVERY_INDEX)
+ {
+ chan->pcm16b = (int16_t)((chan->buf8[1] << 8) | chan->buf8[0]);
+ chan->index = chan->buf8[2] & 0x7F;
+ chan->lastsampcnt = 7;
+ }
+ else
+ {
+ chan->pcm16b = chan->loop_pcm16b;
+ chan->index = chan->loop_index;
+ chan->lastsampcnt = (chan->loopstart << 3);
+ }
+ }
+ else
+ {
+ chan->status = CHANSTAT_STOPPED;
+ SPU->KeyOff(chan->num);
+ SPU->bufpos = SPU->buflength;
+ }
+ }
+}
+
+template<int CHANNELS> inline static void SPU_Mix(SPU_struct* SPU, channel_struct *chan, int32_t data)
+{
+ switch(CHANNELS)
+ {
+ case 0: MixL(SPU, chan, data); break;
+ case 1: MixLR(SPU, chan, data); break;
+ case 2: MixR(SPU, chan, data); break;
+ }
+ SPU->lastdata = data;
+}
+
+//WORK
+template<int FORMAT, SPUInterpolationMode INTERPOLATE_MODE, int CHANNELS>
+ inline static void ____SPU_ChanUpdate(SPU_struct* const SPU, channel_struct* const chan)
+{
+ for (; SPU->bufpos < SPU->buflength; SPU->bufpos++)
+ {
+ if(CHANNELS != -1)
+ {
+ int32_t data;
+ switch(FORMAT)
+ {
+ case 0: Fetch8BitData<INTERPOLATE_MODE>(chan, &data); break;
+ case 1: Fetch16BitData<INTERPOLATE_MODE>(chan, &data); break;
+ case 2: FetchADPCMData<INTERPOLATE_MODE>(chan, &data); break;
+ case 3: FetchPSGData(chan, &data); break;
+ }
+ SPU_Mix<CHANNELS>(SPU, chan, data);
+ }
+
+ switch(FORMAT) {
+ case 0: case 1: TestForLoop<FORMAT>(SPU, chan); break;
+ case 2: TestForLoop2(SPU, chan); break;
+ case 3: chan->sampcnt += chan->sampinc; break;
+ }
+ }
+}
+
+template<int FORMAT, SPUInterpolationMode INTERPOLATE_MODE>
+ inline static void ___SPU_ChanUpdate(const bool actuallyMix, SPU_struct* const SPU, channel_struct* const chan)
+{
+ if(!actuallyMix)
+ ____SPU_ChanUpdate<FORMAT,INTERPOLATE_MODE,-1>(SPU,chan);
+ else if (chan->pan == 0)
+ ____SPU_ChanUpdate<FORMAT,INTERPOLATE_MODE,0>(SPU,chan);
+ else if (chan->pan == 127)
+ ____SPU_ChanUpdate<FORMAT,INTERPOLATE_MODE,2>(SPU,chan);
+ else
+ ____SPU_ChanUpdate<FORMAT,INTERPOLATE_MODE,1>(SPU,chan);
+}
+
+template<SPUInterpolationMode INTERPOLATE_MODE>
+ inline static void __SPU_ChanUpdate(const bool actuallyMix, SPU_struct* const SPU, channel_struct* const chan)
+{
+ switch(chan->format)
+ {
+ case 0: ___SPU_ChanUpdate<0,INTERPOLATE_MODE>(actuallyMix, SPU, chan); break;
+ case 1: ___SPU_ChanUpdate<1,INTERPOLATE_MODE>(actuallyMix, SPU, chan); break;
+ case 2: ___SPU_ChanUpdate<2,INTERPOLATE_MODE>(actuallyMix, SPU, chan); break;
+ case 3: ___SPU_ChanUpdate<3,INTERPOLATE_MODE>(actuallyMix, SPU, chan); break;
+ default: assert(false);
+ }
+}
+
+inline static void _SPU_ChanUpdate(const bool actuallyMix, SPU_struct* const SPU, channel_struct* const chan)
+{
+ switch(CommonSettings.spuInterpolationMode)
+ {
+ case SPUInterpolation_None: __SPU_ChanUpdate<SPUInterpolation_None>(actuallyMix, SPU, chan); break;
+ case SPUInterpolation_Linear: __SPU_ChanUpdate<SPUInterpolation_Linear>(actuallyMix, SPU, chan); break;
+ case SPUInterpolation_Cosine: __SPU_ChanUpdate<SPUInterpolation_Cosine>(actuallyMix, SPU, chan); break;
+ default: assert(false);
+ }
+}
+
+//ENTERNEW
+static void SPU_MixAudio_Advanced(bool, SPU_struct *SPU, int length)
+{
+ //the advanced spu function correctly handles all sound control mixing options, as well as capture
+ //this code is not entirely optimal, as it relies on sort of manhandling the core mixing functions
+ //in order to get the results it needs.
+
+ //THIS IS MAX HACKS!!!!
+ //AND NEEDS TO BE REWRITTEN ALONG WITH THE DEEPEST PARTS OF THE SPU
+ //ONCE WE KNOW THAT IT WORKS
+
+ //BIAS gets ignored since our spu is still not bit perfect,
+ //and it doesnt matter for purposes of capture
+
+ //-----------DEBUG CODE
+ bool skipcap = false;
+ //-----------------
+
+ int32_t samp0[2] = {0,0};
+
+ //believe it or not, we are going to do this one sample at a time.
+ //like i said, it is slower.
+ for(int samp=0;samp<length;samp++)
+ {
+ SPU->sndbuf[0] = 0;
+ SPU->sndbuf[1] = 0;
+ SPU->buflength = 1;
+
+ int32_t capmix[2] = {0,0};
+ int32_t mix[2] = {0,0};
+ int32_t chanout[16];
+ int32_t submix[32];
+
+ //generate each channel, and helpfully mix it at the same time
+ for(int i=0;i<16;i++)
+ {
+ channel_struct *chan = &SPU->channels[i];
+
+ if (chan->status == CHANSTAT_PLAY)
+ {
+ SPU->bufpos = 0;
+
+ bool bypass = false;
+ if(i==1 && SPU->regs.ctl_ch1bypass) bypass=true;
+ if(i==3 && SPU->regs.ctl_ch3bypass) bypass=true;
+
+
+ //output to mixer unless we are bypassed.
+ //dont output to mixer if the user muted us
+ bool outputToMix = true;
+ if(CommonSettings.spu_muteChannels[i]) outputToMix = false;
+ if(bypass) outputToMix = false;
+ bool outputToCap = outputToMix;
+ if(CommonSettings.spu_captureMuted && !bypass) outputToCap = true;
+
+ //channels 1 and 3 should probably always generate their audio
+ //internally at least, just in case they get used by the spu output
+ bool domix = outputToCap || outputToMix || i==1 || i==3;
+
+ //clear the output buffer since this is where _SPU_ChanUpdate wants to accumulate things
+ SPU->sndbuf[0] = SPU->sndbuf[1] = 0;
+
+ //get channel's next output sample.
+ _SPU_ChanUpdate(domix, SPU, chan);
+ chanout[i] = SPU->lastdata >> chan->datashift;
+
+ //save the panned results
+ submix[i*2] = SPU->sndbuf[0];
+ submix[i*2+1] = SPU->sndbuf[1];
+
+ //send sample to our capture mix
+ if(outputToCap)
+ {
+ capmix[0] += submix[i*2];
+ capmix[1] += submix[i*2+1];
+ }
+
+ //send sample to our main mixer
+ if(outputToMix)
+ {
+ mix[0] += submix[i*2];
+ mix[1] += submix[i*2+1];
+ }
+ }
+ else
+ {
+ chanout[i] = 0;
+ submix[i*2] = 0;
+ submix[i*2+1] = 0;
+ }
+ } //foreach channel
+
+ int32_t mixout[2] = {mix[0],mix[1]};
+ int32_t capmixout[2] = {capmix[0],capmix[1]};
+ int32_t sndout[2] = {0,0};
+ int32_t capout[2];
+
+ //create SPU output
+ switch(SPU->regs.ctl_left)
+ {
+ case SPU_struct::REGS::LOM_LEFT_MIXER: sndout[0] = mixout[0]; break;
+ case SPU_struct::REGS::LOM_CH1: sndout[0] = submix[1*2+0]; break;
+ case SPU_struct::REGS::LOM_CH3: sndout[0] = submix[3*2+0]; break;
+ case SPU_struct::REGS::LOM_CH1_PLUS_CH3: sndout[0] = submix[1*2+0] + submix[3*2+0]; break;
+ }
+ switch(SPU->regs.ctl_right)
+ {
+ case SPU_struct::REGS::ROM_RIGHT_MIXER: sndout[1] = mixout[1]; break;
+ case SPU_struct::REGS::ROM_CH1: sndout[1] = submix[1*2+1]; break;
+ case SPU_struct::REGS::ROM_CH3: sndout[1] = submix[3*2+1]; break;
+ case SPU_struct::REGS::ROM_CH1_PLUS_CH3: sndout[1] = submix[1*2+1] + submix[3*2+1]; break;
+ }
+
+
+ //generate capture output ("capture bugs" from gbatek are not emulated)
+ if(SPU->regs.cap[0].source==0)
+ capout[0] = capmixout[0]; //cap0 = L-mix
+ else if(SPU->regs.cap[0].add)
+ capout[0] = chanout[0] + chanout[1]; //cap0 = ch0+ch1
+ else capout[0] = chanout[0]; //cap0 = ch0
+
+ if(SPU->regs.cap[1].source==0)
+ capout[1] = capmixout[1]; //cap1 = R-mix
+ else if(SPU->regs.cap[1].add)
+ capout[1] = chanout[2] + chanout[3]; //cap1 = ch2+ch3
+ else capout[1] = chanout[2]; //cap1 = ch2
+
+ capout[0] = MinMax<int32_t>(capout[0],-0x8000,0x7FFF);
+ capout[1] = MinMax<int32_t>(capout[1],-0x8000,0x7FFF);
+
+ //write the output sample where it is supposed to go
+ if(samp==0)
+ {
+ samp0[0] = sndout[0];
+ samp0[1] = sndout[1];
+ }
+ else
+ {
+ SPU->sndbuf[samp*2+0] = sndout[0];
+ SPU->sndbuf[samp*2+1] = sndout[1];
+ }
+
+ for(int capchan=0;capchan<2;capchan++)
+ {
+ if(SPU->regs.cap[capchan].runtime.running)
+ {
+ SPU_struct::REGS::CAP& cap = SPU->regs.cap[capchan];
+ uint32_t last = u32floor(cap.runtime.sampcnt);
+ cap.runtime.sampcnt += SPU->channels[1+2*capchan].sampinc;
+ uint32_t curr = u32floor(cap.runtime.sampcnt);
+ for(uint32_t j=last;j<curr;j++)
+ {
+ //so, this is a little strange. why go through a fifo?
+ //it seems that some games will set up a reverb effect by capturing
+ //to the nearly same address as playback, but ahead by a couple.
+ //So, playback will always end up being what was captured a couple of samples ago.
+ //This system counts on playback always having read ahead 16 samples.
+ //In that case, playback will end up being what was processed at one entire buffer length ago,
+ //since the 16 samples would have read ahead before they got captured over
+
+ //It's actually the source channels which should have a fifo, but we are
+ //not going to take the hit in speed and complexity. Save it for a future rewrite.
+ //Instead, what we do here is delay the capture by 16 samples to create a similar effect.
+ //Subjectively, it seems to be working.
+
+ //Don't do anything until the fifo is filled, so as to delay it
+ if(cap.runtime.fifo.size<16)
+ {
+ cap.runtime.fifo.enqueue(static_cast<int16_t>(capout[capchan]));
+ continue;
+ }
+
+ //(actually capture sample from fifo instead of most recently generated)
+ uint32_t multiplier;
+ int32_t sample = cap.runtime.fifo.dequeue();
+ cap.runtime.fifo.enqueue(static_cast<int16_t>(capout[capchan]));
+
+ //static FILE* fp = NULL;
+ //if(!fp) fp = fopen("d:\\capout.raw","wb");
+ //fwrite(&sample,2,1,fp);
+
+ if(cap.bits8)
+ {
+ int8_t sample8 = static_cast<int8_t>(sample>>8);
+ if(skipcap) _MMU_write08<1,MMU_AT_DMA>(cap.runtime.curdad,0);
+ else _MMU_write08<1,MMU_AT_DMA>(cap.runtime.curdad,sample8);
+ cap.runtime.curdad++;
+ multiplier = 4;
+ }
+ else
+ {
+ int16_t sample16 = static_cast<int16_t>(sample);
+ if(skipcap) _MMU_write16<1,MMU_AT_DMA>(cap.runtime.curdad,0);
+ else _MMU_write16<1,MMU_AT_DMA>(cap.runtime.curdad,sample16);
+ cap.runtime.curdad+=2;
+ multiplier = 2;
+ }
+
+ if(cap.runtime.curdad>=cap.runtime.maxdad) {
+ cap.runtime.curdad = cap.dad;
+ cap.runtime.sampcnt -= cap.len*multiplier;
+ }
+ } //sampinc loop
+ } //if capchan running
+ } //capchan loop
+ } //main sample loop
+
+ SPU->sndbuf[0] = samp0[0];
+ SPU->sndbuf[1] = samp0[1];
+}
+
+//ENTER
+static void SPU_MixAudio(bool actuallyMix, SPU_struct *SPU, int length)
+{
+ if(actuallyMix)
+ {
+ memset(SPU->sndbuf, 0, length*4*2);
+ memset(SPU->outbuf, 0, length*2*2);
+ }
+
+ //we used to use master enable here, and do nothing if audio is disabled.
+ //now, master enable is emulated better..
+ //but for a speed optimization we will still do it
+ if(!SPU->regs.masteren) return;
+
+ bool advanced = CommonSettings.spu_advanced ;
+
+ //branch here so that slow computers don't have to take the advanced (slower) codepath.
+ //it remainds to be seen exactly how much slower it is
+ //if it isnt much slower then we should refactor everything to be simpler, once it is working
+ if(advanced && SPU == SPU_core)
+ {
+ SPU_MixAudio_Advanced(actuallyMix, SPU, length);
+ }
+ else
+ {
+ //non-advanced mode
+ for(int i=0;i<16;i++)
+ {
+ channel_struct *chan = &SPU->channels[i];
+
+ if (chan->status != CHANSTAT_PLAY)
+ continue;
+
+ SPU->bufpos = 0;
+ SPU->buflength = length;
+
+ // Mix audio
+ _SPU_ChanUpdate(!CommonSettings.spu_muteChannels[i] && actuallyMix, SPU, chan);
+ }
+ }
+
+ //we used to bail out if speakers were disabled.
+ //this is technically wrong. sound may still be captured, or something.
+ //in all likelihood, any game doing this probably master disabled the SPU also
+ //so, optimization of this case is probably not necessary.
+ //later, we'll just silence the output
+ bool speakers = T1ReadWord(MMU.ARM7_REG, 0x304) & 0x01;
+
+ uint8_t vol = SPU->regs.mastervol;
+
+ // convert from 32-bit->16-bit
+ if(actuallyMix && speakers)
+ for (int i = 0; i < length*2; i++)
+ {
+ // Apply Master Volume
+ SPU->sndbuf[i] = spumuldiv7(SPU->sndbuf[i], vol);
+ int16_t outsample = static_cast<int16_t>(MinMax<int32_t>(SPU->sndbuf[i],-0x8000,0x7FFF));
+ SPU->outbuf[i] = outsample;
+ }
+
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//emulates one hline of the cpu core.
+//this will produce a variable number of samples, calculated to keep a 44100hz output
+//in sync with the emulator framerate
+int spu_core_samples = 0;
+void SPU_Emulate_core()
+{
+ samples += samples_per_hline;
+ spu_core_samples = (int)(samples);
+ samples -= spu_core_samples;
+
+ bool synchronize = (synchmode == ESynchMode_Synchronous);
+ bool mix = /*driver->AVI_IsRecording() || driver->WAV_IsRecording() ||*/ synchronize;
+
+ SPU_MixAudio(mix,SPU_core,spu_core_samples);
+ if(synchronize && SPU_currentCoreNum != SNDCORE_DUMMY)
+ synchronizer->enqueue_samples(SPU_core->outbuf, spu_core_samples);
+}
+
+void SPU_Emulate_user(bool mix)
+{
+ uint32_t audiosize;
+
+ // Check to see how much free space there is
+ // If there is some, fill up the buffer
+ if(!SNDCore) return;
+ audiosize = SNDCore->GetAudioSpace();
+
+ if (audiosize > 0)
+ {
+ //printf("mix %i samples\n", audiosize);
+ if (audiosize > (uint32_t)buffersize)
+ audiosize = buffersize;
+
+ int16_t* outbuf;
+ int samplesOutput;
+ if(synchmode == ESynchMode_Synchronous)
+ {
+ static std::vector<int16_t> tempbuf;
+ if(tempbuf.size() < audiosize*2) tempbuf.resize(audiosize*2);
+ outbuf = &tempbuf[0];
+ samplesOutput = synchronizer->output_samples(outbuf, audiosize);
+ }
+ else if(SPU_user)
+ {
+ outbuf = SPU_user->outbuf;
+ samplesOutput = (SPU_MixAudio(mix,SPU_user,audiosize), audiosize);
+ }
+ else return;
+
+ SNDCore->UpdateAudio(outbuf, samplesOutput);
+ //WAV_WavSoundUpdate(SPU_user->outbuf, samplesOutput, WAVMODE_USER);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Dummy Sound Interface
+//////////////////////////////////////////////////////////////////////////////
+
+int SNDDummyInit(int) { return 0; }
+void SNDDummyDeInit() {}
+void SNDDummyUpdateAudio(int16_t *, uint32_t) { }
+uint32_t SNDDummyGetAudioSpace() { return DESMUME_SAMPLE_RATE/60 + 5; }
+void SNDDummyMuteAudio() {}
+void SNDDummyUnMuteAudio() {}
+void SNDDummySetVolume(int) {}
+
+SoundInterface_struct SNDDummy = {
+ SNDCORE_DUMMY,
+ "Dummy Sound Interface",
+ SNDDummyInit,
+ SNDDummyDeInit,
+ SNDDummyUpdateAudio,
+ SNDDummyGetAudioSpace,
+ SNDDummyMuteAudio,
+ SNDDummyUnMuteAudio,
+ SNDDummySetVolume,
+ NULL
+};
+
+//---------wav writer------------
+
+/*typedef struct {
+ char id[4];
+ uint32_t size;
+} chunk_struct;
+
+typedef struct {
+ chunk_struct riff;
+ char rifftype[4];
+} waveheader_struct;
+
+typedef struct {
+ chunk_struct chunk;
+ uint16_t compress;
+ uint16_t numchan;
+ uint32_t rate;
+ uint32_t bytespersec;
+ uint16_t blockalign;
+ uint16_t bitspersample;
+} fmt_struct;
+
+WavWriter::WavWriter()
+: spufp(NULL)
+{
+}
+bool WavWriter::open(const std::string & fname)
+{
+ waveheader_struct waveheader;
+ fmt_struct fmt;
+ chunk_struct data;
+ size_t elems_written = 0;
+
+ if ((spufp = fopen(fname.c_str(), "wb")) == NULL)
+ return false;
+
+ // Do wave header
+ memcpy(waveheader.riff.id, "RIFF", 4);
+ waveheader.riff.size = 0; // we'll fix this after the file is closed
+ memcpy(waveheader.rifftype, "WAVE", 4);
+ elems_written += fwrite((void *)&waveheader, 1, sizeof(waveheader_struct), spufp);
+
+ // fmt chunk
+ memcpy(fmt.chunk.id, "fmt ", 4);
+ fmt.chunk.size = 16; // we'll fix this at the end
+ fmt.compress = 1; // PCM
+ fmt.numchan = 2; // Stereo
+ fmt.rate = DESMUME_SAMPLE_RATE;
+ fmt.bitspersample = 16;
+ fmt.blockalign = fmt.bitspersample / 8 * fmt.numchan;
+ fmt.bytespersec = fmt.rate * fmt.blockalign;
+ elems_written += fwrite((void *)&fmt, 1, sizeof(fmt_struct), spufp);
+
+ // data chunk
+ memcpy(data.id, "data", 4);
+ data.size = 0; // we'll fix this at the end
+ elems_written += fwrite((void *)&data, 1, sizeof(chunk_struct), spufp);
+
+ return true;
+}
+
+void WavWriter::close()
+{
+ if(!spufp) return;
+ size_t elems_written = 0;
+ long length = ftell(spufp);
+
+ // Let's fix the riff chunk size and the data chunk size
+ fseek(spufp, sizeof(waveheader_struct)-0x8, SEEK_SET);
+ length -= 0x8;
+ elems_written += fwrite((void *)&length, 1, 4, spufp);
+
+ fseek(spufp, sizeof(waveheader_struct)+sizeof(fmt_struct)+0x4, SEEK_SET);
+ length -= sizeof(waveheader_struct)+sizeof(fmt_struct);
+ elems_written += fwrite((void *)&length, 1, 4, spufp);
+ fclose(spufp);
+ spufp = NULL;
+}
+
+void WavWriter::update(void* soundData, int numSamples)
+{
+ if(!spufp) return;
+ //TODO - big endian for the int16_t samples??*/
+ /*size_t elems_written = *//*fwrite(soundData, numSamples*2, 2, spufp);
+}
+
+bool WavWriter::isRecording() const
+{
+ return spufp != NULL;
+}*/
+
+
+//static WavWriter wavWriter;
+
+/*void WAV_End()
+{
+ wavWriter.close();
+}*/
+
+/*bool WAV_Begin(const char* fname, WAVMode mode)
+{
+ WAV_End();
+
+ if(!wavWriter.open(fname))
+ return false;
+
+ if(mode == WAVMODE_ANY)
+ mode = WAVMODE_CORE;
+ wavWriter.mode = mode;
+
+ driver->USR_InfoMessage("WAV recording started.");
+
+ return true;
+}*/
+
+/*bool WAV_IsRecording(WAVMode mode)
+{
+ if(wavWriter.mode == mode || mode == WAVMODE_ANY)
+ return wavWriter.isRecording();
+ return false;
+}*/
+
+/*void WAV_WavSoundUpdate(void* soundData, int numSamples, WAVMode mode)
+{
+ if(wavWriter.mode == mode || mode == WAVMODE_ANY)
+ wavWriter.update(soundData, numSamples);
+}*/
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*void spu_savestate(EMUFILE* os)
+{
+ //version
+ write32le(6,os);
+
+ SPU_struct *spu = SPU_core;
+
+ for(int j=0;j<16;j++) {
+ channel_struct &chan = spu->channels[j];
+ write32le(chan.num,os);
+ write8le(chan.vol,os);
+ write8le(chan.datashift,os);
+ write8le(chan.hold,os);
+ write8le(chan.pan,os);
+ write8le(chan.waveduty,os);
+ write8le(chan.repeat,os);
+ write8le(chan.format,os);
+ write8le(chan.status,os);
+ write32le(chan.addr,os);
+ write16le(chan.timer,os);
+ write16le(chan.loopstart,os);
+ write32le(chan.length,os);
+ write64le(double_to_u64(chan.sampcnt),os);
+ write64le(double_to_u64(chan.sampinc),os);
+ write32le(chan.lastsampcnt,os);
+ write16le(chan.pcm16b,os);
+ write16le(chan.pcm16b_last,os);
+ write32le(chan.index,os);
+ write16le(chan.x,os);
+ write16le(chan.psgnoise_last,os);
+ write8le(chan.keyon,os);
+ }
+
+ write64le(double_to_u64(samples),os);
+
+ write8le(spu->regs.mastervol,os);
+ write8le(spu->regs.ctl_left,os);
+ write8le(spu->regs.ctl_right,os);
+ write8le(spu->regs.ctl_ch1bypass,os);
+ write8le(spu->regs.ctl_ch3bypass,os);
+ write8le(spu->regs.masteren,os);
+ write16le(spu->regs.soundbias,os);
+
+ for(int i=0;i<2;i++)
+ {
+ write8le(spu->regs.cap[i].add,os);
+ write8le(spu->regs.cap[i].source,os);
+ write8le(spu->regs.cap[i].oneshot,os);
+ write8le(spu->regs.cap[i].bits8,os);
+ write8le(spu->regs.cap[i].active,os);
+ write32le(spu->regs.cap[i].dad,os);
+ write16le(spu->regs.cap[i].len,os);
+ write8le(spu->regs.cap[i].runtime.running,os);
+ write32le(spu->regs.cap[i].runtime.curdad,os);
+ write32le(spu->regs.cap[i].runtime.maxdad,os);
+ write_double_le(spu->regs.cap[i].runtime.sampcnt,os);
+ }
+
+ for(int i=0;i<2;i++)
+ spu->regs.cap[i].runtime.fifo.save(os);
+}*/
+
+bool spu_loadstate(EMUFILE* is, int)
+{
+ uint64_t temp64;
+
+ //read version
+ uint32_t version;
+ if(read32le(&version,is) != 1) return false;
+
+ SPU_struct *spu = SPU_core;
+ reconstruct(&SPU_core->regs);
+
+ for(int j=0;j<16;j++) {
+ channel_struct &chan = spu->channels[j];
+ read32le(&chan.num,is);
+ read8le(&chan.vol,is);
+ read8le(&chan.datashift,is);
+ read8le(&chan.hold,is);
+ read8le(&chan.pan,is);
+ read8le(&chan.waveduty,is);
+ read8le(&chan.repeat,is);
+ read8le(&chan.format,is);
+ read8le(&chan.status,is);
+ read32le(&chan.addr,is);
+ read16le(&chan.timer,is);
+ read16le(&chan.loopstart,is);
+ read32le(&chan.length,is);
+ chan.totlength = chan.length + chan.loopstart;
+ chan.double_totlength_shifted = (double)(chan.totlength << format_shift[chan.format]);
+ //printf("%f\n",chan.double_totlength_shifted);
+ if(version >= 2)
+ {
+ read64le(&temp64,is); chan.sampcnt = u64_to_double(temp64);
+ read64le(&temp64,is); chan.sampinc = u64_to_double(temp64);
+ }
+ else
+ {
+ read32le((uint32_t*)&chan.sampcnt,is);
+ read32le((uint32_t*)&chan.sampinc,is);
+ }
+ read32le(&chan.lastsampcnt,is);
+ read16le(&chan.pcm16b,is);
+ read16le(&chan.pcm16b_last,is);
+ read32le(&chan.index,is);
+ read16le(&chan.x,is);
+ read16le(&chan.psgnoise_last,is);
+
+ if(version>=4)
+ read8le(&chan.keyon,is);
+
+ //hopefully trigger a recovery of the adpcm looping system
+ chan.loop_index = K_ADPCM_LOOPING_RECOVERY_INDEX;
+
+ //fixup the pointers which we had are supposed to keep cached
+ chan.buf8 = (int8_t*)&MMU.MMU_MEM[1][(chan.addr>>20)&0xFF][(chan.addr & MMU.MMU_MASK[1][(chan.addr >> 20) & 0xFF])];
+ chan.buf16 = (int16_t*)chan.buf8;
+ }
+
+ if(version>=2) {
+ read64le(&temp64,is); samples = u64_to_double(temp64);
+ }
+
+ if(version>=4)
+ {
+ read8le(&spu->regs.mastervol,is);
+ read8le(&spu->regs.ctl_left,is);
+ read8le(&spu->regs.ctl_right,is);
+ read8le(&spu->regs.ctl_ch1bypass,is);
+ read8le(&spu->regs.ctl_ch3bypass,is);
+ read8le(&spu->regs.masteren,is);
+ read16le(&spu->regs.soundbias,is);
+ }
+
+ if(version>=5)
+ {
+ for(int i=0;i<2;i++)
+ {
+ read8le(&spu->regs.cap[i].add,is);
+ read8le(&spu->regs.cap[i].source,is);
+ read8le(&spu->regs.cap[i].oneshot,is);
+ read8le(&spu->regs.cap[i].bits8,is);
+ read8le(&spu->regs.cap[i].active,is);
+ read32le(&spu->regs.cap[i].dad,is);
+ read16le(&spu->regs.cap[i].len,is);
+ read8le(&spu->regs.cap[i].runtime.running,is);
+ read32le(&spu->regs.cap[i].runtime.curdad,is);
+ read32le(&spu->regs.cap[i].runtime.maxdad,is);
+ read_double_le(&spu->regs.cap[i].runtime.sampcnt,is);
+ }
+ }
+
+ if(version>=6)
+ for(int i=0;i<2;i++) spu->regs.cap[i].runtime.fifo.load(is);
+ else
+ for(int i=0;i<2;i++) spu->regs.cap[i].runtime.fifo.reset();
+
+ //older versions didnt store a mastervol;
+ //we must reload this or else games will start silent
+ if(version<4)
+ {
+ spu->regs.mastervol = T1ReadByte(MMU.ARM7_REG, 0x500) & 0x7F;
+ spu->regs.masteren = static_cast<uint8_t>(BIT15(T1ReadWord(MMU.ARM7_REG, 0x500)));
+ }
+
+ //copy the core spu (the more accurate) to the user spu
+ SPU_CloneUser();
+
+ return true;
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/SPU.h
@@ -1,1 +1,255 @@
-
+/*
+ Copyright 2006 Theo Berkau
+ Copyright (C) 2006-2010 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SPU_H
+#define SPU_H
+
+#include <iosfwd>
+#include <string>
+#include <cassert>
+
+#include "types.h"
+#include "matrix.h"
+#include "emufile.h"
+
+#include "metaspu/metaspu.h"
+
+#define SNDCORE_DEFAULT -1
+#define SNDCORE_DUMMY 0
+
+#define CHANSTAT_STOPPED 0
+#define CHANSTAT_PLAY 1
+
+//who made these static? theyre used in multiple places.
+//inline uint32_t sputrunc(float f) { return u32floor(f); }
+//inline uint32_t sputrunc(double d) { return u32floor(d); }
+inline int32_t spumuldiv7(int32_t val, uint8_t multiplier) {
+ assert(multiplier <= 127);
+ return multiplier == 127 ? val : ((val * multiplier) >> 7);
+}
+
+enum SPUInterpolationMode
+{
+ SPUInterpolation_None = 0,
+ SPUInterpolation_Linear = 1,
+ SPUInterpolation_Cosine = 2
+};
+
+struct SoundInterface_struct
+{
+ int id;
+ const char *Name;
+ int (*Init)(int buffersize);
+ void (*DeInit)();
+ void (*UpdateAudio)(int16_t *buffer, uint32_t num_samples);
+ uint32_t (*GetAudioSpace)();
+ void (*MuteAudio)();
+ void (*UnMuteAudio)();
+ void (*SetVolume)(int volume);
+ void (*ClearBuffer)();
+};
+
+extern SoundInterface_struct SNDDummy;
+extern SoundInterface_struct SNDFile;
+extern int SPU_currentCoreNum;
+
+struct channel_struct
+{
+ channel_struct()
+ {}
+ uint32_t num;
+ uint8_t vol;
+ uint8_t datashift;
+ uint8_t hold;
+ uint8_t pan;
+ uint8_t waveduty;
+ uint8_t repeat;
+ uint8_t format;
+ uint8_t keyon;
+ uint8_t status;
+ uint32_t addr;
+ uint16_t timer;
+ uint16_t loopstart;
+ uint32_t length;
+ uint32_t totlength;
+ double double_totlength_shifted;
+ union {
+ int8_t *buf8;
+ int16_t *buf16;
+ };
+ double sampcnt;
+ double sampinc;
+ // ADPCM specific
+ uint32_t lastsampcnt;
+ int16_t pcm16b, pcm16b_last;
+ int16_t loop_pcm16b;
+ int32_t index;
+ int loop_index;
+ uint16_t x;
+ int16_t psgnoise_last;
+};
+
+class SPUFifo
+{
+public:
+ SPUFifo();
+ void enqueue(int16_t val);
+ int16_t dequeue();
+ int16_t buffer[16];
+ int32_t head,tail,size;
+ //void save(EMUFILE* fp);
+ bool load(EMUFILE* fp);
+ void reset();
+};
+
+class SPU_struct
+{
+public:
+ SPU_struct(int buffersize);
+ uint32_t bufpos;
+ uint32_t buflength;
+ int32_t *sndbuf;
+ int32_t lastdata; //the last sample that a channel generated
+ int16_t *outbuf;
+ uint32_t bufsize;
+ channel_struct channels[16];
+
+ //registers
+ struct REGS {
+ REGS()
+ : mastervol(0)
+ , ctl_left(0)
+ , ctl_right(0)
+ , ctl_ch1bypass(0)
+ , ctl_ch3bypass(0)
+ , masteren(0)
+ , soundbias(0)
+ {}
+
+ uint8_t mastervol;
+ uint8_t ctl_left, ctl_right;
+ uint8_t ctl_ch1bypass, ctl_ch3bypass;
+ uint8_t masteren;
+ uint16_t soundbias;
+
+ enum LeftOutputMode
+ {
+ LOM_LEFT_MIXER=0, LOM_CH1=1, LOM_CH3=2, LOM_CH1_PLUS_CH3=3
+ };
+
+ enum RightOutputMode
+ {
+ ROM_RIGHT_MIXER=0, ROM_CH1=1, ROM_CH3=2, ROM_CH1_PLUS_CH3=3
+ };
+
+ struct CAP {
+ CAP()
+ : add(0), source(0), oneshot(0), bits8(0), active(0), dad(0), len(0)
+ {}
+ uint8_t add, source, oneshot, bits8, active;
+ uint32_t dad;
+ uint16_t len;
+ struct Runtime {
+ Runtime()
+ : running(0), curdad(0), maxdad(0)
+ {}
+ uint8_t running;
+ uint32_t curdad;
+ uint32_t maxdad;
+ double sampcnt;
+ SPUFifo fifo;
+ } runtime;
+ } cap[2];
+ } regs;
+
+ void reset();
+ ~SPU_struct();
+ void KeyOff(int channel);
+ void KeyOn(int channel);
+ void KeyProbe(int channel);
+ void ProbeCapture(int which);
+ void WriteByte(uint32_t addr, uint8_t val);
+ uint8_t ReadByte(uint32_t addr);
+ uint16_t ReadWord(uint32_t addr);
+ uint32_t ReadLong(uint32_t addr);
+ void WriteWord(uint32_t addr, uint16_t val);
+ void WriteLong(uint32_t addr, uint32_t val);
+
+ //kills all channels but leaves SPU otherwise running normally
+ void ShutUp();
+};
+
+int SPU_ChangeSoundCore(int coreid, int buffersize);
+//SoundInterface_struct *SPU_SoundCore();
+
+void SPU_ReInit();
+int SPU_Init(int coreid, int buffersize);
+//void SPU_Pause(int pause);
+//void SPU_SetVolume(int volume);
+void SPU_SetSynchMode(ESynchMode mode, ESynchMethod method);
+//void SPU_ClearOutputBuffer();
+void SPU_Reset();
+void SPU_DeInit();
+void SPU_KeyOn(int channel);
+void SPU_WriteByte(uint32_t addr, uint8_t val);
+void SPU_WriteWord(uint32_t addr, uint16_t val);
+void SPU_WriteLong(uint32_t addr, uint32_t val);
+uint8_t SPU_ReadByte(uint32_t addr);
+uint16_t SPU_ReadWord(uint32_t addr);
+uint32_t SPU_ReadLong(uint32_t addr);
+void SPU_Emulate_core();
+void SPU_Emulate_user(bool mix = true);
+
+extern SPU_struct *SPU_core, *SPU_user;
+extern int spu_core_samples;
+
+//void spu_savestate(EMUFILE* os);
+bool spu_loadstate(EMUFILE* is, int size);
+
+/*enum WAVMode
+{
+ WAVMODE_ANY = -1,
+ WAVMODE_CORE = 0,
+ WAVMODE_USER = 1
+};*/
+
+/*class WavWriter
+{
+public:
+ WavWriter();
+ bool open(const std::string & fname);
+ void close();
+ void update(void* soundData, int numSamples);
+ bool isRecording() const;
+ WAVMode mode;
+private:
+ FILE *spufp;
+};*/
+
+//void WAV_End();
+//bool WAV_Begin(const char* fname, WAVMode mode=WAVMODE_CORE);
+//bool WAV_IsRecording(WAVMode mode=WAVMODE_ANY);
+//void WAV_WavSoundUpdate(void* soundData, int numSamples, WAVMode mode=WAVMODE_CORE);
+
+// we should make this configurable eventually
+// but at least defining it somewhere is probably a step in the right direction
+#define DESMUME_SAMPLE_RATE 44100
+//#define DESMUME_SAMPLE_RATE 48000
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/addons/slot1_retail.cpp
@@ -1,1 +1,279 @@
-
+/* Copyright (C) 2010-2011 DeSmuME team
+
+ This file is part of DeSmuME
+
+ DeSmuME is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DeSmuME 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DeSmuME; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "../slot1.h"
+#include "../registers.h"
+#include "../MMU.h"
+#include "../NDSSystem.h"
+
+static void info(char *info) { strcpy(info, "Slot1 Retail card emulation"); }
+static void config() {}
+
+static bool init() { return true; }
+
+static void reset() {}
+
+static void close() {}
+
+static void write08(uint8_t, uint32_t, uint8_t) {}
+static void write16(uint8_t, uint32_t, uint16_t) {}
+
+static void write32_GCROMCTRL(uint8_t PROCNUM, uint32_t)
+{
+ nds_dscard &card = MMU.dscard[PROCNUM];
+
+ switch (card.command[0])
+ {
+ case 0x00: //Data read
+ case 0xB7:
+ card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
+ card.transfer_count = 0x80;
+ break;
+
+ case 0xB8: // Chip ID
+ card.address = 0;
+ card.transfer_count = 1;
+ break;
+
+ default:
+ card.address = 0;
+ card.transfer_count = 0;
+ }
+}
+
+static void write32(uint8_t PROCNUM, uint32_t adr, uint32_t val)
+{
+ switch (adr)
+ {
+ case REG_GCROMCTRL:
+ write32_GCROMCTRL(PROCNUM, val);
+ }
+}
+
+static uint8_t read08(uint8_t, uint32_t)
+{
+ return 0xFF;
+}
+
+static uint16_t read16(uint8_t, uint32_t)
+{
+ return 0xFFFF;
+}
+
+static uint32_t read32_GCDATAIN(uint8_t PROCNUM)
+{
+ nds_dscard &card = MMU.dscard[PROCNUM];
+
+ switch (card.command[0])
+ {
+ // Get ROM chip ID
+ case 0x90:
+ case 0xB8:
+ {
+ // Note: the BIOS stores the chip ID in main memory
+ // Most games continuously compare the chip ID with
+ // the value in memory, probably to know if the card
+ // was removed.
+ // As DeSmuME boots directly from the game, the chip
+ // ID in main mem is zero and this value needs to be
+ // zero too.
+
+ // staff of kings verifies this (it also uses the arm7 IRQ 20)
+ if (nds.cardEjected) // TODO - handle this with ejected card slot1 device (and verify using this case)
+ return 0xFFFFFFFF;
+ else
+ return 0;
+ }
+ break;
+
+ // Data read
+ case 0x00:
+ case 0xB7:
+ {
+ //it seems that etrian odyssey 3 doesnt work unless we mask this to cart size.
+ //but, a thought: does the internal rom address counter register wrap around? we may be making a mistake by keeping the extra precision
+ //but there is no test case yet
+ uint32_t address = card.address & (gameInfo.mask);
+
+ // Make sure any reads below 0x8000 redirect to 0x8000+(adr&0x1FF) as on real cart
+ if((card.command[0] == 0xB7) && (address < 0x8000))
+ {
+ // TODO - refactor this to include the PROCNUM, for debugging purposes if nothing else
+ // (can refactor gbaslot also)
+
+ //INFO("Read below 0x8000 (0x%04X) from: ARM%s %08X\n", card.address, (PROCNUM ? "7":"9"), (PROCNUM ? NDS_ARM7:NDS_ARM9).instruct_adr);
+
+ address = (0x8000 + (address&0x1FF));
+ }
+
+ // as a sanity measure for funny-sized roms (homebrew and perhaps truncated retail roms)
+ // we need to protect ourselves by returning 0xFF for things still out of range
+ if (address >= gameInfo.romsize)
+ {
+ //DEBUG_Notify.ReadBeyondEndOfCart(address, gameInfo. romsize);
+ return 0xFFFFFFFF;
+ }
+
+ return T1ReadLong(MMU.CART_ROM, address);
+ }
+ break;
+ default:
+ return 0;
+ } //switch(card.command[0])
+} //read32_GCDATAIN
+
+static uint32_t read32(uint8_t PROCNUM, uint32_t adr)
+{
+ switch(adr)
+ {
+ case REG_GCDATAIN:
+ return read32_GCDATAIN(PROCNUM);
+ default:
+ return 0;
+ }
+}
+
+SLOT1INTERFACE slot1Retail =
+{
+ "Retail",
+ init,
+ reset,
+ close,
+ config,
+ write08,
+ write16,
+ write32,
+ read08,
+ read16,
+ read32,
+ info
+};
+
+ // ///writetoGCControl:
+ //// --- Ninja SD commands -------------------------------------
+
+ // // NJSD init/reset
+ // case 0x20:
+ // {
+ // card.address = 0;
+ // card.transfer_count = 0;
+ // }
+ // break;
+
+ // // NJSD_sendCLK()
+ // case 0xE0:
+ // {
+ // card.address = 0;
+ // card.transfer_count = 0;
+ // NDS_makeInt(PROCNUM, 20);
+ // }
+ // break;
+
+ // // NJSD_sendCMDN() / NJSD_sendCMDR()
+ // case 0xF0:
+ // case 0xF1:
+ // switch (card.command[2])
+ // {
+ // // GO_IDLE_STATE
+ // case 0x40:
+ // card.address = 0;
+ // card.transfer_count = 0;
+ // NDS_makeInt(PROCNUM, 20);
+ // break;
+
+ // case 0x42: // ALL_SEND_CID
+ // case 0x43: // SEND_RELATIVE_ADDR
+ // case 0x47: // SELECT_CARD
+ // case 0x49: // SEND_CSD
+ // case 0x4D:
+ // case 0x77: // APP_CMD
+ // case 0x69: // SD_APP_OP_COND
+ // card.address = 0;
+ // card.transfer_count = 6;
+ // NDS_makeInt(PROCNUM, 20);
+ // break;
+
+ // // SET_BLOCKLEN
+ // case 0x50:
+ // card.address = 0;
+ // card.transfer_count = 6;
+ // card.blocklen = card.command[6] | (card.command[5] << 8) | (card.command[4] << 16) | (card.command[3] << 24);
+ // NDS_makeInt(PROCNUM, 20);
+ // break;
+
+ // // READ_SINGLE_BLOCK
+ // case 0x51:
+ // card.address = card.command[6] | (card.command[5] << 8) | (card.command[4] << 16) | (card.command[3] << 24);
+ // card.transfer_count = (card.blocklen + 3) >> 2;
+ // NDS_makeInt(PROCNUM, 20);
+ // break;
+ // }
+ // break;
+
+ // // --- Ninja SD commands end ---------------------------------
+
+
+
+ // //GCDATAIN:
+ // // --- Ninja SD commands -------------------------------------
+
+ // // NJSD_sendCMDN() / NJSD_sendCMDR()
+ // case 0xF0:
+ // case 0xF1:
+ // switch (card.command[2])
+ // {
+ // // ALL_SEND_CID
+ // case 0x42:
+ // if (card.transfer_count == 2) val = 0x44534A4E;
+ // else val = 0x00000000;
+
+ // // SEND_RELATIVE_ADDR
+ // case 0x43:
+ // case 0x47:
+ // case 0x49:
+ // case 0x50:
+ // val = 0x00000000;
+ // break;
+
+ // case 0x4D:
+ // if (card.transfer_count == 2) val = 0x09000000;
+ // else val = 0x00000000;
+ // break;
+
+ // // APP_CMD
+ // case 0x77:
+ // if (card.transfer_count == 2) val = 0x00000037;
+ // else val = 0x00000000;
+ // break;
+
+ // // SD_APP_OP_COND
+ // case 0x69:
+ // if (card.transfer_count == 2) val = 0x00008000;
+ // else val = 0x00000000;
+ // break;
+
+ // // READ_SINGLE_BLOCK
+ // case 0x51:
+ // val = 0x00000000;
+ // break;
+ // }
+ // break;
+
+ // // --- Ninja SD commands end ---------------------------------
+
--- /dev/null
+++ b/src/in_2sf/desmume/arm_instructions.cpp
@@ -1,1 +1,6391 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2006-2007 shash
+ Copyright (C) 2008-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// ARM core TODO:
+// - Check all the LDM/STM opcodes: quirks when Rb included in Rlist; opcodes
+// operating on user registers (LDMXX2/STMXX2)
+// - Force User mode memory access for LDRx/STRx opcodes with bit24=0 and bit21=1
+// (has to be done at memory side; once the PU is emulated well enough)
+// - Check LDMxx2/STMxx2 (those opcodes that act on User mode registers instead
+// of current ones)
+
+//#define UNTESTEDOPCODEDEBUG
+#include "cp15.h"
+//#include "debug.h"
+#include "MMU.h"
+#include "armcpu.h"
+#include "NDSSystem.h"
+#include "arm_instructions.h"
+#include "MMU_timing.h"
+
+#define cpu (&ARMPROC)
+#define TEMPLATE template<int PROCNUM>
+
+//-----------------------------------------------------------------------------
+// Shifting macros
+//-----------------------------------------------------------------------------
+
+#define LSL_IMM \
+ uint32_t shift_op = cpu->R[REG_POS(i,0)]<<((i>>7)&0x1F);
+
+#define S_LSL_IMM \
+ uint32_t shift_op = ((i>>7)&0x1F); \
+ uint32_t c = cpu->CPSR.bits.C; \
+ if(shift_op==0) \
+ shift_op=cpu->R[REG_POS(i,0)]; \
+ else \
+ { \
+ c = BIT_N(cpu->R[REG_POS(i,0)], 32-shift_op); \
+ shift_op = cpu->R[REG_POS(i,0)]<<shift_op; \
+ }
+
+#define LSL_REG \
+ uint32_t shift_op = (cpu->R[REG_POS(i,8)])&0xFF; \
+ if(shift_op>=32) \
+ shift_op=0; \
+ else \
+ shift_op=cpu->R[REG_POS(i,0)]<<shift_op;
+
+#define S_LSL_REG \
+ uint32_t shift_op = (cpu->R[REG_POS(i,8)])&0xFF; \
+ uint32_t c = cpu->CPSR.bits.C; \
+ if(shift_op==0) \
+ shift_op=cpu->R[REG_POS(i,0)]; \
+ else \
+ if(shift_op<32) \
+ { \
+ c = BIT_N(cpu->R[REG_POS(i,0)], 32-shift_op); \
+ shift_op = cpu->R[REG_POS(i,0)]<<shift_op; \
+ } \
+ else \
+ if(shift_op==32) \
+ { \
+ shift_op = 0; \
+ c = BIT0(cpu->R[REG_POS(i,0)]); \
+ } \
+ else \
+ { \
+ shift_op = 0; \
+ c = 0; \
+ }
+
+#define LSR_IMM \
+ uint32_t shift_op = ((i>>7)&0x1F); \
+ if(shift_op!=0) \
+ shift_op = cpu->R[REG_POS(i,0)]>>shift_op;
+
+#define S_LSR_IMM \
+ uint32_t shift_op = ((i>>7)&0x1F); \
+ uint32_t c = cpu->CPSR.bits.C; \
+ if(shift_op==0) \
+ { \
+ c = BIT31(cpu->R[REG_POS(i,0)]); \
+ } \
+ else \
+ { \
+ c = BIT_N(cpu->R[REG_POS(i,0)], shift_op-1); \
+ shift_op = cpu->R[REG_POS(i,0)]>>shift_op; \
+ }
+
+#define LSR_REG \
+ uint32_t shift_op = (cpu->R[REG_POS(i,8)])&0xFF; \
+ if(shift_op>=32) \
+ shift_op = 0; \
+ else \
+ shift_op = cpu->R[REG_POS(i,0)]>>shift_op;
+
+#define S_LSR_REG \
+ uint32_t shift_op = (cpu->R[REG_POS(i,8)])&0xFF; \
+ uint32_t c = cpu->CPSR.bits.C; \
+ if(shift_op==0) \
+ { \
+ shift_op = cpu->R[REG_POS(i,0)]; \
+ } \
+ else \
+ if(shift_op<32) \
+ { \
+ c = BIT_N(cpu->R[REG_POS(i,0)], shift_op-1); \
+ shift_op = cpu->R[REG_POS(i,0)]>>shift_op; \
+ } \
+ else \
+ if(shift_op==32) \
+ { \
+ c = BIT31(cpu->R[REG_POS(i,0)]); \
+ shift_op = 0; \
+ } \
+ else \
+ { \
+ c = 0; \
+ shift_op = 0; \
+ }
+
+#define ASR_IMM \
+ uint32_t shift_op = ((i>>7)&0x1F); \
+ if(shift_op==0) \
+ shift_op=BIT31(cpu->R[REG_POS(i,0)])*0xFFFFFFFF; \
+ else \
+ shift_op = (uint32_t)((int32_t)cpu->R[REG_POS(i,0)]>>shift_op);
+
+#define S_ASR_IMM \
+ uint32_t shift_op = ((i>>7)&0x1F); \
+ uint32_t c = cpu->CPSR.bits.C; \
+ if(shift_op==0) \
+ { \
+ shift_op=BIT31(cpu->R[REG_POS(i,0)])*0xFFFFFFFF; \
+ c = BIT31(cpu->R[REG_POS(i,0)]); \
+ } \
+ else \
+ { \
+ c = BIT_N(cpu->R[REG_POS(i,0)], shift_op-1); \
+ shift_op = (uint32_t)((int32_t)cpu->R[REG_POS(i,0)]>>shift_op); \
+ }
+
+#define ASR_REG \
+ uint32_t shift_op = (cpu->R[REG_POS(i,8)])&0xFF; \
+ if(shift_op==0) \
+ shift_op=cpu->R[REG_POS(i,0)]; \
+ else \
+ if(shift_op<32) \
+ shift_op = (uint32_t)((int32_t)cpu->R[REG_POS(i,0)]>>shift_op); \
+ else \
+ shift_op=BIT31(cpu->R[REG_POS(i,0)])*0xFFFFFFFF;
+
+#define S_ASR_REG \
+ uint32_t shift_op = (cpu->R[REG_POS(i,8)])&0xFF; \
+ uint32_t c = cpu->CPSR.bits.C; \
+ if(shift_op==0) \
+ shift_op=cpu->R[REG_POS(i,0)]; \
+ else \
+ if(shift_op<32) \
+ { \
+ c = BIT_N(cpu->R[REG_POS(i,0)], shift_op-1); \
+ shift_op = (uint32_t)((int32_t)cpu->R[REG_POS(i,0)]>>shift_op); \
+ } \
+ else \
+ { \
+ c = BIT31(cpu->R[REG_POS(i,0)]); \
+ shift_op=BIT31(cpu->R[REG_POS(i,0)])*0xFFFFFFFF; \
+ }
+
+#define ROR_IMM \
+ uint32_t shift_op = ((i>>7)&0x1F); \
+ if(shift_op==0) \
+ { \
+ shift_op = ((uint32_t)cpu->CPSR.bits.C<<31)|(cpu->R[REG_POS(i,0)]>>1); \
+ } \
+ else \
+ shift_op = ROR(cpu->R[REG_POS(i,0)],shift_op);
+
+#define S_ROR_IMM \
+ uint32_t shift_op = ((i>>7)&0x1F); \
+ uint32_t c = cpu->CPSR.bits.C; \
+ if(shift_op==0) \
+ { \
+ shift_op = ((uint32_t)cpu->CPSR.bits.C<<31)|(cpu->R[REG_POS(i,0)]>>1); \
+ c = BIT0(cpu->R[REG_POS(i,0)]); \
+ } \
+ else \
+ { \
+ c = BIT_N(cpu->R[REG_POS(i,0)], shift_op-1); \
+ shift_op = ROR(cpu->R[REG_POS(i,0)],shift_op); \
+ }
+
+#define ROR_REG \
+ uint32_t shift_op = (cpu->R[REG_POS(i,8)])&0xFF; \
+ if((shift_op==0)||((shift_op&0x1F)==0)) \
+ shift_op=cpu->R[REG_POS(i,0)]; \
+ else \
+ shift_op = ROR(cpu->R[REG_POS(i,0)],(shift_op&0x1F));
+
+#define S_ROR_REG \
+ uint32_t shift_op = (cpu->R[REG_POS(i,8)])&0xFF; \
+ uint32_t c = cpu->CPSR.bits.C; \
+ if(shift_op==0) \
+ shift_op=cpu->R[REG_POS(i,0)]; \
+ else \
+ { \
+ shift_op&=0x1F; \
+ if(shift_op==0) \
+ { \
+ shift_op=cpu->R[REG_POS(i,0)]; \
+ c = BIT31(cpu->R[REG_POS(i,0)]); \
+ } \
+ else \
+ { \
+ c = BIT_N(cpu->R[REG_POS(i,0)], shift_op-1); \
+ shift_op = ROR(cpu->R[REG_POS(i,0)],shift_op); \
+ } \
+ }
+
+#define IMM_VALUE \
+ uint32_t shift_op = ROR((i&0xFF), (i>>7)&0x1E);
+
+#define S_IMM_VALUE \
+ uint32_t shift_op = ROR((i&0xFF), (i>>7)&0x1E); \
+ uint32_t c = cpu->CPSR.bits.C; \
+ if((i>>8)&0xF) \
+ c = BIT31(shift_op);
+
+#define IMM_OFF (((i>>4)&0xF0)+(i&0xF))
+
+#define IMM_OFF_12 ((i)&0xFFF)
+
+//-----------------------------------------------------------------------------
+// Undefined instruction
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_UND(const uint32_t)
+{
+ TRAPUNDEF(cpu);
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// AND / ANDS
+// Timing: OK
+//-----------------------------------------------------------------------------
+
+#define OP_AND(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] & shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_ANDS(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] & shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ cpu->CPSR.bits.C = c; \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ return a;
+
+TEMPLATE static uint32_t FASTCALL OP_AND_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_AND(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_AND(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_AND(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_AND(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_AND(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_AND(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_AND(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_AND(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_AND(1, 3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_AND_S_LSL_IMM(const uint32_t i)
+{
+ S_LSL_IMM;
+ OP_ANDS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_S_LSL_REG(const uint32_t i)
+{
+ S_LSL_REG;
+ OP_ANDS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_S_LSR_IMM(const uint32_t i)
+{
+ S_LSR_IMM;
+ OP_ANDS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_S_LSR_REG(const uint32_t i)
+{
+ S_LSR_REG;
+ OP_ANDS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_S_ASR_IMM(const uint32_t i)
+{
+ S_ASR_IMM;
+ OP_ANDS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_S_ASR_REG(const uint32_t i)
+{
+ S_ASR_REG;
+ OP_ANDS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_S_ROR_IMM(const uint32_t i)
+{
+ S_ROR_IMM;
+ OP_ANDS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_S_ROR_REG(const uint32_t i)
+{
+ S_ROR_REG;
+ OP_ANDS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_AND_S_IMM_VAL(const uint32_t i)
+{
+ S_IMM_VALUE;
+ OP_ANDS(1, 3);
+}
+
+//-----------------------------------------------------------------------------
+// EOR / EORS
+//-----------------------------------------------------------------------------
+
+#define OP_EOR(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] ^ shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_EORS(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] ^ shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ cpu->CPSR.bits.C = c; \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ return a;
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_EOR(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_EOR(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_EOR(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_EOR(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_EOR(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_EOR(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_EOR(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_EOR(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_EOR(1, 3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_S_LSL_IMM(const uint32_t i)
+{
+ S_LSL_IMM;
+ OP_EORS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_S_LSL_REG(const uint32_t i)
+{
+ S_LSL_REG;
+ OP_EORS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_S_LSR_IMM(const uint32_t i)
+{
+ S_LSR_IMM;
+ OP_EORS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_S_LSR_REG(const uint32_t i)
+{
+ S_LSR_REG;
+ OP_EORS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_S_ASR_IMM(const uint32_t i)
+{
+ S_ASR_IMM;
+ OP_EORS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_S_ASR_REG(const uint32_t i)
+{
+ S_ASR_REG;
+ OP_EORS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_S_ROR_IMM(const uint32_t i)
+{
+ S_ROR_IMM;
+ OP_EORS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_S_ROR_REG(const uint32_t i)
+{
+ S_ROR_REG;
+ OP_EORS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_EOR_S_IMM_VAL(const uint32_t i)
+{
+ S_IMM_VALUE;
+ OP_EORS(1, 3);
+}
+
+//-----------------------------------------------------------------------------
+// SUB / SUBS
+//-----------------------------------------------------------------------------
+
+#define OP_SUB(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] - shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_SUBS(a, b) \
+ cpu->R[REG_POS(i,12)] = v - shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ cpu->CPSR.bits.C = !BorrowFrom(v, shift_op); \
+ cpu->CPSR.bits.V = OverflowFromSUB(cpu->R[REG_POS(i,12)], v, shift_op); \
+ return a;
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_SUB(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_SUB(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_SUB(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_SUB(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_SUB(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_SUB(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_SUB(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_SUB(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_SUB(1, 3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_S_LSL_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_IMM;
+ OP_SUBS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_S_LSL_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_REG;
+ OP_SUBS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_S_LSR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_IMM;
+ OP_SUBS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_S_LSR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_REG;
+ OP_SUBS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_S_ASR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_IMM;
+ OP_SUBS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_S_ASR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_REG;
+ OP_SUBS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_S_ROR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_IMM;
+ OP_SUBS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_S_ROR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_REG;
+ OP_SUBS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_S_IMM_VAL(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ IMM_VALUE;
+ OP_SUBS(1, 3);
+}
+
+//-----------------------------------------------------------------------------
+// RSB / RSBS
+//-----------------------------------------------------------------------------
+
+#define OP_RSB(a, b) \
+ cpu->R[REG_POS(i,12)] = shift_op - cpu->R[REG_POS(i,16)]; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_RSBS(a, b) \
+ cpu->R[REG_POS(i,12)] = shift_op - v; \
+ if(REG_POS(i,12)==15) \
+ { \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ cpu->CPSR.bits.C = !BorrowFrom(shift_op, v); \
+ cpu->CPSR.bits.V = OverflowFromSUB(cpu->R[REG_POS(i,12)], shift_op, v); \
+ return a;
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_RSB(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_RSB(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_RSB(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_RSB(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_RSB(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_RSB(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_RSB(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_RSB(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_RSB(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_S_LSL_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_IMM;
+ OP_RSBS(1, 3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_S_LSL_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_REG;
+ OP_RSBS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_S_LSR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_IMM;
+ OP_RSBS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_S_LSR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_REG;
+ OP_RSBS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_S_ASR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_IMM;
+ OP_RSBS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_S_ASR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_REG;
+ OP_RSBS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_S_ROR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_IMM;
+ OP_RSBS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_S_ROR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_REG;
+ OP_RSBS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSB_S_IMM_VAL(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ IMM_VALUE;
+ OP_RSBS(1, 3);
+}
+
+//-----------------------------------------------------------------------------
+// ADD / ADDS
+//-----------------------------------------------------------------------------
+
+#define OP_ADD(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] + shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_ADDS(a, b) \
+ cpu->R[REG_POS(i,12)] = v + shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ cpu->CPSR.bits.C = CarryFrom(v, shift_op); \
+ cpu->CPSR.bits.V = OverflowFromADD(cpu->R[REG_POS(i,12)], v, shift_op); \
+ return a;
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_ADD(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_ADD(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_ADD(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_ADD(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_ADD(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_ADD(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_ADD(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_ADD(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_ADD(1, 3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_S_LSL_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_IMM;
+ OP_ADDS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_S_LSL_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_REG;
+ OP_ADDS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_S_LSR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_IMM;
+ OP_ADDS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_S_LSR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_REG;
+ OP_ADDS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_S_ASR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_IMM;
+ OP_ADDS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_S_ASR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_REG;
+ OP_ADDS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_S_ROR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_IMM;
+ OP_ADDS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_S_ROR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_REG;
+ OP_ADDS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_S_IMM_VAL(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ IMM_VALUE;
+ OP_ADDS(1, 3);
+}
+
+//-----------------------------------------------------------------------------
+// ADC / ADCS
+//-----------------------------------------------------------------------------
+#define OP_ADC(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] + shift_op + cpu->CPSR.bits.C; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_ADCS(a, b) \
+ { \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->R[REG_POS(i,12)] = v + shift_op + cpu->CPSR.bits.C; \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ if (!cpu->CPSR.bits.C) \
+ { \
+ cpu->R[REG_POS(i,12)] = v + shift_op; \
+ cpu->CPSR.bits.C = cpu->R[REG_POS(i,12)] < v; \
+ } \
+ else \
+ { \
+ cpu->R[REG_POS(i,12)] = v + shift_op + 1; \
+ cpu->CPSR.bits.C = cpu->R[REG_POS(i,12)] <= v; \
+ } \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ cpu->CPSR.bits.V = BIT31((v ^ shift_op ^ -1) & (v ^ cpu->R[REG_POS(i, 12)]));\
+ return a; \
+ }
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_ADC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_ADC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_ADC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_ADC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_ADC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_ADC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_ADC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_ADC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_ADC(1, 3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_S_LSL_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_IMM;
+ OP_ADCS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_S_LSL_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_REG;
+ OP_ADCS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_S_LSR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_IMM;
+ OP_ADCS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_S_LSR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_REG;
+ OP_ADCS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_S_ASR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_IMM;
+ OP_ADCS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_S_ASR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_REG;
+ OP_ADCS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_S_ROR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_IMM;
+ OP_ADCS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_S_ROR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_REG;
+ OP_ADCS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_S_IMM_VAL(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ IMM_VALUE;
+ OP_ADCS(1, 3);
+}
+
+//-----------------------------------------------------------------------------
+// SBC / SBCS
+//-----------------------------------------------------------------------------
+
+#define OP_SBC(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] - shift_op - !cpu->CPSR.bits.C; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_SBCS(a, b) \
+ { \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->R[REG_POS(i,12)] = v - shift_op - !cpu->CPSR.bits.C; \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ if (!cpu->CPSR.bits.C) \
+ { \
+ cpu->R[REG_POS(i,12)] = v - shift_op - 1; \
+ cpu->CPSR.bits.C = v > shift_op; \
+ } \
+ else \
+ { \
+ cpu->R[REG_POS(i,12)] = v - shift_op; \
+ cpu->CPSR.bits.C = v >= shift_op; \
+ } \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ cpu->CPSR.bits.V = BIT31((v ^ shift_op) & (v ^ cpu->R[REG_POS(i, 12)])); \
+ return a; \
+ }
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_SBC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_SBC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_SBC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_SBC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_SBC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_SBC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_SBC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_SBC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_SBC(1, 3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_S_LSL_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_IMM;
+ OP_SBCS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_S_LSL_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_REG;
+ OP_SBCS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_S_LSR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_IMM;
+ OP_SBCS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_S_LSR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_REG;
+ OP_SBCS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_S_ASR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_IMM;
+ OP_SBCS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_S_ASR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_REG;
+ OP_SBCS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_S_ROR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_IMM;
+ OP_SBCS(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_S_ROR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_REG;
+ OP_SBCS(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SBC_S_IMM_VAL(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ IMM_VALUE;
+ OP_SBCS(1, 3);
+}
+
+//-----------------------------------------------------------------------------
+// RSC / RSCS
+//-----------------------------------------------------------------------------
+
+#define OP_RSC(a, b) \
+ cpu->R[REG_POS(i,12)] = shift_op - cpu->R[REG_POS(i,16)] + cpu->CPSR.bits.C - 1; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_RSCS(a, b) \
+ { \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->R[REG_POS(i,12)] = shift_op - v - !cpu->CPSR.bits.C; \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ if (!cpu->CPSR.bits.C) \
+ { \
+ cpu->R[REG_POS(i,12)] = shift_op - v - 1; \
+ cpu->CPSR.bits.C = shift_op > v; \
+ } \
+ else \
+ { \
+ cpu->R[REG_POS(i,12)] = shift_op - v; \
+ cpu->CPSR.bits.C = shift_op >= v; \
+ } \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ cpu->CPSR.bits.V = BIT31((shift_op ^ v) & (shift_op ^ cpu->R[REG_POS(i, 12)])); \
+ return a; \
+ }
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_RSC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_RSC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_RSC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_RSC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_RSC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_RSC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_RSC(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_RSC(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_RSC(1, 3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_S_LSL_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_IMM;
+ OP_RSCS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_S_LSL_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSL_REG;
+ OP_RSCS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_S_LSR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_IMM;
+ OP_RSCS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_S_LSR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ LSR_REG;
+ OP_RSCS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_S_ASR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_IMM;
+ OP_RSCS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_S_ASR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ASR_REG;
+ OP_RSCS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_S_ROR_IMM(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_IMM;
+ OP_RSCS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_S_ROR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ ROR_REG;
+ OP_RSCS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_RSC_S_IMM_VAL(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,16)];
+ IMM_VALUE;
+ OP_RSCS(1,3);
+}
+
+//-----------------------------------------------------------------------------
+// TST
+//-----------------------------------------------------------------------------
+
+#define OP_TST(a) \
+ { \
+ uint32_t tmp = cpu->R[REG_POS(i,16)] & shift_op; \
+ cpu->CPSR.bits.C = c; \
+ cpu->CPSR.bits.N = BIT31(tmp); \
+ cpu->CPSR.bits.Z = (tmp==0); \
+ return a; \
+ }
+
+TEMPLATE static uint32_t FASTCALL OP_TST_LSL_IMM(const uint32_t i)
+{
+ S_LSL_IMM;
+ OP_TST(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TST_LSL_REG(const uint32_t i)
+{
+ S_LSL_REG;
+ OP_TST(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TST_LSR_IMM(const uint32_t i)
+{
+ S_LSR_IMM;
+ OP_TST(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TST_LSR_REG(const uint32_t i)
+{
+ S_LSR_REG;
+ OP_TST(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TST_ASR_IMM(const uint32_t i)
+{
+ S_ASR_IMM;
+ OP_TST(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TST_ASR_REG(const uint32_t i)
+{
+ S_ASR_REG;
+ OP_TST(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TST_ROR_IMM(const uint32_t i)
+{
+ S_ROR_IMM;
+ OP_TST(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TST_ROR_REG(const uint32_t i)
+{
+ S_ROR_REG;
+ OP_TST(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TST_IMM_VAL(const uint32_t i)
+{
+ S_IMM_VALUE;
+ OP_TST(1);
+}
+
+//-----------------------------------------------------------------------------
+// TEQ
+//-----------------------------------------------------------------------------
+
+#define OP_TEQ(a) \
+ { \
+ unsigned tmp = cpu->R[REG_POS(i,16)] ^ shift_op; \
+ cpu->CPSR.bits.C = c; \
+ cpu->CPSR.bits.N = BIT31(tmp); \
+ cpu->CPSR.bits.Z = (tmp==0); \
+ return a; \
+ }
+
+TEMPLATE static uint32_t FASTCALL OP_TEQ_LSL_IMM(const uint32_t i)
+{
+ S_LSL_IMM;
+ OP_TEQ(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TEQ_LSL_REG(const uint32_t i)
+{
+ S_LSL_REG;
+ OP_TEQ(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TEQ_LSR_IMM(const uint32_t i)
+{
+ S_LSR_IMM;
+ OP_TEQ(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TEQ_LSR_REG(const uint32_t i)
+{
+ S_LSR_REG;
+ OP_TEQ(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TEQ_ASR_IMM(const uint32_t i)
+{
+ S_ASR_IMM;
+ OP_TEQ(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TEQ_ASR_REG(const uint32_t i)
+{
+ S_ASR_REG;
+ OP_TEQ(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TEQ_ROR_IMM(const uint32_t i)
+{
+ S_ROR_IMM;
+ OP_TEQ(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TEQ_ROR_REG(const uint32_t i)
+{
+ S_ROR_REG;
+ OP_TEQ(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_TEQ_IMM_VAL(const uint32_t i)
+{
+ S_IMM_VALUE;
+ OP_TEQ(1);
+}
+
+//-----------------------------------------------------------------------------
+// CMP
+//-----------------------------------------------------------------------------
+
+#define OP_CMP(a) \
+ { \
+ uint32_t tmp = cpu->R[REG_POS(i,16)] - shift_op; \
+ cpu->CPSR.bits.N = BIT31(tmp); \
+ cpu->CPSR.bits.Z = (tmp==0); \
+ cpu->CPSR.bits.C = !BorrowFrom(cpu->R[REG_POS(i,16)], shift_op); \
+ cpu->CPSR.bits.V = OverflowFromSUB(tmp, cpu->R[REG_POS(i,16)], shift_op); \
+ return a; \
+ }
+
+TEMPLATE static uint32_t FASTCALL OP_CMP_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_CMP(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMP_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_CMP(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMP_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_CMP(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMP_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_CMP(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMP_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_CMP(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMP_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_CMP(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMP_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_CMP(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMP_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_CMP(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMP_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_CMP(1);
+}
+
+//-----------------------------------------------------------------------------
+// CMN
+//-----------------------------------------------------------------------------
+
+#define OP_CMN(a) \
+ { \
+ uint32_t tmp = cpu->R[REG_POS(i,16)] + shift_op; \
+ cpu->CPSR.bits.N = BIT31(tmp); \
+ cpu->CPSR.bits.Z = (tmp==0); \
+ cpu->CPSR.bits.C = CarryFrom(cpu->R[REG_POS(i,16)], shift_op); \
+ cpu->CPSR.bits.V = OverflowFromADD(tmp, cpu->R[REG_POS(i,16)], shift_op); \
+ return a; \
+ }
+
+TEMPLATE static uint32_t FASTCALL OP_CMN_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_CMN(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMN_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_CMN(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMN_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_CMN(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMN_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_CMN(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMN_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_CMN(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMN_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_CMN(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMN_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_CMN(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMN_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_CMN(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMN_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_CMN(1);
+}
+
+//-----------------------------------------------------------------------------
+// ORR / ORRS
+//-----------------------------------------------------------------------------
+
+#define OP_ORR(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] | shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_ORRS(a,b) \
+ { \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] | shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ cpu->CPSR.bits.C = c; \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ return a; \
+ }
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_ORR(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_ORR(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_ORR(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_ORR(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_ORR(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_ORR(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_ORR(1, 3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_ORR(2, 4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_ORR(1, 3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_S_LSL_IMM(const uint32_t i)
+{
+ S_LSL_IMM;
+ OP_ORRS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_S_LSL_REG(const uint32_t i)
+{
+ S_LSL_REG;
+ OP_ORRS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_S_LSR_IMM(const uint32_t i)
+{
+ S_LSR_IMM;
+ OP_ORRS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_S_LSR_REG(const uint32_t i)
+{
+ S_LSR_REG;
+ OP_ORRS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_S_ASR_IMM(const uint32_t i)
+{
+ S_ASR_IMM;
+ OP_ORRS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_S_ASR_REG(const uint32_t i)
+{
+ S_ASR_REG;
+ OP_ORRS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_S_ROR_IMM(const uint32_t i)
+{
+ S_ROR_IMM;
+ OP_ORRS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_S_ROR_REG(const uint32_t i)
+{
+ S_ROR_REG;
+ OP_ORRS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ORR_S_IMM_VAL(const uint32_t i)
+{
+ S_IMM_VALUE;
+ OP_ORRS(1,3);
+}
+
+//-----------------------------------------------------------------------------
+// MOV / MOVS
+//-----------------------------------------------------------------------------
+
+#define OP_MOV(a, b) \
+ cpu->R[REG_POS(i,12)] = shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = shift_op; \
+ return b; \
+ } \
+ return a;
+
+#define OP_MOVS(a, b) \
+ cpu->R[REG_POS(i,12)] = shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ cpu->CPSR.bits.C = c; \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ return a; \
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_MOV(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ if (REG_POS(i,0) == 15) shift_op += 4;
+ OP_MOV(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_MOV(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ if (REG_POS(i,0) == 15) shift_op += 4;
+ OP_MOV(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_MOV(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_MOV(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_MOV(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_MOV(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_MOV(1,3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_S_LSL_IMM(const uint32_t i)
+{
+ S_LSL_IMM;
+ OP_MOVS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_S_LSL_REG(const uint32_t i)
+{
+ S_LSL_REG;
+ if (REG_POS(i,0) == 15) shift_op += 4;
+ OP_MOVS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_S_LSR_IMM(const uint32_t i)
+{
+ S_LSR_IMM;
+ OP_MOVS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_S_LSR_REG(const uint32_t i)
+{
+ S_LSR_REG;
+ if (REG_POS(i,0) == 15) shift_op += 4;
+ OP_MOVS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_S_ASR_IMM(const uint32_t i)
+{
+ S_ASR_IMM;
+ OP_MOVS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_S_ASR_REG(const uint32_t i)
+{
+ S_ASR_REG;
+ OP_MOVS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_S_ROR_IMM(const uint32_t i)
+{
+ S_ROR_IMM;
+ OP_MOVS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_S_ROR_REG(const uint32_t i)
+{
+ S_ROR_REG;
+ OP_MOVS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_S_IMM_VAL(const uint32_t i)
+{
+ S_IMM_VALUE;
+ OP_MOVS(1,3);
+}
+
+//-----------------------------------------------------------------------------
+// BIC / BICS
+//-----------------------------------------------------------------------------
+
+#define OP_BIC(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] & (~shift_op); \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_BICS(a, b) \
+ cpu->R[REG_POS(i,12)] = cpu->R[REG_POS(i,16)] & (~shift_op); \
+ if(REG_POS(i,12)==15) \
+ { \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ cpu->CPSR.bits.C = c; \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ return a;
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_BIC(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_BIC(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_BIC(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_BIC(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_BIC(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_BIC(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_BIC(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_BIC(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_BIC(1,3);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_S_LSL_IMM(const uint32_t i)
+{
+ S_LSL_IMM;
+ OP_BICS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_S_LSL_REG(const uint32_t i)
+{
+ S_LSL_REG;
+ OP_BICS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_S_LSR_IMM(const uint32_t i)
+{
+ S_LSR_IMM;
+ OP_BICS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_S_LSR_REG(const uint32_t i)
+{
+ S_LSR_REG;
+ OP_BICS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_S_ASR_IMM(const uint32_t i)
+{
+ S_ASR_IMM;
+ OP_BICS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_S_ASR_REG(const uint32_t i)
+{
+ S_ASR_REG;
+ OP_BICS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_S_ROR_IMM(const uint32_t i)
+{
+ S_ROR_IMM;
+ OP_BICS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_S_ROR_REG(const uint32_t i)
+{
+ S_ROR_REG;
+ OP_BICS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BIC_S_IMM_VAL(const uint32_t i)
+{
+ S_IMM_VALUE;
+ OP_BICS(1,3);
+}
+
+//-----------------------------------------------------------------------------
+// MVN / MVNS
+//-----------------------------------------------------------------------------
+
+#define OP_MVN(a, b) \
+ cpu->R[REG_POS(i,12)] = ~shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ return a;
+
+#define OP_MVNS(a, b) \
+ cpu->R[REG_POS(i,12)] = ~shift_op; \
+ if(REG_POS(i,12)==15) \
+ { \
+ Status_Reg SPSR = cpu->SPSR; \
+ armcpu_switchMode(cpu, SPSR.bits.mode); \
+ cpu->CPSR=SPSR; \
+ cpu->changeCPSR(); \
+ cpu->R[15] &= (0xFFFFFFFC|(((uint32_t)cpu->CPSR.bits.T)<<1)); \
+ cpu->next_instruction = cpu->R[15]; \
+ return b; \
+ } \
+ cpu->CPSR.bits.C = c; \
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,12)]); \
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,12)]==0); \
+ return a;
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_LSL_IMM(const uint32_t i)
+{
+ LSL_IMM;
+ OP_MVN(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_LSL_REG(const uint32_t i)
+{
+ LSL_REG;
+ OP_MVN(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_LSR_IMM(const uint32_t i)
+{
+ LSR_IMM;
+ OP_MVN(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_LSR_REG(const uint32_t i)
+{
+ LSR_REG;
+ OP_MVN(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_ASR_IMM(const uint32_t i)
+{
+ ASR_IMM;
+ OP_MVN(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_ASR_REG(const uint32_t i)
+{
+ ASR_REG;
+ OP_MVN(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_ROR_IMM(const uint32_t i)
+{
+ ROR_IMM;
+ OP_MVN(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_ROR_REG(const uint32_t i)
+{
+ ROR_REG;
+ OP_MVN(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+ OP_MVN(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_S_LSL_IMM(const uint32_t i)
+{
+ S_LSL_IMM;
+ OP_MVNS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_S_LSL_REG(const uint32_t i)
+{
+ S_LSL_REG;
+ OP_MVNS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_S_LSR_IMM(const uint32_t i)
+{
+ S_LSR_IMM;
+ OP_MVNS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_S_LSR_REG(const uint32_t i)
+{
+ S_LSR_REG;
+ OP_MVNS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_S_ASR_IMM(const uint32_t i)
+{
+ S_ASR_IMM;
+ OP_MVNS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_S_ASR_REG(const uint32_t i)
+{
+ S_ASR_REG;
+ OP_MVNS(2,4);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_S_ROR_IMM(const uint32_t i)
+{
+ S_ROR_IMM;
+ OP_MVNS(1,3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_S_ROR_REG(const uint32_t i)
+{
+ S_ROR_REG;
+ OP_MVNS(2,4);
+
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MVN_S_IMM_VAL(const uint32_t i)
+{
+ S_IMM_VALUE;
+ OP_MVNS(1,3);
+}
+
+//-----------------------------------------------------------------------------
+// MUL / MULS / MLA / MLAS
+//-----------------------------------------------------------------------------
+
+#define MUL_Mxx_END(c) \
+ v >>= 8; \
+ if((v==0)||(v==0xFFFFFF)) \
+ return c+1; \
+ v >>= 8; \
+ if((v==0)||(v==0xFFFF)) \
+ return c+2; \
+ v >>= 8; \
+ if((v==0)||(v==0xFF)) \
+ return c+3; \
+ return c+4; \
+
+
+TEMPLATE static uint32_t FASTCALL OP_MUL(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,8)];
+ cpu->R[REG_POS(i,16)] = cpu->R[REG_POS(i,0)] * v;
+
+ MUL_Mxx_END(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MLA(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,8)];
+ cpu->R[REG_POS(i,16)] = cpu->R[REG_POS(i,0)] * v + cpu->R[REG_POS(i,12)];
+
+ MUL_Mxx_END(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MUL_S(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,8)];
+ cpu->R[REG_POS(i,16)] = cpu->R[REG_POS(i,0)] * v;
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,16)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,16)]==0);
+
+ MUL_Mxx_END(1);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MLA_S(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,8)];
+ cpu->R[REG_POS(i,16)] = cpu->R[REG_POS(i,0)] * v + cpu->R[REG_POS(i,12)];
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,16)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,16)]==0);
+
+ MUL_Mxx_END(2);
+}
+
+//-----------------------------------------------------------------------------
+// UMULL / UMULLS / UMLAL / UMLALS
+//-----------------------------------------------------------------------------
+
+#define MUL_UMxxL_END(c) \
+ v >>= 8; \
+ if(v==0) \
+ return c+1; \
+ v >>= 8; \
+ if(v==0) \
+ return c+2; \
+ v >>= 8; \
+ if(v==0) \
+ return c+3; \
+ return c+4; \
+
+
+TEMPLATE static uint32_t FASTCALL OP_UMULL(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,8)];
+ uint64_t res = (uint64_t)cpu->R[REG_POS(i,0)] * (uint64_t)v;
+
+ cpu->R[REG_POS(i,12)] = (uint32_t)res;
+ cpu->R[REG_POS(i,16)] = (uint32_t)(res>>32);
+
+ MUL_UMxxL_END(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_UMLAL(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,8)];
+ uint64_t res = (uint64_t)cpu->R[REG_POS(i,0)] * (uint64_t)v;
+
+ // RdLo = (Rm * Rs)[31:0] + RdLo /* Unsigned multiplication */
+ // RdHi = (Rm * Rs)[63:32] + RdHi + CarryFrom((Rm * Rs)[31:0] + RdLo)
+ uint32_t tmp = (uint32_t)res; // low
+ cpu->R[REG_POS(i,16)] = (uint32_t)(res>>32) + cpu->R[REG_POS(i,16)] + CarryFrom(tmp, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,12)] += tmp;
+
+ MUL_UMxxL_END(3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_UMULL_S(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,8)];
+ uint64_t res = ((uint64_t)cpu->R[REG_POS(i,0)] * (uint64_t)v);
+
+ cpu->R[REG_POS(i,12)] = (uint32_t)res;
+ cpu->R[REG_POS(i,16)] = (uint32_t)(res>>32);
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,16)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,16)]==0) && (cpu->R[REG_POS(i,12)]==0);
+
+ MUL_UMxxL_END(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_UMLAL_S(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_POS(i,8)];
+ uint64_t res = (uint64_t)cpu->R[REG_POS(i,0)] * (uint64_t)v;
+
+ // RdLo = (Rm * Rs)[31:0] + RdLo /* Unsigned multiplication */
+ // RdHi = (Rm * Rs)[63:32] + RdHi + CarryFrom((Rm * Rs)[31:0] + RdLo)
+ uint32_t tmp = (uint32_t)res; // low
+ cpu->R[REG_POS(i,16)] = (uint32_t)(res>>32) + cpu->R[REG_POS(i,16)] + CarryFrom(tmp, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,12)] += tmp;
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,16)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,16)]==0) & (cpu->R[REG_POS(i,12)]==0);
+
+ MUL_UMxxL_END(3);
+}
+
+//-----------------------------------------------------------------------------
+// SMULL / SMULLS / SMLAL / SMLALS
+//-----------------------------------------------------------------------------
+
+#define MUL_SMxxL_END(c) \
+ v &= 0xFFFFFFFF; \
+ v >>= 8; \
+ if((v==0)||(v==0xFFFFFF)) \
+ return c+1; \
+ v >>= 8; \
+ if((v==0)||(v==0xFFFF)) \
+ return c+2; \
+ v >>= 8; \
+ if((v==0)||(v==0xFF)) \
+ return c+3; \
+ return c+4; \
+
+
+TEMPLATE static uint32_t FASTCALL OP_SMULL(const uint32_t i)
+{
+ int64_t v = (int32_t)cpu->R[REG_POS(i,8)];
+ int64_t res = v * (int64_t)(int32_t)cpu->R[REG_POS(i,0)];
+
+ cpu->R[REG_POS(i,12)] = (uint32_t)res;
+ cpu->R[REG_POS(i,16)] = (uint32_t)(res>>32);
+
+ MUL_SMxxL_END(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMLAL(const uint32_t i)
+{
+
+ int64_t v = (int32_t)cpu->R[REG_POS(i,8)];
+ int64_t res = v * (int64_t)(int32_t)cpu->R[REG_POS(i,0)];
+
+ //LOG("%08X * %08X + %08X%08X\n", cpu->R[REG_POS(i,0)], cpu->R[REG_POS(i,8)], cpu->R[REG_POS(i,16)], cpu->R[REG_POS(i,12)]);
+
+ uint32_t tmp = (uint32_t)res;
+ cpu->R[REG_POS(i,16)] = (uint32_t)(res>>32) + cpu->R[REG_POS(i,16)] + CarryFrom(tmp, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,12)] += tmp;
+
+ //LOG("= %08X%08X %08X%08X\n", cpu->R[REG_POS(i,16)], cpu->R[REG_POS(i,12)], res);
+
+ MUL_SMxxL_END(3);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMULL_S(const uint32_t i)
+{
+ int64_t v = (int32_t)cpu->R[REG_POS(i,8)];
+ int64_t res = v * (int64_t)(int32_t)cpu->R[REG_POS(i,0)];
+
+ cpu->R[REG_POS(i,12)] = (uint32_t)res;
+ cpu->R[REG_POS(i,16)] = (uint32_t)(res>>32);
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,16)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,16)]==0) & (cpu->R[REG_POS(i,12)]==0);
+
+ MUL_SMxxL_END(2);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMLAL_S(const uint32_t i)
+{
+ int64_t v = (int32_t)cpu->R[REG_POS(i,8)];
+ int64_t res = v * (int64_t)(int32_t)cpu->R[REG_POS(i,0)];
+
+ uint32_t tmp = (uint32_t)res;
+ cpu->R[REG_POS(i,16)] = (uint32_t)(res>>32) + cpu->R[REG_POS(i,16)] + CarryFrom(tmp, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,12)] += tmp;
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_POS(i,16)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_POS(i,16)]==0) & (cpu->R[REG_POS(i,12)]==0);
+
+ MUL_SMxxL_END(3);
+}
+
+//-----------------------------------------------------------------------------
+// SWP / SWPB
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_SWP(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ uint32_t tmp = ROR(READ32(cpu->mem_if->data, adr), (adr & 3)<<3);
+
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,0)]);
+ cpu->R[REG_POS(i,12)] = tmp;
+
+ uint32_t c = MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(adr);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(adr);
+ return MMU_aluMemCycles<PROCNUM>(4, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SWPB(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ uint8_t tmp = READ8(cpu->mem_if->data, adr);
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)(cpu->R[REG_POS(i,0)]&0xFF));
+ cpu->R[REG_POS(i,12)] = tmp;
+
+ uint32_t c = MMU_memAccessCycles<PROCNUM,8,MMU_AD_READ>(adr);
+ c += MMU_memAccessCycles<PROCNUM,8,MMU_AD_WRITE>(adr);
+ return MMU_aluMemCycles<PROCNUM>(4, c);
+}
+
+//-----------------------------------------------------------------------------
+// LDRH
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_PRE_INDE_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_PRE_INDE_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_PRE_INDE_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] =(uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_PRE_INDE_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_POS_INDE_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] += IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_POS_INDE_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] -= IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_POS_INDE_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] += cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_POS_INDE_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] -= cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+//-----------------------------------------------------------------------------
+// STRH
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF;
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF;
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + cpu->R[REG_POS(i,0)];
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - cpu->R[REG_POS(i,0)];
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_PRE_INDE_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_PRE_INDE_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_PRE_INDE_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_PRE_INDE_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_POS_INDE_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] += IMM_OFF;
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_POS_INDE_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] -= IMM_OFF;
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_POS_INDE_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] += cpu->R[REG_POS(i,0)];
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_POS_INDE_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] -= cpu->R[REG_POS(i,0)];
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2,adr);
+}
+
+//-----------------------------------------------------------------------------
+// LDRSH
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_PRE_INDE_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_PRE_INDE_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_PRE_INDE_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_PRE_INDE_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_POS_INDE_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] += IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_POS_INDE_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] -= IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_POS_INDE_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] += cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_POS_INDE_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] -= cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (int32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3,adr);
+}
+
+//-----------------------------------------------------------------------------
+// LDRSB
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_PRE_INDE_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_PRE_INDE_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_PRE_INDE_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_PRE_INDE_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_POS_INDE_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] += IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_POS_INDE_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] -= IMM_OFF;
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_POS_INDE_P_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] += cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_POS_INDE_M_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] -= cpu->R[REG_POS(i,0)];
+ cpu->R[REG_POS(i,12)] = (int32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+//-----------------------------------------------------------------------------
+// MRS / MSR
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_MRS_CPSR(const uint32_t i)
+{
+ cpu->R[REG_POS(i,12)] = cpu->CPSR.val;
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MRS_SPSR(const uint32_t i)
+{
+ cpu->R[REG_POS(i,12)] = cpu->SPSR.val;
+
+ return 1;
+}
+#define v4_UNALLOC_MASK 0x0FFFFF00
+#define v4_USER_MASK 0xF0000000
+#define v4_PRIV_MASK 0x0000000F
+#define v4_STATE_MASK 0x00000020
+
+#define v5_UNALLOC_MASK 0x07FFFF00
+#define v5_USER_MASK 0xF8000000
+#define v5_PRIV_MASK 0x0000000F
+#define v5_STATE_MASK 0x00000020
+
+TEMPLATE static uint32_t FASTCALL OP_MSR_CPSR(const uint32_t i)
+{
+ uint32_t operand = cpu->R[REG_POS(i,0)];
+
+#if 0
+ // TODO
+ uint32_t mask = 0;
+ uint32_t byte_mask = (BIT16(i)?0x000000FF:0x00000000) |
+ (BIT17(i)?0x0000FF00:0x00000000) |
+ (BIT18(i)?0x00FF0000:0x00000000) |
+ (BIT19(i)?0xFF000000:0x00000000);
+
+ if (PROCNUM == 0)
+ {
+ if ((operand & v5_UNALLOC_MASK) != 0) printf("ARM9: MSR_CPSR_REG UNPREDICTABLE UNALLOC (operand %08X)\n", operand);
+ if (cpu->CPSR.bits.mode != USR) // Privileged mode
+ {
+ if ((operand & v5_STATE_MASK) != 0) printf("ARM9: MSR_CPSR_REG UNPREDICTABLE STATE (operand %08X)\n", operand);
+ mask = byte_mask & (v5_USER_MASK | v5_PRIV_MASK);
+ }
+ else
+ mask = byte_mask & v5_USER_MASK;
+ }
+ else
+ {
+ if ((operand & v4_UNALLOC_MASK) != 0) printf("ARM7: MSR_CPSR_REG UNPREDICTABLE UNALLOC (operand %08X)\n", operand);
+ if(cpu->CPSR.bits.mode != USR) // Privileged mode
+ {
+ if ((operand & v4_STATE_MASK) != 0) printf("ARM7: MSR_CPSR_REG UNPREDICTABLE STATE (operand %08X)\n", operand);
+ mask = byte_mask & (v4_USER_MASK | v4_PRIV_MASK);
+ }
+ else
+ mask = byte_mask & v4_USER_MASK;
+ }
+ cpu->CPSR.val = ((cpu->CPSR.val & (~mask)) | (operand & mask));
+ if (BIT16(i)) armcpu_switchMode(cpu, cpu->CPSR.bits.mode);
+ cpu->changeCPSR();
+#else
+ if(cpu->CPSR.bits.mode!=USR)
+ {
+ if(BIT16(i))
+ {
+ armcpu_switchMode(cpu, operand & 0x1F);
+ cpu->CPSR.val = (cpu->CPSR.val & 0xFFFFFF00) | (operand & 0xFF);
+ }
+ if(BIT17(i))
+ cpu->CPSR.val = (cpu->CPSR.val & 0xFFFF00FF) | (operand & 0xFF00);
+ if(BIT18(i))
+ cpu->CPSR.val = (cpu->CPSR.val & 0xFF00FFFF) | (operand & 0xFF0000);
+ }
+ if(BIT19(i))
+ cpu->CPSR.val = (cpu->CPSR.val & 0x00FFFFFF) | (operand & 0xFF000000);
+
+ cpu->changeCPSR();
+#endif
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MSR_SPSR(const uint32_t i)
+{
+ uint32_t operand = cpu->R[REG_POS(i,0)];
+
+#if 0
+ // TODO
+ uint32_t mask = 0;
+ uint32_t byte_mask = (BIT16(i)?0x000000FF:0x00000000) |
+ (BIT17(i)?0x0000FF00:0x00000000) |
+ (BIT18(i)?0x00FF0000:0x00000000) |
+ (BIT19(i)?0xFF000000:0x00000000);
+
+ if (PROCNUM == 0)
+ {
+ if ((operand & v5_UNALLOC_MASK) != 0) printf("ARM9: MSR_SPSR_REG UNPREDICTABLE UNALLOC (operand %08X)\n", operand);
+ // if CurrentModeHasSPSR
+ mask = byte_mask & (v5_USER_MASK | v5_PRIV_MASK | v5_STATE_MASK);
+ }
+ else
+ {
+ if ((operand & v4_UNALLOC_MASK) != 0) printf("ARM7: MSR_SPSR_REG UNPREDICTABLE UNALLOC (operand %08X)\n", operand);
+ // if CurrentModeHasSPSR
+ mask = byte_mask & (v4_USER_MASK | v4_PRIV_MASK | v4_STATE_MASK);
+ }
+ cpu->SPSR.val = ((cpu->SPSR.val & (~mask)) | (operand & mask));
+ cpu->changeCPSR();
+#else
+ if(cpu->CPSR.bits.mode!=USR)
+ {
+ if(BIT16(i))
+ {
+ cpu->SPSR.val = (cpu->SPSR.val & 0xFFFFFF00) | (operand & 0xFF);
+ }
+ if(BIT17(i))
+ cpu->SPSR.val = (cpu->SPSR.val & 0xFFFF00FF) | (operand & 0xFF00);
+ if(BIT18(i))
+ cpu->SPSR.val = (cpu->SPSR.val & 0xFF00FFFF) | (operand & 0xFF0000);
+ }
+ if(BIT19(i))
+ cpu->SPSR.val = (cpu->SPSR.val & 0x00FFFFFF) | (operand & 0xFF000000);
+#endif
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MSR_CPSR_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+
+#if 0
+ // TODO
+ uint32_t operand = shift_op;
+ uint32_t mask = 0;
+ uint32_t byte_mask = (BIT16(i)?0x000000FF:0x00000000) |
+ (BIT17(i)?0x0000FF00:0x00000000) |
+ (BIT18(i)?0x00FF0000:0x00000000) |
+ (BIT19(i)?0xFF000000:0x00000000);
+
+ if (PROCNUM == 0)
+ {
+ if ((operand & v5_UNALLOC_MASK) != 0) printf("ARM9: MSR_CPSR_IMM UNPREDICTABLE UNALLOC (operand %08X)\n", operand);
+ if (cpu->CPSR.bits.mode != USR) // Privileged mode
+ {
+ if ((operand & v5_STATE_MASK) != 0) printf("ARM9: MSR_CPSR_IMM UNPREDICTABLE STATE (operand %08X)\n", operand);
+ mask = byte_mask & (v5_USER_MASK | v5_PRIV_MASK);
+ }
+ else
+ mask = byte_mask & v5_USER_MASK;
+ }
+ else
+ {
+ if ((operand & v4_UNALLOC_MASK) != 0) printf("ARM7: MSR_CPSR_IMM UNPREDICTABLE UNALLOC (operand %08X)\n", operand);
+ if(cpu->CPSR.bits.mode != USR) // Privileged mode
+ {
+ if ((operand & v4_STATE_MASK) != 0) printf("ARM7: MSR_CPSR_IMM UNPREDICTABLE STATE (operand %08X)\n", operand);
+ mask = byte_mask & (v4_USER_MASK | v4_PRIV_MASK);
+ }
+ else
+ mask = byte_mask & v4_USER_MASK;
+ }
+ cpu->CPSR.val = ((cpu->CPSR.val & (~mask)) | (operand & mask));
+ if (BIT16(i)) armcpu_switchMode(cpu, cpu->CPSR.bits.mode);
+ cpu->changeCPSR();
+#else
+ if(cpu->CPSR.bits.mode!=USR)
+ {
+ if(BIT16(i))
+ {
+ armcpu_switchMode(cpu, shift_op & 0x1F);
+ cpu->CPSR.val = (cpu->CPSR.val & 0xFFFFFF00) | (shift_op & 0xFF);
+ }
+ if(BIT17(i))
+ cpu->CPSR.val = (cpu->CPSR.val & 0xFFFF00FF) | (shift_op & 0xFF00);
+ if(BIT18(i))
+ cpu->CPSR.val = (cpu->CPSR.val & 0xFF00FFFF) | (shift_op & 0xFF0000);
+ }
+ if(BIT19(i))
+ {
+ //cpu->CPSR.val = (cpu->CPSR.val & 0xFF000000) | (shift_op & 0xFF000000);
+ cpu->CPSR.val = (cpu->CPSR.val & 0x00FFFFFF) | (shift_op & 0xFF000000);
+ }
+ cpu->changeCPSR();
+#endif
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MSR_SPSR_IMM_VAL(const uint32_t i)
+{
+ IMM_VALUE;
+
+#if 0
+ // TODO
+ uint32_t operand = shift_op;
+ uint32_t mask = 0;
+ uint32_t byte_mask = (BIT16(i)?0x000000FF:0x00000000) |
+ (BIT17(i)?0x0000FF00:0x00000000) |
+ (BIT18(i)?0x00FF0000:0x00000000) |
+ (BIT19(i)?0xFF000000:0x00000000);
+
+ if (PROCNUM == 0)
+ {
+ if ((operand & v5_UNALLOC_MASK) != 0) printf("ARM9: MSR_SPSR_IMM UNPREDICTABLE UNALLOC (operand %08X)\n", operand);
+ // if CurrentModeHasSPSR
+ mask = byte_mask & (v5_USER_MASK | v5_PRIV_MASK | v5_STATE_MASK);
+ }
+ else
+ {
+ if ((operand & v4_UNALLOC_MASK) != 0) printf("ARM7: MSR_SPSR_IMM UNPREDICTABLE UNALLOC (operand %08X)\n", operand);
+ // if CurrentModeHasSPSR
+ mask = byte_mask & (v4_USER_MASK | v4_PRIV_MASK | v4_STATE_MASK);
+ }
+ cpu->SPSR.val = ((cpu->SPSR.val & (~mask)) | (operand & mask));
+#else
+ if(cpu->CPSR.bits.mode!=USR)
+ {
+ if(BIT16(i))
+ {
+ cpu->SPSR.val = (cpu->SPSR.val & 0xFFFFFF00) | (shift_op & 0xFF);
+ }
+ if(BIT17(i))
+ cpu->SPSR.val = (cpu->SPSR.val & 0xFFFF00FF) | (shift_op & 0xFF00);
+ if(BIT18(i))
+ cpu->SPSR.val = (cpu->SPSR.val & 0xFF00FFFF) | (shift_op & 0xFF0000);
+ }
+ if(BIT19(i))
+ {
+ cpu->SPSR.val = (cpu->SPSR.val & 0xFF000000) | (shift_op & 0xFF000000);
+ }
+
+ cpu->changeCPSR();
+#endif
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Branch
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_BX(const uint32_t i)
+{
+ uint32_t tmp = cpu->R[REG_POS(i, 0)];
+
+ if (REG_POS(i, 0) == 15)
+ {
+ //printf("ARM%c: BX using PC as operand\n", PROCNUM?'7':'9');
+ //emu_halt();
+ }
+ cpu->CPSR.bits.T = BIT0(tmp);
+ cpu->R[15] = tmp & (0xFFFFFFFC|(cpu->CPSR.bits.T<<1));
+ cpu->next_instruction = cpu->R[15];
+ return 3;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BLX_REG(const uint32_t i)
+{
+ uint32_t tmp = cpu->R[REG_POS(i, 0)];
+
+ cpu->R[14] = cpu->next_instruction;
+ cpu->CPSR.bits.T = BIT0(tmp);
+ cpu->R[15] = tmp & (0xFFFFFFFC|(cpu->CPSR.bits.T<<1));
+ cpu->next_instruction = cpu->R[15];
+ return 3;
+}
+
+#define SIGNEXTEND_24(i) (((int32_t)i<<8)>>8)
+
+TEMPLATE static uint32_t FASTCALL OP_B(const uint32_t i)
+{
+ /*static const uint32_t mov_r12_r12 = 0xE1A0C00C;
+ const uint32_t last = _MMU_read32<PROCNUM,MMU_AT_DEBUG>(cpu->instruct_adr-4);
+ if(last == mov_r12_r12)
+ {
+ const uint32_t next = _MMU_read16<PROCNUM,MMU_AT_DEBUG>(cpu->instruct_adr+4);
+ if(next == 0x6464)
+ NocashMessage(cpu, 8);
+ }*/
+
+ uint32_t off = SIGNEXTEND_24(i);
+ if(CONDITION(i)==0xF)
+ {
+ cpu->R[14] = cpu->next_instruction;
+ cpu->CPSR.bits.T = 1;
+ }
+ cpu->R[15] += (off<<2);
+ cpu->R[15] &= (0xFFFFFFFC|(cpu->CPSR.bits.T<<1));
+ cpu->next_instruction = cpu->R[15];
+
+ return 3;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BL(const uint32_t i)
+{
+ uint32_t off = SIGNEXTEND_24(i);
+ if(CONDITION(i)==0xF)
+ {
+ cpu->CPSR.bits.T = 1;
+ cpu->R[15] += 2;
+ }
+ cpu->R[14] = cpu->next_instruction;
+ cpu->R[15] += (off<<2);
+ cpu->R[15] &= (0xFFFFFFFC|(cpu->CPSR.bits.T<<1));
+ cpu->next_instruction = cpu->R[15];
+
+ return 3;
+}
+
+//-----------------------------------------------------------------------------
+// CLZ
+//-----------------------------------------------------------------------------
+
+const uint8_t CLZ_TAB[16]=
+{
+ 0, // 0000
+ 1, // 0001
+ 2, 2, // 001X
+ 3, 3, 3, 3, // 01XX
+ 4, 4, 4, 4, 4, 4, 4, 4 // 1XXX
+};
+
+TEMPLATE static uint32_t FASTCALL OP_CLZ(const uint32_t i)
+{
+ uint32_t Rm = cpu->R[REG_POS(i,0)];
+ uint32_t pos;
+
+ if(Rm==0)
+ {
+ cpu->R[REG_POS(i,12)]=32;
+ return 2;
+ }
+
+ Rm |= (Rm >>1);
+ Rm |= (Rm >>2);
+ Rm |= (Rm >>4);
+ Rm |= (Rm >>8);
+ Rm |= (Rm >>16);
+
+ pos =
+ CLZ_TAB[Rm&0xF] +
+ CLZ_TAB[(Rm>>4)&0xF] +
+ CLZ_TAB[(Rm>>8)&0xF] +
+ CLZ_TAB[(Rm>>12)&0xF] +
+ CLZ_TAB[(Rm>>16)&0xF] +
+ CLZ_TAB[(Rm>>20)&0xF] +
+ CLZ_TAB[(Rm>>24)&0xF] +
+ CLZ_TAB[(Rm>>28)&0xF];
+
+ cpu->R[REG_POS(i,12)]=32 - pos;
+
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// QADD / QDADD / QSUB / QDSUB
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_QADD(const uint32_t i)
+{
+ uint32_t res = cpu->R[REG_POS(i,16)]+cpu->R[REG_POS(i,0)];
+
+ //LOG("spe add\n");
+ if(SIGNED_OVERFLOW(cpu->R[REG_POS(i,16)],cpu->R[REG_POS(i,0)], res))
+ {
+ cpu->CPSR.bits.Q=1;
+ cpu->R[REG_POS(i,12)]=0x80000000-BIT31(res);
+ return 2;
+ }
+ cpu->R[REG_POS(i,12)]=res;
+ if(REG_POS(i,12)==15)
+ {
+ cpu->R[15] &= 0xFFFFFFFC;
+ cpu->next_instruction = cpu->R[15];
+ return 3;
+ }
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_QSUB(const uint32_t i)
+{
+ uint32_t res = cpu->R[REG_POS(i,0)]-cpu->R[REG_POS(i,16)];
+
+ //LOG("spe add\n");
+ if(SIGNED_UNDERFLOW(cpu->R[REG_POS(i,0)], cpu->R[REG_POS(i,16)], res))
+ {
+ cpu->CPSR.bits.Q=1;
+ cpu->R[REG_POS(i,12)]=0x80000000-BIT31(res);
+ return 2;
+ }
+
+ cpu->R[REG_POS(i,12)]=res;
+ if(REG_POS(i,12)==15)
+ {
+ cpu->R[15] &= 0xFFFFFFFC;
+ cpu->next_instruction = cpu->R[15];
+ return 3;
+ }
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_QDADD(const uint32_t i)
+{
+ uint32_t mul = cpu->R[REG_POS(i,16)]<<1;
+ uint32_t res;
+
+
+ //LOG("spe add\n");
+ if(BIT31(cpu->R[REG_POS(i,16)])!=BIT31(mul))
+ {
+ cpu->CPSR.bits.Q=1;
+ mul = 0x80000000-BIT31(mul);
+ }
+
+ res = mul + cpu->R[REG_POS(i,0)];
+ if(SIGNED_OVERFLOW(cpu->R[REG_POS(i,0)],mul, res))
+ {
+ cpu->CPSR.bits.Q=1;
+ cpu->R[REG_POS(i,12)]=0x80000000-BIT31(res);
+ return 2;
+ }
+ cpu->R[REG_POS(i,12)]=res;
+ if(REG_POS(i,12)==15)
+ {
+ cpu->R[15] &= 0xFFFFFFFC;
+ cpu->next_instruction = cpu->R[15];
+ return 3;
+ }
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_QDSUB(const uint32_t i)
+{
+ uint32_t mul = cpu->R[REG_POS(i,16)]<<1;
+ uint32_t res;
+
+
+ //LOG("spe add\n");
+ if(BIT31(cpu->R[REG_POS(i,16)])!=BIT31(mul))
+ {
+ cpu->CPSR.bits.Q=1;
+ mul = 0x80000000-BIT31(mul);
+ }
+
+ res = cpu->R[REG_POS(i,0)] - mul;
+ if(SIGNED_UNDERFLOW(cpu->R[REG_POS(i,0)], mul, res))
+ {
+ cpu->CPSR.bits.Q=1;
+ cpu->R[REG_POS(i,12)]=0x80000000-BIT31(res);
+ return 2;
+ }
+ cpu->R[REG_POS(i,12)]=res;
+ if(REG_POS(i,12)==15)
+ {
+ cpu->R[15] &= 0xFFFFFFFC;
+ cpu->next_instruction = cpu->R[15];
+ return 3;
+ }
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// SMUL
+//-----------------------------------------------------------------------------
+
+#define HWORD(i) ((int32_t)(((int32_t)(i))>>16))
+#define LWORD(i) (int32_t)(((int32_t)((i)<<16))>>16)
+
+TEMPLATE static uint32_t FASTCALL OP_SMUL_B_B(const uint32_t i)
+{
+ // checked
+ //INFO("SMUL_B_B\n");
+ cpu->R[REG_POS(i,16)] = (uint32_t)(LWORD(cpu->R[REG_POS(i,0)])* LWORD(cpu->R[REG_POS(i,8)]));
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMUL_B_T(const uint32_t i)
+{
+ //INFO("SMUL_B_T\n");
+ cpu->R[REG_POS(i,16)] = (uint32_t)(LWORD(cpu->R[REG_POS(i,0)])* HWORD(cpu->R[REG_POS(i,8)]));
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMUL_T_B(const uint32_t i)
+{
+ //INFO("SMUL_T_B\n");
+ cpu->R[REG_POS(i,16)] = (uint32_t)(HWORD(cpu->R[REG_POS(i,0)])* LWORD(cpu->R[REG_POS(i,8)]));
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMUL_T_T(const uint32_t i)
+{
+ //INFO("SMUL_T_T\n");
+ cpu->R[REG_POS(i,16)] = (uint32_t)(HWORD(cpu->R[REG_POS(i,0)])* HWORD(cpu->R[REG_POS(i,8)]));
+
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// SMLA
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_SMLA_B_B(const uint32_t i)
+{
+ uint32_t tmp = (uint32_t)((int16_t)cpu->R[REG_POS(i,0)]* (int16_t)cpu->R[REG_POS(i,8)]);
+
+ cpu->R[REG_POS(i,16)] = tmp + cpu->R[REG_POS(i,12)];
+
+ if (OverflowFromADD(cpu->R[REG_POS(i,16)], tmp, cpu->R[REG_POS(i,12)]))
+ cpu->CPSR.bits.Q = 1;
+ //INFO("SMLABB %08X * %08X + %08X = %08X\n", (int16_t)cpu->R[REG_POS(i,0)], (int16_t)cpu->R[REG_POS(i,8)], cpu->R[REG_POS(i,12)], (int32_t)cpu->R[REG_POS(i,16)]);
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMLA_B_T(const uint32_t i)
+{
+ uint32_t tmp = (uint32_t)(LWORD(cpu->R[REG_POS(i,0)])* HWORD(cpu->R[REG_POS(i,8)]));
+ uint32_t a = cpu->R[REG_POS(i,12)];
+
+ //INFO("SMLABT %08X * %08X + %08X = %08X\n", cpu->R[REG_POS(i,0)], cpu->R[REG_POS(i,8)], a, tmp + a);
+ cpu->R[REG_POS(i,16)] = tmp + a;
+
+ if(SIGNED_OVERFLOW(tmp, a, cpu->R[REG_POS(i,16)]))
+ cpu->CPSR.bits.Q = 1;
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMLA_T_B(const uint32_t i)
+{
+ uint32_t tmp = (uint32_t)(HWORD(cpu->R[REG_POS(i,0)])* LWORD(cpu->R[REG_POS(i,8)]));
+ uint32_t a = cpu->R[REG_POS(i,12)];
+
+ //INFO("SMLATB %08X * %08X + %08X = %08X\n", cpu->R[REG_POS(i,0)], cpu->R[REG_POS(i,8)], a, tmp + a);
+ cpu->R[REG_POS(i,16)] = tmp + a;
+
+ if(SIGNED_OVERFLOW(tmp, a, cpu->R[REG_POS(i,16)]))
+ cpu->CPSR.bits.Q = 1;
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMLA_T_T(const uint32_t i)
+{
+ uint32_t tmp = (uint32_t)(HWORD(cpu->R[REG_POS(i,0)])* HWORD(cpu->R[REG_POS(i,8)]));
+ uint32_t a = cpu->R[REG_POS(i,12)];
+
+ //INFO("SMLATT %08X * %08X + %08X = %08X\n", cpu->R[REG_POS(i,0)], cpu->R[REG_POS(i,8)], a, tmp + a);
+ cpu->R[REG_POS(i,16)] = tmp + a;
+
+ if(SIGNED_OVERFLOW(tmp, a, cpu->R[REG_POS(i,16)]))
+ cpu->CPSR.bits.Q = 1;
+
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// SMLAL
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_SMLAL_B_B(const uint32_t i)
+{
+ int64_t tmp = (int64_t)(LWORD(cpu->R[REG_POS(i,0)])* LWORD(cpu->R[REG_POS(i,8)]));
+ uint64_t res = (uint64_t)tmp + cpu->R[REG_POS(i,12)];
+
+ //INFO("SMLALBB %08X * %08X + %08X%08X = %08X%08X\n", (int)cpu->R[REG_POS(i,0)], (int)cpu->R[REG_POS(i,8)], (int)cpu->R[REG_POS(i,16)], (int)cpu->R[REG_POS(i,12)], (int)(cpu->R[REG_POS(i,16)] + (res + ((tmp<0)*0xFFFFFFFF))), (int)(uint32_t) res);
+
+ cpu->R[REG_POS(i,12)] = (uint32_t) res;
+ cpu->R[REG_POS(i,16)] += static_cast<uint32_t>(res + ((tmp<0)*0xFFFFFFFF));
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMLAL_B_T(const uint32_t i)
+{
+ int64_t tmp = (int64_t)(LWORD(cpu->R[REG_POS(i,0)])* HWORD(cpu->R[REG_POS(i,8)]));
+ uint64_t res = (uint64_t)tmp + cpu->R[REG_POS(i,12)];
+
+ //INFO("SMLALBT %08X * %08X + %08X%08X = %08X%08X\n", (int)cpu->R[REG_POS(i,0)], (int)cpu->R[REG_POS(i,8)], (int)cpu->R[REG_POS(i,16)], (int)cpu->R[REG_POS(i,12)], (int)(cpu->R[REG_POS(i,16)] + res + ((tmp<0)*0xFFFFFFFF)), (int)(uint32_t) res);
+
+ cpu->R[REG_POS(i,12)] = (uint32_t) res;
+ cpu->R[REG_POS(i,16)] += static_cast<uint32_t>(res + ((tmp<0)*0xFFFFFFFF));
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMLAL_T_B(const uint32_t i)
+{
+ int64_t tmp = (int64_t)(HWORD(cpu->R[REG_POS(i,0)])* (int64_t)LWORD(cpu->R[REG_POS(i,8)]));
+ uint64_t res = (uint64_t)tmp + cpu->R[REG_POS(i,12)];
+
+ //INFO("SMLALTB %08X * %08X + %08X%08X = %08X%08X\n", (int)cpu->R[REG_POS(i,0)], (int)cpu->R[REG_POS(i,8)], (int)cpu->R[REG_POS(i,16)], (int)cpu->R[REG_POS(i,12)], (int)(cpu->R[REG_POS(i,16)] + res + ((tmp<0)*0xFFFFFFFF)), (int)(uint32_t) res);
+
+ cpu->R[REG_POS(i,12)] = (uint32_t) res;
+ cpu->R[REG_POS(i,16)] += static_cast<uint32_t>(res + ((tmp<0)*0xFFFFFFFF));
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMLAL_T_T(const uint32_t i)
+{
+ int64_t tmp = (int64_t)(HWORD(cpu->R[REG_POS(i,0)])* HWORD(cpu->R[REG_POS(i,8)]));
+ uint64_t res = (uint64_t)tmp + cpu->R[REG_POS(i,12)];
+
+ //INFO("SMLALTT %08X * %08X + %08X%08X = %08X%08X\n", (int)cpu->R[REG_POS(i,0)], (int)cpu->R[REG_POS(i,8)], (int)cpu->R[REG_POS(i,16)], (int)cpu->R[REG_POS(i,12)], (int)(cpu->R[REG_POS(i,16)] + res + ((tmp<0)*0xFFFFFFFF)), (int)(uint32_t) res);
+
+ cpu->R[REG_POS(i,12)] = (uint32_t) res;
+ cpu->R[REG_POS(i,16)] += static_cast<uint32_t>(res + ((tmp<0)*0xFFFFFFFF));
+
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// SMULW
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_SMULW_B(const uint32_t i)
+{
+ int64_t tmp = (int64_t)LWORD(cpu->R[REG_POS(i,8)]) * (int64_t)((int32_t)cpu->R[REG_POS(i,0)]);
+
+ //INFO("SMULWB %08X * %08X = %08X\n", cpu->R[REG_POS(i,0)], cpu->R[REG_POS(i,8)], ((tmp>>16)&0xFFFFFFFF));
+
+ cpu->R[REG_POS(i,16)] = ((tmp>>16)&0xFFFFFFFF);
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMULW_T(const uint32_t i)
+{
+ int64_t tmp = (int64_t)HWORD(cpu->R[REG_POS(i,8)]) * (int64_t)((int32_t)cpu->R[REG_POS(i,0)]);
+
+ //INFO("SMULWT %08X * %08X = %08X\n", cpu->R[REG_POS(i,0)], cpu->R[REG_POS(i,8)], ((tmp>>16)&0xFFFFFFFF));
+
+ cpu->R[REG_POS(i,16)] = ((tmp>>16)&0xFFFFFFFF);
+
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// SMLAW
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_SMLAW_B(const uint32_t i)
+{
+ int64_t tmp = (int64_t)LWORD(cpu->R[REG_POS(i,8)]) * (int64_t)((int32_t)cpu->R[REG_POS(i,0)]);
+ uint32_t a = cpu->R[REG_POS(i,12)];
+
+ //INFO("SMLAWB %08X * %08X + %08X = %08X\n", cpu->R[REG_POS(i,0)], cpu->R[REG_POS(i,8)], a, (tmp>>16) + a);
+
+ tmp = (tmp>>16);
+
+ cpu->R[REG_POS(i,16)] = static_cast<uint32_t>(tmp + a);
+
+ if(SIGNED_OVERFLOW((uint32_t)tmp, a, cpu->R[REG_POS(i,16)]))
+ cpu->CPSR.bits.Q = 1;
+
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SMLAW_T(const uint32_t i)
+{
+ int64_t tmp = (int64_t)HWORD(cpu->R[REG_POS(i,8)]) * (int64_t)((int32_t)cpu->R[REG_POS(i,0)]);
+ uint32_t a = cpu->R[REG_POS(i,12)];
+
+ //INFO("SMLAWT %08X * %08X + %08X = %08X\n", cpu->R[REG_POS(i,0)], cpu->R[REG_POS(i,8)], a, ((tmp>>16)&0xFFFFFFFF) + a);
+
+ tmp = ((tmp>>16)&0xFFFFFFFF);
+ cpu->R[REG_POS(i,16)] = static_cast<uint32_t>(tmp + a);
+
+ if(SIGNED_OVERFLOW((uint32_t)tmp, a, cpu->R[REG_POS(i,16)]))
+ cpu->CPSR.bits.Q = 1;
+
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// LDR
+//-----------------------------------------------------------------------------
+#define OP_LDR(a, b) \
+ cpu->R[REG_POS(i,12)] = ROR(READ32(cpu->mem_if->data, adr), 8*(adr&3)); \
+ \
+ if(REG_POS(i,12)==15) \
+ { \
+ if (cpu->LDTBit) \
+ { \
+ cpu->CPSR.bits.T = BIT0(cpu->R[15]); \
+ cpu->R[15] &= 0xFFFFFFFE; \
+ } \
+ else \
+ { \
+ cpu->R[15] &= 0xFFFFFFFC; \
+ } \
+ cpu->next_instruction = cpu->R[15]; \
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(b,adr); \
+ } \
+ \
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(a,adr);
+
+// PRE
+#define OP_LDR_W(a, b) \
+ cpu->R[REG_POS(i,16)] = adr;\
+ cpu->R[REG_POS(i,12)] = ROR(READ32(cpu->mem_if->data, adr), 8*(adr&3)); \
+ \
+ if(REG_POS(i,12)==15) \
+ { \
+ if (cpu->LDTBit) \
+ { \
+ cpu->CPSR.bits.T = BIT0(cpu->R[15]); \
+ cpu->R[15] &= 0xFFFFFFFE; \
+ } \
+ else \
+ { \
+ cpu->R[15] &= 0xFFFFFFFC; \
+ } \
+ cpu->next_instruction = cpu->R[15]; \
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(b,adr); \
+ } \
+ \
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(a,adr);
+
+// POST
+#define OP_LDR_W2(a, b, c) \
+ uint32_t adr = cpu->R[REG_POS(i,16)]; \
+ cpu->R[REG_POS(i,16)] = adr + c;\
+ cpu->R[REG_POS(i,12)] = ROR(READ32(cpu->mem_if->data, adr), 8*(adr&3)); \
+ \
+ if(REG_POS(i,12)==15) \
+ { \
+ if (cpu->LDTBit) \
+ { \
+ cpu->CPSR.bits.T = BIT0(cpu->R[15]); \
+ cpu->R[15] &= 0xFFFFFFFE; \
+ } \
+ else \
+ { \
+ cpu->R[15] &= 0xFFFFFFFC; \
+ } \
+ cpu->next_instruction = cpu->R[15]; \
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(b,adr); \
+ } \
+ \
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(a,adr);
+
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF_12;
+ OP_LDR(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF_12;
+ OP_LDR(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDREX(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,12)] = ROR(READ32(cpu->mem_if->data, adr), 8*(adr&3));
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_LSL_IMM_OFF(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ OP_LDR(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_LSL_IMM_OFF(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ OP_LDR(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_LSR_IMM_OFF(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ OP_LDR(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_LSR_IMM_OFF(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ OP_LDR(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_ASR_IMM_OFF(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ OP_LDR(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_ASR_IMM_OFF(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ OP_LDR(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_ROR_IMM_OFF(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ OP_LDR(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_ROR_IMM_OFF(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ OP_LDR(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_IMM_OFF_PREIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF_12;
+ OP_LDR_W(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_IMM_OFF_PREIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF_12;
+ OP_LDR_W(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_LSL_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ OP_LDR_W(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_LSL_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ OP_LDR_W(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_LSR_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ OP_LDR_W(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_LSR_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ OP_LDR_W(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_ASR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ OP_LDR_W(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_ASR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ OP_LDR_W(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_ROR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ OP_LDR_W(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_ROR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ OP_LDR_W(3, 5);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_IMM_OFF_POSTIND(const uint32_t i)
+{
+ OP_LDR_W2(3, 5, IMM_OFF_12);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_IMM_OFF_POSTIND(const uint32_t i)
+{
+ OP_LDR_W2(3, 5, -IMM_OFF_12);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_LSL_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSL_IMM;
+ OP_LDR_W2(3, 5, shift_op);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_LSL_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSL_IMM;
+ OP_LDR_W2(3, 5, -shift_op);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_LSR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSR_IMM;
+ OP_LDR_W2(3, 5, shift_op);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_LSR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSR_IMM;
+ OP_LDR_W2(3, 5, -shift_op);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_ASR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ASR_IMM;
+ OP_LDR_W2(3, 5, shift_op);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_ASR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ASR_IMM;
+ OP_LDR_W2(3, 5, -shift_op);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_P_ROR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ROR_IMM;
+ OP_LDR_W2(3, 5, shift_op);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_M_ROR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ROR_IMM;
+ OP_LDR_W2(3, 5, -shift_op);
+}
+
+//-----------------------------------------------------------------------------
+// LDRB
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF_12;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF_12;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_LSL_IMM_OFF(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_LSL_IMM_OFF(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_LSR_IMM_OFF(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,12)] = READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_LSR_IMM_OFF(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_ASR_IMM_OFF(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_ASR_IMM_OFF(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_ROR_IMM_OFF(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_ROR_IMM_OFF(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_IMM_OFF_PREIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF_12;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_IMM_OFF_PREIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF_12;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_LSL_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_LSL_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_LSR_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_LSR_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_ASR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_ASR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_ROR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_ROR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_IMM_OFF_POSTIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] = adr + IMM_OFF_12;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_IMM_OFF_POSTIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] = adr - IMM_OFF_12;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_LSL_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_LSL_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_LSR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_LSR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_ASR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_ASR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_P_ROR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_M_ROR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+ cpu->R[REG_POS(i,12)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3,adr);
+}
+
+//-----------------------------------------------------------------------------
+// STR
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF_12;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF_12;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STREX(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,0)]);
+ cpu->R[REG_POS(i,12)] = 0;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_LSL_IMM_OFF(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_LSL_IMM_OFF(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_LSR_IMM_OFF(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_LSR_IMM_OFF(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_ASR_IMM_OFF(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_ASR_IMM_OFF(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_ROR_IMM_OFF(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_ROR_IMM_OFF(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_IMM_OFF_PREIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF_12;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_IMM_OFF_PREIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF_12;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_LSL_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_LSL_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_LSR_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_LSR_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_ASR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_ASR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_ROR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_ROR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_IMM_OFF_POSTIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr + IMM_OFF_12;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_IMM_OFF_POSTIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr - IMM_OFF_12;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_LSL_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_LSL_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_LSR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_LSR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_ASR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_ASR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_P_ROR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_M_ROR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2,adr);
+}
+
+//-----------------------------------------------------------------------------
+// STRB
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF_12;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF_12;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_LSL_IMM_OFF(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_LSL_IMM_OFF(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_LSR_IMM_OFF(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_LSR_IMM_OFF(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_ASR_IMM_OFF(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_ASR_IMM_OFF(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_ROR_IMM_OFF(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_ROR_IMM_OFF(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_IMM_OFF_PREIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] + IMM_OFF_12;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_IMM_OFF_PREIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)] - IMM_OFF_12;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_LSL_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_LSL_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_LSR_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_LSR_IMM_OFF_PREIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_ASR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_ASR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_ROR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] + shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_ROR_IMM_OFF_PREIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)] - shift_op;
+ cpu->R[REG_POS(i,16)] = adr;
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_IMM_OFF_POSTIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr + IMM_OFF_12;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_IMM_OFF_POSTIND(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr - IMM_OFF_12;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_LSL_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_LSL_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSL_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_LSR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_LSR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ LSR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_ASR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_ASR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ASR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_P_ROR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr + shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_M_ROR_IMM_OFF_POSTIND(const uint32_t i)
+{
+ ROR_IMM;
+ uint32_t adr = cpu->R[REG_POS(i,16)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_POS(i,12)]);
+ cpu->R[REG_POS(i,16)] = adr - shift_op;
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2,adr);
+}
+
+//-----------------------------------------------------------------------------
+// LDMIA / LDMIB / LDMDA / LDMDB
+//-----------------------------------------------------------------------------
+
+#define OP_L_IA(reg, adr) if(BIT##reg(i)) \
+ { \
+ registres[reg] = READ32(cpu->mem_if->data, start); \
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start); \
+ adr += 4; \
+ }
+
+#define OP_L_IB(reg, adr) if(BIT##reg(i)) \
+ { \
+ adr += 4; \
+ registres[reg] = READ32(cpu->mem_if->data, start); \
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start); \
+ }
+
+#define OP_L_DA(reg, adr) if(BIT##reg(i)) \
+ { \
+ registres[reg] = READ32(cpu->mem_if->data, start); \
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start); \
+ adr -= 4; \
+ }
+
+#define OP_L_DB(reg, adr) if(BIT##reg(i)) \
+ { \
+ adr -= 4; \
+ registres[reg] = READ32(cpu->mem_if->data, start); \
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start); \
+ }
+
+TEMPLATE static uint32_t FASTCALL OP_LDMIA(const uint32_t i)
+{
+ uint32_t c = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ uint32_t * registres = cpu->R;
+
+ OP_L_IA(0, start);
+ OP_L_IA(1, start);
+ OP_L_IA(2, start);
+ OP_L_IA(3, start);
+ OP_L_IA(4, start);
+ OP_L_IA(5, start);
+ OP_L_IA(6, start);
+ OP_L_IA(7, start);
+ OP_L_IA(8, start);
+ OP_L_IA(9, start);
+ OP_L_IA(10, start);
+ OP_L_IA(11, start);
+ OP_L_IA(12, start);
+ OP_L_IA(13, start);
+ OP_L_IA(14, start);
+
+ if(BIT15(i))
+ {
+ uint32_t tmp = READ32(cpu->mem_if->data, start);
+ // TODO
+ // The general-purpose registers loaded can include the PC. If they do, the word loaded for the PC is treated
+ // as an address and a branch occurs to that address. In ARMv5 and above, bit[0] of the loaded value
+ // determines whether execution continues after this branch in ARM state or in Thumb state, as though a BX
+ // (loaded_value) instruction had been executed (but see also The T and J bits on page A2-15 for operation on
+ // non-T variants of ARMv5). In earlier versions of the architecture, bits[1:0] of the loaded value are ignored
+ // and execution continues in ARM state, as though the instruction MOV PC,(loaded_value) had been executed.
+ //
+ //value = Memory[address,4]
+ //if (architecture version 5 or above) then
+ // pc = value AND 0xFFFFFFFE
+ // T Bit = value[0]
+ //else
+ // pc = value AND 0xFFFFFFFC
+ if (cpu->LDTBit)
+ {
+ cpu->CPSR.bits.T = BIT0(tmp);
+ registres[15] = tmp & 0xFFFFFFFE;
+ }
+ else
+ registres[15] = tmp & 0xFFFFFFFC;
+
+ //start += 4;
+ cpu->next_instruction = registres[15];
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ }
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMIB(const uint32_t i)
+{
+ uint32_t c = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ uint32_t * registres = cpu->R;
+
+ OP_L_IB(0, start);
+ OP_L_IB(1, start);
+ OP_L_IB(2, start);
+ OP_L_IB(3, start);
+ OP_L_IB(4, start);
+ OP_L_IB(5, start);
+ OP_L_IB(6, start);
+ OP_L_IB(7, start);
+ OP_L_IB(8, start);
+ OP_L_IB(9, start);
+ OP_L_IB(10, start);
+ OP_L_IB(11, start);
+ OP_L_IB(12, start);
+ OP_L_IB(13, start);
+ OP_L_IB(14, start);
+
+ if(BIT15(i))
+ {
+ start += 4;
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ uint32_t tmp = READ32(cpu->mem_if->data, start);
+ if (cpu->LDTBit)
+ {
+ cpu->CPSR.bits.T = BIT0(tmp);
+ registres[15] = tmp & 0xFFFFFFFE;
+ }
+ else
+ registres[15] = tmp & 0xFFFFFFFC;
+ cpu->next_instruction = registres[15];
+ return MMU_aluMemCycles<PROCNUM>(4, c);
+ }
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMDA(const uint32_t i)
+{
+ uint32_t c = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ uint32_t * registres = cpu->R;
+
+ if(BIT15(i))
+ {
+ uint32_t tmp = READ32(cpu->mem_if->data, start);
+ if (cpu->LDTBit)
+ {
+ cpu->CPSR.bits.T = BIT0(tmp);
+ registres[15] = tmp & 0xFFFFFFFE;
+ }
+ else
+ registres[15] = tmp & 0xFFFFFFFC;
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ start -= 4;
+ cpu->next_instruction = registres[15];
+ }
+
+ OP_L_DA(14, start);
+ OP_L_DA(13, start);
+ OP_L_DA(12, start);
+ OP_L_DA(11, start);
+ OP_L_DA(10, start);
+ OP_L_DA(9, start);
+ OP_L_DA(8, start);
+ OP_L_DA(7, start);
+ OP_L_DA(6, start);
+ OP_L_DA(5, start);
+ OP_L_DA(4, start);
+ OP_L_DA(3, start);
+ OP_L_DA(2, start);
+ OP_L_DA(1, start);
+ OP_L_DA(0, start);
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMDB(const uint32_t i)
+{
+ uint32_t c = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ uint32_t * registres = cpu->R;
+
+ if(BIT15(i))
+ {
+ start -= 4;
+ uint32_t tmp = READ32(cpu->mem_if->data, start);
+ if (cpu->LDTBit)
+ {
+ cpu->CPSR.bits.T = BIT0(tmp);
+ registres[15] = tmp & 0xFFFFFFFE;
+ }
+ else
+ registres[15] = tmp & 0xFFFFFFFC;
+ cpu->next_instruction = registres[15];
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ }
+
+ OP_L_DB(14, start);
+ OP_L_DB(13, start);
+ OP_L_DB(12, start);
+ OP_L_DB(11, start);
+ OP_L_DB(10, start);
+ OP_L_DB(9, start);
+ OP_L_DB(8, start);
+ OP_L_DB(7, start);
+ OP_L_DB(6, start);
+ OP_L_DB(5, start);
+ OP_L_DB(4, start);
+ OP_L_DB(3, start);
+ OP_L_DB(2, start);
+ OP_L_DB(1, start);
+ OP_L_DB(0, start);
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMIA_W(const uint32_t i)
+{
+ uint32_t c = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ uint32_t bitList = (~((2 << REG_POS(i,16))-1)) & 0xFFFF;
+
+ uint32_t * registres = cpu->R;
+
+ OP_L_IA(0, start);
+ OP_L_IA(1, start);
+ OP_L_IA(2, start);
+ OP_L_IA(3, start);
+ OP_L_IA(4, start);
+ OP_L_IA(5, start);
+ OP_L_IA(6, start);
+ OP_L_IA(7, start);
+ OP_L_IA(8, start);
+ OP_L_IA(9, start);
+ OP_L_IA(10, start);
+ OP_L_IA(11, start);
+ OP_L_IA(12, start);
+ OP_L_IA(13, start);
+ OP_L_IA(14, start);
+
+ if(BIT15(i))
+ {
+ uint32_t tmp = READ32(cpu->mem_if->data, start);
+ if (cpu->LDTBit)
+ {
+ cpu->CPSR.bits.T = BIT0(tmp);
+ registres[15] = tmp & 0xFFFFFFFE;
+ }
+ else
+ registres[15] = tmp & 0xFFFFFFFC;
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ start += 4;
+ cpu->next_instruction = registres[15];
+ }
+
+ if(i & (1 << REG_POS(i,16))) {
+ if(i & bitList)
+ cpu->R[REG_POS(i,16)] = start;
+ }
+ else
+ cpu->R[REG_POS(i,16)] = start;
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMIB_W(const uint32_t i)
+{
+ uint32_t c = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ uint32_t bitList = (~((2 << REG_POS(i,16))-1)) & 0xFFFF;
+
+ uint32_t * registres = cpu->R;
+
+ OP_L_IB(0, start);
+ OP_L_IB(1, start);
+ OP_L_IB(2, start);
+ OP_L_IB(3, start);
+ OP_L_IB(4, start);
+ OP_L_IB(5, start);
+ OP_L_IB(6, start);
+ OP_L_IB(7, start);
+ OP_L_IB(8, start);
+ OP_L_IB(9, start);
+ OP_L_IB(10, start);
+ OP_L_IB(11, start);
+ OP_L_IB(12, start);
+ OP_L_IB(13, start);
+ OP_L_IB(14, start);
+
+ if(BIT15(i))
+ {
+ uint32_t tmp;
+ start += 4;
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ tmp = READ32(cpu->mem_if->data, start);
+ if (cpu->LDTBit)
+ {
+ cpu->CPSR.bits.T = BIT0(tmp);
+ registres[15] = tmp & 0xFFFFFFFE;
+ }
+ else
+ registres[15] = tmp & 0xFFFFFFFC;
+ cpu->next_instruction = registres[15];
+ }
+
+ if(i & (1 << REG_POS(i,16))) {
+ if(i & bitList)
+ cpu->R[REG_POS(i,16)] = start;
+ }
+ else
+ cpu->R[REG_POS(i,16)] = start;
+
+ if(BIT15(i))
+ return MMU_aluMemCycles<PROCNUM>(4, c);
+ else
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMDA_W(const uint32_t i)
+{
+ uint32_t c = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ uint32_t bitList = (~((2 << REG_POS(i,16))-1)) & 0xFFFF;
+
+ uint32_t * registres = cpu->R;
+
+ if(BIT15(i))
+ {
+ uint32_t tmp = READ32(cpu->mem_if->data, start);
+ if (cpu->LDTBit)
+ {
+ cpu->CPSR.bits.T = BIT0(tmp);
+ registres[15] = tmp & 0xFFFFFFFE;
+ }
+ else
+ registres[15] = tmp & 0xFFFFFFFC;
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ start -= 4;
+ cpu->next_instruction = registres[15];
+ }
+
+ OP_L_DA(14, start);
+ OP_L_DA(13, start);
+ OP_L_DA(12, start);
+ OP_L_DA(11, start);
+ OP_L_DA(10, start);
+ OP_L_DA(9, start);
+ OP_L_DA(8, start);
+ OP_L_DA(7, start);
+ OP_L_DA(6, start);
+ OP_L_DA(5, start);
+ OP_L_DA(4, start);
+ OP_L_DA(3, start);
+ OP_L_DA(2, start);
+ OP_L_DA(1, start);
+ OP_L_DA(0, start);
+
+ if(i & (1 << REG_POS(i,16))) {
+ if(i & bitList)
+ cpu->R[REG_POS(i,16)] = start;
+ }
+ else
+ cpu->R[REG_POS(i,16)] = start;
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMDB_W(const uint32_t i)
+{
+ uint32_t c = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ uint32_t bitList = (~((2 << REG_POS(i,16))-1)) & 0xFFFF;
+ uint32_t * registres = cpu->R;
+
+ if(BIT15(i))
+ {
+ uint32_t tmp;
+ start -= 4;
+ tmp = READ32(cpu->mem_if->data, start);
+ if (cpu->LDTBit)
+ {
+ cpu->CPSR.bits.T = BIT0(tmp);
+ registres[15] = tmp & 0xFFFFFFFE;
+ }
+ else
+ registres[15] = tmp & 0xFFFFFFFC;
+ cpu->next_instruction = registres[15];
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ }
+
+ OP_L_DB(14, start);
+ OP_L_DB(13, start);
+ OP_L_DB(12, start);
+ OP_L_DB(11, start);
+ OP_L_DB(10, start);
+ OP_L_DB(9, start);
+ OP_L_DB(8, start);
+ OP_L_DB(7, start);
+ OP_L_DB(6, start);
+ OP_L_DB(5, start);
+ OP_L_DB(4, start);
+ OP_L_DB(3, start);
+ OP_L_DB(2, start);
+ OP_L_DB(1, start);
+ OP_L_DB(0, start);
+
+ if(i & (1 << REG_POS(i,16))) {
+ if(i & bitList)
+ cpu->R[REG_POS(i,16)] = start;
+ }
+ else
+ cpu->R[REG_POS(i,16)] = start;
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMIA2(const uint32_t i)
+{
+ uint32_t oldmode = 0;
+
+ uint32_t c = 0;
+
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ uint32_t * registres;
+
+ if(BIT15(i)==0)
+ {
+ if((cpu->CPSR.bits.mode==USR)||(cpu->CPSR.bits.mode==SYS)) { printf("ERROR1\n"); return 1; }
+ oldmode = armcpu_switchMode(cpu, SYS);
+ }
+
+ registres = cpu->R;
+
+ OP_L_IA(0, start);
+ OP_L_IA(1, start);
+ OP_L_IA(2, start);
+ OP_L_IA(3, start);
+ OP_L_IA(4, start);
+ OP_L_IA(5, start);
+ OP_L_IA(6, start);
+ OP_L_IA(7, start);
+ OP_L_IA(8, start);
+ OP_L_IA(9, start);
+ OP_L_IA(10, start);
+ OP_L_IA(11, start);
+ OP_L_IA(12, start);
+ OP_L_IA(13, start);
+ OP_L_IA(14, start);
+
+ if(BIT15(i) == 0)
+ {
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ }
+ else
+ {
+
+ uint32_t tmp = READ32(cpu->mem_if->data, start);
+ Status_Reg SPSR;
+ cpu->R[15] = tmp & (0XFFFFFFFC | (BIT0(tmp)<<1));
+ SPSR = cpu->SPSR;
+ armcpu_switchMode(cpu, SPSR.bits.mode);
+ cpu->CPSR=SPSR;
+ cpu->changeCPSR();
+ //start += 4;
+ cpu->next_instruction = cpu->R[15];
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ }
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMIB2(const uint32_t i)
+{
+ uint32_t oldmode = 0;
+ uint32_t c = 0;
+
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ uint32_t * registres;
+
+ //UNTESTEDOPCODELOG("Untested opcode: OP_LDMIB2 \n");
+
+ if(BIT15(i)==0)
+ {
+ if((cpu->CPSR.bits.mode==USR)||(cpu->CPSR.bits.mode==SYS)) { printf("ERROR1\n"); return 1; }
+ oldmode = armcpu_switchMode(cpu, SYS);
+ }
+
+ registres = cpu->R;
+
+ OP_L_IB(0, start);
+ OP_L_IB(1, start);
+ OP_L_IB(2, start);
+ OP_L_IB(3, start);
+ OP_L_IB(4, start);
+ OP_L_IB(5, start);
+ OP_L_IB(6, start);
+ OP_L_IB(7, start);
+ OP_L_IB(8, start);
+ OP_L_IB(9, start);
+ OP_L_IB(10, start);
+ OP_L_IB(11, start);
+ OP_L_IB(12, start);
+ OP_L_IB(13, start);
+ OP_L_IB(14, start);
+
+ if(BIT15(i) == 0)
+ {
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ }
+ else
+ {
+ uint32_t tmp;
+ Status_Reg SPSR;
+ start += 4;
+ tmp = READ32(cpu->mem_if->data, start);
+ registres[15] = tmp & (0XFFFFFFFC | (BIT0(tmp)<<1));
+ SPSR = cpu->SPSR;
+ armcpu_switchMode(cpu, SPSR.bits.mode);
+ cpu->CPSR=SPSR;
+ cpu->changeCPSR();
+ cpu->next_instruction = registres[15];
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ }
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMDA2(const uint32_t i)
+{
+
+ uint32_t oldmode = 0;
+ uint32_t c = 0;
+ uint32_t * registres;
+
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ //UNTESTEDOPCODELOG("Untested opcode: OP_LDMDA2 \n");
+
+ if(BIT15(i)==0)
+ {
+ if((cpu->CPSR.bits.mode==USR)||(cpu->CPSR.bits.mode==SYS)) { printf("ERROR1\n"); return 1; }
+ oldmode = armcpu_switchMode(cpu, SYS);
+ }
+
+ registres = cpu->R;
+
+ if(BIT15(i))
+ {
+ uint32_t tmp = READ32(cpu->mem_if->data, start);
+ registres[15] = tmp & (0XFFFFFFFC | (BIT0(tmp)<<1));
+ cpu->CPSR = cpu->SPSR;
+ cpu->changeCPSR();
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ start -= 4;
+ cpu->next_instruction = registres[15];
+ }
+
+ OP_L_DA(14, start);
+ OP_L_DA(13, start);
+ OP_L_DA(12, start);
+ OP_L_DA(11, start);
+ OP_L_DA(10, start);
+ OP_L_DA(9, start);
+ OP_L_DA(8, start);
+ OP_L_DA(7, start);
+ OP_L_DA(6, start);
+ OP_L_DA(5, start);
+ OP_L_DA(4, start);
+ OP_L_DA(3, start);
+ OP_L_DA(2, start);
+ OP_L_DA(1, start);
+ OP_L_DA(0, start);
+
+ if(BIT15(i)==0)
+ {
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ }
+ else
+ {
+ Status_Reg SPSR = cpu->SPSR;
+ armcpu_switchMode(cpu, SPSR.bits.mode);
+ cpu->CPSR=SPSR;
+ cpu->changeCPSR();
+ }
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMDB2(const uint32_t i)
+{
+ uint32_t oldmode = 0;
+ uint32_t c = 0;
+ uint32_t * registres;
+
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ if(BIT15(i)==0)
+ {
+ if((cpu->CPSR.bits.mode==USR)||(cpu->CPSR.bits.mode==SYS)) { printf("ERROR1\n"); return 1; }
+ oldmode = armcpu_switchMode(cpu, SYS);
+ }
+
+ registres = cpu->R;
+
+ if(BIT15(i))
+ {
+ uint32_t tmp;
+ start -= 4;
+ tmp = READ32(cpu->mem_if->data, start);
+ registres[15] = tmp & (0XFFFFFFFC | (BIT0(tmp)<<1));
+ cpu->CPSR = cpu->SPSR;
+ cpu->changeCPSR();
+ cpu->next_instruction = registres[15];
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ }
+
+ OP_L_DB(14, start);
+ OP_L_DB(13, start);
+ OP_L_DB(12, start);
+ OP_L_DB(11, start);
+ OP_L_DB(10, start);
+ OP_L_DB(9, start);
+ OP_L_DB(8, start);
+ OP_L_DB(7, start);
+ OP_L_DB(6, start);
+ OP_L_DB(5, start);
+ OP_L_DB(4, start);
+ OP_L_DB(3, start);
+ OP_L_DB(2, start);
+ OP_L_DB(1, start);
+ OP_L_DB(0, start);
+
+ if(BIT15(i)==0)
+ {
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ }
+ else
+ {
+ Status_Reg SPSR = cpu->SPSR;
+ armcpu_switchMode(cpu, SPSR.bits.mode);
+ cpu->CPSR=SPSR;
+ cpu->changeCPSR();
+ }
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMIA2_W(const uint32_t i)
+{
+ uint32_t c = 0;
+
+ uint32_t oldmode = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ uint32_t * registres;
+ uint32_t tmp;
+ Status_Reg SPSR;
+// emu_halt();
+ if(BIT15(i)==0)
+ {
+ if((cpu->CPSR.bits.mode==USR)||(cpu->CPSR.bits.mode==SYS)) { printf("ERROR1\n"); return 1; }
+ oldmode = armcpu_switchMode(cpu, SYS);
+ }
+
+ registres = cpu->R;
+
+ OP_L_IA(0, start);
+ OP_L_IA(1, start);
+ OP_L_IA(2, start);
+ OP_L_IA(3, start);
+ OP_L_IA(4, start);
+ OP_L_IA(5, start);
+ OP_L_IA(6, start);
+ OP_L_IA(7, start);
+ OP_L_IA(8, start);
+ OP_L_IA(9, start);
+ OP_L_IA(10, start);
+ OP_L_IA(11, start);
+ OP_L_IA(12, start);
+ OP_L_IA(13, start);
+ OP_L_IA(14, start);
+
+ if(BIT15(i)==0)
+ {
+ if (!BIT_N(i, REG_POS(i,16)))
+ registres[REG_POS(i,16)] = start;
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+ }
+
+ if (!BIT_N(i, REG_POS(i,16)))
+ registres[REG_POS(i,16)] = start + 4;
+ tmp = READ32(cpu->mem_if->data, start);
+ registres[15] = tmp & (0XFFFFFFFC | (BIT0(tmp)<<1));
+ SPSR = cpu->SPSR;
+ armcpu_switchMode(cpu, SPSR.bits.mode);
+ cpu->CPSR=SPSR;
+ cpu->changeCPSR();
+ cpu->next_instruction = registres[15];
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMIB2_W(const uint32_t i)
+{
+ uint32_t c = 0;
+
+ uint32_t oldmode = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ uint32_t * registres;
+ uint32_t tmp;
+ Status_Reg SPSR;
+
+ if(BIT15(i)==0)
+ {
+ if((cpu->CPSR.bits.mode==USR)||(cpu->CPSR.bits.mode==SYS)) { printf("ERROR1\n"); return 1; }
+ oldmode = armcpu_switchMode(cpu, SYS);
+ }
+
+ registres = cpu->R;
+
+ OP_L_IB(0, start);
+ OP_L_IB(1, start);
+ OP_L_IB(2, start);
+ OP_L_IB(3, start);
+ OP_L_IB(4, start);
+ OP_L_IB(5, start);
+ OP_L_IB(6, start);
+ OP_L_IB(7, start);
+ OP_L_IB(8, start);
+ OP_L_IB(9, start);
+ OP_L_IB(10, start);
+ OP_L_IB(11, start);
+ OP_L_IB(12, start);
+ OP_L_IB(13, start);
+ OP_L_IB(14, start);
+
+ if(BIT15(i)==0)
+ {
+ if (!BIT_N(i, REG_POS(i,16)))
+ registres[REG_POS(i,16)] = start;
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+ }
+
+ if (!BIT_N(i, REG_POS(i,16)))
+ registres[REG_POS(i,16)] = start + 4;
+ tmp = READ32(cpu->mem_if->data, start + 4);
+ registres[15] = tmp & (0XFFFFFFFC | (BIT0(tmp)<<1));
+ cpu->CPSR = cpu->SPSR;
+ cpu->changeCPSR();
+ cpu->next_instruction = registres[15];
+ SPSR = cpu->SPSR;
+ armcpu_switchMode(cpu, SPSR.bits.mode);
+ cpu->CPSR=SPSR;
+ cpu->changeCPSR();
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMDA2_W(const uint32_t i)
+{
+ uint32_t c = 0;
+
+ uint32_t oldmode = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ uint32_t * registres;
+ Status_Reg SPSR;
+// emu_halt();
+ if(BIT15(i)==0)
+ {
+ if((cpu->CPSR.bits.mode==USR)||(cpu->CPSR.bits.mode==SYS)) { printf("ERROR1\n"); return 1; }
+ oldmode = armcpu_switchMode(cpu, SYS);
+ }
+
+ registres = cpu->R;
+
+ if(BIT15(i))
+ {
+ if (BIT_N(i, REG_POS(i,16))) printf("error1_1\n");
+ uint32_t tmp = READ32(cpu->mem_if->data, start);
+ registres[15] = tmp & (0XFFFFFFFC | (BIT0(tmp)<<1));
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ start -= 4;
+ cpu->next_instruction = registres[15];
+ }
+
+ OP_L_DA(14, start);
+ OP_L_DA(13, start);
+ OP_L_DA(12, start);
+ OP_L_DA(11, start);
+ OP_L_DA(10, start);
+ OP_L_DA(9, start);
+ OP_L_DA(8, start);
+ OP_L_DA(7, start);
+ OP_L_DA(6, start);
+ OP_L_DA(5, start);
+ OP_L_DA(4, start);
+ OP_L_DA(3, start);
+ OP_L_DA(2, start);
+ OP_L_DA(1, start);
+ OP_L_DA(0, start);
+
+ if (!BIT_N(i, REG_POS(i,16)))
+ registres[REG_POS(i,16)] = start;
+
+ if(BIT15(i)==0)
+ {
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+ }
+
+ SPSR = cpu->SPSR;
+ armcpu_switchMode(cpu, SPSR.bits.mode);
+ cpu->CPSR=SPSR;
+ cpu->changeCPSR();
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMDB2_W(const uint32_t i)
+{
+ uint32_t c = 0;
+
+ uint32_t oldmode = 0;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+ uint32_t * registres;
+ Status_Reg SPSR;
+// emu_halt();
+ if(BIT15(i)==0)
+ {
+ if((cpu->CPSR.bits.mode==USR)||(cpu->CPSR.bits.mode==SYS)) { printf("ERROR1\n"); return 1; }
+ oldmode = armcpu_switchMode(cpu, SYS);
+ }
+
+ registres = cpu->R;
+
+ if(BIT15(i))
+ {
+ if (BIT_N(i, REG_POS(i,16))) printf("error1_2\n");
+ uint32_t tmp;
+ start -= 4;
+ tmp = READ32(cpu->mem_if->data, start);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(start);
+ registres[15] = tmp & (0XFFFFFFFC | (BIT0(tmp)<<1));
+ cpu->CPSR = cpu->SPSR;
+ cpu->changeCPSR();
+ cpu->next_instruction = registres[15];
+ }
+
+ OP_L_DB(14, start);
+ OP_L_DB(13, start);
+ OP_L_DB(12, start);
+ OP_L_DB(11, start);
+ OP_L_DB(10, start);
+ OP_L_DB(9, start);
+ OP_L_DB(8, start);
+ OP_L_DB(7, start);
+ OP_L_DB(6, start);
+ OP_L_DB(5, start);
+ OP_L_DB(4, start);
+ OP_L_DB(3, start);
+ OP_L_DB(2, start);
+ OP_L_DB(1, start);
+ OP_L_DB(0, start);
+
+ if (!BIT_N(i, REG_POS(i,16)))
+ registres[REG_POS(i,16)] = start;
+
+ if(BIT15(i)==0)
+ {
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+ }
+
+ SPSR = cpu->SPSR;
+ armcpu_switchMode(cpu, SPSR.bits.mode);
+ cpu->CPSR=SPSR;
+ cpu->changeCPSR();
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+//-----------------------------------------------------------------------------
+// STMIA / STMIB / STMDA / STMDB
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_STMIA(const uint32_t i)
+{
+ uint32_t c = 0, b;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, b))
+ {
+ WRITE32(cpu->mem_if->data, start, cpu->R[b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ start += 4;
+ }
+ }
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMIB(const uint32_t i)
+{
+ uint32_t c = 0, b;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, b))
+ {
+ start += 4;
+ WRITE32(cpu->mem_if->data, start, cpu->R[b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ }
+ }
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMDA(const uint32_t i)
+{
+ uint32_t c = 0, b;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, 15-b))
+ {
+ WRITE32(cpu->mem_if->data, start, cpu->R[15-b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ start -= 4;
+ }
+ }
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMDB(const uint32_t i)
+{
+ uint32_t c = 0, b;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, 15-b))
+ {
+ start -= 4;
+ WRITE32(cpu->mem_if->data, start, cpu->R[15-b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ }
+ }
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMIA_W(const uint32_t i)
+{
+ uint32_t c = 0, b;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, b))
+ {
+ WRITE32(cpu->mem_if->data, start, cpu->R[b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ start += 4;
+ }
+ }
+
+ cpu->R[REG_POS(i,16)] = start;
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMIB_W(const uint32_t i)
+{
+ uint32_t c = 0, b;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, b))
+ {
+ start += 4;
+ WRITE32(cpu->mem_if->data, start, cpu->R[b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ }
+ }
+ cpu->R[REG_POS(i,16)] = start;
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMDA_W(const uint32_t i)
+{
+ uint32_t c = 0, b;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, 15-b))
+ {
+ WRITE32(cpu->mem_if->data, start, cpu->R[15-b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ start -= 4;
+ }
+ }
+
+ cpu->R[REG_POS(i,16)] = start;
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMDB_W(const uint32_t i)
+{
+ uint32_t c = 0, b;
+ uint32_t start = cpu->R[REG_POS(i,16)];
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, 15-b))
+ {
+ start -= 4;
+ WRITE32(cpu->mem_if->data, start, cpu->R[15-b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ }
+ }
+
+ cpu->R[REG_POS(i,16)] = start;
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMIA2(const uint32_t i)
+{
+ uint32_t c, b;
+ uint32_t start;
+ uint32_t oldmode;
+
+ if(cpu->CPSR.bits.mode==USR)
+ return 2;
+
+ c = 0;
+ start = cpu->R[REG_POS(i,16)];
+ oldmode = armcpu_switchMode(cpu, SYS);
+
+ //UNTESTEDOPCODELOG("Untested opcode: OP_STMIA2 \n");
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, b))
+ {
+ WRITE32(cpu->mem_if->data, start, cpu->R[b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ start += 4;
+ }
+ }
+
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMIB2(const uint32_t i)
+{
+ uint32_t c, b;
+ uint32_t start;
+ uint32_t oldmode;
+
+ if(cpu->CPSR.bits.mode==USR)
+ return 2;
+
+ c = 0;
+ start = cpu->R[REG_POS(i,16)];
+ oldmode = armcpu_switchMode(cpu, SYS);
+
+ //UNTESTEDOPCODELOG("Untested opcode: OP_STMIB2 \n");
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, b))
+ {
+ start += 4;
+ WRITE32(cpu->mem_if->data, start, cpu->R[b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ }
+ }
+
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMDA2(const uint32_t i)
+{
+ uint32_t c, b;
+ uint32_t start;
+ uint32_t oldmode;
+
+ if(cpu->CPSR.bits.mode==USR)
+ return 2;
+
+ c = 0;
+ start = cpu->R[REG_POS(i,16)];
+ oldmode = armcpu_switchMode(cpu, SYS);
+
+ //UNTESTEDOPCODELOG("Untested opcode: OP_STMDA2 \n");
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, 15-b))
+ {
+ WRITE32(cpu->mem_if->data, start, cpu->R[15-b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ start -= 4;
+ }
+ }
+
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMDB2(const uint32_t i)
+{
+ uint32_t c, b;
+ uint32_t start;
+ uint32_t oldmode;
+
+ if(cpu->CPSR.bits.mode==USR)
+ return 2;
+
+ c=0;
+ start = cpu->R[REG_POS(i,16)];
+ oldmode = armcpu_switchMode(cpu, SYS);
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, 15-b))
+ {
+ start -= 4;
+ WRITE32(cpu->mem_if->data, start, cpu->R[15-b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ }
+ }
+
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMIA2_W(const uint32_t i)
+{
+ uint32_t c, b;
+ uint32_t start;
+ uint32_t oldmode;
+
+ if(cpu->CPSR.bits.mode==USR)
+ return 2;
+
+ c=0;
+ start = cpu->R[REG_POS(i,16)];
+ oldmode = armcpu_switchMode(cpu, SYS);
+
+ //UNTESTEDOPCODELOG("Untested opcode: OP_STMIA2_W \n");
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, b))
+ {
+ WRITE32(cpu->mem_if->data, start, cpu->R[b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ start += 4;
+ }
+ }
+
+ cpu->R[REG_POS(i,16)] = start;
+
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMIB2_W(const uint32_t i)
+{
+ uint32_t c, b;
+ uint32_t start;
+ uint32_t oldmode;
+
+ if(cpu->CPSR.bits.mode==USR)
+ return 2;
+ c=0;
+ start = cpu->R[REG_POS(i,16)];
+ oldmode = armcpu_switchMode(cpu, SYS);
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, b))
+ {
+ start += 4;
+ WRITE32(cpu->mem_if->data, start, cpu->R[b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ }
+ }
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ cpu->R[REG_POS(i,16)] = start;
+
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMDA2_W(const uint32_t i)
+{
+ uint32_t c, b;
+ uint32_t start;
+ uint32_t oldmode;
+
+ if(cpu->CPSR.bits.mode==USR)
+ return 2;
+
+ c = 0;
+ start = cpu->R[REG_POS(i,16)];
+ oldmode = armcpu_switchMode(cpu, SYS);
+
+ //UNTESTEDOPCODELOG("Untested opcode: OP_STMDA2_W \n");
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, 15-b))
+ {
+ WRITE32(cpu->mem_if->data, start, cpu->R[15-b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ start -= 4;
+ }
+ }
+
+ cpu->R[REG_POS(i,16)] = start;
+
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STMDB2_W(const uint32_t i)
+{
+ uint32_t c, b;
+ uint32_t start;
+ uint32_t oldmode;
+
+ if(cpu->CPSR.bits.mode==USR)
+ return 2;
+
+ c = 0;
+
+ start = cpu->R[REG_POS(i,16)];
+ oldmode = armcpu_switchMode(cpu, SYS);
+
+ //UNTESTEDOPCODELOG("Untested opcode: OP_STMDB2_W \n");
+
+ for(b=0; b<16; b++)
+ {
+ if(BIT_N(i, 15-b))
+ {
+ start -= 4;
+ WRITE32(cpu->mem_if->data, start, cpu->R[15-b]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(start);
+ }
+ }
+
+ cpu->R[REG_POS(i,16)] = start;
+
+ armcpu_switchMode(cpu, static_cast<uint8_t>(oldmode));
+ return MMU_aluMemCycles<PROCNUM>(1, c);
+}
+
+//-----------------------------------------------------------------------------
+// LDRD / STRD
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_LDRD_STRD_POST_INDEX(const uint32_t i)
+{
+ uint32_t Rd_num = REG_POS( i, 12);
+ uint32_t addr = cpu->R[REG_POS(i,16)];
+ uint32_t index;
+ //printf("%s POST\n", BIT5(i)?"STRD":"LDRD");
+ /* I bit - immediate or register */
+ if ( BIT22(i))
+ index = IMM_OFF;
+ else
+ index = cpu->R[REG_POS(i,0)];
+
+ // U bit - add or subtract
+ if ( BIT23(i))
+ cpu->R[REG_POS(i,16)] += index;
+ else
+ cpu->R[REG_POS(i,16)] -= index;
+
+ uint32_t c = 0;
+ if ( !(Rd_num & 0x1))
+ {
+ // Store/Load
+ if ( BIT5(i))
+ {
+ WRITE32(cpu->mem_if->data, addr, cpu->R[Rd_num]);
+ WRITE32(cpu->mem_if->data, addr + 4, cpu->R[Rd_num + 1]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(addr);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(addr + 4);
+ }
+ else
+ {
+ cpu->R[Rd_num] = READ32(cpu->mem_if->data, addr);
+ cpu->R[Rd_num + 1] = READ32(cpu->mem_if->data, addr + 4);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(addr);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(addr + 4);
+ }
+ }
+
+ return MMU_aluMemCycles<PROCNUM>(3, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRD_STRD_OFFSET_PRE_INDEX(const uint32_t i)
+{
+ uint32_t Rd_num = REG_POS( i, 12);
+ uint32_t addr = cpu->R[REG_POS(i,16)];
+ uint32_t index;
+
+ //printf("%s PRE\n", BIT5(i)?"STRD":"LDRD");
+ // I bit - immediate or register
+ if ( BIT22(i))
+ index = IMM_OFF;
+ else
+ index = cpu->R[REG_POS(i,0)];
+
+ // U bit - add or subtract
+ if ( BIT23(i))
+ addr += index;
+ else
+ addr -= index;
+
+ uint32_t c = 0;
+ if ( !(Rd_num & 0x1))
+ {
+ // Store/Load
+ if ( BIT5(i))
+ {
+ WRITE32(cpu->mem_if->data, addr, cpu->R[Rd_num]);
+ WRITE32(cpu->mem_if->data, addr + 4, cpu->R[Rd_num + 1]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(addr);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(addr + 4);
+ // W bit - writeback
+ if ( BIT21(i))
+ cpu->R[REG_POS(i,16)] = addr;
+ }
+ else
+ {
+ // W bit - writeback
+ if ( BIT21(i))
+ cpu->R[REG_POS(i,16)] = addr;
+ cpu->R[Rd_num] = READ32(cpu->mem_if->data, addr);
+ cpu->R[Rd_num + 1] = READ32(cpu->mem_if->data, addr + 4);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(addr);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(addr + 4);
+ }
+ }
+
+ return MMU_aluMemCycles<PROCNUM>(3, c);
+}
+
+//-----------------------------------------------------------------------------
+// STC
+// the NDS has no coproc that responses to a STC, no feedback is given to the arm
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_STC_P_IMM_OFF(const uint32_t)
+{
+ //INFO("OP_STC_P_IMM_OFF\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STC_M_IMM_OFF(const uint32_t)
+{
+ //INFO("OP_STC_M_IMM_OFF\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STC_P_PREIND(const uint32_t)
+{
+ //INFO("OP_STC_P_PREIND\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STC_M_PREIND(const uint32_t)
+{
+ //INFO("OP_STC_M_PREIND\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STC_P_POSTIND(const uint32_t)
+{
+ //INFO("OP_STC_P_POSTIND: cp_num %i\n", (i>>8)&0x0F);
+ return TRAPUNDEF(cpu);
+
+
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STC_M_POSTIND(const uint32_t)
+{
+ //INFO("OP_STC_M_POSTIND\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STC_OPTION(const uint32_t)
+{
+ //INFO("OP_STC_OPTION\n");
+ return TRAPUNDEF(cpu);
+}
+
+//-----------------------------------------------------------------------------
+// LDC
+// the NDS has no coproc that responses to a LDC, no feedback is given to the arm
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_LDC_P_IMM_OFF(const uint32_t)
+{
+ //INFO("OP_LDC_P_IMM_OFF\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDC_M_IMM_OFF(const uint32_t)
+{
+ //INFO("OP_LDC_M_IMM_OFF\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDC_P_PREIND(const uint32_t)
+{
+ //INFO("OP_LDC_P_PREIND\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDC_M_PREIND(const uint32_t)
+{
+ //INFO("OP_LDC_M_PREIND\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDC_P_POSTIND(const uint32_t)
+{
+ //INFO("OP_LDC_P_POSTIND\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDC_M_POSTIND(const uint32_t)
+{
+ //INFO("OP_LDC_M_POSTIND\n");
+ return TRAPUNDEF(cpu);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDC_OPTION(const uint32_t)
+{
+ //INFO("OP_LDC_OPTION\n");
+ return TRAPUNDEF(cpu);
+}
+
+//-----------------------------------------------------------------------------
+// MCR / MRC
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_MCR(const uint32_t i)
+{
+ uint32_t cpnum = REG_POS(i, 8);
+
+ if(!cpu->coproc[cpnum])
+ {
+ //emu_halt();
+ //INFO("Stopped (OP_MCR) \n");
+ /*INFO("ARM%c: MCR P%i, 0, R%i, C%i, C%i, %i, %i (don't allocated coprocessor)\n",
+ PROCNUM?'7':'9', cpnum, REG_POS(i, 12), REG_POS(i, 16), REG_POS(i, 0), (i>>21)&0x7, (i>>5)&0x7);*/
+ return 2;
+ }
+
+ armcp15_moveARM2CP((armcp15_t*)cpu->coproc[cpnum], cpu->R[REG_POS(i, 12)], static_cast<uint8_t>(REG_POS(i, 16)), static_cast<uint8_t>(REG_POS(i, 0)), (i>>21)&0x7, (i>>5)&0x7);
+ //cpu->coproc[cpnum]->moveARM2CP(cpu->R[REG_POS(i, 12)], REG_POS(i, 16), REG_POS(i, 0), (i>>21)&7, (i>>5)&7);
+ return 2;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MRC(const uint32_t i)
+{
+ //if (PROCNUM != 0) return 1;
+
+ uint32_t cpnum = REG_POS(i, 8);
+
+ if(!cpu->coproc[cpnum])
+ {
+ //emu_halt();
+ //INFO("Stopped (OP_MRC) \n");
+ /*INFO("ARM%c: MRC P%i, 0, R%i, C%i, C%i, %i, %i (don't allocated coprocessor)\n",
+ PROCNUM?'7':'9', cpnum, REG_POS(i, 12), REG_POS(i, 16), REG_POS(i, 0), (i>>21)&0x7, (i>>5)&0x7);*/
+ return 2;
+ }
+
+ // ARM REF:
+ //data = value from Coprocessor[cp_num]
+ //if Rd is R15 then
+ // N flag = data[31]
+ // Z flag = data[30]
+ // C flag = data[29]
+ // V flag = data[28]
+ //else /* Rd is not R15 */
+ // Rd = data
+
+ uint32_t data = 0;
+ armcp15_moveCP2ARM((armcp15_t*)cpu->coproc[cpnum], &data, static_cast<uint8_t>(REG_POS(i, 16)), static_cast<uint8_t>(REG_POS(i, 0)), (i>>21)&0x7, (i>>5)&0x7);
+ if (REG_POS(i, 12) == 15)
+ {
+ cpu->CPSR.bits.N = BIT31(data);
+ cpu->CPSR.bits.Z = BIT30(data);
+ cpu->CPSR.bits.C = BIT29(data);
+ cpu->CPSR.bits.V = BIT28(data);
+ }
+ else
+ cpu->R[REG_POS(i, 12)] = data;
+ //cpu->coproc[cpnum]->moveCP2ARM(&cpu->R[REG_POS(i, 12)], REG_POS(i, 16), REG_POS(i, 0), (i>>21)&7, (i>>5)&7);
+ return 4;
+}
+
+//-----------------------------------------------------------------------------
+// SWI
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_SWI(const uint32_t i)
+{
+ uint32_t swinum = (i>>16)&0xFF;
+
+ //ideas-style debug prints (execute this SWI with the null terminated string address in R0)
+ if(swinum==0xFC)
+ {
+ //IdeasLog(cpu);
+ return 0;
+ }
+
+ //if the user has changed the intVector to point away from the nds bioses,
+ //then it doesn't really make any sense to use the builtin SWI's since
+ //the bios ones aren't getting called anyway
+ bool bypassBuiltinSWI =
+ (cpu->intVector == 0x00000000 && PROCNUM==0)
+ || (cpu->intVector == 0xFFFF0000 && PROCNUM==1);
+
+ if(cpu->swi_tab && !bypassBuiltinSWI)
+ {
+ swinum &= 0x1F;
+ //printf("%d ARM SWI %d \n",PROCNUM,swinum);
+ return cpu->swi_tab[swinum]() + 3;
+ }
+ else
+ {
+ /* TODO (#1#): translocated SWI vectors */
+ /* we use an irq thats not in the irq tab, as
+ it was replaced duie to a changed intVector */
+ Status_Reg tmp = cpu->CPSR;
+ armcpu_switchMode(cpu, SVC); /* enter svc mode */
+ cpu->R[14] = cpu->next_instruction;
+ cpu->SPSR = tmp; /* save old CPSR as new SPSR */
+ cpu->CPSR.bits.T = 0; /* handle as ARM32 code */
+ cpu->CPSR.bits.I = 1;
+ cpu->changeCPSR();
+ cpu->R[15] = cpu->intVector + 0x08;
+ cpu->next_instruction = cpu->R[15];
+ return 4;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// BKPT
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_BKPT(const uint32_t i)
+{
+ static uint32_t last_bkpt = 0xFFFFFFFF;
+ if(i != last_bkpt)
+ printf("ARM OP_BKPT triggered\n");
+ last_bkpt = i;
+
+ //this is not 100% correctly emulated, but it does the job
+ cpu->next_instruction = cpu->instruct_adr;
+ return 4;
+}
+
+//-----------------------------------------------------------------------------
+// CDP
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_CDP(const uint32_t)
+{
+ //INFO("Stopped (OP_CDP) \n");
+ return TRAPUNDEF(cpu);
+}
+
+//-----------------------------------------------------------------------------
+// The End
+//-----------------------------------------------------------------------------
+
+#define TABDECL(x) x<0>
+const ArmOpFunc arm_instructions_set_0[4096] = {
+#include "instruction_tabdef.inc"
+};
+#undef TABDECL
+
+#define TABDECL(x) x<1>
+const ArmOpFunc arm_instructions_set_1[4096] = {
+#include "instruction_tabdef.inc"
+};
+#undef TABDECL
+
+/*#define TABDECL(x) #x
+const char* arm_instruction_names[4096] = {
+#include "instruction_tabdef.inc"
+};
+#undef TABDECL*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/arm_instructions.h
@@ -1,1 +1,32 @@
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2006-2009 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef ARMINSTRUCTION_H
+#define ARMINSTRUCTION_H
+
+#include "armcpu.h"
+
+typedef uint32_t (FASTCALL *ArmOpFunc)(const uint32_t);
+
+extern const ArmOpFunc arm_instructions_set_0[4096];
+extern const ArmOpFunc arm_instructions_set_1[4096];
+
+//extern const char *arm_instruction_names[4096];
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/armcpu.cpp
@@ -1,1 +1,735 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2009-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cstdlib>
+#include <cstdio>
+#include <cassert>
+#include <algorithm>
+
+#include "types.h"
+#include "arm_instructions.h"
+#include "thumb_instructions.h"
+#include "cp15.h"
+#include "bios.h"
+//#include "debug.h"
+//#include "Disassembler.h"
+#include "NDSSystem.h"
+#include "MMU_timing.h"
+#ifdef HAVE_LUA
+#include "lua-engine.h"
+#endif
+
+template<uint32_t> static uint32_t armcpu_prefetch();
+
+inline uint32_t armcpu_prefetch(armcpu_t *armcpu) {
+ if(armcpu->proc_ID==0) return armcpu_prefetch<0>();
+ else return armcpu_prefetch<1>();
+}
+
+const unsigned char arm_cond_table[16*16] = {
+ /* N=0, Z=0, C=0, V=0 */
+ 0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,
+ 0x00,0xFF,0xFF,0x00,0xFF,0x00,0xFF,0x20,
+ /* N=0, Z=0, C=0, V=1 */
+ 0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x00,
+ 0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
+ /* N=0, Z=0, C=1, V=0 */
+ 0x00,0xFF,0xFF,0x00,0x00,0xFF,0x00,0xFF,
+ 0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x20,
+ /* N=0, Z=0, C=1, V=1 */
+ 0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x00,
+ 0xFF,0x00,0x00,0xFF,0x00,0xFF,0xFF,0x20,
+ /* N=0, Z=1, C=0, V=0 */
+ 0xFF,0x00,0x00,0xFF,0x00,0xFF,0x00,0xFF,
+ 0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x20,
+ /* N=0, Z=1, C=0, V=1 */
+ 0xFF,0x00,0x00,0xFF,0x00,0xFF,0xFF,0x00,
+ 0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
+ /* N=0, Z=1, C=1, V=0 */
+ 0xFF,0x00,0xFF,0x00,0x00,0xFF,0x00,0xFF,
+ 0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x20,
+ /* N=0, Z=1, C=1, V=1 */
+ 0xFF,0x00,0xFF,0x00,0x00,0xFF,0xFF,0x00,
+ 0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
+ /* N=1, Z=0, C=0, V=0 */
+ 0x00,0xFF,0x00,0xFF,0xFF,0x00,0x00,0xFF,
+ 0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
+ /* N=1, Z=0, C=0, V=1 */
+ 0x00,0xFF,0x00,0xFF,0xFF,0x00,0xFF,0x00,
+ 0x00,0xFF,0xFF,0x00,0xFF,0x00,0xFF,0x20,
+ /* N=1, Z=0, C=1, V=0 */
+ 0x00,0xFF,0xFF,0x00,0xFF,0x00,0x00,0xFF,
+ 0xFF,0x00,0x00,0xFF,0x00,0xFF,0xFF,0x20,
+ /* N=1, Z=0, C=1, V=1 */
+ 0x00,0xFF,0xFF,0x00,0xFF,0x00,0xFF,0x00,
+ 0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x20,
+ /* N=1, Z=1, C=0, V=0 */
+ 0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,
+ 0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
+ /* N=1, Z=1, C=0, V=1 */
+ 0xFF,0x00,0x00,0xFF,0xFF,0x00,0xFF,0x00,
+ 0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x20,
+ /* N=1, Z=1, C=1, V=0 */
+ 0xFF,0x00,0xFF,0x00,0xFF,0x00,0x00,0xFF,
+ 0x00,0xFF,0x00,0xFF,0x00,0xFF,0xFF,0x20,
+ /* N=1, Z=1, C=1, V=1 */
+ 0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,
+ 0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0x20,
+};
+
+armcpu_t NDS_ARM7;
+armcpu_t NDS_ARM9;
+
+/*#define SWAP(a, b, c) do \
+ { \
+ c=a; \
+ a=b; \
+ b=c; \
+ } \
+ while(0)*/
+template<typename T> static inline void SWAP(T &a, T &b)
+{
+ T c = a;
+ a = b;
+ b = c;
+}
+
+#ifdef GDB_STUB
+
+#define STALLED_CYCLE_COUNT 10
+
+static void
+stall_cpu( void *instance) {
+ armcpu_t *armcpu = (armcpu_t *)instance;
+ printf("UNSTALL\n");
+ armcpu->stalled = 1;
+}
+
+static void
+unstall_cpu( void *instance) {
+ armcpu_t *armcpu = (armcpu_t *)instance;
+ printf("UNSTALL\n");
+ armcpu->stalled = 0;
+}
+
+static void
+install_post_exec_fn( void *instance,
+ void (*ex_fn)( void *, uint32_t adr, int thumb),
+ void *fn_data) {
+ armcpu_t *armcpu = (armcpu_t *)instance;
+
+
+ armcpu->post_ex_fn = ex_fn;
+ armcpu->post_ex_fn_data = fn_data;
+}
+
+static void
+remove_post_exec_fn( void *instance) {
+ armcpu_t *armcpu = (armcpu_t *)instance;
+
+ armcpu->post_ex_fn = NULL;
+}
+#endif
+
+#ifdef GDB_STUB
+static uint32_t read_cpu_reg( void *instance, uint32_t reg_num)
+{
+ armcpu_t *armcpu = (armcpu_t *)instance;
+
+ if ( reg_num <= 14) {
+ return armcpu->R[reg_num];
+ }
+ else if ( reg_num == 15) {
+ return armcpu->instruct_adr;
+ }
+ else if ( reg_num == 16) {
+ //CPSR
+ return armcpu->CPSR.val;
+ }
+}
+
+static void
+set_cpu_reg( void *instance, uint32_t reg_num, uint32_t value) {
+ armcpu_t *armcpu = (armcpu_t *)instance;
+
+ if ( reg_num <= 14) {
+ armcpu->R[reg_num] = value;
+ }
+ else if ( reg_num == 15) {
+ armcpu->next_instruction = value;
+ }
+ else if ( reg_num == 16) {
+ /* FIXME: setting the CPSR */
+ }
+}
+#endif
+
+#ifdef GDB_STUB
+int armcpu_new( armcpu_t *armcpu, uint32_t id,
+ struct armcpu_memory_iface *mem_if,
+ struct armcpu_ctrl_iface **ctrl_iface_ret)
+#else
+int armcpu_new( armcpu_t *armcpu, uint32_t id)
+#endif
+{
+ armcpu->proc_ID = id;
+
+#ifdef GDB_STUB
+ armcpu->mem_if = mem_if;
+
+ /* populate the control interface */
+ armcpu->ctrl_iface.stall = stall_cpu;
+ armcpu->ctrl_iface.unstall = unstall_cpu;
+ armcpu->ctrl_iface.read_reg = read_cpu_reg;
+ armcpu->ctrl_iface.set_reg = set_cpu_reg;
+ armcpu->ctrl_iface.install_post_ex_fn = install_post_exec_fn;
+ armcpu->ctrl_iface.remove_post_ex_fn = remove_post_exec_fn;
+ armcpu->ctrl_iface.data = armcpu;
+
+ *ctrl_iface_ret = &armcpu->ctrl_iface;
+
+ armcpu->post_ex_fn = NULL;
+#endif
+
+ armcpu->stalled = 0;
+
+ armcpu_init(armcpu, 0);
+
+ return 0;
+}
+
+//call this whenever CPSR is changed (other than CNVZQ or T flags); interrupts may need to be unleashed
+void armcpu_t::changeCPSR()
+{
+ //but all it does is give them a chance to unleash by forcing an immediate reschedule
+ //TODO - we could actually set CPSR through here and look for a change in the I bit
+ //that would be a little optimization as well as a safety measure if we prevented setting CPSR directly
+ NDS_Reschedule();
+}
+
+void armcpu_init(armcpu_t *armcpu, uint32_t adr)
+{
+ armcpu->LDTBit = (armcpu->proc_ID==0); //Si ARM9 utiliser le syte v5 pour le load
+ armcpu->intVector = 0xFFFF0000 * (armcpu->proc_ID==0);
+ armcpu->waitIRQ = false;
+ armcpu->halt_IE_and_IF = false;
+ armcpu->intrWaitARM_state = 0;
+
+//#ifdef GDB_STUB
+// armcpu->irq_flag = 0;
+//#endif
+
+ for(int i = 0; i < 16; ++i)
+ {
+ armcpu->R[i] = 0;
+ if(armcpu->coproc[i]) free(armcpu->coproc[i]);
+ armcpu->coproc[i] = NULL;
+ }
+
+ armcpu->CPSR.val = armcpu->SPSR.val = SYS;
+
+ armcpu->R13_usr = armcpu->R14_usr = 0;
+ armcpu->R13_svc = armcpu->R14_svc = 0;
+ armcpu->R13_abt = armcpu->R14_abt = 0;
+ armcpu->R13_und = armcpu->R14_und = 0;
+ armcpu->R13_irq = armcpu->R14_irq = 0;
+ armcpu->R8_fiq = armcpu->R9_fiq = armcpu->R10_fiq = armcpu->R11_fiq = armcpu->R12_fiq = armcpu->R13_fiq = armcpu->R14_fiq = 0;
+
+ armcpu->SPSR_svc.val = armcpu->SPSR_abt.val = armcpu->SPSR_und.val = armcpu->SPSR_irq.val = armcpu->SPSR_fiq.val = 0;
+
+//#ifdef GDB_STUB
+// armcpu->instruct_adr = adr;
+// armcpu->R[15] = adr + 8;
+//#else
+ //armcpu->R[15] = adr;
+//#endif
+
+ armcpu->next_instruction = adr;
+
+ // only ARM9 have co-processor
+ if (armcpu->proc_ID==0)
+ armcpu->coproc[15] = (armcp_t*)armcp15_new(armcpu);
+
+//#ifndef GDB_STUB
+ armcpu_prefetch(armcpu);
+//#endif
+}
+
+uint32_t armcpu_switchMode(armcpu_t *armcpu, uint8_t mode)
+{
+ uint32_t oldmode = armcpu->CPSR.bits.mode;
+
+ switch(oldmode)
+ {
+ case USR :
+ case SYS :
+ armcpu->R13_usr = armcpu->R[13];
+ armcpu->R14_usr = armcpu->R[14];
+ break;
+
+ case FIQ :
+ {
+ //uint32_t tmp;
+ SWAP(armcpu->R[8], armcpu->R8_fiq/*, tmp*/);
+ SWAP(armcpu->R[9], armcpu->R9_fiq/*, tmp*/);
+ SWAP(armcpu->R[10], armcpu->R10_fiq/*, tmp*/);
+ SWAP(armcpu->R[11], armcpu->R11_fiq/*, tmp*/);
+ SWAP(armcpu->R[12], armcpu->R12_fiq/*, tmp*/);
+ armcpu->R13_fiq = armcpu->R[13];
+ armcpu->R14_fiq = armcpu->R[14];
+ armcpu->SPSR_fiq = armcpu->SPSR;
+ break;
+ }
+ case IRQ :
+ armcpu->R13_irq = armcpu->R[13];
+ armcpu->R14_irq = armcpu->R[14];
+ armcpu->SPSR_irq = armcpu->SPSR;
+ break;
+
+ case SVC :
+ armcpu->R13_svc = armcpu->R[13];
+ armcpu->R14_svc = armcpu->R[14];
+ armcpu->SPSR_svc = armcpu->SPSR;
+ break;
+
+ case ABT :
+ armcpu->R13_abt = armcpu->R[13];
+ armcpu->R14_abt = armcpu->R[14];
+ armcpu->SPSR_abt = armcpu->SPSR;
+ break;
+
+ case UND :
+ armcpu->R13_und = armcpu->R[13];
+ armcpu->R14_und = armcpu->R[14];
+ armcpu->SPSR_und = armcpu->SPSR;
+ break;
+ default :
+ break;
+ }
+
+ switch(mode)
+ {
+ case USR :
+ case SYS :
+ armcpu->R[13] = armcpu->R13_usr;
+ armcpu->R[14] = armcpu->R14_usr;
+ //SPSR = CPSR;
+ break;
+
+ case FIQ :
+ {
+ //uint32_t tmp;
+ SWAP(armcpu->R[8], armcpu->R8_fiq/*, tmp*/);
+ SWAP(armcpu->R[9], armcpu->R9_fiq/*, tmp*/);
+ SWAP(armcpu->R[10], armcpu->R10_fiq/*, tmp*/);
+ SWAP(armcpu->R[11], armcpu->R11_fiq/*, tmp*/);
+ SWAP(armcpu->R[12], armcpu->R12_fiq/*, tmp*/);
+ armcpu->R[13] = armcpu->R13_fiq;
+ armcpu->R[14] = armcpu->R14_fiq;
+ armcpu->SPSR = armcpu->SPSR_fiq;
+ break;
+ }
+
+ case IRQ :
+ armcpu->R[13] = armcpu->R13_irq;
+ armcpu->R[14] = armcpu->R14_irq;
+ armcpu->SPSR = armcpu->SPSR_irq;
+ break;
+
+ case SVC :
+ armcpu->R[13] = armcpu->R13_svc;
+ armcpu->R[14] = armcpu->R14_svc;
+ armcpu->SPSR = armcpu->SPSR_svc;
+ break;
+
+ case ABT :
+ armcpu->R[13] = armcpu->R13_abt;
+ armcpu->R[14] = armcpu->R14_abt;
+ armcpu->SPSR = armcpu->SPSR_abt;
+ break;
+
+ case UND :
+ armcpu->R[13] = armcpu->R13_und;
+ armcpu->R[14] = armcpu->R14_und;
+ armcpu->SPSR = armcpu->SPSR_und;
+ break;
+
+ default :
+ break;
+ }
+
+ armcpu->CPSR.bits.mode = mode & 0x1F;
+ armcpu->changeCPSR();
+ return oldmode;
+}
+
+uint32_t armcpu_Wait4IRQ(armcpu_t *cpu)
+{
+ cpu->waitIRQ = true;
+ cpu->halt_IE_and_IF = true;
+ return 1;
+}
+
+template<uint32_t PROCNUM>
+inline static uint32_t armcpu_prefetch()
+{
+ armcpu_t* const armcpu = &ARMPROC;
+//#ifdef GDB_STUB
+// uint32_t temp_instruction;
+//#endif
+ uint32_t curInstruction = armcpu->next_instruction;
+
+ if(armcpu->CPSR.bits.T == 0)
+ {
+//#ifdef GDB_STUB
+// temp_instruction =
+// armcpu->mem_if->prefetch32( armcpu->mem_if->data,
+// armcpu->next_instruction);
+//
+// if ( !armcpu->stalled) {
+// armcpu->instruction = temp_instruction;
+// armcpu->instruct_adr = armcpu->next_instruction;
+// armcpu->next_instruction += 4;
+// armcpu->R[15] = armcpu->next_instruction + 4;
+// }
+//#else
+ curInstruction &= 0xFFFFFFFC; //please don't change this to 0x0FFFFFFC -- the NDS will happily run on 0xF******* addresses all day long
+ //please note that we must setup R[15] before reading the instruction since there is a protection
+ //which prevents PC > 0x3FFF from reading the bios region
+ armcpu->instruct_adr = curInstruction;
+ armcpu->next_instruction = curInstruction + 4;
+ armcpu->R[15] = curInstruction + 8;
+ armcpu->instruction = _MMU_read32<PROCNUM, MMU_AT_CODE>(curInstruction);
+//#endif
+
+ return MMU_codeFetchCycles<PROCNUM,32>(curInstruction);
+ }
+
+//#ifdef GDB_STUB
+// temp_instruction =
+// armcpu->mem_if->prefetch16( armcpu->mem_if->data,
+// armcpu->next_instruction);
+//
+// if ( !armcpu->stalled) {
+// armcpu->instruction = temp_instruction;
+// armcpu->instruct_adr = armcpu->next_instruction;
+// armcpu->next_instruction = armcpu->next_instruction + 2;
+// armcpu->R[15] = armcpu->next_instruction + 2;
+// }
+//#else
+ curInstruction &= 0xFFFFFFFE; //please don't change this to 0x0FFFFFFE -- the NDS will happily run on 0xF******* addresses all day long
+ //please note that we must setup R[15] before reading the instruction since there is a protection
+ //which prevents PC > 0x3FFF from reading the bios region
+ armcpu->instruct_adr = curInstruction;
+ armcpu->next_instruction = curInstruction + 2;
+ armcpu->R[15] = curInstruction + 4;
+ armcpu->instruction = _MMU_read16<PROCNUM, MMU_AT_CODE>(curInstruction);
+//#endif
+
+ if(PROCNUM==0)
+ {
+ // arm9 fetches 2 instructions at a time in thumb mode
+ if(!(curInstruction == armcpu->instruct_adr + 2 && (curInstruction & 2)))
+ return MMU_codeFetchCycles<PROCNUM,32>(curInstruction);
+ else
+ return 0;
+ }
+
+ return MMU_codeFetchCycles<PROCNUM,16>(curInstruction);
+}
+
+#if 0 /* not used */
+static bool FASTCALL test_EQ(Status_Reg CPSR) { return CPSR.bits.Z; }
+static bool FASTCALL test_NE(Status_Reg CPSR) { return !CPSR.bits.Z; }
+static bool FASTCALL test_CS(Status_Reg CPSR) { return CPSR.bits.C; }
+static bool FASTCALL test_CC(Status_Reg CPSR) { return !CPSR.bits.C; }
+static bool FASTCALL test_MI(Status_Reg CPSR) { return CPSR.bits.N; }
+static bool FASTCALL test_PL(Status_Reg CPSR) { return !CPSR.bits.N; }
+static bool FASTCALL test_VS(Status_Reg CPSR) { return CPSR.bits.V; }
+static bool FASTCALL test_VC(Status_Reg CPSR) { return !CPSR.bits.V; }
+static bool FASTCALL test_HI(Status_Reg CPSR) { return CPSR.bits.C && !CPSR.bits.Z; }
+static bool FASTCALL test_LS(Status_Reg CPSR) { return CPSR.bits.Z || !CPSR.bits.C; }
+static bool FASTCALL test_GE(Status_Reg CPSR) { return CPSR.bits.N==CPSR.bits.V; }
+static bool FASTCALL test_LT(Status_Reg CPSR) { return CPSR.bits.N!=CPSR.bits.V; }
+static bool FASTCALL test_GT(Status_Reg CPSR) { return !CPSR.bits.Z && CPSR.bits.N==CPSR.bits.V; }
+static bool FASTCALL test_LE(Status_Reg CPSR) { return CPSR.bits.Z || CPSR.bits.N!=CPSR.bits.V; }
+static bool FASTCALL test_AL(Status_Reg CPSR) { return 1; }
+
+static bool (FASTCALL* test_conditions[])(Status_Reg CPSR)= {
+ test_EQ , test_NE ,
+ test_CS , test_CC ,
+ test_MI , test_PL ,
+ test_VS , test_VC ,
+ test_HI , test_LS ,
+ test_GE , test_LT ,
+ test_GT , test_LE ,
+ test_AL
+};
+#define TEST_COND2(cond, CPSR) \
+ (cond<15&&test_conditions[cond](CPSR))
+#endif
+
+//TODO - merge with armcpu_irqException?
+//http://www.ethernut.de/en/documents/arm-exceptions.html
+//http://docs.google.com/viewer?a=v&q=cache:V4ht1YkxprMJ:www.cs.nctu.edu.tw/~wjtsai/EmbeddedSystemDesign/Ch3-1.pdf+arm+exception+handling&hl=en&gl=us&pid=bl&srcid=ADGEEShx9VTHbUhWdDOrTVRzLkcCsVfJiijncNDkkgkrlJkLa7D0LCpO8fQ_hhU3DTcgZh9rcZWWQq4TYhhCovJ625h41M0ZUX3WGasyzWQFxYzDCB-VS6bsUmpoJnRxAc-bdkD0qmsu&sig=AHIEtbR9VHvDOCRmZFQDUVwy53iJDjoSPQ
+void armcpu_exception(armcpu_t *cpu, uint32_t number)
+{
+ Mode cpumode = USR;
+ switch(number)
+ {
+ case EXCEPTION_RESET: cpumode = SVC; break;
+ case EXCEPTION_UNDEFINED_INSTRUCTION: cpumode = UND; break;
+ case EXCEPTION_SWI: cpumode = SVC; break;
+ case EXCEPTION_PREFETCH_ABORT: cpumode = ABT; break;
+ case EXCEPTION_DATA_ABORT: cpumode = ABT; break;
+ case EXCEPTION_RESERVED_0x14: execute = false;/*emu_halt();*/ break;
+ case EXCEPTION_IRQ: cpumode = IRQ; break;
+ case EXCEPTION_FAST_IRQ: cpumode = FIQ; break;
+ }
+
+ Status_Reg tmp = cpu->CPSR;
+ armcpu_switchMode(cpu, cpumode); //enter new mode
+ cpu->R[14] = cpu->next_instruction;
+ cpu->SPSR = tmp; //save old CPSR as new SPSR
+ cpu->CPSR.bits.T = 0; //handle as ARM32 code
+ cpu->CPSR.bits.I = 1;
+ cpu->changeCPSR();
+ cpu->R[15] = cpu->intVector + number;
+ cpu->next_instruction = cpu->R[15];
+ printf("armcpu_exception!\n");
+ //extern bool dolog;
+ //dolog=true;
+
+ //HOW DOES THIS WORTK WITHOUT A PREFETCH, LIKE IRQ BELOW?
+ //I REALLY WISH WE DIDNT PREFETCH BEFORE EXECUTING
+}
+
+bool armcpu_irqException(armcpu_t *armcpu)
+{
+ Status_Reg tmp;
+
+ //TODO - remove GDB specific code
+//#ifdef GDB_STUB
+// armcpu->irq_flag = 0;
+//#endif
+
+ tmp = armcpu->CPSR;
+ armcpu_switchMode(armcpu, IRQ);
+
+ //TODO - remove GDB specific code
+//#ifdef GDB_STUB
+// armcpu->R[14] = armcpu->next_instruction + 4;
+//#else
+ armcpu->R[14] = armcpu->instruct_adr + 4;
+//#endif
+ armcpu->SPSR = tmp;
+ armcpu->CPSR.bits.T = 0;
+ armcpu->CPSR.bits.I = 1;
+ armcpu->next_instruction = armcpu->intVector + 0x18;
+ armcpu->waitIRQ = 0;
+
+ //must retain invariant of having next instruction to be executed prefetched
+ //(yucky)
+ armcpu_prefetch(armcpu);
+
+ return true;
+}
+
+//TODO - remove GDB specific code
+//bool
+//armcpu_flagIrq( armcpu_t *armcpu) {
+// if(armcpu->CPSR.bits.I) return false;
+//
+// armcpu->waitIRQ = 0;
+//
+//#ifdef GDB_STUB
+// armcpu->irq_flag = 1;
+//#endif
+//
+// return true;
+//}
+
+uint32_t TRAPUNDEF(armcpu_t* cpu)
+{
+ //INFO("ARM%c: Undefined instruction: 0x%08X (%s) PC=0x%08X\n", cpu->proc_ID?'7':'9', cpu->instruction, decodeIntruction(false, cpu->instruction), cpu->instruct_adr);
+
+ if (((cpu->intVector != 0) ^ (cpu->proc_ID == ARMCPU_ARM9)))
+ {
+ armcpu_exception(&NDS_ARM9,EXCEPTION_UNDEFINED_INSTRUCTION);
+ return 4;
+ }
+ else
+ {
+ //emu_halt();
+ execute = false;
+ return 4;
+ }
+}
+
+//bool
+//armcpu_flagIrq( armcpu_t *armcpu) {
+// if(armcpu->CPSR.bits.I) return false;
+//
+// armcpu->waitIRQ = 0;
+//
+//#ifdef GDB_STUB
+// armcpu->irq_flag = 1;
+//#endif
+//
+// return true;
+//}
+
+template<int PROCNUM>
+uint32_t armcpu_exec()
+{
+ // Usually, fetching and executing are processed parallelly.
+ // So this function stores the cycles of each process to
+ // the variables below, and returns appropriate cycle count.
+ uint32_t cFetch = 0;
+ uint32_t cExecute = 0;
+
+ //this assert is annoying. but sometimes it is handy.
+ //assert(ARMPROC.instruct_adr!=0x00000000);
+//#ifdef DEVELOPER
+#if 0
+ if ((((ARMPROC.instruct_adr & 0x0F000000) == 0x0F000000) && (PROCNUM == 0)) ||
+ (((ARMPROC.instruct_adr & 0x0F000000) == 0x00000000) && (PROCNUM == 1)))
+ {
+ switch (ARMPROC.instruct_adr & 0xFFFF)
+ {
+ case 0x00000000:
+ printf("BIOS%c: Reset!!!\n", PROCNUM?'7':'9');
+ emu_halt();
+ break;
+ case 0x00000004:
+ printf("BIOS%c: Undefined instruction\n", PROCNUM?'7':'9');
+ //emu_halt();
+ break;
+ case 0x00000008:
+ //printf("BIOS%c: SWI\n", PROCNUM?'7':'9');
+ break;
+ case 0x0000000C:
+ printf("BIOS%c: Prefetch Abort!!!\n", PROCNUM?'7':'9');
+ //emu_halt();
+ break;
+ case 0x00000010:
+ //printf("BIOS%c: Data Abort!!!\n", PROCNUM?'7':'9');
+ //emu_halt();
+ break;
+ case 0x00000014:
+ printf("BIOS%c: Reserved!!!\n", PROCNUM?'7':'9');
+ break;
+ case 0x00000018:
+ //printf("BIOS%c: IRQ\n", PROCNUM?'7':'9');
+ break;
+ case 0x0000001C:
+ printf("BIOS%c: Fast IRQ\n", PROCNUM?'7':'9');
+ break;
+ }
+ }
+#endif
+
+#if 0 //#ifdef GDB_STUB
+ if (ARMPROC.stalled) {
+ return STALLED_CYCLE_COUNT;
+ }
+
+ /* check for interrupts */
+ if (ARMPROC.irq_flag) {
+ armcpu_irqException(&ARMPROC);
+ }
+
+ cFetch = armcpu_prefetch(&ARMPROC);
+
+ if (ARMPROC.stalled) {
+ return MMU_fetchExecuteCycles<PROCNUM>(cExecute, cFetch);
+ }
+#endif
+
+ //cFetch = armcpu_prefetch(&ARMPROC);
+
+ //printf("%d: %08X\n",PROCNUM,ARMPROC.instruct_adr);
+
+ if(ARMPROC.CPSR.bits.T == 0)
+ {
+ if(
+ CONDITION(ARMPROC.instruction) == 0x0E //fast path for unconditional instructions
+ || (TEST_COND(CONDITION(ARMPROC.instruction), CODE(ARMPROC.instruction), ARMPROC.CPSR)) //handles any condition
+ )
+ {
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(ARMPROC.instruct_adr, 4, ARMPROC.instruction, LUAMEMHOOK_EXEC); // should report even if condition=false?
+#endif
+ if(PROCNUM==0) {
+ #ifdef DEVELOPER
+ DEBUG_statistics.instructionHits[0].arm[INSTRUCTION_INDEX(ARMPROC.instruction)]++;
+ #endif
+ cExecute = arm_instructions_set_0[INSTRUCTION_INDEX(ARMPROC.instruction)](ARMPROC.instruction);
+ }
+ else {
+ #ifdef DEVELOPER
+ DEBUG_statistics.instructionHits[1].arm[INSTRUCTION_INDEX(ARMPROC.instruction)]++;
+ #endif
+ cExecute = arm_instructions_set_1[INSTRUCTION_INDEX(ARMPROC.instruction)](ARMPROC.instruction);
+ }
+ }
+ else
+ cExecute = 1; // If condition=false: 1S cycle
+#ifdef GDB_STUB
+ if ( ARMPROC.post_ex_fn != NULL) {
+ /* call the external post execute function */
+ ARMPROC.post_ex_fn(ARMPROC.post_ex_fn_data, ARMPROC.instruct_adr, 0);
+ }
+ ARMPROC.mem_if->prefetch32( ARMPROC.mem_if->data, ARMPROC.next_instruction);
+#endif
+ cFetch = armcpu_prefetch<PROCNUM>();
+ return MMU_fetchExecuteCycles<PROCNUM>(cExecute, cFetch);
+ }
+
+#ifdef HAVE_LUA
+ CallRegisteredLuaMemHook(ARMPROC.instruct_adr, 2, ARMPROC.instruction, LUAMEMHOOK_EXEC);
+#endif
+ if(PROCNUM==0)
+ {
+ #ifdef DEVELOPER
+ DEBUG_statistics.instructionHits[0].thumb[ARMPROC.instruction>>6]++;
+ #endif
+ cExecute = thumb_instructions_set_0[ARMPROC.instruction>>6](ARMPROC.instruction);
+ }
+ else {
+ #ifdef DEVELOPER
+ DEBUG_statistics.instructionHits[1].thumb[ARMPROC.instruction>>6]++;
+ #endif
+ cExecute = thumb_instructions_set_1[ARMPROC.instruction>>6](ARMPROC.instruction);
+ }
+
+#ifdef GDB_STUB
+ if ( ARMPROC.post_ex_fn != NULL) {
+ /* call the external post execute function */
+ ARMPROC.post_ex_fn( ARMPROC.post_ex_fn_data, ARMPROC.instruct_adr, 1);
+ }
+ ARMPROC.mem_if->prefetch32( ARMPROC.mem_if->data, ARMPROC.next_instruction);
+#endif
+ cFetch = armcpu_prefetch<PROCNUM>();
+ return MMU_fetchExecuteCycles<PROCNUM>(cExecute, cFetch);
+}
+
+//these templates needed to be instantiated manually
+template uint32_t armcpu_exec<0>();
+template uint32_t armcpu_exec<1>();
+
--- /dev/null
+++ b/src/in_2sf/desmume/armcpu.h
@@ -1,1 +1,278 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2006-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef ARM_CPU
+#define ARM_CPU
+
+#include "types.h"
+#include "bits.h"
+#include "MMU.h"
+#include "common.h"
+
+static inline uint32_t CODE(uint32_t i) { return (i >> 25) & 0x7; }
+
+static const uint32_t EXCEPTION_RESET = 0x00;
+static const uint32_t EXCEPTION_UNDEFINED_INSTRUCTION = 0x04;
+static const uint32_t EXCEPTION_SWI = 0x08;
+static const uint32_t EXCEPTION_PREFETCH_ABORT = 0x0C;
+static const uint32_t EXCEPTION_DATA_ABORT = 0x10;
+static const uint32_t EXCEPTION_RESERVED_0x14 = 0x14;
+static const uint32_t EXCEPTION_IRQ = 0x18;
+static const uint32_t EXCEPTION_FAST_IRQ = 0x1C;
+
+static inline uint32_t INSTRUCTION_INDEX(uint32_t i) { return ((i >> 16) & 0xFF0) | ((i >> 4) & 0xF); }
+
+static inline uint32_t ROR(uint32_t i, uint32_t j) { return (i >> j) | (i << (32 - j)); }
+
+template<typename T> static inline T UNSIGNED_OVERFLOW(T a, T b, T c) { return BIT31((a & b) | ((a | b) & ~c)); }
+
+template<typename T> static inline T UNSIGNED_UNDERFLOW(T a, T b, T c) { return BIT31((~a & b) | ((~a | b) & c)); }
+
+template<typename T> static inline T SIGNED_OVERFLOW(T a, T b, T c) { return BIT31((a & b & ~c) | (~a & ~b & c)); }
+
+template<typename T> static inline T SIGNED_UNDERFLOW(T a, T b, T c) { return BIT31((a & ~b & ~c) | (~a & b & c)); }
+
+// ============================= CPRS flags funcs
+static inline bool CarryFrom(int32_t left, int32_t right)
+{
+ uint32_t res = 0xFFFFFFFFU - static_cast<uint32_t>(left);
+
+ return static_cast<uint32_t>(right) > res;
+}
+
+static inline bool BorrowFrom(int32_t left, int32_t right)
+{
+ return static_cast<uint32_t>(right) > static_cast<uint32_t>(left);
+}
+
+static inline bool OverflowFromADD(int32_t alu_out, int32_t left, int32_t right)
+{
+ return ((left >= 0 && right >= 0) || (left < 0 && right < 0)) && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
+}
+
+inline bool OverflowFromSUB(int32_t alu_out, int32_t left, int32_t right)
+{
+ return ((left < 0 && right >= 0) || (left >= 0 && right < 0)) && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
+}
+
+//zero 15-feb-2009 - these werent getting used and they were getting in my way
+//#define EQ 0x0
+//#define NE 0x1
+//#define CS 0x2
+//#define CC 0x3
+//#define MI 0x4
+//#define PL 0x5
+//#define VS 0x6
+//#define VC 0x7
+//#define HI 0x8
+//#define LS 0x9
+//#define GE 0xA
+//#define LT 0xB
+//#define GT 0xC
+//#define LE 0xD
+//#define AL 0xE
+
+extern const uint8_t arm_cond_table[16 * 16];
+
+enum Mode
+{
+ USR = 0x10,
+ FIQ = 0x11,
+ IRQ = 0x12,
+ SVC = 0x13,
+ ABT = 0x17,
+ UND = 0x1B,
+ SYS = 0x1F
+};
+
+#ifdef WORDS_BIGENDIAN
+typedef union
+{
+ struct
+ {
+ uint32_t N : 1,
+ Z : 1,
+ C : 1,
+ V : 1,
+ Q : 1,
+ RAZ : 19,
+ I : 1,
+ F : 1,
+ T : 1,
+ mode : 5;
+ } bits;
+ uint32_t val;
+} Status_Reg;
+#else
+typedef union
+{
+ struct
+ {
+ uint32_t mode : 5,
+ T : 1,
+ F : 1,
+ I : 1,
+ RAZ : 19,
+ Q : 1,
+ V : 1,
+ C : 1,
+ Z : 1,
+ N : 1;
+ } bits;
+ uint32_t val;
+} Status_Reg;
+#endif
+
+static inline uint8_t TEST_COND(uint32_t cond, uint32_t inst, Status_Reg CPSR) { return arm_cond_table[((CPSR.val >> 24) & 0xf0) | cond] & (1 << inst); }
+
+/**
+ * The control interface to a CPU
+ */
+/*struct armcpu_ctrl_iface
+{*/
+ /** stall the processor */
+ //void (*stall)(void *instance);
+
+ /** unstall the processor */
+ //void (*unstall)(void *instance);
+
+ /** read a register value */
+ //uint32_t (*read_reg)(void *instance, uint32_t reg_num);
+
+ /** set a register value */
+ //void (*set_reg)(void *instance, uint32_t reg_num, uint32_t value);
+
+ /** install the post execute function */
+ //void (*install_post_ex_fn)( void *instance, void (*fn)(void *, uint32_t, int), void *fn_data);
+
+ /** remove the post execute function */
+ //void (*remove_post_ex_fn)(void *instance);
+
+ /** the private data passed to all interface functions */
+ /*void *data;
+};*/
+
+typedef void *armcp_t;
+
+struct armcpu_t
+{
+ uint32_t proc_ID;
+ uint32_t instruction; //4
+ uint32_t instruct_adr; //8
+ uint32_t next_instruction; //12
+
+ uint32_t R[16]; //16
+ Status_Reg CPSR; //80
+ Status_Reg SPSR;
+
+ void changeCPSR();
+
+ uint32_t R13_usr, R14_usr;
+ uint32_t R13_svc, R14_svc;
+ uint32_t R13_abt, R14_abt;
+ uint32_t R13_und, R14_und;
+ uint32_t R13_irq, R14_irq;
+ uint32_t R8_fiq, R9_fiq, R10_fiq, R11_fiq, R12_fiq, R13_fiq, R14_fiq;
+ Status_Reg SPSR_svc, SPSR_abt, SPSR_und, SPSR_irq, SPSR_fiq;
+
+ armcp_t *coproc[16];
+
+ uint32_t intVector;
+ uint8_t LDTBit; // 1 : ARMv5 style 0 : non ARMv5
+ bool waitIRQ;
+ bool halt_IE_and_IF; //the cpu is halted, waiting for IE&IF to signal something
+ uint8_t intrWaitARM_state;
+
+ bool BIOS_loaded;
+
+ uint32_t (**swi_tab)();
+
+ // flag indicating if the processor is stalled (for debugging)
+ int stalled;
+
+#ifdef GDB_STUB
+ /** there is a pending irq for the cpu */
+ int irq_flag;
+
+ /** the post executed function (if installed) */
+ void (*post_ex_fn)(void *, uint32_t adr, int thumb);
+
+ /** data for the post executed function */
+ void *post_ex_fn_data;
+
+ /** the memory interface */
+ armcpu_memory_iface *mem_if;
+
+ /** the ctrl interface */
+ armcpu_ctrl_iface ctrl_iface;
+#endif
+};
+
+#ifdef GDB_STUB
+int armcpu_new(armcpu_t *armcpu, uint32_t id, armcpu_memory_iface *mem_if, armcpu_ctrl_iface **ctrl_iface_ret);
+#else
+int armcpu_new(armcpu_t *armcpu, uint32_t id);
+#endif
+void armcpu_init(armcpu_t *armcpu, uint32_t adr);
+uint32_t armcpu_switchMode(armcpu_t *armcpu, uint8_t mode);
+
+template<int PROCNUM> uint32_t armcpu_exec();
+
+bool armcpu_irqException(armcpu_t *armcpu);
+//bool armcpu_flagIrq( armcpu_t *armcpu);
+void armcpu_exception(armcpu_t *cpu, uint32_t number);
+uint32_t TRAPUNDEF(armcpu_t* cpu);
+uint32_t armcpu_Wait4IRQ(armcpu_t *cpu);
+
+extern armcpu_t NDS_ARM7, NDS_ARM9;
+
+static inline void setIF(int PROCNUM, uint32_t flag)
+{
+ // don't set generated bits!!!
+ assert(!(flag&0x00200000));
+
+ MMU.reg_IF_bits[PROCNUM] |= flag;
+
+ extern void NDS_Reschedule();
+ NDS_Reschedule();
+}
+
+static inline void NDS_makeIrq(int PROCNUM, uint32_t num)
+{
+ setIF(PROCNUM, 1<<num);
+}
+
+/*static inline char *decodeIntruction(bool thumb_mode, uint32_t instr)
+{
+ char txt[20] = "";
+ uint32_t tmp = 0;
+ if (thumb_mode)
+ {
+ tmp = instr >> 6;
+ strcpy(txt, intToBin(static_cast<uint16_t>(tmp)) + 6);
+ }
+ else
+ {
+ tmp = ((instr >> 16) & 0x0FF0) | ((instr >> 4) & 0x0F);
+ strcpy(txt, intToBin(tmp) + 20);
+ }
+ return _strdup(txt);
+}*/
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/bios.cpp
@@ -1,1 +1,1181 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2008-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cmath>
+
+#include "cp15.h"
+#include "MMU.h"
+//#include "debug.h"
+#include "NDSSystem.h"
+
+#define cpu (&ARMPROC)
+#define TEMPLATE template<int PROCNUM>
+
+static const uint16_t getsinetbl[] = {
+0x0000, 0x0324, 0x0648, 0x096A, 0x0C8C, 0x0FAB, 0x12C8, 0x15E2,
+0x18F9, 0x1C0B, 0x1F1A, 0x2223, 0x2528, 0x2826, 0x2B1F, 0x2E11,
+0x30FB, 0x33DF, 0x36BA, 0x398C, 0x3C56, 0x3F17, 0x41CE, 0x447A,
+0x471C, 0x49B4, 0x4C3F, 0x4EBF, 0x5133, 0x539B, 0x55F5, 0x5842,
+0x5A82, 0x5CB3, 0x5ED7, 0x60EB, 0x62F1, 0x64E8, 0x66CF, 0x68A6,
+0x6A6D, 0x6C23, 0x6DC9, 0x6F5E, 0x70E2, 0x7254, 0x73B5, 0x7504,
+0x7641, 0x776B, 0x7884, 0x7989, 0x7A7C, 0x7B5C, 0x7C29, 0x7CE3,
+0x7D89, 0x7E1D, 0x7E9C, 0x7F09, 0x7F61, 0x7FA6, 0x7FD8, 0x7FF5
+};
+
+static const uint16_t getpitchtbl[] = {
+0x0000, 0x003B, 0x0076, 0x00B2, 0x00ED, 0x0128, 0x0164, 0x019F,
+0x01DB, 0x0217, 0x0252, 0x028E, 0x02CA, 0x0305, 0x0341, 0x037D,
+0x03B9, 0x03F5, 0x0431, 0x046E, 0x04AA, 0x04E6, 0x0522, 0x055F,
+0x059B, 0x05D8, 0x0614, 0x0651, 0x068D, 0x06CA, 0x0707, 0x0743,
+0x0780, 0x07BD, 0x07FA, 0x0837, 0x0874, 0x08B1, 0x08EF, 0x092C,
+0x0969, 0x09A7, 0x09E4, 0x0A21, 0x0A5F, 0x0A9C, 0x0ADA, 0x0B18,
+0x0B56, 0x0B93, 0x0BD1, 0x0C0F, 0x0C4D, 0x0C8B, 0x0CC9, 0x0D07,
+0x0D45, 0x0D84, 0x0DC2, 0x0E00, 0x0E3F, 0x0E7D, 0x0EBC, 0x0EFA,
+0x0F39, 0x0F78, 0x0FB6, 0x0FF5, 0x1034, 0x1073, 0x10B2, 0x10F1,
+0x1130, 0x116F, 0x11AE, 0x11EE, 0x122D, 0x126C, 0x12AC, 0x12EB,
+0x132B, 0x136B, 0x13AA, 0x13EA, 0x142A, 0x146A, 0x14A9, 0x14E9,
+0x1529, 0x1569, 0x15AA, 0x15EA, 0x162A, 0x166A, 0x16AB, 0x16EB,
+0x172C, 0x176C, 0x17AD, 0x17ED, 0x182E, 0x186F, 0x18B0, 0x18F0,
+0x1931, 0x1972, 0x19B3, 0x19F5, 0x1A36, 0x1A77, 0x1AB8, 0x1AFA,
+0x1B3B, 0x1B7D, 0x1BBE, 0x1C00, 0x1C41, 0x1C83, 0x1CC5, 0x1D07,
+0x1D48, 0x1D8A, 0x1DCC, 0x1E0E, 0x1E51, 0x1E93, 0x1ED5, 0x1F17,
+0x1F5A, 0x1F9C, 0x1FDF, 0x2021, 0x2064, 0x20A6, 0x20E9, 0x212C,
+0x216F, 0x21B2, 0x21F5, 0x2238, 0x227B, 0x22BE, 0x2301, 0x2344,
+0x2388, 0x23CB, 0x240E, 0x2452, 0x2496, 0x24D9, 0x251D, 0x2561,
+0x25A4, 0x25E8, 0x262C, 0x2670, 0x26B4, 0x26F8, 0x273D, 0x2781,
+0x27C5, 0x280A, 0x284E, 0x2892, 0x28D7, 0x291C, 0x2960, 0x29A5,
+0x29EA, 0x2A2F, 0x2A74, 0x2AB9, 0x2AFE, 0x2B43, 0x2B88, 0x2BCD,
+0x2C13, 0x2C58, 0x2C9D, 0x2CE3, 0x2D28, 0x2D6E, 0x2DB4, 0x2DF9,
+0x2E3F, 0x2E85, 0x2ECB, 0x2F11, 0x2F57, 0x2F9D, 0x2FE3, 0x302A,
+0x3070, 0x30B6, 0x30FD, 0x3143, 0x318A, 0x31D0, 0x3217, 0x325E,
+0x32A5, 0x32EC, 0x3332, 0x3379, 0x33C1, 0x3408, 0x344F, 0x3496,
+0x34DD, 0x3525, 0x356C, 0x35B4, 0x35FB, 0x3643, 0x368B, 0x36D3,
+0x371A, 0x3762, 0x37AA, 0x37F2, 0x383A, 0x3883, 0x38CB, 0x3913,
+0x395C, 0x39A4, 0x39ED, 0x3A35, 0x3A7E, 0x3AC6, 0x3B0F, 0x3B58,
+0x3BA1, 0x3BEA, 0x3C33, 0x3C7C, 0x3CC5, 0x3D0E, 0x3D58, 0x3DA1,
+0x3DEA, 0x3E34, 0x3E7D, 0x3EC7, 0x3F11, 0x3F5A, 0x3FA4, 0x3FEE,
+0x4038, 0x4082, 0x40CC, 0x4116, 0x4161, 0x41AB, 0x41F5, 0x4240,
+0x428A, 0x42D5, 0x431F, 0x436A, 0x43B5, 0x4400, 0x444B, 0x4495,
+0x44E1, 0x452C, 0x4577, 0x45C2, 0x460D, 0x4659, 0x46A4, 0x46F0,
+0x473B, 0x4787, 0x47D3, 0x481E, 0x486A, 0x48B6, 0x4902, 0x494E,
+0x499A, 0x49E6, 0x4A33, 0x4A7F, 0x4ACB, 0x4B18, 0x4B64, 0x4BB1,
+0x4BFE, 0x4C4A, 0x4C97, 0x4CE4, 0x4D31, 0x4D7E, 0x4DCB, 0x4E18,
+0x4E66, 0x4EB3, 0x4F00, 0x4F4E, 0x4F9B, 0x4FE9, 0x5036, 0x5084,
+0x50D2, 0x5120, 0x516E, 0x51BC, 0x520A, 0x5258, 0x52A6, 0x52F4,
+0x5343, 0x5391, 0x53E0, 0x542E, 0x547D, 0x54CC, 0x551A, 0x5569,
+0x55B8, 0x5607, 0x5656, 0x56A5, 0x56F4, 0x5744, 0x5793, 0x57E2,
+0x5832, 0x5882, 0x58D1, 0x5921, 0x5971, 0x59C1, 0x5A10, 0x5A60,
+0x5AB0, 0x5B01, 0x5B51, 0x5BA1, 0x5BF1, 0x5C42, 0x5C92, 0x5CE3,
+0x5D34, 0x5D84, 0x5DD5, 0x5E26, 0x5E77, 0x5EC8, 0x5F19, 0x5F6A,
+0x5FBB, 0x600D, 0x605E, 0x60B0, 0x6101, 0x6153, 0x61A4, 0x61F6,
+0x6248, 0x629A, 0x62EC, 0x633E, 0x6390, 0x63E2, 0x6434, 0x6487,
+0x64D9, 0x652C, 0x657E, 0x65D1, 0x6624, 0x6676, 0x66C9, 0x671C,
+0x676F, 0x67C2, 0x6815, 0x6869, 0x68BC, 0x690F, 0x6963, 0x69B6,
+0x6A0A, 0x6A5E, 0x6AB1, 0x6B05, 0x6B59, 0x6BAD, 0x6C01, 0x6C55,
+0x6CAA, 0x6CFE, 0x6D52, 0x6DA7, 0x6DFB, 0x6E50, 0x6EA4, 0x6EF9,
+0x6F4E, 0x6FA3, 0x6FF8, 0x704D, 0x70A2, 0x70F7, 0x714D, 0x71A2,
+0x71F7, 0x724D, 0x72A2, 0x72F8, 0x734E, 0x73A4, 0x73FA, 0x7450,
+0x74A6, 0x74FC, 0x7552, 0x75A8, 0x75FF, 0x7655, 0x76AC, 0x7702,
+0x7759, 0x77B0, 0x7807, 0x785E, 0x78B4, 0x790C, 0x7963, 0x79BA,
+0x7A11, 0x7A69, 0x7AC0, 0x7B18, 0x7B6F, 0x7BC7, 0x7C1F, 0x7C77,
+0x7CCF, 0x7D27, 0x7D7F, 0x7DD7, 0x7E2F, 0x7E88, 0x7EE0, 0x7F38,
+0x7F91, 0x7FEA, 0x8042, 0x809B, 0x80F4, 0x814D, 0x81A6, 0x81FF,
+0x8259, 0x82B2, 0x830B, 0x8365, 0x83BE, 0x8418, 0x8472, 0x84CB,
+0x8525, 0x857F, 0x85D9, 0x8633, 0x868E, 0x86E8, 0x8742, 0x879D,
+0x87F7, 0x8852, 0x88AC, 0x8907, 0x8962, 0x89BD, 0x8A18, 0x8A73,
+0x8ACE, 0x8B2A, 0x8B85, 0x8BE0, 0x8C3C, 0x8C97, 0x8CF3, 0x8D4F,
+0x8DAB, 0x8E07, 0x8E63, 0x8EBF, 0x8F1B, 0x8F77, 0x8FD4, 0x9030,
+0x908C, 0x90E9, 0x9146, 0x91A2, 0x91FF, 0x925C, 0x92B9, 0x9316,
+0x9373, 0x93D1, 0x942E, 0x948C, 0x94E9, 0x9547, 0x95A4, 0x9602,
+0x9660, 0x96BE, 0x971C, 0x977A, 0x97D8, 0x9836, 0x9895, 0x98F3,
+0x9952, 0x99B0, 0x9A0F, 0x9A6E, 0x9ACD, 0x9B2C, 0x9B8B, 0x9BEA,
+0x9C49, 0x9CA8, 0x9D08, 0x9D67, 0x9DC7, 0x9E26, 0x9E86, 0x9EE6,
+0x9F46, 0x9FA6, 0xA006, 0xA066, 0xA0C6, 0xA127, 0xA187, 0xA1E8,
+0xA248, 0xA2A9, 0xA30A, 0xA36B, 0xA3CC, 0xA42D, 0xA48E, 0xA4EF,
+0xA550, 0xA5B2, 0xA613, 0xA675, 0xA6D6, 0xA738, 0xA79A, 0xA7FC,
+0xA85E, 0xA8C0, 0xA922, 0xA984, 0xA9E7, 0xAA49, 0xAAAC, 0xAB0E,
+0xAB71, 0xABD4, 0xAC37, 0xAC9A, 0xACFD, 0xAD60, 0xADC3, 0xAE27,
+0xAE8A, 0xAEED, 0xAF51, 0xAFB5, 0xB019, 0xB07C, 0xB0E0, 0xB145,
+0xB1A9, 0xB20D, 0xB271, 0xB2D6, 0xB33A, 0xB39F, 0xB403, 0xB468,
+0xB4CD, 0xB532, 0xB597, 0xB5FC, 0xB662, 0xB6C7, 0xB72C, 0xB792,
+0xB7F7, 0xB85D, 0xB8C3, 0xB929, 0xB98F, 0xB9F5, 0xBA5B, 0xBAC1,
+0xBB28, 0xBB8E, 0xBBF5, 0xBC5B, 0xBCC2, 0xBD29, 0xBD90, 0xBDF7,
+0xBE5E, 0xBEC5, 0xBF2C, 0xBF94, 0xBFFB, 0xC063, 0xC0CA, 0xC132,
+0xC19A, 0xC202, 0xC26A, 0xC2D2, 0xC33A, 0xC3A2, 0xC40B, 0xC473,
+0xC4DC, 0xC544, 0xC5AD, 0xC616, 0xC67F, 0xC6E8, 0xC751, 0xC7BB,
+0xC824, 0xC88D, 0xC8F7, 0xC960, 0xC9CA, 0xCA34, 0xCA9E, 0xCB08,
+0xCB72, 0xCBDC, 0xCC47, 0xCCB1, 0xCD1B, 0xCD86, 0xCDF1, 0xCE5B,
+0xCEC6, 0xCF31, 0xCF9C, 0xD008, 0xD073, 0xD0DE, 0xD14A, 0xD1B5,
+0xD221, 0xD28D, 0xD2F8, 0xD364, 0xD3D0, 0xD43D, 0xD4A9, 0xD515,
+0xD582, 0xD5EE, 0xD65B, 0xD6C7, 0xD734, 0xD7A1, 0xD80E, 0xD87B,
+0xD8E9, 0xD956, 0xD9C3, 0xDA31, 0xDA9E, 0xDB0C, 0xDB7A, 0xDBE8,
+0xDC56, 0xDCC4, 0xDD32, 0xDDA0, 0xDE0F, 0xDE7D, 0xDEEC, 0xDF5B,
+0xDFC9, 0xE038, 0xE0A7, 0xE116, 0xE186, 0xE1F5, 0xE264, 0xE2D4,
+0xE343, 0xE3B3, 0xE423, 0xE493, 0xE503, 0xE573, 0xE5E3, 0xE654,
+0xE6C4, 0xE735, 0xE7A5, 0xE816, 0xE887, 0xE8F8, 0xE969, 0xE9DA,
+0xEA4B, 0xEABC, 0xEB2E, 0xEB9F, 0xEC11, 0xEC83, 0xECF5, 0xED66,
+0xEDD9, 0xEE4B, 0xEEBD, 0xEF2F, 0xEFA2, 0xF014, 0xF087, 0xF0FA,
+0xF16D, 0xF1E0, 0xF253, 0xF2C6, 0xF339, 0xF3AD, 0xF420, 0xF494,
+0xF507, 0xF57B, 0xF5EF, 0xF663, 0xF6D7, 0xF74C, 0xF7C0, 0xF834,
+0xF8A9, 0xF91E, 0xF992, 0xFA07, 0xFA7C, 0xFAF1, 0xFB66, 0xFBDC,
+0xFC51, 0xFCC7, 0xFD3C, 0xFDB2, 0xFE28, 0xFE9E, 0xFF14, 0xFF8A
+};
+
+static const uint8_t getvoltbl[] = {
+0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
+0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08,
+0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
+0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E,
+0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10,
+0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14,
+0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x18,
+0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C,
+0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
+0x22, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x29,
+0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x31, 0x31,
+0x32, 0x32, 0x33, 0x33, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3A, 0x3A, 0x3B,
+0x3C, 0x3C, 0x3D, 0x3E, 0x3F, 0x3F, 0x40, 0x41, 0x42, 0x42, 0x43, 0x44, 0x45, 0x45, 0x46, 0x47,
+0x48, 0x49, 0x4A, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x52, 0x53, 0x54, 0x55,
+0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67,
+0x68, 0x69, 0x6A, 0x6B, 0x6D, 0x6E, 0x6F, 0x71, 0x72, 0x73, 0x75, 0x76, 0x77, 0x79, 0x7A, 0x7B,
+0x7D, 0x7E, 0x7F, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25,
+0x26, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D,
+0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x31, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x36,
+0x36, 0x37, 0x37, 0x38, 0x39, 0x39, 0x3A, 0x3B, 0x3B, 0x3C, 0x3D, 0x3E, 0x3E, 0x3F, 0x40, 0x40,
+0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4D,
+0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D,
+0x5E, 0x5F, 0x60, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6F, 0x70,
+0x71, 0x73, 0x74, 0x75, 0x77, 0x78, 0x79, 0x7B, 0x7C, 0x7E, 0x7E, 0x40, 0x41, 0x42, 0x43, 0x43,
+0x44, 0x45, 0x46, 0x47, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
+0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
+0x62, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x71, 0x72, 0x74, 0x75,
+0x76, 0x78, 0x79, 0x7B, 0x7C, 0x7D, 0x7E, 0x40, 0x41, 0x42, 0x42, 0x43, 0x44, 0x45, 0x46, 0x46,
+0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55,
+0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x65, 0x66,
+0x67, 0x68, 0x69, 0x6A, 0x6C, 0x6D, 0x6E, 0x6F, 0x71, 0x72, 0x73, 0x75, 0x76, 0x77, 0x79, 0x7A,
+0x7C, 0x7D, 0x7E, 0x7F
+};
+
+TEMPLATE static uint32_t bios_nop()
+{
+ /*LOG("SWI: ARM%c Unimplemented BIOS function %02X was used. R0:%08X, R1:%08X, R2:%08X\n", PROCNUM?'7':'9',
+ (cpu->instruction)&0x1F, cpu->R[0], cpu->R[1], cpu->R[2]);*/
+ return 3;
+}
+
+TEMPLATE static uint32_t WaitByLoop()
+{
+ uint32_t elapsed;
+
+ //printf("%lld waitbyloop\n",nds_timer);
+ //INFO("ARM%c: SWI 0x03 (WaitByLoop)\n", PROCNUM?'7':'9');
+ if (PROCNUM == ARMCPU_ARM9)
+ {
+ armcp15_t *cp = (armcp15_t*)(cpu->coproc[15]);
+
+ if (cp->ctrl & ((1<<16)|(1<<18))) // DTCM or ITCM is on (cache)
+ elapsed = cpu->R[0] * 2;
+ else
+ elapsed = cpu->R[0] * 8;
+ }
+ else
+ elapsed = cpu->R[0] * 4;
+ cpu->R[0] = 0;
+ return elapsed;
+}
+
+TEMPLATE static uint32_t wait4IRQ()
+{
+ cpu->waitIRQ = true;
+ cpu->halt_IE_and_IF = true;
+ return 1;
+}
+
+TEMPLATE uint32_t intrWaitARM()
+{
+ //TODO - account for differences between arm7 and arm9 (according to gbatek, the "bug doesn't work")
+
+ const uint32_t intrFlagAdr = (PROCNUM == ARMCPU_ARM7)
+ ? 0x380FFF8
+ : (((armcp15_t *)(cpu->coproc[15]))->DTCMRegion&0xFFFFF000)+0x3FF8;
+
+ //set IME=1
+ //without this, no irq handlers can happen (even though IF&IE waits can happily happen)
+ //and so no bits in the OS irq flag variable can get set by the handlers
+ _MMU_write32<PROCNUM>(0x04000208, 1);
+
+ //analyze the OS irq flag variable
+ uint32_t intr = _MMU_read32<PROCNUM>(intrFlagAdr);
+ uint32_t intrFlag = (cpu->R[1] & intr);
+
+ //if the user requested us to discard flags, then clear the flag(s) we're going to be waiting on.
+ //(be sure to only do this only on the first run through. use a little state machine to control that)
+ if(cpu->intrWaitARM_state==0 && cpu->R[0]==1)
+ {
+ intr ^= intrFlag;
+ _MMU_write32<PROCNUM>(intrFlagAdr, intr);
+
+ //we want to make sure we wait at least once below
+ intrFlag = 0;
+ }
+
+ cpu->intrWaitARM_state = 1;
+
+ //now, if the condition is satisfied (and it won't be the first time through, no matter what, due to cares taken above)
+ if(intrFlag)
+ {
+ //write back the OS irq flags with the ones we were waiting for cleared
+ intr ^= intrFlag;
+ _MMU_write32<PROCNUM>(intrFlagAdr, intr);
+
+ cpu->intrWaitARM_state = 0;
+ return 1;
+ }
+
+ //the condition wasn't satisfied. this means that we need to halt, wait for some enabled interrupt,
+ //and then ensure that we return to this opcode again to check the condition again
+ cpu->waitIRQ = true;
+ cpu->halt_IE_and_IF = true;
+
+ //(rewire PC to jump back to this opcode)
+ uint32_t instructAddr = cpu->instruct_adr;
+ cpu->R[15] = instructAddr;
+ cpu->next_instruction = instructAddr;
+ return 1;
+}
+
+TEMPLATE static uint32_t waitVBlankARM()
+{
+ cpu->R[0] = 1;
+ cpu->R[1] = 1;
+ return intrWaitARM<PROCNUM>();
+}
+
+TEMPLATE static uint32_t sleep()
+{
+ _MMU_write08<PROCNUM>(0x04000301, 0xC0);
+ return 1;
+}
+
+TEMPLATE static uint32_t divide()
+{
+ int32_t num = (int32_t)cpu->R[0];
+ int32_t dnum = (int32_t)cpu->R[1];
+
+ if(dnum==0) return 0;
+
+ int32_t res = num / dnum;
+ cpu->R[0] = (uint32_t)res;
+ cpu->R[1] = (uint32_t)(num % dnum);
+ cpu->R[3] = (uint32_t)abs(res);
+
+ //INFO("ARM%c: SWI 0x09 (divide): in num %i, dnum %i, out R0:%i, R1:%i, R3:%i\n", PROCNUM?'7':'9', num, dnum, cpu->R[0], cpu->R[1], cpu->R[3]);
+
+ return 6;
+}
+
+TEMPLATE static uint32_t copy()
+{
+ uint32_t src = cpu->R[0];
+ uint32_t dst = cpu->R[1];
+ uint32_t cnt = cpu->R[2];
+
+ //INFO("swi copy from %08X to %08X, cnt=%08X\n", src, dst, cnt);
+
+ switch(BIT26(cnt))
+ {
+ case 0:
+ src &= 0xFFFFFFFE;
+ dst &= 0xFFFFFFFE;
+ switch(BIT24(cnt))
+ {
+ case 0:
+ cnt &= 0x1FFFFF;
+ while(cnt)
+ {
+ _MMU_write16<PROCNUM>(dst, _MMU_read16<PROCNUM>(src));
+ cnt--;
+ dst+=2;
+ src+=2;
+ }
+ break;
+ case 1:
+ {
+ uint32_t val = _MMU_read16<PROCNUM>(src);
+ cnt &= 0x1FFFFF;
+ while(cnt)
+ {
+ _MMU_write16<PROCNUM>(dst, static_cast<uint16_t>(val));
+ cnt--;
+ dst+=2;
+ }
+ }
+ break;
+ }
+ break;
+ case 1:
+ src &= 0xFFFFFFFC;
+ dst &= 0xFFFFFFFC;
+ switch(BIT24(cnt))
+ {
+ case 0:
+ cnt &= 0x1FFFFF;
+ while(cnt)
+ {
+ _MMU_write32<PROCNUM>(dst, _MMU_read32<PROCNUM>(src));
+ cnt--;
+ dst+=4;
+ src+=4;
+ }
+ break;
+ case 1:
+ {
+ uint32_t val = _MMU_read32<PROCNUM>(src);
+ cnt &= 0x1FFFFF;
+ while(cnt)
+ {
+ _MMU_write32<PROCNUM>(dst, val);
+ cnt--;
+ dst+=4;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ return 1;
+}
+
+TEMPLATE static uint32_t fastCopy()
+{
+ uint32_t src = cpu->R[0] & 0xFFFFFFFC;
+ uint32_t dst = cpu->R[1] & 0xFFFFFFFC;
+ uint32_t cnt = cpu->R[2];
+
+ //INFO("swi fastcopy from %08X to %08X, cnt=%08X\n", src, dst, cnt);
+
+ switch(BIT24(cnt))
+ {
+ case 0:
+ cnt &= 0x1FFFFF;
+ while(cnt)
+ {
+ _MMU_write32<PROCNUM>(dst, _MMU_read32<PROCNUM>(src));
+ cnt--;
+ dst+=4;
+ src+=4;
+ }
+ break;
+ case 1:
+ {
+ uint32_t val = _MMU_read32<PROCNUM>(src);
+ cnt &= 0x1FFFFF;
+ while(cnt)
+ {
+ _MMU_write32<PROCNUM>(dst, val);
+ cnt--;
+ dst+=4;
+ }
+ }
+ break;
+ }
+ return 1;
+}
+
+TEMPLATE static uint32_t LZ77UnCompVram()
+{
+ int i1, i2;
+ int byteCount;
+ int byteShift;
+ uint32_t writeValue;
+ int len;
+ uint32_t source = cpu->R[0];
+ uint32_t dest = cpu->R[1];
+ uint32_t header = _MMU_read32<PROCNUM>(source);
+ source += 4;
+
+ //INFO("swi lz77uncompvram\n");
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return 0;
+
+ byteCount = 0;
+ byteShift = 0;
+ writeValue = 0;
+
+ len = header >> 8;
+
+ while(len > 0) {
+ uint8_t d = _MMU_read08<PROCNUM>(source++);
+
+ if(d) {
+ for(i1 = 0; i1 < 8; i1++) {
+ if(d & 0x80) {
+ int length;
+ int offset;
+ uint32_t windowOffset;
+ uint16_t data = _MMU_read08<PROCNUM>(source++) << 8;
+ data |= _MMU_read08<PROCNUM>(source++);
+ length = (data >> 12) + 3;
+ offset = (data & 0x0FFF);
+ windowOffset = dest + byteCount - offset - 1;
+ for(i2 = 0; i2 < length; i2++) {
+ writeValue |= (_MMU_read08<PROCNUM>(windowOffset++) << byteShift);
+ byteShift += 8;
+ byteCount++;
+
+ if(byteCount == 2) {
+ _MMU_write16<PROCNUM>(dest, static_cast<uint16_t>(writeValue));
+ dest += 2;
+ byteCount = 0;
+ byteShift = 0;
+ writeValue = 0;
+ }
+ len--;
+ if(len == 0)
+ return 0;
+ }
+ } else {
+ writeValue |= (_MMU_read08<PROCNUM>(source++) << byteShift);
+ byteShift += 8;
+ byteCount++;
+ if(byteCount == 2) {
+ _MMU_write16<PROCNUM>(dest, static_cast<uint16_t>(writeValue));
+ dest += 2;
+ byteCount = 0;
+ byteShift = 0;
+ writeValue = 0;
+ }
+ len--;
+ if(len == 0)
+ return 0;
+ }
+ d <<= 1;
+ }
+ } else {
+ for(i1 = 0; i1 < 8; i1++) {
+ writeValue |= (_MMU_read08<PROCNUM>(source++) << byteShift);
+ byteShift += 8;
+ byteCount++;
+ if(byteCount == 2) {
+ _MMU_write16<PROCNUM>(dest, static_cast<uint16_t>(writeValue));
+ dest += 2;
+ byteShift = 0;
+ byteCount = 0;
+ writeValue = 0;
+ }
+ len--;
+ if(len == 0)
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+TEMPLATE static uint32_t LZ77UnCompWram()
+{
+ int i1, i2;
+ int len;
+ uint32_t source = cpu->R[0];
+ uint32_t dest = cpu->R[1];
+
+ uint32_t header = _MMU_read32<PROCNUM>(source);
+ source += 4;
+
+ //INFO("swi lz77uncompwram\n");
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return 0;
+
+ len = header >> 8;
+
+ while(len > 0) {
+ uint8_t d = _MMU_read08<PROCNUM>(source++);
+
+ if(d) {
+ for(i1 = 0; i1 < 8; i1++) {
+ if(d & 0x80) {
+ int length;
+ int offset;
+ uint32_t windowOffset;
+ uint16_t data = _MMU_read08<PROCNUM>(source++) << 8;
+ data |= _MMU_read08<PROCNUM>(source++);
+ length = (data >> 12) + 3;
+ offset = (data & 0x0FFF);
+ windowOffset = dest - offset - 1;
+ for(i2 = 0; i2 < length; i2++) {
+ _MMU_write08<PROCNUM>(dest++, _MMU_read08<PROCNUM>(windowOffset++));
+ len--;
+ if(len == 0)
+ return 0;
+ }
+ } else {
+ _MMU_write08<PROCNUM>(dest++, _MMU_read08<PROCNUM>(source++));
+ len--;
+ if(len == 0)
+ return 0;
+ }
+ d <<= 1;
+ }
+ } else {
+ for(i1 = 0; i1 < 8; i1++) {
+ _MMU_write08<PROCNUM>(dest++, _MMU_read08<PROCNUM>(source++));
+ len--;
+ if(len == 0)
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+TEMPLATE static uint32_t RLUnCompVram()
+{
+ int i;
+ int len;
+ int byteCount;
+ int byteShift;
+ uint32_t writeValue;
+ uint32_t source = cpu->R[0];
+ uint32_t dest = cpu->R[1];
+
+ uint32_t header = _MMU_read32<PROCNUM>(source);
+ source += 4;
+
+ //INFO("swi rluncompvram\n");
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return 0;
+
+ len = header >> 8;
+ byteCount = 0;
+ byteShift = 0;
+ writeValue = 0;
+
+ while(len > 0) {
+ uint8_t d = _MMU_read08<PROCNUM>(source++);
+ int l = d & 0x7F;
+ if(d & 0x80) {
+ uint8_t data = _MMU_read08<PROCNUM>(source++);
+ l += 3;
+ for(i = 0;i < l; i++) {
+ writeValue |= (data << byteShift);
+ byteShift += 8;
+ byteCount++;
+
+ if(byteCount == 2) {
+ _MMU_write16<PROCNUM>(dest, static_cast<uint16_t>(writeValue));
+ dest += 2;
+ byteCount = 0;
+ byteShift = 0;
+ writeValue = 0;
+ }
+ len--;
+ if(len == 0)
+ return 0;
+ }
+ } else {
+ l++;
+ for(i = 0; i < l; i++) {
+ writeValue |= (_MMU_read08<PROCNUM>(source++) << byteShift);
+ byteShift += 8;
+ byteCount++;
+ if(byteCount == 2) {
+ _MMU_write16<PROCNUM>(dest, static_cast<uint16_t>(writeValue));
+ dest += 2;
+ byteCount = 0;
+ byteShift = 0;
+ writeValue = 0;
+ }
+ len--;
+ if(len == 0)
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+TEMPLATE static uint32_t RLUnCompWram()
+{
+ int i;
+ int len;
+ uint32_t source = cpu->R[0];
+ uint32_t dest = cpu->R[1];
+
+ uint32_t header = _MMU_read32<PROCNUM>(source);
+ source += 4;
+
+ //INFO("swi rluncompwram\n");
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return 0;
+
+ len = header >> 8;
+
+ while(len > 0) {
+ uint8_t d = _MMU_read08<PROCNUM>(source++);
+ int l = d & 0x7F;
+ if(d & 0x80) {
+ uint8_t data = _MMU_read08<PROCNUM>(source++);
+ l += 3;
+ for(i = 0;i < l; i++) {
+ _MMU_write08<PROCNUM>(dest++, data);
+ len--;
+ if(len == 0)
+ return 0;
+ }
+ } else {
+ l++;
+ for(i = 0; i < l; i++) {
+ _MMU_write08<PROCNUM>(dest++, _MMU_read08<PROCNUM>(source++));
+ len--;
+ if(len == 0)
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+TEMPLATE static uint32_t UnCompHuffman()
+{
+ uint32_t source, dest, writeValue, header, treeStart, mask;
+ uint32_t data;
+ uint8_t treeSize, currentNode, rootNode;
+ int byteCount, byteShift, len, pos;
+ int writeData;
+
+ source = cpu->R[0];
+ dest = cpu->R[1];
+
+ header = _MMU_read08<PROCNUM>(source);
+ source += 4;
+
+ //INFO("swi uncomphuffman\n");
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return 0;
+
+ treeSize = _MMU_read08<PROCNUM>(source++);
+
+ treeStart = source;
+
+ source += ((treeSize+1)<<1)-1; // minus because we already skipped one byte
+
+ len = header >> 8;
+
+ mask = 0x80000000;
+ data = _MMU_read08<PROCNUM>(source);
+ source += 4;
+
+ pos = 0;
+ rootNode = _MMU_read08<PROCNUM>(treeStart);
+ currentNode = rootNode;
+ writeData = 0;
+ byteShift = 0;
+ byteCount = 0;
+ writeValue = 0;
+
+ if((header & 0x0F) == 8) {
+ while(len > 0) {
+ // take left
+ if(pos == 0)
+ pos++;
+ else
+ pos += (((currentNode & 0x3F)+1)<<1);
+
+ if(data & mask) {
+ // right
+ if(currentNode & 0x40)
+ writeData = 1;
+ currentNode = _MMU_read08<PROCNUM>(treeStart+pos+1);
+ } else {
+ // left
+ if(currentNode & 0x80)
+ writeData = 1;
+ currentNode = _MMU_read08<PROCNUM>(treeStart+pos);
+ }
+
+ if(writeData) {
+ writeValue |= (currentNode << byteShift);
+ byteCount++;
+ byteShift += 8;
+
+ pos = 0;
+ currentNode = rootNode;
+ writeData = 0;
+
+ if(byteCount == 4) {
+ byteCount = 0;
+ byteShift = 0;
+ _MMU_write08<PROCNUM>(dest, static_cast<uint8_t>(writeValue));
+ writeValue = 0;
+ dest += 4;
+ len -= 4;
+ }
+ }
+ mask >>= 1;
+ if(mask == 0) {
+ mask = 0x80000000;
+ data = _MMU_read08<PROCNUM>(source);
+ source += 4;
+ }
+ }
+ } else {
+ int halfLen = 0;
+ int value = 0;
+ while(len > 0) {
+ // take left
+ if(pos == 0)
+ pos++;
+ else
+ pos += (((currentNode & 0x3F)+1)<<1);
+
+ if((data & mask)) {
+ // right
+ if(currentNode & 0x40)
+ writeData = 1;
+ currentNode = _MMU_read08<PROCNUM>(treeStart+pos+1);
+ } else {
+ // left
+ if(currentNode & 0x80)
+ writeData = 1;
+ currentNode = _MMU_read08<PROCNUM>(treeStart+pos);
+ }
+
+ if(writeData) {
+ if(halfLen == 0)
+ value |= currentNode;
+ else
+ value |= (currentNode<<4);
+
+ halfLen += 4;
+ if(halfLen == 8) {
+ writeValue |= (value << byteShift);
+ byteCount++;
+ byteShift += 8;
+
+ halfLen = 0;
+ value = 0;
+
+ if(byteCount == 4) {
+ byteCount = 0;
+ byteShift = 0;
+ _MMU_write08<PROCNUM>(dest, static_cast<uint8_t>(writeValue));
+ dest += 4;
+ writeValue = 0;
+ len -= 4;
+ }
+ }
+ pos = 0;
+ currentNode = rootNode;
+ writeData = 0;
+ }
+ mask >>= 1;
+ if(mask == 0) {
+ mask = 0x80000000;
+ data = _MMU_read08<PROCNUM>(source);
+ source += 4;
+ }
+ }
+ }
+ return 1;
+}
+
+TEMPLATE static uint32_t BitUnPack()
+{
+ uint32_t source,dest,header,base,d,temp;
+ int len,bits,revbits,dataSize,data,bitwritecount,mask,bitcount,addBase;
+ uint8_t b;
+
+ source = cpu->R[0];
+ dest = cpu->R[1];
+ header = cpu->R[2];
+
+ len = _MMU_read16<PROCNUM>(header);
+ bits = _MMU_read08<PROCNUM>(header+2);
+ switch (bits)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default: return 0; // error
+ }
+ dataSize = _MMU_read08<PROCNUM>(header+3);
+ switch (dataSize)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ break;
+ default: return 0; // error
+ }
+
+ revbits = 8 - bits;
+ // uint32_t value = 0;
+ base = _MMU_read08<PROCNUM>(header+4);
+ addBase = (base & 0x80000000) ? 1 : 0;
+ base &= 0x7fffffff;
+
+ //INFO("SWI10: bitunpack src 0x%08X dst 0x%08X hdr 0x%08X (src len %05i src bits %02i dst bits %02i)\n\n", source, dest, header, len, bits, dataSize);
+
+ data = 0;
+ bitwritecount = 0;
+ while(1) {
+ len -= 1;
+ if(len < 0)
+ break;
+ mask = 0xff >> revbits;
+ b = _MMU_read08<PROCNUM>(source);
+ source++;
+ bitcount = 0;
+ while(1) {
+ if(bitcount >= 8)
+ break;
+ d = b & mask;
+ temp = d >> bitcount;
+ if(!temp && addBase) {
+ temp += base;
+ }
+ data |= temp << bitwritecount;
+ bitwritecount += dataSize;
+ if(bitwritecount >= 32) {
+ _MMU_write08<PROCNUM>(dest, data);
+ dest += 4;
+ data = 0;
+ bitwritecount = 0;
+ }
+ mask <<= bits;
+ bitcount += bits;
+ }
+ }
+ return 1;
+}
+
+TEMPLATE static uint32_t Diff8bitUnFilterWram()
+{
+ uint32_t source,dest,header;
+ uint8_t data,diff;
+ int len;
+
+ source = cpu->R[0];
+ dest = cpu->R[1];
+
+ header = _MMU_read08<PROCNUM>(source);
+ source += 4;
+
+ //INFO("swi diff8bitunfilterwram\n");
+
+ if(((source & 0xe000000) == 0) ||
+ (( (source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0))
+ return 0;
+
+ len = header >> 8;
+
+ data = _MMU_read08<PROCNUM>(source++);
+ _MMU_write08<PROCNUM>(dest++, data);
+ len--;
+
+ while(len > 0) {
+ diff = _MMU_read08<PROCNUM>(source++);
+ data += diff;
+ _MMU_write08<PROCNUM>(dest++, data);
+ len--;
+ }
+ return 1;
+}
+
+TEMPLATE static uint32_t Diff16bitUnFilter()
+{
+ uint32_t source,dest,header;
+ uint16_t data;
+ int len;
+
+ source = cpu->R[0];
+ dest = cpu->R[1];
+
+ //INFO("swi diff16bitunfilter\n");
+
+ header = _MMU_read08<PROCNUM>(source);
+ source += 4;
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return 0;
+
+ len = header >> 8;
+
+ data = _MMU_read16<PROCNUM>(source);
+ source += 2;
+ _MMU_write16<PROCNUM>(dest, data);
+ dest += 2;
+ len -= 2;
+
+ while(len >= 2) {
+ uint16_t diff = _MMU_read16<PROCNUM>(source);
+ source += 2;
+ data += diff;
+ _MMU_write16<PROCNUM>(dest, data);
+ dest += 2;
+ len -= 2;
+ }
+ return 1;
+}
+
+TEMPLATE static uint32_t bios_sqrt()
+{
+ cpu->R[0] = (uint32_t)sqrt((double)(cpu->R[0]));
+ return 1;
+}
+
+TEMPLATE static uint32_t setHaltCR()
+{
+ _MMU_write08<PROCNUM>(0x4000300+cpu->proc_ID, static_cast<uint8_t>(cpu->R[0]));
+ return 1;
+}
+
+TEMPLATE static uint32_t getSineTab()
+{
+ //ds returns garbage according to gbatek, but we must protect ourselves
+ if(cpu->R[0] >= ARRAY_SIZE(getsinetbl))
+ {
+ printf("Invalid SWI getSineTab: %08X\n",cpu->R[0]);
+ return 1;
+ }
+
+
+ cpu->R[0] = getsinetbl[cpu->R[0]];
+ return 1;
+}
+
+TEMPLATE static uint32_t getPitchTab()
+{
+ //ds returns garbage according to gbatek, but we must protect ourselves
+ if(cpu->R[0] >= ARRAY_SIZE(getpitchtbl))
+ {
+ printf("Invalid SWI getPitchTab: %08X\n",cpu->R[0]);
+ return 1;
+ }
+
+ cpu->R[0] = getpitchtbl[cpu->R[0]];
+ return 1;
+}
+
+TEMPLATE static uint32_t getVolumeTab()
+{
+ //ds returns garbage according to gbatek, but we must protect ourselves
+ if(cpu->R[0] >= ARRAY_SIZE(getvoltbl))
+ {
+ printf("Invalid SWI getVolumeTab: %08X\n",cpu->R[0]);
+ return 1;
+ }
+
+
+ cpu->R[0] = getvoltbl[cpu->R[0]];
+ return 1;
+}
+
+
+//TEMPLATE static uint32_t getCRC16_old(uint32_t crc, uint32_t datap, uint32_t size)
+//{
+// unsigned int i,j;
+//
+// const uint16_t val[] = { 0xC0C1,0xC181,0xC301,0xC601,0xCC01,0xD801,0xF001,0xA001 };
+// for(i = 0; i < size; i++)
+// {
+// crc = crc ^ _MMU_read08<PROCNUM>(datap + i);
+//
+// for(j = 0; j < 8; j++) {
+// int do_bit = 0;
+//
+// if ( crc & 0x1)
+// do_bit = 1;
+//
+// crc = crc >> 1;
+//
+// if ( do_bit) {
+// crc = crc ^ (val[j] << (7-j));
+// }
+// }
+// }
+// return crc;
+//}
+
+TEMPLATE static uint32_t getCRC16()
+{
+ //gbatek is wrong.
+
+ //dawn of sorrow uses this to checksum its save data;
+ //if this implementation is wrong, then it won't match what the real bios returns,
+ //and savefiles created with a bios will be invalid when loaded with non-bios (and vice-versa)
+
+ //uint32_t old = getCRC16_old<PROCNUM>(cpu->R[0],cpu->R[1],cpu->R[2]);
+
+ uint16_t crc = (uint16_t)cpu->R[0];
+ uint32_t datap = cpu->R[1];
+ uint32_t size = cpu->R[2]>>1;
+ uint16_t currVal = 0;
+
+ const uint16_t val[] = { 0x0000,0xCC01,0xD801,0x1400,0xF001,0x3C00,0x2800,0xE401,0xA001,0x6C00,0x7800,0xB401,0x5000,0x9C01,0x8801,0x4400};
+
+ for(uint32_t i = 0; i < size; i++)
+ {
+ currVal = _MMU_read16<PROCNUM>(datap + i*2);
+
+ for(int j=0;j<4;j++)
+ {
+ uint16_t tabVal = val[crc&0xF];
+ crc >>= 4;
+ crc ^= tabVal;
+
+ uint16_t tempVal = currVal >> (4*j);
+ tabVal = val[tempVal&0xF];
+ crc ^= tabVal;
+ }
+ }
+
+ // R3 contains the last processed halfword
+ cpu->R[3] = currVal;
+ return 1;
+}
+
+TEMPLATE static uint32_t isDebugger()
+{
+ //gbatek has additional specifications which are not emulated here
+/*#ifdef DEVELOPER
+ cpu->R[0] = 1;
+#else*/
+ cpu->R[0] = 0;
+//#endif
+ return 1;
+}
+
+TEMPLATE static uint32_t SoundBias()
+{
+ uint32_t curBias = _MMU_read32<ARMCPU_ARM7>(0x04000504);
+ uint32_t newBias = (curBias == 0) ? 0x000:0x200;
+ uint32_t delay = (newBias > curBias) ? (newBias-curBias) : (curBias-newBias);
+
+ _MMU_write32<ARMCPU_ARM7>(0x04000504, newBias);
+ return cpu->R[1] * delay;
+}
+
+TEMPLATE static uint32_t getBootProcs()
+{
+ cpu->R[0] = 0x00000A2E;
+ cpu->R[1] = 0x00002C3C;
+ cpu->R[3] = 0x000005FF;
+ return 1;
+}
+
+uint32_t (* ARM9_swi_tab[32])()={
+ bios_nop<ARMCPU_ARM9>, // 0x00
+ bios_nop<ARMCPU_ARM9>, // 0x01
+ bios_nop<ARMCPU_ARM9>, // 0x02
+ WaitByLoop<ARMCPU_ARM9>, // 0x03
+ intrWaitARM<ARMCPU_ARM9>, // 0x04
+ waitVBlankARM<ARMCPU_ARM9>, // 0x05
+ wait4IRQ<ARMCPU_ARM9>, // 0x06
+ bios_nop<ARMCPU_ARM9>, // 0x07
+ bios_nop<ARMCPU_ARM9>, // 0x08
+ divide<ARMCPU_ARM9>, // 0x09
+ bios_nop<ARMCPU_ARM9>, // 0x0A
+ copy<ARMCPU_ARM9>, // 0x0B
+ fastCopy<ARMCPU_ARM9>, // 0x0C
+ bios_sqrt<ARMCPU_ARM9>, // 0x0D
+ getCRC16<ARMCPU_ARM9>, // 0x0E
+ isDebugger<ARMCPU_ARM9>, // 0x0F
+ BitUnPack<ARMCPU_ARM9>, // 0x10
+ LZ77UnCompWram<ARMCPU_ARM9>, // 0x11
+ LZ77UnCompVram<ARMCPU_ARM9>, // 0x12
+ UnCompHuffman<ARMCPU_ARM9>, // 0x13
+ RLUnCompWram<ARMCPU_ARM9>, // 0x14
+ RLUnCompVram<ARMCPU_ARM9>, // 0x15
+ Diff8bitUnFilterWram<ARMCPU_ARM9>, // 0x16
+ bios_nop<ARMCPU_ARM9>, // 0x17
+ Diff16bitUnFilter<ARMCPU_ARM9>, // 0x18
+ bios_nop<ARMCPU_ARM9>, // 0x19
+ bios_nop<ARMCPU_ARM9>, // 0x1A
+ bios_nop<ARMCPU_ARM9>, // 0x1B
+ bios_nop<ARMCPU_ARM9>, // 0x1C
+ bios_nop<ARMCPU_ARM9>, // 0x1D
+ bios_nop<ARMCPU_ARM9>, // 0x1E
+ setHaltCR<ARMCPU_ARM9>, // 0x1F
+};
+
+uint32_t (* ARM7_swi_tab[32])()={
+ bios_nop<ARMCPU_ARM7>, // 0x00
+ bios_nop<ARMCPU_ARM7>, // 0x01
+ bios_nop<ARMCPU_ARM7>, // 0x02
+ WaitByLoop<ARMCPU_ARM7>, // 0x03
+ intrWaitARM<ARMCPU_ARM7>, // 0x04
+ waitVBlankARM<ARMCPU_ARM7>, // 0x05
+ wait4IRQ<ARMCPU_ARM7>, // 0x06
+ sleep<ARMCPU_ARM7>, // 0x07
+ SoundBias<ARMCPU_ARM7>, // 0x08
+ divide<ARMCPU_ARM7>, // 0x09
+ bios_nop<ARMCPU_ARM7>, // 0x0A
+ copy<ARMCPU_ARM7>, // 0x0B
+ fastCopy<ARMCPU_ARM7>, // 0x0C
+ bios_sqrt<ARMCPU_ARM7>, // 0x0D
+ getCRC16<ARMCPU_ARM7>, // 0x0E
+ isDebugger<ARMCPU_ARM7>, // 0x0F
+ BitUnPack<ARMCPU_ARM7>, // 0x10
+ LZ77UnCompWram<ARMCPU_ARM7>, // 0x11
+ LZ77UnCompVram<ARMCPU_ARM7>, // 0x12
+ UnCompHuffman<ARMCPU_ARM7>, // 0x13
+ RLUnCompWram<ARMCPU_ARM7>, // 0x14
+ RLUnCompVram<ARMCPU_ARM7>, // 0x15
+ Diff8bitUnFilterWram<ARMCPU_ARM7>, // 0x16
+ bios_nop<ARMCPU_ARM7>, // 0x17
+ bios_nop<ARMCPU_ARM7>, // 0x18
+ bios_nop<ARMCPU_ARM7>, // 0x19
+ getSineTab<ARMCPU_ARM7>, // 0x1A
+ getPitchTab<ARMCPU_ARM7>, // 0x1B
+ getVolumeTab<ARMCPU_ARM7>, // 0x1C
+ getBootProcs<ARMCPU_ARM7>, // 0x1D
+ bios_nop<ARMCPU_ARM7>, // 0x1E
+ setHaltCR<ARMCPU_ARM7>, // 0x1F
+};
+
--- /dev/null
+++ b/src/in_2sf/desmume/bios.h
@@ -1,1 +1,28 @@
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2006-2009 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BIOS_H
+#define BIOS_H
+
+#include "armcpu.h"
+
+extern uint32_t (*ARM9_swi_tab[32])();
+extern uint32_t (*ARM7_swi_tab[32])();
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/bits.h
@@ -1,1 +1,45 @@
+#ifndef BITS_H
+#define BITS_H
+static inline uint32_t BIT(uint32_t n) { return 1 << n; }
+
+static inline uint32_t BIT_N(uint32_t i, uint32_t n) { return (i >> n) & 1; }
+static inline uint32_t BIT0(uint32_t i) { return i & 1; }
+static inline uint32_t BIT1(uint32_t i) { return BIT_N(i, 1); }
+static inline uint32_t BIT2(uint32_t i) { return BIT_N(i, 2); }
+static inline uint32_t BIT3(uint32_t i) { return BIT_N(i, 3); }
+static inline uint32_t BIT4(uint32_t i) { return BIT_N(i, 4); }
+static inline uint32_t BIT5(uint32_t i) { return BIT_N(i, 5); }
+static inline uint32_t BIT6(uint32_t i) { return BIT_N(i, 6); }
+static inline uint32_t BIT7(uint32_t i) { return BIT_N(i, 7); }
+static inline uint32_t BIT8(uint32_t i) { return BIT_N(i, 8); }
+static inline uint32_t BIT9(uint32_t i) { return BIT_N(i, 9); }
+static inline uint32_t BIT10(uint32_t i) { return BIT_N(i, 10); }
+static inline uint32_t BIT11(uint32_t i) { return BIT_N(i, 11); }
+static inline uint32_t BIT12(uint32_t i) { return BIT_N(i, 12); }
+static inline uint32_t BIT13(uint32_t i) { return BIT_N(i, 13); }
+static inline uint32_t BIT14(uint32_t i) { return BIT_N(i, 14); }
+static inline uint32_t BIT15(uint32_t i) { return BIT_N(i, 15); }
+static inline uint32_t BIT16(uint32_t i) { return BIT_N(i, 16); }
+static inline uint32_t BIT17(uint32_t i) { return BIT_N(i, 17); }
+static inline uint32_t BIT18(uint32_t i) { return BIT_N(i, 18); }
+static inline uint32_t BIT19(uint32_t i) { return BIT_N(i, 19); }
+static inline uint32_t BIT20(uint32_t i) { return BIT_N(i, 20); }
+static inline uint32_t BIT21(uint32_t i) { return BIT_N(i, 21); }
+static inline uint32_t BIT22(uint32_t i) { return BIT_N(i, 22); }
+static inline uint32_t BIT23(uint32_t i) { return BIT_N(i, 23); }
+static inline uint32_t BIT24(uint32_t i) { return BIT_N(i, 24); }
+static inline uint32_t BIT25(uint32_t i) { return BIT_N(i, 25); }
+static inline uint32_t BIT26(uint32_t i) { return BIT_N(i, 26); }
+static inline uint32_t BIT27(uint32_t i) { return BIT_N(i, 27); }
+static inline uint32_t BIT28(uint32_t i) { return BIT_N(i, 28); }
+static inline uint32_t BIT29(uint32_t i) { return BIT_N(i, 29); }
+static inline uint32_t BIT30(uint32_t i) { return BIT_N(i, 30); }
+static inline uint32_t BIT31(uint32_t i) { return i >> 31; }
+
+static inline uint32_t CONDITION(uint32_t i) { return i >> 28; }
+
+static inline uint32_t REG_POS(uint32_t i, uint32_t n) { return (i >> n) & 0xF; }
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/common.cpp
@@ -1,1 +1,68 @@
+/*
+ Copyright (C) 2008-2010 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+//TODO - move this into ndssystem where it belongs probably
+
+#include <string>
+#include <cstring>
+
+#include "common.h"
+
+const uint8_t logo_data[156] = {
+ 0x24,0xFF,0xAE,0x51,0x69,0x9A,0xA2,0x21,0x3D,0x84,0x82,0x0A,0x84,0xE4,0x09,0xAD,
+ 0x11,0x24,0x8B,0x98,0xC0,0x81,0x7F,0x21,0xA3,0x52,0xBE,0x19,0x93,0x09,0xCE,0x20,
+ 0x10,0x46,0x4A,0x4A,0xF8,0x27,0x31,0xEC,0x58,0xC7,0xE8,0x33,0x82,0xE3,0xCE,0xBF,
+ 0x85,0xF4,0xDF,0x94,0xCE,0x4B,0x09,0xC1,0x94,0x56,0x8A,0xC0,0x13,0x72,0xA7,0xFC,
+ 0x9F,0x84,0x4D,0x73,0xA3,0xCA,0x9A,0x61,0x58,0x97,0xA3,0x27,0xFC,0x03,0x98,0x76,
+ 0x23,0x1D,0xC7,0x61,0x03,0x04,0xAE,0x56,0xBF,0x38,0x84,0x00,0x40,0xA7,0x0E,0xFD,
+ 0xFF,0x52,0xFE,0x03,0x6F,0x95,0x30,0xF1,0x97,0xFB,0xC0,0x85,0x60,0xD6,0x80,0x25,
+ 0xA9,0x63,0xBE,0x03,0x01,0x4E,0x38,0xE2,0xF9,0xA2,0x34,0xFF,0xBB,0x3E,0x03,0x44,
+ 0x78,0x00,0x90,0xCB,0x88,0x11,0x3A,0x94,0x65,0xC0,0x7C,0x63,0x87,0xF0,0x3C,0xAF,
+ 0xD6,0x25,0xE4,0x8B,0x38,0x0A,0xAC,0x72,0x21,0xD4,0xF8,0x07};
+
+/*char *trim(char *s, int len)
+{
+ char *ptr = NULL;
+ if (!s) return NULL;
+ if (!*s) return s;
+
+ if(len==-1)
+ ptr = s + strlen(s) - 1;
+ else ptr = s+len - 1;
+ for (; (ptr >= s) && (!*ptr || isspace((uint8_t)*ptr)) ; ptr--);
+ ptr[1] = '\0';
+ return s;
+}*/
+
+/*char *removeSpecialChars(char *s)
+{
+ char *buf = s;
+ if (!s) return NULL;
+ if (!*s) return s;
+
+ for (uint32_t i = 0; i < strlen(s); i++)
+ {
+ if (isspace((uint8_t)s[i]) && (s[i] != 0x20))
+ *buf = 0x20;
+ else
+ *buf = s[i];
+ buf++;
+ }
+ *buf = 0;
+ return s;
+}*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/common.h
@@ -1,1 +1,77 @@
+/*
+ Copyright (C) 2008-2010 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+//TODO - dismantle this file
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <string>
+#include <cstdio>
+#include <cstring>
+
+#include "types.h"
+
+extern const uint8_t logo_data[156];
+
+#ifdef WIN32
+# include "windowsh_wrapper.h"
+//# define WIN32_LEAN_AND_MEAN
+//# include <winsock2.h>
+
+/*# define CLASSNAME "DeSmuME"
+
+extern HINSTANCE hAppInst;
+
+extern bool romloaded;
+
+extern char IniName[MAX_PATH];
+extern void GetINIPath();
+extern void WritePrivateProfileInt(char *appname, char *keyname, int val, char *file);
+
+bool GetPrivateProfileBool(const char *appname, const char *keyname, bool defval, const char *filename);
+void WritePrivateProfileBool(char *appname, char *keyname, bool val, char *file);
+#else // non Windows
+#define sscanf_s sscanf*/
+#endif
+
+/*template<typename T> T reverseBits(T x)
+{
+ T h = 0;
+
+ for (unsigned i = 0; i < sizeof(T) * 8; ++i)
+ {
+ h = (h << 1) + (x & 1);
+ x >>= 1;
+ }
+
+ return h;
+}*/
+
+/*template<typename T> char *intToBin(T val)
+{
+ char buf[256] = "";
+ for (int i = sizeof(T) * 8, t = 0; i > 0; --i, ++t)
+ buf[i - 1] = val & (1<<t) ? '1' : '0';
+ return _strdup(buf);
+}*/
+
+//extern char *trim(char *s, int len = -1);
+//extern char *removeSpecialChars(char *s);
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/cp15.cpp
@@ -1,1 +1,575 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2006-2011 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cstdlib>
+
+#include "cp15.h"
+//#include "debug.h"
+#include "MMU.h"
+
+armcp15_t *armcp15_new(armcpu_t * c)
+{
+ int i;
+ armcp15_t *armcp15 = (armcp15_t*)malloc(sizeof(armcp15_t));
+ if(!armcp15) return NULL;
+
+
+ armcp15->cpu = c;
+ armcp15->IDCode = 0x41059461;
+ armcp15->cacheType = 0x0F0D2112;
+ armcp15->TCMSize = 0x00140180;
+ armcp15->ctrl = 0x00012078;
+ armcp15->DCConfig = 0x0;
+ armcp15->ICConfig = 0x0;
+ armcp15->writeBuffCtrl = 0x0;
+ armcp15->und = 0x0;
+ armcp15->DaccessPerm = 0x22222222;
+ armcp15->IaccessPerm = 0x22222222;
+ armcp15->protectBaseSize0 = 0x0;
+ armcp15->protectBaseSize1 = 0x0;
+ armcp15->protectBaseSize2 = 0x0;
+ armcp15->protectBaseSize3 = 0x0;
+ armcp15->protectBaseSize4 = 0x0;
+ armcp15->protectBaseSize5 = 0x0;
+ armcp15->protectBaseSize6 = 0x0;
+ armcp15->protectBaseSize7 = 0x0;
+ armcp15->cacheOp = 0x0;
+ armcp15->DcacheLock = 0x0;
+ armcp15->IcacheLock = 0x0;
+ armcp15->ITCMRegion = 0x0C;
+ armcp15->DTCMRegion = 0x0080000A;
+ armcp15->processID = 0;
+
+ MMU.ARM9_RW_MODE = static_cast<uint8_t>(BIT7(armcp15->ctrl));
+ armcp15->cpu->intVector = 0xFFFF0000 * (BIT13(armcp15->ctrl));
+ armcp15->cpu->LDTBit = !BIT15(armcp15->ctrl); //TBit
+
+ /* preset calculated regionmasks */
+ for (i=0;i<8;i++) {
+ armcp15->regionWriteMask_USR[i] = 0 ;
+ armcp15->regionWriteMask_SYS[i] = 0 ;
+ armcp15->regionReadMask_USR[i] = 0 ;
+ armcp15->regionReadMask_SYS[i] = 0 ;
+ armcp15->regionExecuteMask_USR[i] = 0 ;
+ armcp15->regionExecuteMask_SYS[i] = 0 ;
+ armcp15->regionWriteSet_USR[i] = 0 ;
+ armcp15->regionWriteSet_SYS[i] = 0 ;
+ armcp15->regionReadSet_USR[i] = 0 ;
+ armcp15->regionReadSet_SYS[i] = 0 ;
+ armcp15->regionExecuteSet_USR[i] = 0 ;
+ armcp15->regionExecuteSet_SYS[i] = 0 ;
+ } ;
+
+ return armcp15;
+}
+
+//#define ACCESSTYPE(val,n) (((val) >> (4*n)) & 0x0F)
+static inline uint32_t ACCESSTYPE(uint32_t val, unsigned char n) { return (val >> (4 * n)) & 0x0F; }
+//#define SIZEIDENTIFIER(val) ((((val) >> 1) & 0x1F))
+static inline uint32_t SIZEIDENTIFIER(uint32_t val) { return (val >> 1) & 0x1F; }
+//#define SIZEBINARY(val) (1 << (SIZEIDENTIFIER(val)+1))
+static inline uint32_t SIZEBINARY(uint32_t val) { return 1 << (SIZEIDENTIFIER(val) + 1); }
+//#define MASKFROMREG(val) (~((SIZEBINARY(val)-1) | 0x3F))
+static inline uint32_t MASKFROMREG(uint32_t val) { return ~((SIZEBINARY(val) - 1) | 0x3F); }
+//#define SETFROMREG(val) ((val) & MASKFROMREG(val))
+static inline uint32_t SETFROMREG(uint32_t val) { return val & MASKFROMREG(val); }
+/* sets the precalculated regions to mask,set for the affected accesstypes */
+static void armcp15_setSingleRegionAccess(armcp15_t *armcp15,uint32_t dAccess,uint32_t iAccess,unsigned char num, uint32_t mask,uint32_t set) {
+
+ switch (ACCESSTYPE(dAccess,num)) {
+ case 4: /* UNP */
+ case 7: /* UNP */
+ case 8: /* UNP */
+ case 9: /* UNP */
+ case 10: /* UNP */
+ case 11: /* UNP */
+ case 12: /* UNP */
+ case 13: /* UNP */
+ case 14: /* UNP */
+ case 15: /* UNP */
+ case 0: /* no access at all */
+ armcp15->regionWriteMask_USR[num] = 0 ;
+ armcp15->regionWriteSet_USR[num] = 0xFFFFFFFF ;
+ armcp15->regionReadMask_USR[num] = 0 ;
+ armcp15->regionReadSet_USR[num] = 0xFFFFFFFF ;
+ armcp15->regionWriteMask_SYS[num] = 0 ;
+ armcp15->regionWriteSet_SYS[num] = 0xFFFFFFFF ;
+ armcp15->regionReadMask_SYS[num] = 0 ;
+ armcp15->regionReadSet_SYS[num] = 0xFFFFFFFF ;
+ break ;
+ case 1: /* no access at USR, all to sys */
+ armcp15->regionWriteMask_USR[num] = 0 ;
+ armcp15->regionWriteSet_USR[num] = 0xFFFFFFFF ;
+ armcp15->regionReadMask_USR[num] = 0 ;
+ armcp15->regionReadSet_USR[num] = 0xFFFFFFFF ;
+ armcp15->regionWriteMask_SYS[num] = mask ;
+ armcp15->regionWriteSet_SYS[num] = set ;
+ armcp15->regionReadMask_SYS[num] = mask ;
+ armcp15->regionReadSet_SYS[num] = set ;
+ break ;
+ case 2: /* read at USR, all to sys */
+ armcp15->regionWriteMask_USR[num] = 0 ;
+ armcp15->regionWriteSet_USR[num] = 0xFFFFFFFF ;
+ armcp15->regionReadMask_USR[num] = mask ;
+ armcp15->regionReadSet_USR[num] = set ;
+ armcp15->regionWriteMask_SYS[num] = mask ;
+ armcp15->regionWriteSet_SYS[num] = set ;
+ armcp15->regionReadMask_SYS[num] = mask ;
+ armcp15->regionReadSet_SYS[num] = set ;
+ break ;
+ case 3: /* all to USR, all to sys */
+ armcp15->regionWriteMask_USR[num] = mask ;
+ armcp15->regionWriteSet_USR[num] = set ;
+ armcp15->regionReadMask_USR[num] = mask ;
+ armcp15->regionReadSet_USR[num] = set ;
+ armcp15->regionWriteMask_SYS[num] = mask ;
+ armcp15->regionWriteSet_SYS[num] = set ;
+ armcp15->regionReadMask_SYS[num] = mask ;
+ armcp15->regionReadSet_SYS[num] = set ;
+ break ;
+ case 5: /* no access at USR, read to sys */
+ armcp15->regionWriteMask_USR[num] = 0 ;
+ armcp15->regionWriteSet_USR[num] = 0xFFFFFFFF ;
+ armcp15->regionReadMask_USR[num] = 0 ;
+ armcp15->regionReadSet_USR[num] = 0xFFFFFFFF ;
+ armcp15->regionWriteMask_SYS[num] = 0 ;
+ armcp15->regionWriteSet_SYS[num] = 0xFFFFFFFF ;
+ armcp15->regionReadMask_SYS[num] = mask ;
+ armcp15->regionReadSet_SYS[num] = set ;
+ break ;
+ case 6: /* read at USR, read to sys */
+ armcp15->regionWriteMask_USR[num] = 0 ;
+ armcp15->regionWriteSet_USR[num] = 0xFFFFFFFF ;
+ armcp15->regionReadMask_USR[num] = mask ;
+ armcp15->regionReadSet_USR[num] = set ;
+ armcp15->regionWriteMask_SYS[num] = 0 ;
+ armcp15->regionWriteSet_SYS[num] = 0xFFFFFFFF ;
+ armcp15->regionReadMask_SYS[num] = mask ;
+ armcp15->regionReadSet_SYS[num] = set ;
+ break ;
+ }
+ switch (ACCESSTYPE(iAccess,num)) {
+ case 4: /* UNP */
+ case 7: /* UNP */
+ case 8: /* UNP */
+ case 9: /* UNP */
+ case 10: /* UNP */
+ case 11: /* UNP */
+ case 12: /* UNP */
+ case 13: /* UNP */
+ case 14: /* UNP */
+ case 15: /* UNP */
+ case 0: /* no access at all */
+ armcp15->regionExecuteMask_USR[num] = 0 ;
+ armcp15->regionExecuteSet_USR[num] = 0xFFFFFFFF ;
+ armcp15->regionExecuteMask_SYS[num] = 0 ;
+ armcp15->regionExecuteSet_SYS[num] = 0xFFFFFFFF ;
+ break ;
+ case 1:
+ armcp15->regionExecuteMask_USR[num] = 0 ;
+ armcp15->regionExecuteSet_USR[num] = 0xFFFFFFFF ;
+ armcp15->regionExecuteMask_SYS[num] = mask ;
+ armcp15->regionExecuteSet_SYS[num] = set ;
+ break ;
+ case 2:
+ case 3:
+ case 6:
+ armcp15->regionExecuteMask_USR[num] = mask ;
+ armcp15->regionExecuteSet_USR[num] = set ;
+ armcp15->regionExecuteMask_SYS[num] = mask ;
+ armcp15->regionExecuteSet_SYS[num] = set ;
+ break ;
+ }
+}
+
+/* precalculate region masks/sets from cp15 register */
+static void armcp15_maskPrecalc(armcp15_t *armcp15)
+{
+#define precalc(num) { \
+ uint32_t mask = 0, set = 0xFFFFFFFF ; /* (x & 0) == 0xFF..FF is allways false (disabled) */ \
+ if (BIT_N(armcp15->protectBaseSize##num,0)) /* if region is enabled */ \
+ { /* reason for this define: naming includes var */ \
+ mask = MASKFROMREG(armcp15->protectBaseSize##num) ; \
+ set = SETFROMREG(armcp15->protectBaseSize##num) ; \
+ if (SIZEIDENTIFIER(armcp15->protectBaseSize##num)==0x1F) \
+ { /* for the 4GB region, uint32_t suffers wraparound */ \
+ mask = 0 ; set = 0 ; /* (x & 0) == 0 is allways true (enabled) */ \
+} \
+} \
+ armcp15_setSingleRegionAccess(armcp15,armcp15->DaccessPerm,armcp15->IaccessPerm,num,mask,set) ; \
+}
+ precalc(0) ;
+ precalc(1) ;
+ precalc(2) ;
+ precalc(3) ;
+ precalc(4) ;
+ precalc(5) ;
+ precalc(6) ;
+ precalc(7) ;
+}
+
+/*bool armcp15_isAccessAllowed(armcp15_t *armcp15,uint32_t address,uint32_t access)
+{
+ int i ;
+ if (!(armcp15->ctrl & 1)) return true ;*/ /* protection checking is not enabled */
+ /*for (i=0;i<8;i++) {
+ switch (access) {
+ case CP15_ACCESS_WRITEUSR:
+ if ((address & armcp15->regionWriteMask_USR[i]) == armcp15->regionWriteSet_USR[i]) return true ;
+ break ;
+ case CP15_ACCESS_WRITESYS:
+ if ((address & armcp15->regionWriteMask_SYS[i]) == armcp15->regionWriteSet_SYS[i]) return true ;
+ break ;
+ case CP15_ACCESS_READUSR:
+ if ((address & armcp15->regionReadMask_USR[i]) == armcp15->regionReadSet_USR[i]) return true ;
+ break ;
+ case CP15_ACCESS_READSYS:
+ if ((address & armcp15->regionReadMask_SYS[i]) == armcp15->regionReadSet_SYS[i]) return true ;
+ break ;
+ case CP15_ACCESS_EXECUSR:
+ if ((address & armcp15->regionExecuteMask_USR[i]) == armcp15->regionExecuteSet_USR[i]) return true ;
+ break ;
+ case CP15_ACCESS_EXECSYS:
+ if ((address & armcp15->regionExecuteMask_SYS[i]) == armcp15->regionExecuteSet_SYS[i]) return true ;
+ break ;
+ }
+ }*/
+ /* when protections are enabled, but no region allows access, deny access */
+ /*return false ;
+}*/
+
+/*bool armcp15_dataProcess(armcp15_t *, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)
+{
+ //LOG("Unsupported CP15 operation : DataProcess\n");
+ return false;
+}*/
+
+/*bool armcp15_load(armcp15_t *, uint8_t, uint8_t)
+{
+ //LOG("Unsupported CP15 operation : Load\n");
+ return false;
+}*/
+
+/*bool armcp15_store(armcp15_t *, uint8_t, uint8_t)
+{
+ //LOG("Unsupported CP15 operation : Store\n");
+ return false;
+}*/
+
+bool armcp15_moveCP2ARM(armcp15_t *armcp15, uint32_t * R, uint8_t CRn, uint8_t CRm, uint8_t opcode1, uint8_t opcode2)
+{
+ if(armcp15->cpu->CPSR.bits.mode == USR) return false;
+
+ switch(CRn)
+ {
+ case 0:
+ if((opcode1 == 0)&&(CRm==0))
+ {
+ switch(opcode2)
+ {
+ case 1:
+ *R = armcp15->cacheType;
+ return true;
+ case 2:
+ *R = armcp15->TCMSize;
+ return true;
+ default:
+ *R = armcp15->IDCode;
+ return true;
+ }
+ }
+ return false;
+ case 1:
+ if((opcode1==0) && (opcode2==0) && (CRm==0))
+ {
+ *R = armcp15->ctrl;
+ //LOG("CP15: CPtoARM ctrl %08X\n", armcp15->ctrl);
+ return true;
+ }
+ return false;
+
+ case 2:
+ if((opcode1==0) && (CRm==0))
+ {
+ switch(opcode2)
+ {
+ case 0:
+ *R = armcp15->DCConfig;
+ return true;
+ case 1:
+ *R = armcp15->ICConfig;
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+ case 3:
+ if((opcode1==0) && (opcode2==0) && (CRm==0))
+ {
+ *R = armcp15->writeBuffCtrl;
+ //LOG("CP15: CPtoARM writeBuffer ctrl %08X\n", armcp15->writeBuffCtrl);
+ return true;
+ }
+ return false;
+ case 5:
+ if((opcode1==0) && (CRm==0))
+ {
+ switch(opcode2)
+ {
+ case 2:
+ *R = armcp15->DaccessPerm;
+ return true;
+ case 3:
+ *R = armcp15->IaccessPerm;
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+ case 6:
+ if((opcode1==0) && (opcode2==0))
+ {
+ switch(CRm)
+ {
+ case 0:
+ *R = armcp15->protectBaseSize0;
+ return true;
+ case 1:
+ *R = armcp15->protectBaseSize1;
+ return true;
+ case 2:
+ *R = armcp15->protectBaseSize2;
+ return true;
+ case 3:
+ *R = armcp15->protectBaseSize3;
+ return true;
+ case 4:
+ *R = armcp15->protectBaseSize4;
+ return true;
+ case 5:
+ *R = armcp15->protectBaseSize5;
+ return true;
+ case 6:
+ *R = armcp15->protectBaseSize6;
+ return true;
+ case 7:
+ *R = armcp15->protectBaseSize7;
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+ case 9:
+ if((opcode1==0))
+ {
+ switch(CRm)
+ {
+ case 0:
+ switch(opcode2)
+ {
+ case 0:
+ *R = armcp15->DcacheLock;
+ return true;
+ case 1:
+ *R = armcp15->IcacheLock;
+ return true;
+ default:
+ return false;
+ }
+ case 1:
+ switch(opcode2)
+ {
+ case 0:
+ *R = armcp15->DTCMRegion;
+ return true;
+ case 1:
+ *R = armcp15->ITCMRegion;
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+ return false;
+ default:
+ //LOG("Unsupported CP15 operation : MRC\n");
+ return false;
+ }
+}
+
+static uint32_t CP15wait4IRQ(armcpu_t *cpu)
+{
+ cpu->waitIRQ = true;
+ cpu->halt_IE_and_IF = true;
+ //IME set deliberately omitted: only SWI sets IME to 1
+ return 1;
+}
+
+bool armcp15_moveARM2CP(armcp15_t *armcp15, uint32_t val, uint8_t CRn, uint8_t CRm, uint8_t opcode1, uint8_t opcode2)
+{
+ if(armcp15->cpu->CPSR.bits.mode == USR) return false;
+
+ switch(CRn)
+ {
+ case 1:
+ if((opcode1==0) && (opcode2==0) && (CRm==0))
+ {
+
+ //On the NDS bit0,2,7,12..19 are R/W, Bit3..6 are always set, all other bits are always zero.
+ armcp15->ctrl = (val & 0x000FF085) | 0x00000078;
+ MMU.ARM9_RW_MODE = static_cast<uint8_t>(BIT7(val));
+ //zero 31-jan-2010: change from 0x0FFF0000 to 0xFFFF0000 per gbatek
+ armcp15->cpu->intVector = 0xFFFF0000 * (BIT13(val));
+ armcp15->cpu->LDTBit = !BIT15(val); //TBit
+ //LOG("CP15: ARMtoCP ctrl %08X (val %08X)\n", armcp15->ctrl, val);
+ return true;
+ }
+ return false;
+ case 2:
+ if((opcode1==0) && (CRm==0))
+ {
+ switch(opcode2)
+ {
+ case 0:
+ armcp15->DCConfig = val;
+ return true;
+ case 1:
+ armcp15->ICConfig = val;
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+ case 3:
+ if((opcode1==0) && (opcode2==0) && (CRm==0))
+ {
+ armcp15->writeBuffCtrl = val;
+ //LOG("CP15: ARMtoCP writeBuffer ctrl %08X\n", armcp15->writeBuffCtrl);
+ return true;
+ }
+ return false;
+ case 5:
+ if((opcode1==0) && (CRm==0))
+ {
+ switch(opcode2)
+ {
+ case 2:
+ armcp15->DaccessPerm = val;
+ armcp15_maskPrecalc(armcp15);
+ return true;
+ case 3:
+ armcp15->IaccessPerm = val;
+ armcp15_maskPrecalc(armcp15);
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+ case 6:
+ if((opcode1==0) && (opcode2==0))
+ {
+ switch(CRm)
+ {
+ case 0:
+ armcp15->protectBaseSize0 = val;
+ armcp15_maskPrecalc(armcp15) ;
+ return true;
+ case 1:
+ armcp15->protectBaseSize1 = val;
+ armcp15_maskPrecalc(armcp15) ;
+ return true;
+ case 2:
+ armcp15->protectBaseSize2 = val;
+ armcp15_maskPrecalc(armcp15) ;
+ return true;
+ case 3:
+ armcp15->protectBaseSize3 = val;
+ armcp15_maskPrecalc(armcp15) ;
+ return true;
+ case 4:
+ armcp15->protectBaseSize4 = val;
+ armcp15_maskPrecalc(armcp15) ;
+ return true;
+ case 5:
+ armcp15->protectBaseSize5 = val;
+ armcp15_maskPrecalc(armcp15) ;
+ return true;
+ case 6:
+ armcp15->protectBaseSize6 = val;
+ armcp15_maskPrecalc(armcp15) ;
+ return true;
+ case 7:
+ armcp15->protectBaseSize7 = val;
+ armcp15_maskPrecalc(armcp15) ;
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+ case 7:
+ if((CRm==0)&&(opcode1==0)&&((opcode2==4)))
+ {
+ CP15wait4IRQ(armcp15->cpu);
+ return true;
+ }
+ return false;
+ case 9:
+ if((opcode1==0))
+ {
+ switch(CRm)
+ {
+ case 0:
+ switch(opcode2)
+ {
+ case 0:
+ armcp15->DcacheLock = val;
+ return true;
+ case 1:
+ armcp15->IcacheLock = val;
+ return true;
+ default:
+ return false;
+ }
+ case 1:
+ switch(opcode2)
+ {
+ case 0:
+ MMU.DTCMRegion = armcp15->DTCMRegion = val & 0x0FFFF000;
+ return true;
+ case 1:
+ armcp15->ITCMRegion = val;
+ //ITCM base is not writeable!
+ MMU.ITCMRegion = 0;
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/cp15.h
@@ -1,1 +1,90 @@
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2006-2010 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __CP15_H__
+#define __CP15_H__
+
+#include "armcpu.h"
+
+struct armcp15_t
+{
+ uint32_t IDCode;
+ uint32_t cacheType;
+ uint32_t TCMSize;
+ uint32_t ctrl;
+ uint32_t DCConfig;
+ uint32_t ICConfig;
+ uint32_t writeBuffCtrl;
+ uint32_t und;
+ uint32_t DaccessPerm;
+ uint32_t IaccessPerm;
+ uint32_t protectBaseSize0;
+ uint32_t protectBaseSize1;
+ uint32_t protectBaseSize2;
+ uint32_t protectBaseSize3;
+ uint32_t protectBaseSize4;
+ uint32_t protectBaseSize5;
+ uint32_t protectBaseSize6;
+ uint32_t protectBaseSize7;
+ uint32_t cacheOp;
+ uint32_t DcacheLock;
+ uint32_t IcacheLock;
+ uint32_t ITCMRegion;
+ uint32_t DTCMRegion;
+ uint32_t processID;
+ uint32_t RAM_TAG;
+ uint32_t testState;
+ uint32_t cacheDbg;
+ /* calculated bitmasks for the regions to decide rights uppon */
+ /* calculation is done in the MCR instead of on mem access for performance */
+ uint32_t regionWriteMask_USR[8];
+ uint32_t regionWriteMask_SYS[8];
+ uint32_t regionReadMask_USR[8];
+ uint32_t regionReadMask_SYS[8];
+ uint32_t regionExecuteMask_USR[8];
+ uint32_t regionExecuteMask_SYS[8];
+ uint32_t regionWriteSet_USR[8];
+ uint32_t regionWriteSet_SYS[8];
+ uint32_t regionReadSet_USR[8];
+ uint32_t regionReadSet_SYS[8];
+ uint32_t regionExecuteSet_USR[8];
+ uint32_t regionExecuteSet_SYS[8];
+
+ armcpu_t *cpu;
+};
+
+armcp15_t *armcp15_new(armcpu_t *c);
+//bool armcp15_dataProcess(armcp15_t *armcp15, uint8_t CRd, uint8_t CRn, uint8_t CRm, uint8_t opcode1, uint8_t opcode2);
+//bool armcp15_load(armcp15_t *armcp15, uint8_t CRd, uint8_t adr);
+//bool armcp15_store(armcp15_t *armcp15, uint8_t CRd, uint8_t adr);
+bool armcp15_moveCP2ARM(armcp15_t *armcp15, uint32_t * R, uint8_t CRn, uint8_t CRm, uint8_t opcode1, uint8_t opcode2);
+bool armcp15_moveARM2CP(armcp15_t *armcp15, uint32_t val, uint8_t CRn, uint8_t CRm, uint8_t opcode1, uint8_t opcode2);
+//bool armcp15_isAccessAllowed(armcp15_t *armcp15,uint32_t address,uint32_t access);
+
+static const uint32_t CP15_ACCESS_WRITE = 0;
+static const uint32_t CP15_ACCESS_READ = 2;
+static const uint32_t CP15_ACCESS_EXECUTE = 4;
+static const uint32_t CP15_ACCESS_WRITEUSR = CP15_ACCESS_WRITE;
+static const uint32_t CP15_ACCESS_WRITESYS = 1;
+static const uint32_t CP15_ACCESS_READUSR = CP15_ACCESS_READ;
+static const uint32_t CP15_ACCESS_READSYS = 3;
+static const uint32_t CP15_ACCESS_EXECUSR = CP15_ACCESS_EXECUTE;
+static const uint32_t CP15_ACCESS_EXECSYS = 5;
+
+#endif /* __CP15_H__*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/debug.cpp
@@ -1,1 +1,411 @@
-
+/* Copyright (C) 2008 Guillaume Duhamel
+ Copyright (C) 2009-2010 DeSmuME team
+
+ This file is part of DeSmuME
+
+ DeSmuME is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DeSmuME 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DeSmuME; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <algorithm>
+#include <cstdarg>
+#include <cstdio>
+
+#include "debug.h"
+#include "MMU.h"
+#include "armcpu.h"
+#include "arm_instructions.h"
+#include "thumb_instructions.h"
+#include "cp15.h"
+#include "NDSSystem.h"
+#include "utils/xstring.h"
+//#include "movie.h"
+
+#ifdef HAVE_LUA
+#include "lua-engine.h"
+#endif
+
+armcpu_t* TDebugEventData::cpu() { return procnum==0?&NDS_ARM9:&NDS_ARM7; }
+
+TDebugEventData DebugEventData;
+uint32_t debugFlag;
+
+//DEBUG CONFIGURATION
+const bool debug_acl = false;
+
+static bool acl_check_access(uint32_t adr, uint32_t access) {
+
+ //non-user modes get separate access handling, so check that here
+ if(NDS_ARM9.CPSR.bits.mode != USR)
+ access |= 1;
+
+ if (armcp15_isAccessAllowed((armcp15_t *)NDS_ARM9.coproc[15],adr,access)==false) {
+ HandleDebugEvent(DEBUG_EVENT_ACL_EXCEPTION);
+ }
+ return true;
+}
+
+void HandleDebugEvent_ACL_Exception()
+{
+ printf("ACL EXCEPTION!\n");
+ if(DebugEventData.memAccessType == MMU_AT_CODE)
+ armcpu_exception(DebugEventData.cpu(),EXCEPTION_PREFETCH_ABORT);
+ else if(DebugEventData.memAccessType == MMU_AT_DATA)
+ armcpu_exception(DebugEventData.cpu(),EXCEPTION_DATA_ABORT);
+}
+
+
+/*static bool CheckRange(uint32_t adr, uint32_t min, uint32_t len)
+{
+ return (adr>=min && adr<min+len);
+}*/
+
+void HandleDebugEvent_Read()
+{
+ if(!debug_acl) return;
+ if(DebugEventData.procnum != ARMCPU_ARM9) return; //acl only valid on arm9
+ acl_check_access(DebugEventData.addr,CP15_ACCESS_READ);
+}
+
+void HandleDebugEvent_Write()
+{
+ if(!debug_acl) return;
+ if(DebugEventData.procnum != ARMCPU_ARM9) return; //acl only valid on arm9
+ acl_check_access(DebugEventData.addr,CP15_ACCESS_WRITE);
+}
+
+void HandleDebugEvent_Execute()
+{
+ //HACKY BREAKPOINTS!
+ //extern bool nds_debug_continuing[2];
+ //if(!nds_debug_continuing[DebugEventData.procnum]) //dont keep hitting the same breakpoint
+ //{
+ // if((DebugEventData.addr & 0xFFFFFFF0) == 0x02000000)
+ // {
+ // void NDS_debug_break();
+ // NDS_debug_break();
+ // }
+ //}
+ if(!debug_acl) return;
+ if(DebugEventData.procnum != ARMCPU_ARM9) return; //acl only valid on arm9
+ acl_check_access(DebugEventData.addr,CP15_ACCESS_EXECUTE);
+}
+
+//------------------------------------------------
+DebugStatistics DEBUG_statistics;
+
+DebugStatistics::DebugStatistics()
+{
+}
+
+DebugStatistics::InstructionHits::InstructionHits()
+{
+ memset(&arm,0,sizeof(arm));
+ memset(&thumb,0,sizeof(thumb));
+}
+
+
+static DebugStatistics::InstructionHits combinedHits[2];
+
+template<int proc, int which>
+static bool debugStatsSort(int num1, int num2) {
+ if(which==0) {
+ if(combinedHits[proc].arm[num2] == combinedHits[proc].arm[num1]) return false;
+ if(combinedHits[proc].arm[num1] == 0xFFFFFFFF) return false;
+ if(combinedHits[proc].arm[num2] == 0xFFFFFFFF) return true;
+ return combinedHits[proc].arm[num2] < combinedHits[proc].arm[num1];
+ }
+ else {
+ if(combinedHits[proc].thumb[num2] == combinedHits[proc].thumb[num1]) return false;
+ if(combinedHits[proc].thumb[num1] == 0xFFFFFFFF) return false;
+ if(combinedHits[proc].thumb[num2] == 0xFFFFFFFF) return true;
+ return combinedHits[proc].thumb[num2] < combinedHits[proc].thumb[num1];
+ }
+}
+
+void DebugStatistics::print()
+{
+ //consolidate opcodes with the same names
+ for(int i=0;i<2;i++) {
+ combinedHits[i] = DEBUG_statistics.instructionHits[i];
+
+ for(int j=0;j<4096;j++) {
+ if(combinedHits[i].arm[j] == 0xFFFFFFFF)
+ continue;
+ std::string name = arm_instruction_names[j];
+ for(int k=j+1;k<4096;k++) {
+ if(combinedHits[i].arm[k] == 0xFFFFFFFF)
+ continue;
+ if(name == arm_instruction_names[k]) {
+ //printf("combining %s with %d and %d\n",name.c_str(),combinedHits[i].arm[j],combinedHits[i].arm[k]);
+ combinedHits[i].arm[j] += combinedHits[i].arm[k];
+ combinedHits[i].arm[k] = 0xFFFFFFFF;
+ }
+
+ }
+ }
+
+ for(int j=0;j<1024;j++) {
+ if(combinedHits[i].thumb[j] == 0xFFFFFFFF)
+ continue;
+ std::string name = thumb_instruction_names[j];
+ for(int k=j+1;k<1024;k++) {
+ if(combinedHits[i].thumb[k] == 0xFFFFFFFF)
+ continue;
+ if(name == thumb_instruction_names[k]) {
+ //printf("combining %s with %d and %d\n",name.c_str(),combinedHits[i].arm[j],combinedHits[i].arm[k]);
+ combinedHits[i].thumb[j] += combinedHits[i].thumb[k];
+ combinedHits[i].thumb[k] = 0xFFFFFFFF;
+ }
+
+ }
+ }
+ }
+
+ InstructionHits sorts[2];
+ for(int i=0;i<2;i++) {
+ for(int j=0;j<4096;j++) sorts[i].arm[j] = j;
+ for(int j=0;j<1024;j++) sorts[i].thumb[j] = j;
+ }
+ std::sort(sorts[0].arm, sorts[0].arm+4096, debugStatsSort<0,0>);
+ std::sort(sorts[0].thumb, sorts[0].thumb+1024, debugStatsSort<0,1>);
+ std::sort(sorts[1].arm, sorts[1].arm+4096, debugStatsSort<1,0>);
+ std::sort(sorts[1].thumb, sorts[1].thumb+1024, debugStatsSort<1,1>);
+
+ for(int i=0;i<2;i++) {
+ printf("Top arm instructions for ARM%d:\n",7+i*2);
+ for(int j=0;j<10;j++) {
+ int val = sorts[i].arm[j];
+ printf("%08d: %s\n", combinedHits[i].arm[val], arm_instruction_names[val]);
+ }
+ printf("Top thumb instructions for ARM%d:\n",7+i*2);
+ for(int j=0;j<10;j++) {
+ int val = sorts[i].thumb[j];
+ printf("%08d: %s\n", combinedHits[i].thumb[val], thumb_instruction_names[val]);
+ }
+ }
+}
+
+void DebugStatistics::printSequencerExecutionCounters()
+{
+ for(int i=0;i<21;i++) printf("%06d ",sequencerExecutionCounters[i]);
+ printf("\n");
+}
+
+void DEBUG_reset()
+{
+ //for now, just enable all debugging in developer builds
+#ifdef DEVELOPER
+ debugFlag = 1;
+#endif
+
+ DEBUG_Notify = DebugNotify();
+ DEBUG_statistics = DebugStatistics();
+ printf("DEBUG_reset: %08X\n",&DebugStatistics::print); //force a reference to this function
+}
+
+/*static void DEBUG_dumpMemory_fill(EMUFILE *fp, uint32_t size)
+{
+ static std::vector<uint8_t> buf;
+ buf.resize(size);
+ memset(&buf[0],0,size);
+ fp->fwrite(&buf[0],size);
+}*/
+
+void DEBUG_dumpMemory(EMUFILE* fp)
+{
+ fp->fseek(0x000000,SEEK_SET); fp->fwrite(MMU.MAIN_MEM,0x800000); //arm9 main mem (8192K)
+ fp->fseek(0x900000,SEEK_SET); fp->fwrite(MMU.ARM9_DTCM,0x4000); //arm9 DTCM (16K)
+ fp->fseek(0xA00000,SEEK_SET); fp->fwrite(MMU.ARM9_ITCM,0x8000); //arm9 ITCM (32K)
+ fp->fseek(0xB00000,SEEK_SET); fp->fwrite(MMU.ARM9_LCD,0xA4000); //LCD mem 656K
+ fp->fseek(0xC00000,SEEK_SET); fp->fwrite(MMU.ARM9_VMEM,0x800); //OAM
+ fp->fseek(0xD00000,SEEK_SET); fp->fwrite(MMU.ARM7_ERAM,0x10000); //arm7 WRAM (64K)
+ fp->fseek(0xE00000,SEEK_SET); fp->fwrite(MMU.ARM7_WIRAM,0x10000); //arm7 wifi RAM ?
+ fp->fseek(0xF00000,SEEK_SET); fp->fwrite(MMU.SWIRAM,0x8000); //arm9/arm7 shared WRAM (32KB)
+}
+
+//----------------------------------------------------
+
+std::vector<Logger *> Logger::channels;
+
+
+static void defaultCallback(const Logger& logger, const char * message) {
+ logger.getOutput() << message;
+}
+
+Logger::Logger() {
+ out = &std::cout;
+ callback = defaultCallback;
+ flags = 0;
+}
+
+Logger::~Logger() {
+ for(int i=0;i<(int)channels.size();i++)
+ delete channels[i];
+}
+
+void Logger::vprintf(const char * format, va_list l, const char * file, unsigned int line) {
+ char buffer[1024];
+ char * cur = buffer;
+
+ if (flags & Logger::FILE) cur += sprintf(cur, "%s:", file);
+ if (flags & Logger::LINE) cur += sprintf(cur, "%d:", line);
+ if (flags) cur += sprintf(cur, " ");
+
+ ::vsnprintf(cur, 1024, format, l);
+ callback(*this, buffer);
+}
+
+void Logger::setOutput(std::ostream * o) {
+ out = o;
+}
+
+void Logger::setCallback(void (*cback)(const Logger& logger, const char * message)) {
+ callback = cback;
+}
+
+void Logger::setFlag(unsigned int flag) {
+ this->flags = flag;
+}
+
+void Logger::fixSize(unsigned int channel) {
+ while(channel >= channels.size()) {
+ channels.push_back(new Logger());
+ }
+}
+
+std::ostream& Logger::getOutput() const {
+ return *out;
+}
+
+void Logger::log(unsigned int channel, const char * file, unsigned int line, const char * format, ...) {
+ fixSize(channel);
+
+ va_list l;
+ va_start(l, format);
+ channels[channel]->vprintf(format, l, file, line);
+ va_end(l);
+}
+
+void Logger::log(unsigned int channel, const char *, unsigned int, std::ostream& os) {
+ fixSize(channel);
+
+ channels[channel]->setOutput(&os);
+}
+
+void Logger::log(unsigned int channel, const char *, unsigned int, unsigned int flag) {
+ fixSize(channel);
+
+ channels[channel]->setFlag(flag);
+}
+
+void Logger::log(unsigned int channel, const char *, unsigned int, void (*callback)(const Logger& logger, const char * message)) {
+ fixSize(channel);
+
+ channels[channel]->setCallback(callback);
+}
+
+void IdeasLog(armcpu_t* cpu)
+{
+ uint32_t adr = cpu->R[0];
+ for(;;) {
+ uint8_t c = _MMU_read08(cpu->proc_ID, MMU_AT_DEBUG, adr);
+ adr++;
+ if(!c) break;
+ printf("%c",c);
+ }
+ //don't emit a newline. that is a pain in the butt.
+}
+
+void NocashMessage(armcpu_t* cpu)
+{
+ uint32_t adr = cpu->instruct_adr + 6;
+
+ std::string todo;
+ for(;;) {
+ uint8_t c = _MMU_read08(cpu->proc_ID, MMU_AT_DEBUG, adr);
+ adr++;
+ if(!c) break;
+ todo.push_back(c);
+ }
+
+ //r0,r1,r2,...,r15 show register content (displayed as 32bit Hex number)
+ //sp,lr,pc alias for r13,r14,r15
+ //scanline show current scanline number
+ //frame show total number of frames since coldboot
+ //totalclks show total number of clock cycles since coldboot
+ //lastclks show number of cycles since previous lastclks (or zeroclks)
+ //zeroclks resets the 'lastclks' counter
+
+ //this is very inefficiently coded!
+ char tmp[100];
+ todo = mass_replace(todo,"%sp%","%r13%");
+ todo = mass_replace(todo,"%lr%","%r14%");
+ todo = mass_replace(todo,"%pc%","%r15%");
+ sprintf(tmp,"%08X",cpu->R[0]); todo = mass_replace(todo,"%r0%",tmp);
+ sprintf(tmp,"%08X",cpu->R[1]); todo = mass_replace(todo,"%r1%",tmp);
+ sprintf(tmp,"%08X",cpu->R[2]); todo = mass_replace(todo,"%r2%",tmp);
+ sprintf(tmp,"%08X",cpu->R[3]); todo = mass_replace(todo,"%r3%",tmp);
+ sprintf(tmp,"%08X",cpu->R[4]); todo = mass_replace(todo,"%r4%",tmp);
+ sprintf(tmp,"%08X",cpu->R[5]); todo = mass_replace(todo,"%r5%",tmp);
+ sprintf(tmp,"%08X",cpu->R[6]); todo = mass_replace(todo,"%r6%",tmp);
+ sprintf(tmp,"%08X",cpu->R[7]); todo = mass_replace(todo,"%r7%",tmp);
+ sprintf(tmp,"%08X",cpu->R[8]); todo = mass_replace(todo,"%r8%",tmp);
+ sprintf(tmp,"%08X",cpu->R[9]); todo = mass_replace(todo,"%r9%",tmp);
+ sprintf(tmp,"%08X",cpu->R[10]); todo = mass_replace(todo,"%r10%",tmp);
+ sprintf(tmp,"%08X",cpu->R[11]); todo = mass_replace(todo,"%r11%",tmp);
+ sprintf(tmp,"%08X",cpu->R[12]); todo = mass_replace(todo,"%r12%",tmp);
+ sprintf(tmp,"%08X",cpu->R[13]); todo = mass_replace(todo,"%r13%",tmp);
+ sprintf(tmp,"%08X",cpu->R[14]); todo = mass_replace(todo,"%r14%",tmp);
+ sprintf(tmp,"%08X",cpu->R[15]); todo = mass_replace(todo,"%r15%",tmp);
+ sprintf(tmp,"%d",nds.VCount); todo = mass_replace(todo,"%scanline%",tmp);
+ /*sprintf(tmp,"%d",currFrameCounter); */todo = mass_replace(todo,"%frame%",tmp);
+ sprintf(tmp,"%lld",nds_timer); todo = mass_replace(todo,"%totalclks%",tmp);
+
+ printf("%s",todo.c_str());
+}
+
+//-------
+DebugNotify DEBUG_Notify;
+
+//enable bits arent being used right now.
+//if you want exhaustive logging, move the print before the early return (or comment the early return)
+
+//the intent of this system is to provide a compact dialog box showing which debug notifies have been
+//triggered in this frame (with a glowing LED!) and which debug notifies have been triggered EVER
+//which can be cleared, like a clip indicator in an audio tool.
+//obviously all this isnt implemented yet.
+
+void DebugNotify::NextFrame()
+{
+#ifdef DEVELOPER
+ pingBits.reset();
+#endif
+}
+
+void DebugNotify::ReadBeyondEndOfCart(uint32_t addr, uint32_t romsize)
+{
+#ifdef DEVELOPER
+ if(!ping(DEBUG_NOTIFY_READ_BEYOND_END_OF_CART)) return;
+ INFO("Reading beyond end of cart! ... %08X >= %08X\n",addr,romsize);
+#endif
+}
+
+bool DebugNotify::ping(EDEBUG_NOTIFY which)
+{
+ bool wasPinged = pingBits[(int)which];
+ pingBits[(int)which] = true;
+ return !wasPinged;
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/debug.h
@@ -1,1 +1,217 @@
-
+/* Copyright (C) 2008 Guillaume Duhamel
+ Copyright (C) 2009-2010 DeSmuME team
+
+ This file is part of DeSmuME
+
+ DeSmuME is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DeSmuME 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DeSmuME; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <vector>
+#include <iostream>
+#include <bitset>
+#include <cstdarg>
+
+#include "types.h"
+#include "mem.h"
+#include "emufile.h"
+
+struct DebugStatistics
+{
+ DebugStatistics();
+ struct InstructionHits {
+ InstructionHits();
+ uint32_t thumb[1024];
+ uint32_t arm[4096];
+ } instructionHits[2]; //one for each cpu
+
+ int32_t sequencerExecutionCounters[32];
+
+ void print();
+ void printSequencerExecutionCounters();
+};
+
+extern DebugStatistics DEBUG_statistics;
+
+void DEBUG_reset();
+void DEBUG_dumpMemory(EMUFILE* fp);
+
+struct armcpu_t;
+
+class Logger {
+protected:
+ void (*callback)(const Logger& logger, const char * format);
+ std::ostream * out;
+ unsigned int flags;
+
+ static std::vector<Logger *> channels;
+
+ static void fixSize(unsigned int channel);
+public:
+ Logger();
+ ~Logger();
+
+ void vprintf(const char * format, va_list l, const char * filename, unsigned int line);
+ void setOutput(std::ostream * o);
+ void setCallback(void (*cback)(const Logger& logger, const char * message));
+ void setFlag(unsigned int flag);
+
+ std::ostream& getOutput() const;
+
+ static const int LINE = 1;
+ static const int FILE = 2;
+
+ static void log(unsigned int channel, const char * file, unsigned int line, const char * format, ...);
+ static void log(unsigned int channel, const char * file, unsigned int line, std::ostream& os);
+ static void log(unsigned int channel, const char * file, unsigned int line, unsigned int flag);
+ static void log(unsigned int channel, const char * file, unsigned int line, void (*callback)(const Logger& logger, const char * message));
+};
+
+#if defined(DEBUG) || defined(GPUDEBUG) || defined(DIVDEBUG) || defined(SQRTDEBUG) || defined(DMADEBUG) || defined(DEVELOPER)
+#define LOGC(channel, ...) Logger::log(channel, __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define LOGC(...) {}
+#endif
+
+#ifdef DEBUG
+#define LOG(...) LOGC(0, __VA_ARGS__)
+#else
+#define LOG(...) {}
+#endif
+
+#ifdef GPUDEBUG
+#define GPULOG(...) LOGC(1, __VA_ARGS__)
+#else
+#define GPULOG(...) {}
+#endif
+
+#ifdef DIVDEBUG
+#define DIVLOG(...) LOGC(2, __VA_ARGS__)
+#else
+#define DIVLOG(...) {}
+#endif
+
+#ifdef SQRTDEBUG
+#define SQRTLOG(...) LOGC(3, __VA_ARGS__)
+#else
+#define SQRTLOG(...) {}
+#endif
+
+#ifdef DMADEBUG
+#define DMALOG(...) LOGC(4, __VA_ARGS__)
+#else
+#define DMALOG(...) {}
+#endif
+
+#ifdef CFLASHDEBUG
+#define CFLASHLOG(...) LOGC(5, __VA_ARGS__)
+#else
+#define CFLASHLOG(...) {}
+#endif
+
+#ifdef UNTESTEDOPCODEDEBUG
+#define UNTESTEDOPCODELOG(...) LOGC(6, __VA_ARGS__)
+#else
+#define UNTESTEDOPCODELOG(...) {}
+#endif
+
+
+#ifdef DEVELOPER
+#define PROGINFO(...) LOGC(7, __VA_ARGS__)
+#else
+#define PROGINFO(...) {}
+#endif
+
+
+#define INFOC(channel, ...) Logger::log(channel, __FILE__, __LINE__, __VA_ARGS__)
+#define INFO(...) INFOC(10, __VA_ARGS__)
+
+void IdeasLog(armcpu_t* cpu);
+void NocashMessage(armcpu_t* cpu);
+
+enum EDEBUG_EVENT
+{
+ DEBUG_EVENT_READ=1, //read from arm9 or arm7 bus, including cpu prefetch
+ DEBUG_EVENT_WRITE=2, //write on arm9 or arm7 bus
+ DEBUG_EVENT_EXECUTE=4, //prefetch on arm9 or arm7, triggered after the read event
+ DEBUG_EVENT_ACL_EXCEPTION=8, //acl exception on arm9
+};
+
+enum EDEBUG_NOTIFY
+{
+ DEBUG_NOTIFY_READ_BEYOND_END_OF_CART,
+ DEBUG_NOTIFY_MAX
+};
+
+class DebugNotify
+{
+public:
+ void NextFrame();
+ void ReadBeyondEndOfCart(uint32_t addr, uint32_t romsize);
+private:
+ std::bitset<DEBUG_NOTIFY_MAX> pingBits;
+ std::bitset<DEBUG_NOTIFY_MAX> enableBits;
+ bool ping(EDEBUG_NOTIFY which);
+};
+
+extern DebugNotify DEBUG_Notify;
+struct armcpu_t;
+
+//information about a debug event will be stuffed into here by the generator
+struct TDebugEventData
+{
+ MMU_ACCESS_TYPE memAccessType;
+ uint32_t procnum, addr, size, val;
+ armcpu_t* cpu();
+};
+
+extern TDebugEventData DebugEventData;
+
+//bits in here are set according to what debug handlers are installed?
+//for now it is just a single bit
+extern uint32_t debugFlag;
+
+inline bool CheckDebugEvent(EDEBUG_EVENT)
+{
+ //for now, debug events are only handled in dev+ builds
+#ifndef DEVELOPER
+ return false;
+#else
+ if(!debugFlag) return false;
+
+ return true;
+#endif
+}
+
+void HandleDebugEvent_Read();
+void HandleDebugEvent_Write();
+void HandleDebugEvent_Execute();
+void HandleDebugEvent_ACL_Exception();
+
+inline void HandleDebugEvent(EDEBUG_EVENT event)
+{
+ switch(event)
+ {
+ case DEBUG_EVENT_READ: HandleDebugEvent_Read(); return;
+ case DEBUG_EVENT_WRITE: HandleDebugEvent_Write(); return;
+ case DEBUG_EVENT_EXECUTE: HandleDebugEvent_Execute(); return;
+ case DEBUG_EVENT_ACL_EXCEPTION: HandleDebugEvent_ACL_Exception(); return;
+ }
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/emufile.cpp
@@ -1,1 +1,259 @@
-
+/*
+The MIT License
+
+Copyright (C) 2009-2010 DeSmuME team
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <vector>
+
+#include "emufile.h"
+
+/*bool EMUFILE::readAllBytes(std::vector<uint8_t>* dstbuf, const std::string& fname)
+{
+ EMUFILE_FILE file(fname.c_str(),"rb");
+ if(file.fail()) return false;
+ int size = file.size();
+ dstbuf->resize(size);
+ file.fread(&dstbuf->at(0),size);
+ return true;
+}*/
+
+size_t EMUFILE_MEMORY::_fread(void *ptr, size_t bytes){
+ uint32_t remain = len-pos;
+ uint32_t todo = std::min<uint32_t>(remain,(uint32_t)bytes);
+ if(len==0)
+ {
+ failbit = true;
+ return 0;
+ }
+ if(todo<=4)
+ {
+ uint8_t* src = buf()+pos;
+ uint8_t* dst = (uint8_t*)ptr;
+ for(uint32_t i=0;i<todo;i++)
+ *dst++ = *src++;
+ }
+ else
+ {
+ memcpy(ptr,buf()+pos,todo);
+ }
+ pos += todo;
+ if(todo<bytes)
+ failbit = true;
+ return todo;
+}
+
+/*void EMUFILE_FILE::truncate(int32_t length)
+{
+ ::fflush(fp);
+ #if defined(_MSC_VER) || defined(__MINGW32__)
+ _chsize(_fileno(fp),length);
+ #else
+ ftruncate(fileno(fp),length);
+ #endif
+ fclose(fp);
+ fp = NULL;
+ open(fname.c_str(),mode);
+}*/
+
+
+/*EMUFILE* EMUFILE_FILE::memwrap()
+{
+ EMUFILE_MEMORY* mem = new EMUFILE_MEMORY(size());
+ if(size()==0) return mem;
+ fread(mem->buf(),size());
+ return mem;
+}*/
+
+/*EMUFILE* EMUFILE_MEMORY::memwrap()
+{
+ return this;
+}*/
+
+/*void EMUFILE::write64le(uint64_t *val)
+{
+ write64le(*val);
+}
+
+void EMUFILE::write64le(uint64_t val)
+{
+#ifdef LOCAL_BE
+ uint8_t s[8];
+ s[0]=(uint8_t)val;
+ s[1]=(uint8_t)(val>>8);
+ s[2]=(uint8_t)(val>>16);
+ s[3]=(uint8_t)(val>>24);
+ s[4]=(uint8_t)(val>>32);
+ s[5]=(uint8_t)(val>>40);
+ s[6]=(uint8_t)(val>>48);
+ s[7]=(uint8_t)(val>>56);
+ fwrite((char*)&s,8);
+#else
+ fwrite(&val,8);
+#endif
+}
+
+size_t EMUFILE::read64le(uint64_t *Bufo)
+{
+ uint64_t buf;
+ if(fread((char*)&buf,8) != 8)
+ return 0;
+#ifndef LOCAL_BE
+ *Bufo=buf;
+#else
+ *Bufo = LE_TO_LOCAL_64(buf);
+#endif
+ return 1;
+}
+
+uint64_t EMUFILE::read64le()
+{
+ uint64_t temp;
+ read64le(&temp);
+ return temp;
+}
+
+void EMUFILE::write32le(uint32_t *val)
+{
+ write32le(*val);
+}
+
+void EMUFILE::write32le(uint32_t val)
+{
+#ifdef LOCAL_BE
+ uint8_t s[4];
+ s[0]=(uint8_t)val;
+ s[1]=(uint8_t)(val>>8);
+ s[2]=(uint8_t)(val>>16);
+ s[3]=(uint8_t)(val>>24);
+ fwrite(s,4);
+#else
+ fwrite(&val,4);
+#endif
+}
+
+size_t EMUFILE::read32le(int32_t *Bufo) { return read32le((uint32_t *)Bufo); }
+
+size_t EMUFILE::read32le(uint32_t *Bufo)
+{
+ uint32_t buf;
+ if(fread(&buf,4)<4)
+ return 0;
+#ifndef LOCAL_BE
+ *(uint32_t *)Bufo=buf;
+#else
+ *(uint32_t *)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
+#endif
+ return 1;
+}
+
+uint32_t EMUFILE::read32le()
+{
+ uint32_t ret;
+ read32le(&ret);
+ return ret;
+}
+
+void EMUFILE::write16le(uint16_t *val)
+{
+ write16le(*val);
+}
+
+void EMUFILE::write16le(uint16_t val)
+{
+#ifdef LOCAL_BE
+ uint8_t s[2];
+ s[0]=(uint8_t)val;
+ s[1]=(uint8_t)(val>>8);
+ fwrite(s,2);
+#else
+ fwrite(&val,2);
+#endif
+}
+
+size_t EMUFILE::read16le(int16_t *Bufo) { return read16le((uint16_t *)Bufo); }
+
+size_t EMUFILE::read16le(uint16_t *Bufo)
+{
+ uint32_t buf;
+ if(fread(&buf,2)<2)
+ return 0;
+#ifndef LOCAL_BE
+ *(uint16_t *)Bufo=buf;
+#else
+ *Bufo = LE_TO_LOCAL_16(buf);
+#endif
+ return 1;
+}
+
+uint16_t EMUFILE::read16le()
+{
+ uint16_t ret;
+ read16le(&ret);
+ return ret;
+}
+
+void EMUFILE::write8le(uint8_t *val)
+{
+ write8le(*val);
+}
+
+void EMUFILE::write8le(uint8_t val)
+{
+ fwrite(&val,1);
+}
+
+size_t EMUFILE::read8le(uint8_t *val)
+{
+ return fread(val,1);
+}
+
+uint8_t EMUFILE::read8le()
+{
+ uint8_t temp;
+ fread(&temp,1);
+ return temp;
+}
+
+void EMUFILE::writedouble(double* val)
+{
+ write64le(double_to_u64(*val));
+}
+void EMUFILE::writedouble(double val)
+{
+ write64le(double_to_u64(val));
+}
+
+double EMUFILE::readdouble()
+{
+ double temp;
+ readdouble(&temp);
+ return temp;
+}
+
+size_t EMUFILE::readdouble(double* val)
+{
+ uint64_t temp;
+ size_t ret = read64le(&temp);
+ *val = u64_to_double(temp);
+ return ret;
+}*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/emufile.h
@@ -1,1 +1,386 @@
-
+/*
+The MIT License
+
+Copyright (C) 2009-2012 DeSmuME team
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+//don't use emufile for files bigger than 2GB! you have been warned! some day this will be fixed.
+
+#ifndef EMUFILE_H
+#define EMUFILE_H
+
+#include <vector>
+#include <algorithm>
+#include <string>
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <cstdarg>
+#include <cmath>
+
+#include "types.h"
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+/*#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <io.h>*/
+#include "windowsh_wrapper.h"
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+class EMUFILE
+{
+protected:
+ bool failbit;
+
+public:
+ EMUFILE() : failbit(false)
+ {
+ }
+
+ //returns a new EMUFILE which is guranteed to be in memory. the EMUFILE you call this on may be deleted. use the returned EMUFILE in its place
+ //virtual EMUFILE* memwrap() = 0;
+
+ virtual ~EMUFILE() {}
+
+ //static bool readAllBytes(std::vector<uint8_t> *buf, const std::string &fname);
+
+ bool fail(bool unset = false)
+ {
+ bool ret = failbit;
+ if (unset)
+ unfail();
+ return ret;
+ }
+ void unfail() { failbit = false; }
+
+ //bool eof() { return size() == ftell(); }
+
+ size_t fread(void *ptr, size_t bytes)
+ {
+ return _fread(ptr, bytes);
+ }
+
+ //void unget() { fseek(-1, SEEK_CUR); }
+
+ //virtuals
+public:
+ //virtual FILE *get_fp() = 0;
+
+ //virtual int fprintf(const char *format, ...) = 0;
+
+ //virtual int fgetc() = 0;
+ //virtual int fputc(int c) = 0;
+
+ virtual size_t _fread(void *ptr, size_t bytes) = 0;
+
+ //removing these return values for now so we can find any code that might be using them and make sure
+ //they handle the return values correctly
+
+ //virtual void fwrite(const void *ptr, size_t bytes) = 0;
+
+ /*void write64le(uint64_t *val);
+ void write64le(uint64_t val);
+ size_t read64le(uint64_t *val);
+ uint64_t read64le();
+ void write32le(uint32_t *val);
+ void write32le(int32_t *val) { write32le((uint32_t *)val); }
+ void write32le(uint32_t val);
+ size_t read32le(uint32_t *val);
+ size_t read32le(int32_t *val);
+ uint32_t read32le();
+ void write16le(uint16_t *val);
+ void write16le(int16_t *val) { write16le((uint16_t *)val); }
+ void write16le(uint16_t val);
+ size_t read16le(int16_t *Bufo);
+ size_t read16le(uint16_t *val);
+ uint16_t read16le();
+ void write8le(uint8_t *val);
+ void write8le(uint8_t val);
+ size_t read8le(uint8_t *val);
+ uint8_t read8le();
+ void writedouble(double* val);
+ void writedouble(double val);
+ double readdouble();
+ size_t readdouble(double* val);*/
+
+ virtual int fseek(int offset, int origin) = 0;
+
+ virtual size_t ftell() = 0;
+ virtual size_t size() = 0;
+
+ //virtual void truncate(int32_t length) = 0;
+};
+
+//todo - handle read-only specially?
+class EMUFILE_MEMORY : public EMUFILE
+{
+protected:
+ std::vector<uint8_t> *vec;
+ bool ownvec;
+ int32_t pos, len;
+
+ void reserve(uint32_t amt)
+ {
+ if (vec->size() < amt)
+ vec->resize(amt);
+ }
+
+public:
+ EMUFILE_MEMORY(std::vector<uint8_t> *underlying) : vec(underlying), ownvec(false), pos(0), len(static_cast<int32_t>(underlying->size())) { }
+ EMUFILE_MEMORY(uint32_t preallocate) : vec(new std::vector<uint8_t>()), ownvec(true), pos(0), len(0)
+ {
+ vec->resize(preallocate);
+ len = preallocate;
+ }
+ EMUFILE_MEMORY() : vec(new std::vector<uint8_t>()), ownvec(true), pos(0), len(0) { vec->reserve(1024); }
+ EMUFILE_MEMORY(void *Buf, int32_t Size) : vec(new std::vector<uint8_t>()), ownvec(true), pos(0), len(Size)
+ {
+ vec->resize(Size);
+ if (Size)
+ memcpy(&(*vec)[0], Buf, Size);
+ }
+
+ ~EMUFILE_MEMORY()
+ {
+ if (ownvec)
+ delete vec;
+ }
+
+ //virtual EMUFILE *memwrap();
+
+ /*virtual void truncate(int32_t length)
+ {
+ vec->resize(length);
+ len = length;
+ if (pos>length)
+ pos = length;
+ }*/
+
+ uint8_t *buf() {
+ if(size()==0) reserve(1);
+ return &(*vec)[0];
+ }
+
+ //std::vector<uint8_t> *get_vec() { return vec; };
+
+ //virtual FILE *get_fp() { return NULL; }
+
+ /*virtual int fprintf(const char *format, ...)
+ {
+ va_list argptr;
+ va_start(argptr, format);
+
+ //we dont generate straight into the buffer because it will null terminate (one more byte than we want)
+ int amt = vsnprintf(0, 0, format,argptr);
+ char *tempbuf = new char[amt + 1];
+
+ va_end(argptr);
+ va_start(argptr, format);
+ vsprintf(tempbuf, format, argptr);
+
+ fwrite(tempbuf, amt);
+ delete [] tempbuf;
+
+ va_end(argptr);
+ return amt;
+ };*/
+
+ /*virtual int fgetc()
+ {
+ uint8_t temp;
+
+ //need an optimized codepath
+ //if(_fread(&temp,1) != 1)
+ // return EOF;
+ //else return temp;
+ uint32_t remain = len-pos;
+ if (remain < 1)
+ {
+ failbit = true;
+ return -1;
+ }
+ temp = buf()[pos];
+ ++pos;
+ return temp;
+ }*/
+
+ /*virtual int fputc(int c)
+ {
+ uint8_t temp = static_cast<uint8_t>(c);
+ //TODO
+ //if(fwrite(&temp,1)!=1) return EOF;
+ fwrite(&temp, 1);
+
+ return 0;
+ }*/
+
+ virtual size_t _fread(void *ptr, size_t bytes);
+
+ //removing these return values for now so we can find any code that might be using them and make sure
+ //they handle the return values correctly
+
+ /*virtual void fwrite(const void *ptr, size_t bytes)
+ {
+ reserve(pos + bytes);
+ memcpy(buf() + pos, ptr, bytes);
+ pos += bytes;
+ len = std::max(pos, len);
+ }*/
+
+ virtual int fseek(int offset, int origin)
+ {
+ //work differently for read-only...?
+ switch (origin)
+ {
+ case SEEK_SET:
+ pos = offset;
+ break;
+ case SEEK_CUR:
+ pos += offset;
+ break;
+ case SEEK_END:
+ pos = size() + offset;
+ break;
+ default:
+ assert(false);
+ }
+ reserve(pos);
+ return 0;
+ }
+
+ virtual size_t ftell()
+ {
+ return pos;
+ }
+
+ /*void trim()
+ {
+ vec->resize(len);
+ }*/
+
+ virtual size_t size() { return len; }
+};
+
+class EMUFILE_FILE : public EMUFILE
+{
+protected:
+ FILE *fp;
+ std::string fname;
+ char mode[16];
+
+private:
+ void open(const char *fn, const char *Mode)
+ {
+ fp = fopen(fn, Mode);
+ if (!fp)
+ failbit = true;
+ this->fname = fn;
+ strcpy(this->mode, Mode);
+ }
+
+public:
+ EMUFILE_FILE(const std::string &fn, const char *Mode) { open(fn.c_str(), Mode); }
+ EMUFILE_FILE(const char *fn, const char *Mode) { open(fn, Mode); }
+
+ virtual ~EMUFILE_FILE()
+ {
+ if (fp)
+ fclose(fp);
+ }
+
+ /*virtual FILE *get_fp()
+ {
+ return fp;
+ }*/
+
+ //virtual EMUFILE *memwrap();
+
+ //bool is_open() { return fp != NULL; }
+
+ //virtual void truncate(int32_t length);
+
+ /*virtual int fprintf(const char *format, ...)
+ {
+ va_list argptr;
+ va_start(argptr, format);
+ int ret = ::vfprintf(fp, format, argptr);
+ va_end(argptr);
+ return ret;
+ };*/
+
+ /*virtual int fgetc()
+ {
+ return ::fgetc(fp);
+ }*/
+
+ /*virtual int fputc(int c)
+ {
+ return ::fputc(c, fp);
+ }*/
+
+ virtual size_t _fread(void *ptr, size_t bytes)
+ {
+ size_t ret = ::fread(ptr, 1, bytes, fp);
+ if (ret < bytes)
+ failbit = true;
+ return ret;
+ }
+
+ //removing these return values for now so we can find any code that might be using them and make sure
+ //they handle the return values correctly
+
+ /*virtual void fwrite(const void *ptr, size_t bytes)
+ {
+ size_t ret = ::fwrite(ptr, 1, bytes, fp);
+ if (ret < bytes)
+ failbit = true;
+ }*/
+
+ virtual int fseek(int offset, int origin)
+ {
+ return ::fseek(fp, offset, origin);
+ }
+
+ virtual size_t ftell()
+ {
+ return static_cast<uint32_t>(::ftell(fp));
+ }
+
+ virtual size_t size()
+ {
+ int oldpos = ftell();
+ fseek(0, SEEK_END);
+ int len = ftell();
+ fseek(oldpos, SEEK_SET);
+ return len;
+ }
+
+ /*virtual void fflush()
+ {
+ ::fflush(fp);
+ }*/
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/firmware.cpp
@@ -1,1 +1,924 @@
-
+/*
+ Copyright (C) 2009-2011 DeSmuME Team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "firmware.h"
+#include "NDSSystem.h"
+#include "path.h"
+
+//#define DWNUM(i) ((i) >> 2)
+static inline uint32_t DWNUM(uint32_t i) { return i >> 2; }
+
+bool CFIRMWARE::getKeyBuf()
+{
+ FILE *file = fopen(CommonSettings.ARM7BIOS, "rb");
+ if (!file) return false;
+
+ fseek(file, 0x30, SEEK_SET);
+ size_t res = fread(keyBuf, 4, 0x412, file);
+ fclose(file);
+ return res == 0x412;
+}
+
+void CFIRMWARE::crypt64BitUp(uint32_t *ptr)
+{
+ uint32_t Y = ptr[0];
+ uint32_t X = ptr[1];
+
+ for(uint32_t i = 0x00; i <= 0x0F; i++)
+ {
+ uint32_t Z = (keyBuf[i] ^ X);
+ X = keyBuf[DWNUM(0x048 + (((Z >> 24) & 0xFF) << 2))];
+ X = (keyBuf[DWNUM(0x448 + (((Z >> 16) & 0xFF) << 2))] + X);
+ X = (keyBuf[DWNUM(0x848 + (((Z >> 8) & 0xFF) << 2))] ^ X);
+ X = (keyBuf[DWNUM(0xC48 + ((Z & 0xFF) << 2))] + X);
+ X = (Y ^ X);
+ Y = Z;
+ }
+
+ ptr[0] = (X ^ keyBuf[DWNUM(0x40)]);
+ ptr[1] = (Y ^ keyBuf[DWNUM(0x44)]);
+}
+
+void CFIRMWARE::crypt64BitDown(uint32_t *ptr)
+{
+ uint32_t Y = ptr[0];
+ uint32_t X = ptr[1];
+
+ for(uint32_t i = 0x11; i >= 0x02; i--)
+ {
+ uint32_t Z = (keyBuf[i] ^ X);
+ X = keyBuf[DWNUM(0x048 + (((Z >> 24) & 0xFF) << 2))];
+ X = (keyBuf[DWNUM(0x448 + (((Z >> 16) & 0xFF) << 2))] + X);
+ X = (keyBuf[DWNUM(0x848 + (((Z >> 8) & 0xFF) << 2))] ^ X);
+ X = (keyBuf[DWNUM(0xC48 + ((Z & 0xFF) << 2))] + X);
+ X = (Y ^ X);
+ Y = Z;
+ }
+
+ ptr[0] = (X ^ keyBuf[DWNUM(0x04)]);
+ ptr[1] = (Y ^ keyBuf[DWNUM(0x00)]);
+}
+
+//#define bswap32(val) (((val & 0x000000FF) << 24) | ((val & 0x0000FF00) << 8) | ((val & 0x00FF0000) >> 8) | ((val & 0xFF000000) >> 24))
+static inline uint32_t bswap32(uint32_t val) { return ((val & 0x000000FF) << 24) | ((val & 0x0000FF00) << 8) | ((val & 0x00FF0000) >> 8) | ((val & 0xFF000000) >> 24); }
+void CFIRMWARE::applyKeycode(uint32_t modulo)
+{
+ crypt64BitUp(&keyCode[1]);
+ crypt64BitUp(&keyCode[0]);
+
+ uint32_t scratch[2] = {0x00000000, 0x00000000};
+
+ for(uint32_t i = 0; i <= 0x44; i += 4)
+ {
+ keyBuf[DWNUM(i)] = (keyBuf[DWNUM(i)] ^ bswap32(keyCode[DWNUM(i % modulo)]));
+ }
+
+ for(uint32_t i = 0; i <= 0x1040; i += 8)
+ {
+ crypt64BitUp(scratch);
+ keyBuf[DWNUM(i)] = scratch[1];
+ keyBuf[DWNUM(i+4)] = scratch[0];
+ }
+}
+//#undef bswap32
+
+bool CFIRMWARE::initKeycode(uint32_t idCode, int level, uint32_t modulo)
+{
+ if(getKeyBuf() == false)
+ return false;
+
+ keyCode[0] = idCode;
+ keyCode[1] = (idCode >> 1);
+ keyCode[2] = (idCode << 1);
+
+ if(level >= 1) applyKeycode(modulo);
+ if(level >= 2) applyKeycode(modulo);
+
+ keyCode[1] <<= 1;
+ keyCode[2] >>= 1;
+
+ if(level >= 3) applyKeycode(modulo);
+
+ return true;
+}
+
+uint16_t CFIRMWARE::getBootCodeCRC16()
+{
+ unsigned int i, j;
+ uint32_t crc = 0xFFFF;
+ const uint16_t val[8] = {0xC0C1, 0xC181, 0xC301, 0xC601, 0xCC01, 0xD801, 0xF001, 0xA001};
+
+ for(i = 0; i < size9; i++)
+ {
+ crc = (crc ^ tmp_data9[i]);
+
+ for(j = 0; j < 8; j++)
+ {
+ if(crc & 0x0001)
+ crc = ((crc >> 1) ^ (val[j] << (7-j)));
+ else
+ crc = (crc >> 1);
+ }
+ }
+
+ for(i = 0; i < size7; i++)
+ {
+ crc = (crc ^ tmp_data7[i]);
+
+ for(j = 0; j < 8; j++)
+ {
+ if(crc & 0x0001)
+ crc = ((crc >> 1) ^ (val[j] << (7-j)));
+ else
+ crc = (crc >> 1);
+ }
+ }
+
+ return crc & 0xFFFF;
+}
+
+uint32_t CFIRMWARE::decrypt(const uint8_t *in, uint8_t* &out)
+{
+ uint32_t curBlock[2] = { 0 };
+ uint32_t blockSize = 0;
+ uint32_t xLen = 0;
+
+ uint32_t i = 0, j = 0;
+ uint32_t xIn = 4, xOut = 0;
+ uint32_t len = 0;
+ uint32_t offset = 0;
+ uint32_t windowOffset = 0;
+ uint8_t d = 0;
+
+ uint16_t data = 0;
+
+ memcpy(curBlock, in, 8);
+ crypt64BitDown(curBlock);
+ blockSize = (curBlock[0] >> 8);
+
+ if (blockSize == 0) return 0;
+
+ out = new uint8_t [blockSize];
+ if (!out ) return 0;
+ memset(out, 0xFF, blockSize);
+
+ xLen = blockSize;
+ while(xLen > 0)
+ {
+ d = T1ReadByte((uint8_t*)curBlock, (xIn % 8));
+ xIn++;
+ if((xIn % 8) == 0)
+ {
+ memcpy(curBlock, in + xIn, 8);
+ crypt64BitDown(curBlock);
+ }
+
+ for(i = 0; i < 8; i++)
+ {
+ if(d & 0x80)
+ {
+ data = (T1ReadByte((uint8_t*)curBlock, (xIn % 8)) << 8);
+ xIn++;
+ if((xIn % 8) == 0)
+ {
+ memcpy(curBlock, in + xIn, 8);
+ crypt64BitDown(curBlock);
+ }
+ data |= T1ReadByte((uint8_t*)curBlock, (xIn % 8));
+ xIn++;
+ if((xIn % 8) == 0)
+ {
+ memcpy(curBlock, in + xIn, 8);
+ crypt64BitDown(curBlock);
+ }
+
+ len = (data >> 12) + 3;
+ offset = (data & 0xFFF);
+ windowOffset = (xOut - offset - 1);
+
+ for(j = 0; j < len; j++)
+ {
+ T1WriteByte(out, xOut, T1ReadByte(out, windowOffset));
+ xOut++;
+ windowOffset++;
+
+ xLen--;
+ if(xLen == 0) return blockSize;
+ }
+ }
+ else
+ {
+ T1WriteByte(out, xOut, T1ReadByte((uint8_t*)curBlock, (xIn % 8)));
+ xOut++;
+ xIn++;
+ if((xIn % 8) == 0)
+ {
+ memcpy(curBlock, in + xIn, 8);
+ crypt64BitDown(curBlock);
+ }
+
+ xLen--;
+ if(xLen == 0) return blockSize;
+ }
+
+ d = ((d << 1) & 0xFF);
+ }
+ }
+
+ return blockSize;
+}
+
+uint32_t CFIRMWARE::decompress(const uint8_t *in, uint8_t* &out)
+{
+ uint32_t curBlock[2] = { 0 };
+ uint32_t blockSize = 0;
+ uint32_t xLen = 0;
+
+ uint32_t i = 0, j = 0;
+ uint32_t xIn = 4, xOut = 0;
+ uint32_t len = 0;
+ uint32_t offset = 0;
+ uint32_t windowOffset = 0;
+ uint8_t d = 0;
+ uint16_t data = 0;
+
+ memcpy(curBlock, in, 8);
+ blockSize = (curBlock[0] >> 8);
+
+ if (blockSize == 0) return 0;
+
+ out = new uint8_t [blockSize];
+ if (!out ) return 0;
+ memset(out, 0xFF, blockSize);
+
+ xLen = blockSize;
+ while(xLen > 0)
+ {
+ d = T1ReadByte((uint8_t*)curBlock, (xIn % 8));
+ xIn++;
+ if((xIn % 8) == 0)
+ {
+ memcpy(curBlock, in + xIn, 8);
+ }
+
+ for(i = 0; i < 8; i++)
+ {
+ if(d & 0x80)
+ {
+ data = (T1ReadByte((uint8_t*)curBlock, (xIn % 8)) << 8);
+ xIn++;
+ if((xIn % 8) == 0)
+ {
+ memcpy(curBlock, in + xIn, 8);
+ }
+ data |= T1ReadByte((uint8_t*)curBlock, (xIn % 8));
+ xIn++;
+ if((xIn % 8) == 0)
+ {
+ memcpy(curBlock, in + xIn, 8);
+ }
+
+ len = (data >> 12) + 3;
+ offset = (data & 0xFFF);
+ windowOffset = (xOut - offset - 1);
+
+ for(j = 0; j < len; j++)
+ {
+ T1WriteByte(out, xOut, T1ReadByte(out, windowOffset));
+ xOut++;
+ windowOffset++;
+
+ xLen--;
+ if(xLen == 0) return blockSize;
+ }
+ }
+ else
+ {
+ T1WriteByte(out, xOut, T1ReadByte((uint8_t*)curBlock, (xIn % 8)));
+ xOut++;
+ xIn++;
+ if((xIn % 8) == 0)
+ {
+ memcpy(curBlock, in + xIn, 8);
+ }
+
+ xLen--;
+ if(xLen == 0) return blockSize;
+ }
+
+ d = ((d << 1) & 0xFF);
+ }
+ }
+
+ return blockSize;
+}
+//================================================================================
+bool CFIRMWARE::load()
+{
+ uint32_t size = 0;
+ uint8_t *data = NULL;
+ uint16_t shift1 = 0, shift2 = 0, shift3 = 0, shift4 = 0;
+ uint32_t part1addr = 0, part2addr = 0/*, part3addr = 0, part4addr = 0, part5addr = 0*/;
+ uint32_t part1ram = 0, part2ram = 0;
+
+ uint32_t src = 0;
+
+ if (CommonSettings.UseExtFirmware == false)
+ return false;
+ if (strlen(CommonSettings.Firmware) == 0)
+ return false;
+
+ FILE *fp = fopen(CommonSettings.Firmware, "rb");
+ if (!fp)
+ return false;
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ if( (size != 256*1024) && (size != 512*1024) )
+ {
+ fclose(fp);
+ return false;
+ }
+
+#if 1
+ if (size == 512*1024)
+ {
+ //INFO("ERROR: 32Mbit (512Kb) firmware not supported\n");
+ fclose(fp);
+ return false;
+ }
+#endif
+
+ data = new uint8_t [size];
+ if (!data)
+ {
+ fclose(fp);
+ return false;
+ }
+
+ if (fread(data, 1, size, fp) != size)
+ {
+ delete [] data;
+ fclose(fp);
+ return false;
+ }
+
+ memcpy(&header, data, sizeof(header));
+ if ((header.fw_identifier[0] != 'M') ||
+ (header.fw_identifier[1] != 'A') ||
+ (header.fw_identifier[2] != 'C'))
+ {
+ delete [] data;
+ fclose(fp);
+ return false;
+ }
+
+ shift1 = ((header.shift_amounts >> 0) & 0x07);
+ shift2 = ((header.shift_amounts >> 3) & 0x07);
+ shift3 = ((header.shift_amounts >> 6) & 0x07);
+ shift4 = ((header.shift_amounts >> 9) & 0x07);
+
+ // todo - add support for 512Kb
+ part1addr = (header.part1_rom_boot9_addr << (2 + shift1));
+ part1ram = (0x02800000 - (header.part1_ram_boot9_addr << (2+shift2)));
+ part2addr = (header.part2_rom_boot7_addr << (2+shift3));
+ part2ram = (0x03810000 - (header.part2_ram_boot7_addr << (2+shift4)));
+ //part3addr = (header.part3_rom_gui9_addr << 3);
+ //part4addr = (header.part4_rom_wifi7_addr << 3);
+ //part5addr = (header.part5_data_gfx_addr << 3);
+
+ ARM9bootAddr = part1ram;
+ ARM7bootAddr = part2ram;
+
+ if(initKeycode(T1ReadLong(data, 0x08), 1, 0xC) == false)
+ {
+ delete [] data;
+ fclose(fp);
+ return false;
+ }
+
+#if 0
+ crypt64BitDown((uint32_t*)&data[0x18]);
+#else
+ // fix touch coords
+ data[0x18] = 0x00;
+ data[0x19] = 0x00;
+ data[0x1A] = 0x00;
+ data[0x1B] = 0x00;
+
+ data[0x1C] = 0x00;
+ data[0x1D] = 0xFF;
+ data[0x1E] = 0x00;
+ data[0x1F] = 0x00;
+#endif
+
+ if(initKeycode(T1ReadLong(data, 0x08), 2, 0xC) == false)
+ {
+ delete [] data;
+ fclose(fp);
+ return false;
+ }
+
+ size9 = decrypt(data + part1addr, tmp_data9);
+ if (!tmp_data9)
+ {
+ delete [] data;
+ fclose(fp);
+ return false;
+ }
+
+ size7 = decrypt(data + part2addr, tmp_data7);
+ if (!tmp_data7)
+ {
+ delete [] tmp_data9;
+ delete [] data;
+ fclose(fp);
+ return false;
+ }
+
+ uint16_t crc16_mine = getBootCodeCRC16();
+
+ if (crc16_mine != header.part12_boot_crc16)
+ {
+ //INFO("Firmware: ERROR: the boot code CRC16 (0x%04X) doesn't match the value in the firmware header (0x%04X)", crc16_mine, header.part12_boot_crc16);
+ delete [] tmp_data9;
+ delete [] tmp_data7;
+ delete [] data;
+ fclose(fp);
+ return false;
+ }
+
+ // Copy firmware boot codes to their respective locations
+ src = 0;
+ for(uint32_t i = 0; i < (size9 >> 2); i++)
+ {
+ _MMU_write32<ARMCPU_ARM9>(part1ram, T1ReadLong(tmp_data9, src));
+ src += 4; part1ram += 4;
+ }
+
+ src = 0;
+ for(uint32_t i = 0; i < (size7 >> 2); i++)
+ {
+ _MMU_write32<ARMCPU_ARM7>(part2ram, T1ReadLong(tmp_data7, src));
+ src += 4; part2ram += 4;
+ }
+ delete [] tmp_data7;
+ delete [] tmp_data9;
+
+ patched = false;
+ if (data[0x17C] != 0xFF)
+ patched = true;
+
+ //INFO("Firmware:\n");
+ //INFO("- path: %s\n", CommonSettings.Firmware);
+ //INFO("- size: %i bytes (%i Mbit)\n", size, size/1024/8);
+ //INFO("- CRC : 0x%04X\n", header.part12_boot_crc16);
+ //INFO("- header: \n");
+ //INFO(" * size firmware %i\n", ((header.shift_amounts >> 12) & 0xF) * 128 * 1024);
+ //INFO(" * ARM9 boot code address: 0x%08X\n", part1addr);
+ //INFO(" * ARM9 boot code RAM address: 0x%08X\n", ARM9bootAddr);
+ //INFO(" * ARM9 unpacked size: 0x%08X (%i) bytes\n", size9, size9);
+ //INFO(" * ARM9 GUI code address: 0x%08X\n", part3addr);
+ //INFO("\n");
+ //INFO(" * ARM7 boot code address: 0x%08X\n", part2addr);
+ //INFO(" * ARM7 boot code RAM address: 0x%08X\n", ARM7bootAddr);
+ //INFO(" * ARM7 WiFi code address: 0x%08X\n", part4addr);
+ //INFO(" * ARM7 unpacked size: 0x%08X (%i) bytes\n", size7, size7);
+ //INFO("\n");
+ //INFO(" * Data/GFX address: 0x%08X\n", part5addr);
+
+ if (patched)
+ {
+ uint32_t patch_offset = 0x3FC80;
+ if (data[0x17C] > 1)
+ patch_offset = 0x3F680;
+
+ memcpy(&header, data + patch_offset, sizeof(header));
+
+ shift1 = ((header.shift_amounts >> 0) & 0x07);
+ shift2 = ((header.shift_amounts >> 3) & 0x07);
+ shift3 = ((header.shift_amounts >> 6) & 0x07);
+ shift4 = ((header.shift_amounts >> 9) & 0x07);
+
+ // todo - add support for 512Kb
+ part1addr = (header.part1_rom_boot9_addr << (2 + shift1));
+ part1ram = (0x02800000 - (header.part1_ram_boot9_addr << (2+shift2)));
+ part2addr = (header.part2_rom_boot7_addr << (2+shift3));
+ part2ram = (0x03810000 - (header.part2_ram_boot7_addr << (2+shift4)));
+
+ ARM9bootAddr = part1ram;
+ ARM7bootAddr = part2ram;
+
+ size9 = decompress(data + part1addr, tmp_data9);
+ if (!tmp_data9)
+ {
+ delete [] data;
+ fclose(fp);
+ return false;
+ }
+
+ size7 = decompress(data + part2addr, tmp_data7);
+ if (!tmp_data7)
+ {
+ delete [] tmp_data9;
+ delete [] data;
+ fclose(fp);
+ return false;
+ };
+ // Copy firmware boot codes to their respective locations
+ src = 0;
+ for(uint32_t i = 0; i < (size9 >> 2); i++)
+ {
+ _MMU_write32<ARMCPU_ARM9>(part1ram, T1ReadLong(tmp_data9, src));
+ src += 4; part1ram += 4;
+ }
+
+ src = 0;
+ for(uint32_t i = 0; i < (size7 >> 2); i++)
+ {
+ _MMU_write32<ARMCPU_ARM7>(part2ram, T1ReadLong(tmp_data7, src));
+ src += 4; part2ram += 4;
+ }
+ delete [] tmp_data7;
+ delete [] tmp_data9;
+
+ //INFO("\nFlashme:\n");
+ //INFO("- header: \n");
+ //INFO(" * ARM9 boot code address: 0x%08X\n", part1addr);
+ //INFO(" * ARM9 boot code RAM address: 0x%08X\n", ARM9bootAddr);
+ //INFO(" * ARM9 unpacked size: 0x%08X (%i) bytes\n", size9, size9);
+ //INFO("\n");
+ //INFO(" * ARM7 boot code address: 0x%08X\n", part2addr);
+ //INFO(" * ARM7 boot code RAM address: 0x%08X\n", ARM7bootAddr);
+ //INFO(" * ARM7 unpacked size: 0x%08X (%i) bytes\n", size7, size7);
+ }
+
+ // Generate the path for the external firmware config file.
+ std::string extFilePath = CFIRMWARE::GetExternalFilePath();
+ strncpy(MMU.fw.userfile, extFilePath.c_str(), MAX_PATH);
+
+ fclose(fp);
+ fp = fopen(MMU.fw.userfile, "rb");
+ if (fp)
+ {
+ char buf[0x300];
+ memset(buf, 0, 0x300);
+ if (fread(buf, 1, 0x100, fp) == 0x100)
+ {
+ printf("- loaded from %s:\n", MMU.fw.userfile);
+ memcpy(&data[0x3FE00], &buf[0], 0x100);
+ memcpy(&data[0x3FF00], &buf[0], 0x100);
+ printf(" * User settings\n");
+ memset(buf, 0, 0x100);
+ if (fread(buf, 1, 0x1D6, fp) == 0x1D6)
+ {
+ memcpy(&data[0x002A], &buf[0], 0x1D6);
+ printf(" * WiFi settings\n");
+
+ memset(buf, 0, 0x1D6);
+ if (fread(buf, 1, 0x300, fp) == 0x300)
+ {
+ memcpy(&data[0x3FA00], &buf[0], 0x300);
+ printf(" * WiFi AP settings\n");
+ }
+ }
+
+ }
+ fclose(fp);
+ }
+ printf("\n");
+
+ // TODO: add 512Kb support
+ memcpy(&MMU.fw.data[0], data, 256*1024);
+ MMU.fw.fp = NULL;
+
+ delete [] data; data = NULL;
+ return true;
+}
+
+std::string CFIRMWARE::GetExternalFilePath()
+{
+ std::string fwPath = CommonSettings.Firmware;
+ std::string fwFileName = Path::GetFileNameFromPathWithoutExt(fwPath);
+ std::string configPath = path.pathToBattery;
+ std::string finalPath = configPath + DIRECTORY_DELIMITER_CHAR + fwFileName + FILE_EXT_DELIMITER_CHAR + FW_CONFIG_FILE_EXT;
+
+ return finalPath;
+}
+
+//=====================================================================================================
+static uint32_t
+calc_CRC16( uint32_t start, const uint8_t *data, int count) {
+ int i,j;
+ uint32_t crc = start & 0xffff;
+ const uint16_t val[8] = { 0xC0C1,0xC181,0xC301,0xC601,0xCC01,0xD801,0xF001,0xA001 };
+ for(i = 0; i < count; i++)
+ {
+ crc = crc ^ data[i];
+
+ for(j = 0; j < 8; j++) {
+ int do_bit = 0;
+
+ if ( crc & 0x1)
+ do_bit = 1;
+
+ crc = crc >> 1;
+
+ if ( do_bit) {
+ crc = crc ^ (val[j] << (7-j));
+ }
+ }
+ }
+ return crc;
+}
+
+int copy_firmware_user_data( uint8_t *dest_buffer, const uint8_t *fw_data)
+{
+ /*
+ * Determine which of the two user settings in the firmware is the current
+ * and valid one and then copy this into the destination buffer.
+ *
+ * The current setting will have a greater count.
+ * Settings are only valid if its CRC16 is correct.
+ */
+ int user1_valid = 0;
+ int user2_valid = 0;
+ uint32_t user_settings_offset;
+ uint32_t fw_crc;
+ uint32_t crc;
+ int copy_good = 0;
+
+ user_settings_offset = fw_data[0x20];
+ user_settings_offset |= fw_data[0x21] << 8;
+ user_settings_offset <<= 3;
+
+ if ( user_settings_offset <= 0x3FE00) {
+ int32_t copy_settings_offset = -1;
+
+ crc = calc_CRC16( 0xffff, &fw_data[user_settings_offset],
+ NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT);
+ fw_crc = fw_data[user_settings_offset + 0x72];
+ fw_crc |= fw_data[user_settings_offset + 0x73] << 8;
+ if ( crc == fw_crc) {
+ user1_valid = 1;
+ }
+
+ crc = calc_CRC16( 0xffff, &fw_data[user_settings_offset + 0x100],
+ NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT);
+ fw_crc = fw_data[user_settings_offset + 0x100 + 0x72];
+ fw_crc |= fw_data[user_settings_offset + 0x100 + 0x73] << 8;
+ if ( crc == fw_crc) {
+ user2_valid = 1;
+ }
+
+ if ( user1_valid) {
+ if ( user2_valid) {
+ uint16_t count1, count2;
+
+ count1 = fw_data[user_settings_offset + 0x70];
+ count1 |= fw_data[user_settings_offset + 0x71] << 8;
+
+ count2 = fw_data[user_settings_offset + 0x100 + 0x70];
+ count2 |= fw_data[user_settings_offset + 0x100 + 0x71] << 8;
+
+ if ( count2 > count1) {
+ copy_settings_offset = user_settings_offset + 0x100;
+ }
+ else {
+ copy_settings_offset = user_settings_offset;
+ }
+ }
+ else {
+ copy_settings_offset = user_settings_offset;
+ }
+ }
+ else if ( user2_valid) {
+ /* copy the second user settings */
+ copy_settings_offset = user_settings_offset + 0x100;
+ }
+
+ if ( copy_settings_offset > 0) {
+ memcpy( dest_buffer, &fw_data[copy_settings_offset],
+ NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT);
+ copy_good = 1;
+ }
+ }
+
+ return copy_good;
+}
+
+/*static void fill_user_data_area( struct NDS_fw_config_data *user_settings,uint8_t *data, int count)
+{
+ uint32_t crc;
+ int i;
+ //uint8_t *ts_cal_data_area;
+
+ memset( data, 0, 0x100);
+
+ // version
+ data[0x00] = 5;
+ data[0x01] = 0;
+
+ // colour
+ data[0x02] = user_settings->fav_colour;
+
+ // birthday month and day
+ data[0x03] = user_settings->birth_month;
+ data[0x04] = user_settings->birth_day;
+
+ //nickname and length
+ for ( i = 0; i < MAX_FW_NICKNAME_LENGTH; i++) {
+ data[0x06 + (i * 2)] = user_settings->nickname[i] & 0xff;
+ data[0x06 + (i * 2) + 1] = (user_settings->nickname[i] >> 8) & 0xff;
+ }
+
+ data[0x1a] = user_settings->nickname_len;
+
+ //Message
+ for ( i = 0; i < MAX_FW_MESSAGE_LENGTH; i++) {
+ data[0x1c + (i * 2)] = user_settings->message[i] & 0xff;
+ data[0x1c + (i * 2) + 1] = (user_settings->message[i] >> 8) & 0xff;
+ }
+
+ data[0x50] = user_settings->message_len;*/
+
+ //touch screen calibration
+ /*ts_cal_data_area = &data[0x58];
+ for ( i = 0; i < 2; i++) {
+ // ADC x y
+ *ts_cal_data_area++ = user_settings->touch_cal[i].adc_x & 0xff;
+ *ts_cal_data_area++ = (user_settings->touch_cal[i].adc_x >> 8) & 0xff;
+ *ts_cal_data_area++ = user_settings->touch_cal[i].adc_y & 0xff;
+ *ts_cal_data_area++ = (user_settings->touch_cal[i].adc_y >> 8) & 0xff;
+
+ //screen x y
+ *ts_cal_data_area++ = user_settings->touch_cal[i].screen_x;
+ *ts_cal_data_area++ = user_settings->touch_cal[i].screen_y;
+ }*/
+
+ //language and flags
+ /*data[0x64] = user_settings->language;
+ data[0x65] = 0xfc;
+
+ //update count and crc
+ data[0x70] = count & 0xff;
+ data[0x71] = (count >> 8) & 0xff;
+
+ crc = calc_CRC16( 0xffff, data, 0x70);
+ data[0x72] = crc & 0xff;
+ data[0x73] = (crc >> 8) & 0xff;
+
+ memset( &data[0x74], 0xff, 0x100 - 0x74);
+}*/
+
+// creates an firmware flash image, which contains all needed info to initiate a wifi connection
+/*int NDS_CreateDummyFirmware( struct NDS_fw_config_data *user_settings)
+{
+ //Create the firmware header
+
+ memset(&MMU.fw.data[0], 0, 0x40000);
+
+ //firmware identifier
+ MMU.fw.data[0x8] = 'M';
+ MMU.fw.data[0x8 + 1] = 'A';
+ MMU.fw.data[0x8 + 2] = 'C';
+ MMU.fw.data[0x8 + 3] = 'P';
+
+ // DS type
+ if ( user_settings->ds_type == NDS_FW_DS_TYPE_LITE)
+ MMU.fw.data[0x1d] = 0x20;
+ else
+ MMU.fw.data[0x1d] = 0xff;
+
+ //User Settings offset 0x3fe00 / 8
+ MMU.fw.data[0x20] = 0xc0;
+ MMU.fw.data[0x21] = 0x7f;
+
+
+ //User settings (at 0x3FE00 and 0x3FF00)
+
+ fill_user_data_area( user_settings, &MMU.fw.data[ 0x3FE00], 0);
+ fill_user_data_area( user_settings, &MMU.fw.data[ 0x3FF00], 1);
+
+ // Wifi config length
+ //MMU.fw.data[0x2C] = 0x38;
+ //MMU.fw.data[0x2D] = 0x01;
+
+ //MMU.fw.data[0x2E] = 0x00;
+
+ //Wifi version
+ //MMU.fw.data[0x2F] = 0x00;
+
+ //MAC address
+ //memcpy((MMU.fw.data + 0x36), FW_Mac, sizeof(FW_Mac));
+
+ //Enabled channels
+ MMU.fw.data[0x3C] = 0xFE;
+ MMU.fw.data[0x3D] = 0x3F;
+
+ MMU.fw.data[0x3E] = 0xFF;
+ MMU.fw.data[0x3F] = 0xFF;
+
+ //RF related
+ MMU.fw.data[0x40] = 0x02;
+ MMU.fw.data[0x41] = 0x18;
+ MMU.fw.data[0x42] = 0x0C;
+
+ MMU.fw.data[0x43] = 0x01;
+
+ //Wifi I/O init values
+ //memcpy((MMU.fw.data + 0x44), FW_WIFIInit, sizeof(FW_WIFIInit));
+
+ //Wifi BB init values
+ //memcpy((MMU.fw.data + 0x64), FW_BBInit, sizeof(FW_BBInit));
+
+ //Wifi RF init values
+ //memcpy((MMU.fw.data + 0xCE), FW_RFInit, sizeof(FW_RFInit));
+
+ //Wifi channel-related init values
+ //memcpy((MMU.fw.data + 0xF2), FW_RFChannel, sizeof(FW_RFChannel));
+ //memcpy((MMU.fw.data + 0x146), FW_BBChannel, sizeof(FW_BBChannel));
+ memset(&MMU.fw.data[0x154], 0x10, 0xE);*/
+
+ //WFC profiles
+ /*memcpy((MMU.fw.data + 0x3FA40), &FW_WFCProfile1, sizeof(FW_WFCProfile));
+ memcpy((MMU.fw.data + 0x3FB40), &FW_WFCProfile2, sizeof(FW_WFCProfile));
+ memcpy((MMU.fw.data + 0x3FC40), &FW_WFCProfile3, sizeof(FW_WFCProfile));
+ (*(uint16_t*)(MMU.fw.data + 0x3FAFE)) = (uint16_t)calc_CRC16(0, (MMU.fw.data + 0x3FA00), 0xFE);
+ (*(uint16_t*)(MMU.fw.data + 0x3FBFE)) = (uint16_t)calc_CRC16(0, (MMU.fw.data + 0x3FB00), 0xFE);
+ (*(uint16_t*)(MMU.fw.data + 0x3FCFE)) = (uint16_t)calc_CRC16(0, (MMU.fw.data + 0x3FC00), 0xFE);*/
+
+
+ /*MMU.fw.data[0x162] = 0x19;
+ memset(&MMU.fw.data[0x163], 0xFF, 0x9D);
+
+ //Wifi settings CRC16
+ (*(uint16_t*)(&MMU.fw.data[0x2A])) = calc_CRC16(0, &MMU.fw.data[0x2C], 0x138);
+
+ if (&CommonSettings.InternalFirmConf != user_settings)
+ memcpy(&CommonSettings.InternalFirmConf, user_settings, sizeof(struct NDS_fw_config_data));
+
+ return true ;
+}*/
+
+void NDS_FillDefaultFirmwareConfigData( struct NDS_fw_config_data *fw_config) {
+ const char *default_nickname = "DeSmuME";
+ const char *default_message = "DeSmuME makes you happy!";
+ int i;
+ int str_length;
+
+ memset( fw_config, 0, sizeof( struct NDS_fw_config_data));
+ fw_config->ds_type = NDS_CONSOLE_TYPE_FAT;
+
+ fw_config->fav_colour = 7;
+
+ fw_config->birth_day = 23;
+ fw_config->birth_month = 6;
+
+ str_length = strlen( default_nickname);
+ for ( i = 0; i < str_length; i++) {
+ fw_config->nickname[i] = default_nickname[i];
+ }
+ fw_config->nickname_len = str_length;
+
+ str_length = strlen( default_message);
+ for ( i = 0; i < str_length; i++) {
+ fw_config->message[i] = default_message[i];
+ }
+ fw_config->message_len = str_length;
+
+ /* default to English */
+ fw_config->language = 1;
+
+ /* default touchscreen calibration */
+ //fw_config->touch_cal[0].adc_x = 0x200;
+ //fw_config->touch_cal[0].adc_y = 0x200;
+ //fw_config->touch_cal[0].screen_x = 0x20 + 1; // calibration screen coords are 1-based,
+ //fw_config->touch_cal[0].screen_y = 0x20 + 1; // either that or NDS_getADCTouchPosX/Y are wrong.
+
+ //fw_config->touch_cal[1].adc_x = 0xe00;
+ //fw_config->touch_cal[1].adc_y = 0x800;
+ //fw_config->touch_cal[1].screen_x = 0xe0 + 1;
+ //fw_config->touch_cal[1].screen_y = 0x80 + 1;
+}
+
+/*void NDS_PatchFirmwareMAC()
+{
+ //memcpy((MMU.fw.data + 0x36), FW_Mac, sizeof(FW_Mac));
+ //(*(uint16_t*)(MMU.fw.data + 0x2A)) = calc_CRC16(0, (MMU.fw.data + 0x2C), 0x138);
+}*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/firmware.h
@@ -1,1 +1,89 @@
+/*
+ Copyright (C) 2009-2011 DeSmuME Team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _FIRMWARE_H_
+#define _FIRMWARE_H_
+
+#include "common.h"
+
+// the count of bytes copied from the firmware into memory
+static const int NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT = 0x70;
+
+#define FW_CONFIG_FILE_EXT "dfc"
+
+class CFIRMWARE
+{
+private:
+ uint8_t *tmp_data9;
+ uint8_t *tmp_data7;
+ uint32_t size9, size7;
+
+ uint32_t keyBuf[0x412];
+ uint32_t keyCode[3];
+
+ bool getKeyBuf();
+ void crypt64BitUp(uint32_t *ptr);
+ void crypt64BitDown(uint32_t *ptr);
+ void applyKeycode(uint32_t modulo);
+ bool initKeycode(uint32_t idCode, int level, uint32_t modulo);
+ uint16_t getBootCodeCRC16();
+ uint32_t decrypt(const uint8_t *in, uint8_t* &out);
+ uint32_t decompress(const uint8_t *in, uint8_t* &out);
+
+public:
+ CFIRMWARE(): size9(0), size7(0), ARM9bootAddr(0), ARM7bootAddr(0), patched(0) {}
+
+ bool load();
+
+ static std::string GetExternalFilePath();
+
+ struct HEADER
+ {
+ uint16_t part3_rom_gui9_addr; // 000h
+ uint16_t part4_rom_wifi7_addr; // 002h
+ uint16_t part34_gui_wifi_crc16; // 004h
+ uint16_t part12_boot_crc16; // 006h
+ uint8_t fw_identifier[4]; // 008h
+ uint16_t part1_rom_boot9_addr; // 00Ch
+ uint16_t part1_ram_boot9_addr; // 00Eh
+ uint16_t part2_rom_boot7_addr; // 010h
+ uint16_t part2_ram_boot7_addr; // 012h
+ uint16_t shift_amounts; // 014h
+ uint16_t part5_data_gfx_addr; // 016h
+
+ uint8_t fw_timestamp[5]; // 018h
+ uint8_t console_type; // 01Dh
+ uint16_t unused1; // 01Eh
+ uint16_t user_settings_offset; // 020h
+ uint16_t unknown1; // 022h
+ uint16_t unknown2; // 024h
+ uint16_t part5_crc16; // 026h
+ uint16_t unused2; // 028h - FFh filled
+ } header;
+
+ uint32_t ARM9bootAddr;
+ uint32_t ARM7bootAddr;
+ bool patched;
+};
+
+int copy_firmware_user_data(uint8_t *dest_buffer, const uint8_t *fw_data);
+//int NDS_CreateDummyFirmware(struct NDS_fw_config_data *user_settings);
+void NDS_FillDefaultFirmwareConfigData(struct NDS_fw_config_data *fw_config);
+//void NDS_PatchFirmwareMAC();
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/instruction_tabdef.inc
@@ -1,1 +1,4119 @@
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2007-2012 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* 0XX000X0 */
+
+/* 0000 0000 0000 */ TABDECL( OP_AND_LSL_IMM),
+/* 0000 0000 0001 */ TABDECL( OP_AND_LSL_REG),
+/* 0000 0000 0010 */ TABDECL( OP_AND_LSR_IMM),
+/* 0000 0000 0011 */ TABDECL( OP_AND_LSR_REG),
+/* 0000 0000 0100 */ TABDECL( OP_AND_ASR_IMM),
+/* 0000 0000 0101 */ TABDECL( OP_AND_ASR_REG),
+/* 0000 0000 0110 */ TABDECL( OP_AND_ROR_IMM),
+/* 0000 0000 0111 */ TABDECL( OP_AND_ROR_REG),
+/* 0000 0000 1000 */ TABDECL( OP_AND_LSL_IMM),
+/* 0000 0000 1001 */ TABDECL( OP_MUL),
+/* 0000 0000 1010 */ TABDECL( OP_AND_LSR_IMM),
+/* 0000 0000 1011 */ TABDECL( OP_STRH_POS_INDE_M_REG_OFF),
+/* 0000 0000 1100 */ TABDECL( OP_AND_ASR_IMM),
+/* 0000 0000 1101 */ TABDECL( OP_LDRD_STRD_POST_INDEX),
+/* 0000 0000 1110 */ TABDECL( OP_AND_ROR_IMM),
+/* 0000 0000 1111 */ TABDECL( OP_LDRD_STRD_POST_INDEX),
+/* 0000 0001 0000 */ TABDECL( OP_AND_S_LSL_IMM),
+/* 0000 0001 0001 */ TABDECL( OP_AND_S_LSL_REG),
+/* 0000 0001 0010 */ TABDECL( OP_AND_S_LSR_IMM),
+/* 0000 0001 0011 */ TABDECL( OP_AND_S_LSR_REG),
+/* 0000 0001 0100 */ TABDECL( OP_AND_S_ASR_IMM),
+/* 0000 0001 0101 */ TABDECL( OP_AND_S_ASR_REG),
+/* 0000 0001 0110 */ TABDECL( OP_AND_S_ROR_IMM),
+/* 0000 0001 0111 */ TABDECL( OP_AND_S_ROR_REG),
+/* 0000 0001 1000 */ TABDECL( OP_AND_S_LSL_IMM),
+/* 0000 0001 1001 */ TABDECL( OP_MUL_S),
+/* 0000 0001 1010 */ TABDECL( OP_AND_S_LSR_IMM),
+/* 0000 0001 1011 */ TABDECL( OP_LDRH_POS_INDE_M_REG_OFF),
+/* 0000 0001 1100 */ TABDECL( OP_AND_S_ASR_IMM),
+/* 0000 0001 1101 */ TABDECL( OP_LDRSB_POS_INDE_M_REG_OFF),
+/* 0000 0001 1110 */ TABDECL( OP_AND_S_ROR_IMM),
+/* 0000 0001 1111 */ TABDECL( OP_LDRSH_POS_INDE_M_REG_OFF),
+/* 0000 0010 0000 */ TABDECL( OP_EOR_LSL_IMM),
+/* 0000 0010 0001 */ TABDECL( OP_EOR_LSL_REG),
+/* 0000 0010 0010 */ TABDECL( OP_EOR_LSR_IMM),
+/* 0000 0010 0011 */ TABDECL( OP_EOR_LSR_REG),
+/* 0000 0010 0100 */ TABDECL( OP_EOR_ASR_IMM),
+/* 0000 0010 0101 */ TABDECL( OP_EOR_ASR_REG),
+/* 0000 0010 0110 */ TABDECL( OP_EOR_ROR_IMM),
+/* 0000 0010 0111 */ TABDECL( OP_EOR_ROR_REG),
+/* 0000 0010 1000 */ TABDECL( OP_EOR_LSL_IMM),
+/* 0000 0010 1001 */ TABDECL( OP_MLA),
+/* 0000 0010 1010 */ TABDECL( OP_EOR_LSR_IMM), // OOO OOO1 O 1010
+/* 0000 0010 1011 */ TABDECL( OP_UND),
+/* 0000 0010 1100 */ TABDECL( OP_EOR_ASR_IMM),
+/* 0000 0010 1101 */ TABDECL( OP_UND),
+/* 0000 0010 1110 */ TABDECL( OP_EOR_ROR_IMM),
+/* 0000 0010 1111 */ TABDECL( OP_UND),
+/* 0000 0011 0000 */ TABDECL( OP_EOR_S_LSL_IMM),
+/* 0000 0011 0001 */ TABDECL( OP_EOR_S_LSL_REG),
+/* 0000 0011 0010 */ TABDECL( OP_EOR_S_LSR_IMM),
+/* 0000 0011 0011 */ TABDECL( OP_EOR_S_LSR_REG),
+/* 0000 0011 0100 */ TABDECL( OP_EOR_S_ASR_IMM),
+/* 0000 0011 0101 */ TABDECL( OP_EOR_S_ASR_REG),
+/* 0000 0011 0110 */ TABDECL( OP_EOR_S_ROR_IMM),
+/* 0000 0011 0111 */ TABDECL( OP_EOR_S_ROR_REG),
+/* 0000 0011 1000 */ TABDECL( OP_EOR_S_LSL_IMM),
+/* 0000 0011 1001 */ TABDECL( OP_MLA_S),
+/* 0000 0011 1010 */ TABDECL( OP_EOR_S_LSR_IMM),
+/* 0000 0011 1011 */ TABDECL( OP_UND),
+/* 0000 0011 1100 */ TABDECL( OP_EOR_S_ASR_IMM),
+/* 0000 0011 1101 */ TABDECL( OP_UND),
+/* 0000 0011 1110 */ TABDECL( OP_EOR_S_ROR_IMM),
+/* 0000 0011 1111 */ TABDECL( OP_UND),
+/* 0000 0100 0000 */ TABDECL( OP_SUB_LSL_IMM),
+/* 0000 0100 0001 */ TABDECL( OP_SUB_LSL_REG),
+/* 0000 0100 0010 */ TABDECL( OP_SUB_LSR_IMM),
+/* 0000 0100 0011 */ TABDECL( OP_SUB_LSR_REG),
+/* 0000 0100 0100 */ TABDECL( OP_SUB_ASR_IMM),
+/* 0000 0100 0101 */ TABDECL( OP_SUB_ASR_REG),
+/* 0000 0100 0110 */ TABDECL( OP_SUB_ROR_IMM),
+/* 0000 0100 0111 */ TABDECL( OP_SUB_ROR_REG),
+/* 0000 0100 1000 */ TABDECL( OP_SUB_LSL_IMM),
+/* 0000 0100 1001 */ TABDECL( OP_UND),
+/* 0000 0100 1010 */ TABDECL( OP_SUB_LSR_IMM), // OOO OO1O O 1010
+/* 0000 0100 1011 */ TABDECL( OP_STRH_POS_INDE_M_IMM_OFF),
+/* 0000 0100 1100 */ TABDECL( OP_SUB_ASR_IMM),
+/* 0000 0100 1101 */ TABDECL( OP_LDRD_STRD_POST_INDEX),
+/* 0000 0100 1110 */ TABDECL( OP_SUB_ROR_IMM),
+/* 0000 0100 1111 */ TABDECL( OP_LDRD_STRD_POST_INDEX),
+/* 0000 0101 0000 */ TABDECL( OP_SUB_S_LSL_IMM),
+/* 0000 0101 0001 */ TABDECL( OP_SUB_S_LSL_REG),
+/* 0000 0101 0010 */ TABDECL( OP_SUB_S_LSR_IMM),
+/* 0000 0101 0011 */ TABDECL( OP_SUB_S_LSR_REG),
+/* 0000 0101 0100 */ TABDECL( OP_SUB_S_ASR_IMM),
+/* 0000 0101 0101 */ TABDECL( OP_SUB_S_ASR_REG),
+/* 0000 0101 0110 */ TABDECL( OP_SUB_S_ROR_IMM),
+/* 0000 0101 0111 */ TABDECL( OP_SUB_S_ROR_REG),
+/* 0000 0101 1000 */ TABDECL( OP_SUB_S_LSL_IMM),
+/* 0000 0101 1001 */ TABDECL( OP_UND),
+/* 0000 0101 1010 */ TABDECL( OP_SUB_S_LSR_IMM),
+/* 0000 0101 1011 */ TABDECL( OP_LDRH_POS_INDE_M_IMM_OFF),
+/* 0000 0101 1100 */ TABDECL( OP_SUB_S_ASR_IMM),
+/* 0000 0101 1101 */ TABDECL( OP_LDRSB_POS_INDE_M_IMM_OFF),
+/* 0000 0101 1110 */ TABDECL( OP_SUB_S_ROR_IMM),
+/* 0000 0101 1111 */ TABDECL( OP_LDRSH_POS_INDE_M_IMM_OFF),
+/* 0000 0110 0000 */ TABDECL( OP_RSB_LSL_IMM),
+/* 0000 0110 0001 */ TABDECL( OP_RSB_LSL_REG),
+/* 0000 0110 0010 */ TABDECL( OP_RSB_LSR_IMM),
+/* 0000 0110 0011 */ TABDECL( OP_RSB_LSR_REG),
+/* 0000 0110 0100 */ TABDECL( OP_RSB_ASR_IMM),
+/* 0000 0110 0101 */ TABDECL( OP_RSB_ASR_REG),
+/* 0000 0110 0110 */ TABDECL( OP_RSB_ROR_IMM),
+/* 0000 0110 0111 */ TABDECL( OP_RSB_ROR_REG),
+/* 0000 0110 1000 */ TABDECL( OP_RSB_LSL_IMM),
+/* 0000 0110 1001 */ TABDECL( OP_UND),
+/* 0000 0110 1010 */ TABDECL( OP_RSB_LSR_IMM), // OOO OO11 O 1010
+/* 0000 0110 1011 */ TABDECL( OP_UND),
+/* 0000 0110 1100 */ TABDECL( OP_RSB_ASR_IMM),
+/* 0000 0110 1101 */ TABDECL( OP_UND),
+/* 0000 0110 1110 */ TABDECL( OP_RSB_ROR_IMM),
+/* 0000 0110 1111 */ TABDECL( OP_UND),
+/* 0000 0111 0000 */ TABDECL( OP_RSB_S_LSL_IMM),
+/* 0000 0111 0001 */ TABDECL( OP_RSB_S_LSL_REG),
+/* 0000 0111 0010 */ TABDECL( OP_RSB_S_LSR_IMM),
+/* 0000 0111 0011 */ TABDECL( OP_RSB_S_LSR_REG),
+/* 0000 0111 0100 */ TABDECL( OP_RSB_S_ASR_IMM),
+/* 0000 0111 0101 */ TABDECL( OP_RSB_S_ASR_REG),
+/* 0000 0111 0110 */ TABDECL( OP_RSB_S_ROR_IMM),
+/* 0000 0111 0111 */ TABDECL( OP_RSB_S_ROR_REG),
+/* 0000 0111 1000 */ TABDECL( OP_RSB_S_LSL_IMM),
+/* 0000 0111 1001 */ TABDECL( OP_UND),
+/* 0000 0111 1010 */ TABDECL( OP_RSB_S_LSR_IMM),
+/* 0000 0111 1011 */ TABDECL( OP_UND),
+/* 0000 0111 1100 */ TABDECL( OP_RSB_S_ASR_IMM),
+/* 0000 0111 1101 */ TABDECL( OP_UND),
+/* 0000 0111 1110 */ TABDECL( OP_RSB_S_ROR_IMM),
+/* 0000 0111 1111 */ TABDECL( OP_UND),
+/* 0000 1000 0000 */ TABDECL( OP_ADD_LSL_IMM),
+/* 0000 1000 0001 */ TABDECL( OP_ADD_LSL_REG),
+/* 0000 1000 0010 */ TABDECL( OP_ADD_LSR_IMM),
+/* 0000 1000 0011 */ TABDECL( OP_ADD_LSR_REG),
+/* 0000 1000 0100 */ TABDECL( OP_ADD_ASR_IMM),
+/* 0000 1000 0101 */ TABDECL( OP_ADD_ASR_REG),
+/* 0000 1000 0110 */ TABDECL( OP_ADD_ROR_IMM),
+/* 0000 1000 0111 */ TABDECL( OP_ADD_ROR_REG),
+/* 0000 1000 1000 */ TABDECL( OP_ADD_LSL_IMM),
+/* 0000 1000 1001 */ TABDECL( OP_UMULL),
+/* 0000 1000 1010 */ TABDECL( OP_ADD_LSR_IMM), // OOO O10O O 1010
+/* 0000 1000 1011 */ TABDECL( OP_STRH_POS_INDE_P_REG_OFF),
+/* 0000 1000 1100 */ TABDECL( OP_ADD_ASR_IMM),
+/* 0000 1000 1101 */ TABDECL( OP_LDRD_STRD_POST_INDEX),
+/* 0000 1000 1110 */ TABDECL( OP_ADD_ROR_IMM),
+/* 0000 1000 1111 */ TABDECL( OP_LDRD_STRD_POST_INDEX),
+/* 0000 1001 0000 */ TABDECL( OP_ADD_S_LSL_IMM),
+/* 0000 1001 0001 */ TABDECL( OP_ADD_S_LSL_REG),
+/* 0000 1001 0010 */ TABDECL( OP_ADD_S_LSR_IMM),
+/* 0000 1001 0011 */ TABDECL( OP_ADD_S_LSR_REG),
+/* 0000 1001 0100 */ TABDECL( OP_ADD_S_ASR_IMM),
+/* 0000 1001 0101 */ TABDECL( OP_ADD_S_ASR_REG),
+/* 0000 1001 0110 */ TABDECL( OP_ADD_S_ROR_IMM),
+/* 0000 1001 0111 */ TABDECL( OP_ADD_S_ROR_REG),
+/* 0000 1001 1000 */ TABDECL( OP_ADD_S_LSL_IMM),
+/* 0000 1001 1001 */ TABDECL( OP_UMULL_S),
+/* 0000 1001 1010 */ TABDECL( OP_ADD_S_LSR_IMM),
+/* 0000 1001 1011 */ TABDECL( OP_LDRH_POS_INDE_P_REG_OFF),
+/* 0000 1001 1100 */ TABDECL( OP_ADD_S_ASR_IMM),
+/* 0000 1001 1101 */ TABDECL( OP_LDRSB_POS_INDE_P_REG_OFF),
+/* 0000 1001 1110 */ TABDECL( OP_ADD_S_ROR_IMM),
+/* 0000 1001 1111 */ TABDECL( OP_LDRSH_POS_INDE_P_REG_OFF),
+/* 0000 1010 0000 */ TABDECL( OP_ADC_LSL_IMM),
+/* 0000 1010 0001 */ TABDECL( OP_ADC_LSL_REG),
+/* 0000 1010 0010 */ TABDECL( OP_ADC_LSR_IMM),
+/* 0000 1010 0011 */ TABDECL( OP_ADC_LSR_REG),
+/* 0000 1010 0100 */ TABDECL( OP_ADC_ASR_IMM),
+/* 0000 1010 0101 */ TABDECL( OP_ADC_ASR_REG),
+/* 0000 1010 0110 */ TABDECL( OP_ADC_ROR_IMM),
+/* 0000 1010 0111 */ TABDECL( OP_ADC_ROR_REG),
+/* 0000 1010 1000 */ TABDECL( OP_ADC_LSL_IMM),
+/* 0000 1010 1001 */ TABDECL( OP_UMLAL),
+/* 0000 1010 1010 */ TABDECL( OP_ADC_LSR_IMM), // OOO O101 O 1010
+/* 0000 1010 1011 */ TABDECL( OP_UND),
+/* 0000 1010 1100 */ TABDECL( OP_ADC_ASR_IMM),
+/* 0000 1010 1101 */ TABDECL( OP_UND),
+/* 0000 1010 1110 */ TABDECL( OP_ADC_ROR_IMM),
+/* 0000 1010 1111 */ TABDECL( OP_UND),
+/* 0000 1011 0000 */ TABDECL( OP_ADC_S_LSL_IMM),
+/* 0000 1011 0001 */ TABDECL( OP_ADC_S_LSL_REG),
+/* 0000 1011 0010 */ TABDECL( OP_ADC_S_LSR_IMM),
+/* 0000 1011 0011 */ TABDECL( OP_ADC_S_LSR_REG),
+/* 0000 1011 0100 */ TABDECL( OP_ADC_S_ASR_IMM),
+/* 0000 1011 0101 */ TABDECL( OP_ADC_S_ASR_REG),
+/* 0000 1011 0110 */ TABDECL( OP_ADC_S_ROR_IMM),
+/* 0000 1011 0111 */ TABDECL( OP_ADC_S_ROR_REG),
+/* 0000 1011 1000 */ TABDECL( OP_ADC_S_LSL_IMM),
+/* 0000 1011 1001 */ TABDECL( OP_UMLAL_S),
+/* 0000 1011 1010 */ TABDECL( OP_ADC_S_LSR_IMM),
+/* 0000 1011 1011 */ TABDECL( OP_UND),
+/* 0000 1011 1100 */ TABDECL( OP_ADC_S_ASR_IMM),
+/* 0000 1011 1101 */ TABDECL( OP_UND),
+/* 0000 1011 1110 */ TABDECL( OP_ADC_S_ROR_IMM),
+/* 0000 1011 1111 */ TABDECL( OP_UND),
+/* 0000 1100 0000 */ TABDECL( OP_SBC_LSL_IMM),
+/* 0000 1100 0001 */ TABDECL( OP_SBC_LSL_REG),
+/* 0000 1100 0010 */ TABDECL( OP_SBC_LSR_IMM),
+/* 0000 1100 0011 */ TABDECL( OP_SBC_LSR_REG),
+/* 0000 1100 0100 */ TABDECL( OP_SBC_ASR_IMM),
+/* 0000 1100 0101 */ TABDECL( OP_SBC_ASR_REG),
+/* 0000 1100 0110 */ TABDECL( OP_SBC_ROR_IMM),
+/* 0000 1100 0111 */ TABDECL( OP_SBC_ROR_REG),
+/* 0000 1100 1000 */ TABDECL( OP_SBC_LSL_IMM),
+/* 0000 1100 1001 */ TABDECL( OP_SMULL),
+/* 0000 1100 1010 */ TABDECL( OP_SBC_LSR_IMM), // OOO O11O O 1010
+/* 0000 1100 1011 */ TABDECL( OP_STRH_POS_INDE_P_IMM_OFF),
+/* 0000 1100 1100 */ TABDECL( OP_SBC_ASR_IMM),
+/* 0000 1100 1101 */ TABDECL( OP_LDRD_STRD_POST_INDEX),
+/* 0000 1100 1110 */ TABDECL( OP_SBC_ROR_IMM),
+/* 0000 1100 1111 */ TABDECL( OP_LDRD_STRD_POST_INDEX),
+/* 0000 1101 0000 */ TABDECL( OP_SBC_S_LSL_IMM),
+/* 0000 1101 0001 */ TABDECL( OP_SBC_S_LSL_REG),
+/* 0000 1101 0010 */ TABDECL( OP_SBC_S_LSR_IMM),
+/* 0000 1101 0011 */ TABDECL( OP_SBC_S_LSR_REG),
+/* 0000 1101 0100 */ TABDECL( OP_SBC_S_ASR_IMM),
+/* 0000 1101 0101 */ TABDECL( OP_SBC_S_ASR_REG),
+/* 0000 1101 0110 */ TABDECL( OP_SBC_S_ROR_IMM),
+/* 0000 1101 0111 */ TABDECL( OP_SBC_S_ROR_REG),
+/* 0000 1101 1000 */ TABDECL( OP_SBC_S_LSL_IMM),
+/* 0000 1101 1001 */ TABDECL( OP_SMULL_S),
+/* 0000 1101 1010 */ TABDECL( OP_SBC_S_LSR_IMM),
+/* 0000 1101 1011 */ TABDECL( OP_LDRH_POS_INDE_P_IMM_OFF),
+/* 0000 1101 1100 */ TABDECL( OP_SBC_S_ASR_IMM),
+/* 0000 1101 1101 */ TABDECL( OP_LDRSB_POS_INDE_P_IMM_OFF),
+/* 0000 1101 1110 */ TABDECL( OP_SBC_S_ROR_IMM),
+/* 0000 1101 1111 */ TABDECL( OP_LDRSH_POS_INDE_P_IMM_OFF),
+/* 0000 1110 0000 */ TABDECL( OP_RSC_LSL_IMM),
+/* 0000 1110 0001 */ TABDECL( OP_RSC_LSL_REG),
+/* 0000 1110 0010 */ TABDECL( OP_RSC_LSR_IMM),
+/* 0000 1110 0011 */ TABDECL( OP_RSC_LSR_REG),
+/* 0000 1110 0100 */ TABDECL( OP_RSC_ASR_IMM),
+/* 0000 1110 0101 */ TABDECL( OP_RSC_ASR_REG),
+/* 0000 1110 0110 */ TABDECL( OP_RSC_ROR_IMM),
+/* 0000 1110 0111 */ TABDECL( OP_RSC_ROR_REG),
+/* 0000 1110 1000 */ TABDECL( OP_RSC_LSL_IMM),
+/* 0000 1110 1001 */ TABDECL( OP_SMLAL),
+/* 0000 1110 1010 */ TABDECL( OP_RSC_LSR_IMM), // OOO O111 O 1010
+/* 0000 1110 1011 */ TABDECL( OP_UND),
+/* 0000 1110 1100 */ TABDECL( OP_RSC_ASR_IMM),
+/* 0000 1110 1101 */ TABDECL( OP_UND),
+/* 0000 1110 1110 */ TABDECL( OP_RSC_ROR_IMM),
+/* 0000 1110 1111 */ TABDECL( OP_UND),
+/* 0000 1111 0000 */ TABDECL( OP_RSC_S_LSL_IMM),
+/* 0000 1111 0001 */ TABDECL( OP_RSC_S_LSL_REG),
+/* 0000 1111 0010 */ TABDECL( OP_RSC_S_LSR_IMM),
+/* 0000 1111 0011 */ TABDECL( OP_RSC_S_LSR_REG),
+/* 0000 1111 0100 */ TABDECL( OP_RSC_S_ASR_IMM),
+/* 0000 1111 0101 */ TABDECL( OP_RSC_S_ASR_REG),
+/* 0000 1111 0110 */ TABDECL( OP_RSC_S_ROR_IMM),
+/* 0000 1111 0111 */ TABDECL( OP_RSC_S_ROR_REG),
+/* 0000 1111 1000 */ TABDECL( OP_RSC_S_LSL_IMM),
+/* 0000 1111 1001 */ TABDECL( OP_SMLAL_S),
+/* 0000 1111 1010 */ TABDECL( OP_RSC_S_LSR_IMM),
+/* 0000 1111 1011 */ TABDECL( OP_UND),
+/* 0000 1111 1100 */ TABDECL( OP_RSC_S_ASR_IMM),
+/* 0000 1111 1101 */ TABDECL( OP_UND),
+/* 0000 1111 1110 */ TABDECL( OP_RSC_S_ROR_IMM),
+/* 0000 1111 1111 */ TABDECL( OP_UND),
+/* 0001 0000 0000 */ TABDECL( OP_MRS_CPSR),
+/* 0001 0000 0001 */ TABDECL( OP_UND),
+/* 0001 0000 0010 */ TABDECL( OP_UND),
+/* 0001 0000 0011 */ TABDECL( OP_UND),
+/* 0001 0000 0100 */ TABDECL( OP_UND),
+/* 0001 0000 0101 */ TABDECL( OP_QADD),
+/* 0001 0000 0110 */ TABDECL( OP_UND),
+/* 0001 0000 0111 */ TABDECL( OP_UND),
+/* 0001 0000 1000 */ TABDECL( OP_SMLA_B_B),
+/* 0001 0000 1001 */ TABDECL( OP_SWP),
+/* 0001 0000 1010 */ TABDECL( OP_SMLA_T_B),
+/* 0001 0000 1011 */ TABDECL( OP_STRH_M_REG_OFF),
+/* 0001 0000 1100 */ TABDECL( OP_SMLA_B_T),
+/* 0001 0000 1101 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 0000 1110 */ TABDECL( OP_SMLA_T_T),
+/* 0001 0000 1111 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 0001 0000 */ TABDECL( OP_TST_LSL_IMM),
+/* 0001 0001 0001 */ TABDECL( OP_TST_LSL_REG),
+/* 0001 0001 0010 */ TABDECL( OP_TST_LSR_IMM),
+/* 0001 0001 0011 */ TABDECL( OP_TST_LSR_REG),
+/* 0001 0001 0100 */ TABDECL( OP_TST_ASR_IMM),
+/* 0001 0001 0101 */ TABDECL( OP_TST_ASR_REG),
+/* 0001 0001 0110 */ TABDECL( OP_TST_ROR_IMM),
+/* 0001 0001 0111 */ TABDECL( OP_TST_ROR_REG),
+/* 0001 0001 1000 */ TABDECL( OP_TST_LSL_IMM),
+/* 0001 0001 1001 */ TABDECL( OP_UND),
+/* 0001 0001 1010 */ TABDECL( OP_TST_LSR_IMM), // OOO 100O 1 1010
+/* 0001 0001 1011 */ TABDECL( OP_LDRH_M_REG_OFF),
+/* 0001 0001 1100 */ TABDECL( OP_TST_ASR_IMM),
+/* 0001 0001 1101 */ TABDECL( OP_LDRSB_M_REG_OFF),
+/* 0001 0001 1110 */ TABDECL( OP_TST_ROR_IMM),
+/* 0001 0001 1111 */ TABDECL( OP_LDRSH_M_REG_OFF),
+/* 0001 0010 0000 */ TABDECL( OP_MSR_CPSR),
+/* 0001 0010 0001 */ TABDECL( OP_BX),
+/* 0001 0010 0010 */ TABDECL( OP_UND),
+/* 0001 0010 0011 */ TABDECL( OP_BLX_REG),
+/* 0001 0010 0100 */ TABDECL( OP_UND),
+/* 0001 0010 0101 */ TABDECL( OP_QSUB),
+/* 0001 0010 0110 */ TABDECL( OP_UND),
+/* 0001 0010 0111 */ TABDECL( OP_BKPT),
+/* 0001 0010 1000 */ TABDECL( OP_SMLAW_B),
+/* 0001 0010 1001 */ TABDECL( OP_UND),
+/* 0001 0010 1010 */ TABDECL( OP_SMULW_B),
+/* 0001 0010 1011 */ TABDECL( OP_STRH_PRE_INDE_M_REG_OFF),
+/* 0001 0010 1100 */ TABDECL( OP_SMLAW_T),
+/* 0001 0010 1101 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 0010 1110 */ TABDECL( OP_SMULW_T),
+/* 0001 0010 1111 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 0011 0000 */ TABDECL( OP_TEQ_LSL_IMM),
+/* 0001 0011 0001 */ TABDECL( OP_TEQ_LSL_REG),
+/* 0001 0011 0010 */ TABDECL( OP_TEQ_LSR_IMM),
+/* 0001 0011 0011 */ TABDECL( OP_TEQ_LSR_REG),
+/* 0001 0011 0100 */ TABDECL( OP_TEQ_ASR_IMM),
+/* 0001 0011 0101 */ TABDECL( OP_TEQ_ASR_REG),
+/* 0001 0011 0110 */ TABDECL( OP_TEQ_ROR_IMM),
+/* 0001 0011 0111 */ TABDECL( OP_TEQ_ROR_REG),
+/* 0001 0011 1000 */ TABDECL( OP_TEQ_LSL_IMM),
+/* 0001 0011 1001 */ TABDECL( OP_UND),
+/* 0001 0011 1010 */ TABDECL( OP_TEQ_LSR_IMM), // OOO 1001 1 1010
+/* 0001 0011 1011 */ TABDECL( OP_LDRH_PRE_INDE_M_REG_OFF),
+/* 0001 0011 1100 */ TABDECL( OP_TEQ_ASR_IMM),
+/* 0001 0011 1101 */ TABDECL( OP_LDRSB_PRE_INDE_M_REG_OFF),
+/* 0001 0011 1110 */ TABDECL( OP_TEQ_ROR_IMM),
+/* 0001 0011 1111 */ TABDECL( OP_LDRSH_PRE_INDE_M_REG_OFF),
+/* 0001 0100 0000 */ TABDECL( OP_MRS_SPSR),
+/* 0001 0100 0001 */ TABDECL( OP_UND),
+/* 0001 0100 0010 */ TABDECL( OP_UND),
+/* 0001 0100 0011 */ TABDECL( OP_UND),
+/* 0001 0100 0100 */ TABDECL( OP_UND),
+/* 0001 0100 0101 */ TABDECL( OP_QDADD),
+/* 0001 0100 0110 */ TABDECL( OP_UND),
+/* 0001 0100 0111 */ TABDECL( OP_UND),
+/* 0001 0100 1000 */ TABDECL( OP_SMLAL_B_B),
+/* 0001 0100 1001 */ TABDECL( OP_SWPB),
+/* 0001 0100 1010 */ TABDECL( OP_SMLAL_T_B),
+/* 0001 0100 1011 */ TABDECL( OP_STRH_M_IMM_OFF),
+/* 0001 0100 1100 */ TABDECL( OP_SMLAL_B_T),
+/* 0001 0100 1101 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 0100 1110 */ TABDECL( OP_SMLAL_T_T),
+/* 0001 0100 1111 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 0101 0000 */ TABDECL( OP_CMP_LSL_IMM),
+/* 0001 0101 0001 */ TABDECL( OP_CMP_LSL_REG),
+/* 0001 0101 0010 */ TABDECL( OP_CMP_LSR_IMM),
+/* 0001 0101 0011 */ TABDECL( OP_CMP_LSR_REG),
+/* 0001 0101 0100 */ TABDECL( OP_CMP_ASR_IMM),
+/* 0001 0101 0101 */ TABDECL( OP_CMP_ASR_REG),
+/* 0001 0101 0110 */ TABDECL( OP_CMP_ROR_IMM),
+/* 0001 0101 0111 */ TABDECL( OP_CMP_ROR_REG),
+/* 0001 0101 1000 */ TABDECL( OP_CMP_LSL_IMM),
+/* 0001 0101 1001 */ TABDECL( OP_UND),
+/* 0001 0101 1010 */ TABDECL( OP_CMP_LSR_IMM), // OOO 1O1O 1 1010
+/* 0001 0101 1011 */ TABDECL( OP_LDRH_M_IMM_OFF),
+/* 0001 0101 1100 */ TABDECL( OP_CMP_ASR_IMM),
+/* 0001 0101 1101 */ TABDECL( OP_LDRSB_M_IMM_OFF),
+/* 0001 0101 1110 */ TABDECL( OP_CMP_ROR_IMM),
+/* 0001 0101 1111 */ TABDECL( OP_LDRSH_M_IMM_OFF),
+/* 0001 0110 0000 */ TABDECL( OP_MSR_SPSR),
+/* 0001 0110 0001 */ TABDECL( OP_CLZ),
+/* 0001 0110 0010 */ TABDECL( OP_UND),
+/* 0001 0110 0011 */ TABDECL( OP_UND),
+/* 0001 0110 0100 */ TABDECL( OP_UND),
+/* 0001 0110 0101 */ TABDECL( OP_QDSUB),
+/* 0001 0110 0110 */ TABDECL( OP_UND),
+/* 0001 0110 0111 */ TABDECL( OP_UND),
+/* 0001 0110 1000 */ TABDECL( OP_SMUL_B_B),
+/* 0001 0110 1001 */ TABDECL( OP_UND),
+/* 0001 0110 1010 */ TABDECL( OP_SMUL_T_B),
+/* 0001 0110 1011 */ TABDECL( OP_STRH_PRE_INDE_M_IMM_OFF),
+/* 0001 0110 1100 */ TABDECL( OP_SMUL_B_T),
+/* 0001 0110 1101 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 0110 1110 */ TABDECL( OP_SMUL_T_T),
+/* 0001 0110 1111 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 0111 0000 */ TABDECL( OP_CMN_LSL_IMM),
+/* 0001 0111 0001 */ TABDECL( OP_CMN_LSL_REG),
+/* 0001 0111 0010 */ TABDECL( OP_CMN_LSR_IMM),
+/* 0001 0111 0011 */ TABDECL( OP_CMN_LSR_REG),
+/* 0001 0111 0100 */ TABDECL( OP_CMN_ASR_IMM),
+/* 0001 0111 0101 */ TABDECL( OP_CMN_ASR_REG),
+/* 0001 0111 0110 */ TABDECL( OP_CMN_ROR_IMM),
+/* 0001 0111 0111 */ TABDECL( OP_CMN_ROR_REG),
+/* 0001 0111 1000 */ TABDECL( OP_CMN_LSL_IMM),
+/* 0001 0111 1001 */ TABDECL( OP_UND),
+/* 0001 0111 1010 */ TABDECL( OP_CMN_LSR_IMM), // OOO 1O11 1 1010
+/* 0001 0111 1011 */ TABDECL( OP_LDRH_PRE_INDE_M_IMM_OFF),
+/* 0001 0111 1100 */ TABDECL( OP_CMN_ASR_IMM),
+/* 0001 0111 1101 */ TABDECL( OP_LDRSB_PRE_INDE_M_IMM_OFF),
+/* 0001 0111 1110 */ TABDECL( OP_CMN_ROR_IMM),
+/* 0001 0111 1111 */ TABDECL( OP_LDRSH_PRE_INDE_M_IMM_OFF),
+/* 0001 1000 0000 */ TABDECL( OP_ORR_LSL_IMM),
+/* 0001 1000 0001 */ TABDECL( OP_ORR_LSL_REG),
+/* 0001 1000 0010 */ TABDECL( OP_ORR_LSR_IMM),
+/* 0001 1000 0011 */ TABDECL( OP_ORR_LSR_REG),
+/* 0001 1000 0100 */ TABDECL( OP_ORR_ASR_IMM),
+/* 0001 1000 0101 */ TABDECL( OP_ORR_ASR_REG),
+/* 0001 1000 0110 */ TABDECL( OP_ORR_ROR_IMM),
+/* 0001 1000 0111 */ TABDECL( OP_ORR_ROR_REG),
+/* 0001 1000 1000 */ TABDECL( OP_ORR_LSL_IMM),
+/* 0001 1000 1001 */ TABDECL( OP_STREX),
+/* 0001 1000 1010 */ TABDECL( OP_ORR_LSR_IMM), // OOO 110O O 1010
+/* 0001 1000 1011 */ TABDECL( OP_STRH_P_REG_OFF),
+/* 0001 1000 1100 */ TABDECL( OP_ORR_ASR_IMM),
+/* 0001 1000 1101 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 1000 1110 */ TABDECL( OP_ORR_ROR_IMM),
+/* 0001 1000 1111 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 1001 0000 */ TABDECL( OP_ORR_S_LSL_IMM),
+/* 0001 1001 0001 */ TABDECL( OP_ORR_S_LSL_REG),
+/* 0001 1001 0010 */ TABDECL( OP_ORR_S_LSR_IMM),
+/* 0001 1001 0011 */ TABDECL( OP_ORR_S_LSR_REG),
+/* 0001 1001 0100 */ TABDECL( OP_ORR_S_ASR_IMM),
+/* 0001 1001 0101 */ TABDECL( OP_ORR_S_ASR_REG),
+/* 0001 1001 0110 */ TABDECL( OP_ORR_S_ROR_IMM),
+/* 0001 1001 0111 */ TABDECL( OP_ORR_S_ROR_REG),
+/* 0001 1001 1000 */ TABDECL( OP_ORR_S_LSL_IMM),
+/* 0001 1001 1001 */ TABDECL( OP_LDREX),
+/* 0001 1001 1010 */ TABDECL( OP_ORR_S_LSR_IMM),
+/* 0001 1001 1011 */ TABDECL( OP_LDRH_P_REG_OFF),
+/* 0001 1001 1100 */ TABDECL( OP_ORR_S_ASR_IMM),
+/* 0001 1001 1101 */ TABDECL( OP_LDRSB_P_REG_OFF),
+/* 0001 1001 1110 */ TABDECL( OP_ORR_S_ROR_IMM),
+/* 0001 1001 1111 */ TABDECL( OP_LDRSH_P_REG_OFF),
+/* 0001 1010 0000 */ TABDECL( OP_MOV_LSL_IMM),
+/* 0001 1010 0001 */ TABDECL( OP_MOV_LSL_REG),
+/* 0001 1010 0010 */ TABDECL( OP_MOV_LSR_IMM),
+/* 0001 1010 0011 */ TABDECL( OP_MOV_LSR_REG),
+/* 0001 1010 0100 */ TABDECL( OP_MOV_ASR_IMM),
+/* 0001 1010 0101 */ TABDECL( OP_MOV_ASR_REG),
+/* 0001 1010 0110 */ TABDECL( OP_MOV_ROR_IMM),
+/* 0001 1010 0111 */ TABDECL( OP_MOV_ROR_REG),
+/* 0001 1010 1000 */ TABDECL( OP_MOV_LSL_IMM),
+/* 0001 1010 1001 */ TABDECL( OP_UND),
+/* 0001 1010 1010 */ TABDECL( OP_MOV_LSR_IMM), // OOO 1101 O 1010
+/* 0001 1010 1011 */ TABDECL( OP_STRH_PRE_INDE_P_REG_OFF),
+/* 0001 1010 1100 */ TABDECL( OP_MOV_ASR_IMM),
+/* 0001 1010 1101 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 1010 1110 */ TABDECL( OP_MOV_ROR_IMM),
+/* 0001 1010 1111 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 1011 0000 */ TABDECL( OP_MOV_S_LSL_IMM),
+/* 0001 1011 0001 */ TABDECL( OP_MOV_S_LSL_REG),
+/* 0001 1011 0010 */ TABDECL( OP_MOV_S_LSR_IMM),
+/* 0001 1011 0011 */ TABDECL( OP_MOV_S_LSR_REG),
+/* 0001 1011 0100 */ TABDECL( OP_MOV_S_ASR_IMM),
+/* 0001 1011 0101 */ TABDECL( OP_MOV_S_ASR_REG),
+/* 0001 1011 0110 */ TABDECL( OP_MOV_S_ROR_IMM),
+/* 0001 1011 0111 */ TABDECL( OP_MOV_S_ROR_REG),
+/* 0001 1011 1000 */ TABDECL( OP_MOV_S_LSL_IMM),
+/* 0001 1011 1001 */ TABDECL( OP_UND),
+/* 0001 1011 1010 */ TABDECL( OP_MOV_S_LSR_IMM),
+/* 0001 1011 1011 */ TABDECL( OP_LDRH_PRE_INDE_P_REG_OFF),
+/* 0001 1011 1100 */ TABDECL( OP_MOV_S_ASR_IMM),
+/* 0001 1011 1101 */ TABDECL( OP_LDRSB_PRE_INDE_P_REG_OFF),
+/* 0001 1011 1110 */ TABDECL( OP_MOV_S_ROR_IMM),
+/* 0001 1011 1111 */ TABDECL( OP_LDRSH_PRE_INDE_P_REG_OFF),
+/* 0001 1100 0000 */ TABDECL( OP_BIC_LSL_IMM),
+/* 0001 1100 0001 */ TABDECL( OP_BIC_LSL_REG),
+/* 0001 1100 0010 */ TABDECL( OP_BIC_LSR_IMM),
+/* 0001 1100 0011 */ TABDECL( OP_BIC_LSR_REG),
+/* 0001 1100 0100 */ TABDECL( OP_BIC_ASR_IMM),
+/* 0001 1100 0101 */ TABDECL( OP_BIC_ASR_REG),
+/* 0001 1100 0110 */ TABDECL( OP_BIC_ROR_IMM),
+/* 0001 1100 0111 */ TABDECL( OP_BIC_ROR_REG),
+/* 0001 1100 1000 */ TABDECL( OP_BIC_LSL_IMM),
+/* 0001 1100 1001 */ TABDECL( OP_UND),
+/* 0001 1100 1010 */ TABDECL( OP_BIC_LSR_IMM), // OOO 111O O 1010
+/* 0001 1100 1011 */ TABDECL( OP_STRH_P_IMM_OFF),
+/* 0001 1100 1100 */ TABDECL( OP_BIC_ASR_IMM),
+/* 0001 1100 1101 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 1100 1110 */ TABDECL( OP_BIC_ROR_IMM),
+/* 0001 1100 1111 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 1101 0000 */ TABDECL( OP_BIC_S_LSL_IMM),
+/* 0001 1101 0001 */ TABDECL( OP_BIC_S_LSL_REG),
+/* 0001 1101 0010 */ TABDECL( OP_BIC_S_LSR_IMM),
+/* 0001 1101 0011 */ TABDECL( OP_BIC_S_LSR_REG),
+/* 0001 1101 0100 */ TABDECL( OP_BIC_S_ASR_IMM),
+/* 0001 1101 0101 */ TABDECL( OP_BIC_S_ASR_REG),
+/* 0001 1101 0110 */ TABDECL( OP_BIC_S_ROR_IMM),
+/* 0001 1101 0111 */ TABDECL( OP_BIC_S_ROR_REG),
+/* 0001 1101 1000 */ TABDECL( OP_BIC_S_LSL_IMM),
+/* 0001 1101 1001 */ TABDECL( OP_UND),
+/* 0001 1101 1010 */ TABDECL( OP_BIC_S_LSR_IMM),
+/* 0001 1101 1011 */ TABDECL( OP_LDRH_P_IMM_OFF),
+/* 0001 1101 1100 */ TABDECL( OP_BIC_S_ASR_IMM),
+/* 0001 1101 1101 */ TABDECL( OP_LDRSB_P_IMM_OFF),
+/* 0001 1101 1110 */ TABDECL( OP_BIC_S_ROR_IMM),
+/* 0001 1101 1111 */ TABDECL( OP_LDRSH_P_IMM_OFF),
+/* 0001 1110 0000 */ TABDECL( OP_MVN_LSL_IMM),
+/* 0001 1110 0001 */ TABDECL( OP_MVN_LSL_REG),
+/* 0001 1110 0010 */ TABDECL( OP_MVN_LSR_IMM),
+/* 0001 1110 0011 */ TABDECL( OP_MVN_LSR_REG),
+/* 0001 1110 0100 */ TABDECL( OP_MVN_ASR_IMM),
+/* 0001 1110 0101 */ TABDECL( OP_MVN_ASR_REG),
+/* 0001 1110 0110 */ TABDECL( OP_MVN_ROR_IMM),
+/* 0001 1110 0111 */ TABDECL( OP_MVN_ROR_REG),
+/* 0001 1110 1000 */ TABDECL( OP_MVN_LSL_IMM),
+/* 0001 1110 1001 */ TABDECL( OP_UND),
+/* 0001 1110 1010 */ TABDECL( OP_MVN_LSR_IMM), // OOO 1111 O 1010
+/* 0001 1110 1011 */ TABDECL( OP_STRH_PRE_INDE_P_IMM_OFF),
+/* 0001 1110 1100 */ TABDECL( OP_MVN_ASR_IMM),
+/* 0001 1110 1101 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 1110 1110 */ TABDECL( OP_MVN_ROR_IMM),
+/* 0001 1110 1111 */ TABDECL( OP_LDRD_STRD_OFFSET_PRE_INDEX),
+/* 0001 1111 0000 */ TABDECL( OP_MVN_S_LSL_IMM),
+/* 0001 1111 0001 */ TABDECL( OP_MVN_S_LSL_REG),
+/* 0001 1111 0010 */ TABDECL( OP_MVN_S_LSR_IMM),
+/* 0001 1111 0011 */ TABDECL( OP_MVN_S_LSR_REG),
+/* 0001 1111 0100 */ TABDECL( OP_MVN_S_ASR_IMM),
+/* 0001 1111 0101 */ TABDECL( OP_MVN_S_ASR_REG),
+/* 0001 1111 0110 */ TABDECL( OP_MVN_S_ROR_IMM),
+/* 0001 1111 0111 */ TABDECL( OP_MVN_S_ROR_REG),
+/* 0001 1111 1000 */ TABDECL( OP_MVN_S_LSL_IMM),
+/* 0001 1111 1001 */ TABDECL( OP_UND),
+/* 0001 1111 1010 */ TABDECL( OP_MVN_S_LSR_IMM),
+/* 0001 1111 1011 */ TABDECL( OP_LDRH_PRE_INDE_P_IMM_OFF),
+/* 0001 1111 1100 */ TABDECL( OP_MVN_S_ASR_IMM),
+/* 0001 1111 1101 */ TABDECL( OP_LDRSB_PRE_INDE_P_IMM_OFF),
+/* 0001 1111 1110 */ TABDECL( OP_MVN_S_ROR_IMM),
+/* 0001 1111 1111 */ TABDECL( OP_LDRSH_PRE_INDE_P_IMM_OFF),
+/* 0010 0000 0000 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 0001 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 0010 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 0011 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 0100 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 0101 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 0110 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 0111 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 1000 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 1001 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 1010 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 1011 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 1100 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 1101 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 1110 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0000 1111 */ TABDECL( OP_AND_IMM_VAL),
+/* 0010 0001 0000 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 0001 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 0010 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 0011 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 0100 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 0101 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 0110 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 0111 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 1000 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 1001 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 1010 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 1011 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 1100 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 1101 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 1110 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0001 1111 */ TABDECL( OP_AND_S_IMM_VAL),
+/* 0010 0010 0000 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 0001 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 0010 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 0011 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 0100 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 0101 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 0110 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 0111 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 1000 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 1001 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 1010 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 1011 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 1100 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 1101 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 1110 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0010 1111 */ TABDECL( OP_EOR_IMM_VAL),
+/* 0010 0011 0000 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 0001 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 0010 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 0011 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 0100 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 0101 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 0110 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 0111 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 1000 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 1001 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 1010 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 1011 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 1100 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 1101 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 1110 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0011 1111 */ TABDECL( OP_EOR_S_IMM_VAL),
+/* 0010 0100 0000 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 0001 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 0010 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 0011 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 0100 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 0101 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 0110 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 0111 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 1000 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 1001 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 1010 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 1011 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 1100 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 1101 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 1110 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0100 1111 */ TABDECL( OP_SUB_IMM_VAL),
+/* 0010 0101 0000 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 0001 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 0010 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 0011 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 0100 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 0101 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 0110 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 0111 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 1000 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 1001 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 1010 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 1011 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 1100 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 1101 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 1110 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0101 1111 */ TABDECL( OP_SUB_S_IMM_VAL),
+/* 0010 0110 0000 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 0001 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 0010 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 0011 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 0100 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 0101 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 0110 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 0111 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 1000 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 1001 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 1010 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 1011 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 1100 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 1101 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 1110 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0110 1111 */ TABDECL( OP_RSB_IMM_VAL),
+/* 0010 0111 0000 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 0001 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 0010 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 0011 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 0100 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 0101 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 0110 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 0111 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 1000 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 1001 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 1010 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 1011 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 1100 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 1101 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 1110 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 0111 1111 */ TABDECL( OP_RSB_S_IMM_VAL),
+/* 0010 1000 0000 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 0001 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 0010 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 0011 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 0100 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 0101 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 0110 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 0111 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 1000 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 1001 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 1010 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 1011 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 1100 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 1101 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 1110 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1000 1111 */ TABDECL( OP_ADD_IMM_VAL),
+/* 0010 1001 0000 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 0001 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 0010 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 0011 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 0100 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 0101 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 0110 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 0111 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 1000 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 1001 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 1010 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 1011 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 1100 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 1101 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 1110 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1001 1111 */ TABDECL( OP_ADD_S_IMM_VAL),
+/* 0010 1010 0000 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 0001 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 0010 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 0011 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 0100 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 0101 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 0110 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 0111 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 1000 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 1001 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 1010 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 1011 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 1100 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 1101 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 1110 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1010 1111 */ TABDECL( OP_ADC_IMM_VAL),
+/* 0010 1011 0000 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 0001 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 0010 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 0011 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 0100 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 0101 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 0110 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 0111 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 1000 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 1001 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 1010 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 1011 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 1100 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 1101 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 1110 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1011 1111 */ TABDECL( OP_ADC_S_IMM_VAL),
+/* 0010 1100 0000 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 0001 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 0010 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 0011 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 0100 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 0101 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 0110 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 0111 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 1000 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 1001 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 1010 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 1011 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 1100 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 1101 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 1110 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1100 1111 */ TABDECL( OP_SBC_IMM_VAL),
+/* 0010 1101 0000 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 0001 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 0010 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 0011 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 0100 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 0101 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 0110 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 0111 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 1000 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 1001 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 1010 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 1011 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 1100 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 1101 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 1110 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1101 1111 */ TABDECL( OP_SBC_S_IMM_VAL),
+/* 0010 1110 0000 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 0001 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 0010 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 0011 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 0100 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 0101 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 0110 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 0111 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 1000 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 1001 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 1010 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 1011 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 1100 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 1101 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 1110 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1110 1111 */ TABDECL( OP_RSC_IMM_VAL),
+/* 0010 1111 0000 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 0001 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 0010 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 0011 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 0100 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 0101 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 0110 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 0111 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 1000 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 1001 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 1010 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 1011 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 1100 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 1101 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 1110 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0010 1111 1111 */ TABDECL( OP_RSC_S_IMM_VAL),
+/* 0011 0000 0000 */ TABDECL( OP_UND),
+/* 0011 0000 0001 */ TABDECL( OP_UND),
+/* 0011 0000 0010 */ TABDECL( OP_UND),
+/* 0011 0000 0011 */ TABDECL( OP_UND),
+/* 0011 0000 0100 */ TABDECL( OP_UND),
+/* 0011 0000 0101 */ TABDECL( OP_UND),
+/* 0011 0000 0110 */ TABDECL( OP_UND),
+/* 0011 0000 0111 */ TABDECL( OP_UND),
+/* 0011 0000 1000 */ TABDECL( OP_UND),
+/* 0011 0000 1001 */ TABDECL( OP_UND),
+/* 0011 0000 1010 */ TABDECL( OP_UND),
+/* 0011 0000 1011 */ TABDECL( OP_UND),
+/* 0011 0000 1100 */ TABDECL( OP_UND),
+/* 0011 0000 1101 */ TABDECL( OP_UND),
+/* 0011 0000 1110 */ TABDECL( OP_UND),
+/* 0011 0000 1111 */ TABDECL( OP_UND),
+/* 0011 0001 0000 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 0001 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 0010 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 0011 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 0100 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 0101 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 0110 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 0111 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 1000 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 1001 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 1010 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 1011 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 1100 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 1101 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 1110 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0001 1111 */ TABDECL( OP_TST_IMM_VAL),
+/* 0011 0010 0000 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 0001 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 0010 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 0011 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 0100 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 0101 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 0110 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 0111 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 1000 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 1001 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 1010 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 1011 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 1100 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 1101 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 1110 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0010 1111 */ TABDECL( OP_MSR_CPSR_IMM_VAL),
+/* 0011 0011 0000 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 0001 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 0010 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 0011 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 0100 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 0101 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 0110 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 0111 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 1000 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 1001 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 1010 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 1011 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 1100 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 1101 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 1110 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0011 1111 */ TABDECL( OP_TEQ_IMM_VAL),
+/* 0011 0100 0000 */ TABDECL( OP_UND),
+/* 0011 0100 0001 */ TABDECL( OP_UND),
+/* 0011 0100 0010 */ TABDECL( OP_UND),
+/* 0011 0100 0011 */ TABDECL( OP_UND),
+/* 0011 0100 0100 */ TABDECL( OP_UND),
+/* 0011 0100 0101 */ TABDECL( OP_UND),
+/* 0011 0100 0110 */ TABDECL( OP_UND),
+/* 0011 0100 0111 */ TABDECL( OP_UND),
+/* 0011 0100 1000 */ TABDECL( OP_UND),
+/* 0011 0100 1001 */ TABDECL( OP_UND),
+/* 0011 0100 1010 */ TABDECL( OP_UND),
+/* 0011 0100 1011 */ TABDECL( OP_UND),
+/* 0011 0100 1100 */ TABDECL( OP_UND),
+/* 0011 0100 1101 */ TABDECL( OP_UND),
+/* 0011 0100 1110 */ TABDECL( OP_UND),
+/* 0011 0100 1111 */ TABDECL( OP_UND),
+/* 0011 0101 0000 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 0001 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 0010 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 0011 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 0100 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 0101 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 0110 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 0111 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 1000 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 1001 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 1010 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 1011 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 1100 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 1101 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 1110 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0101 1111 */ TABDECL( OP_CMP_IMM_VAL),
+/* 0011 0110 0000 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 0001 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 0010 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 0011 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 0100 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 0101 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 0110 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 0111 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 1000 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 1001 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 1010 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 1011 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 1100 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 1101 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 1110 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0110 1111 */ TABDECL( OP_MSR_SPSR_IMM_VAL),
+/* 0011 0111 0000 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 0001 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 0010 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 0011 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 0100 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 0101 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 0110 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 0111 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 1000 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 1001 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 1010 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 1011 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 1100 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 1101 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 1110 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 0111 1111 */ TABDECL( OP_CMN_IMM_VAL),
+/* 0011 1000 0000 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 0001 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 0010 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 0011 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 0100 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 0101 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 0110 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 0111 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 1000 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 1001 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 1010 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 1011 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 1100 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 1101 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 1110 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1000 1111 */ TABDECL( OP_ORR_IMM_VAL),
+/* 0011 1001 0000 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 0001 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 0010 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 0011 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 0100 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 0101 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 0110 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 0111 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 1000 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 1001 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 1010 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 1011 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 1100 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 1101 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 1110 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1001 1111 */ TABDECL( OP_ORR_S_IMM_VAL),
+/* 0011 1010 0000 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 0001 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 0010 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 0011 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 0100 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 0101 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 0110 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 0111 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 1000 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 1001 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 1010 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 1011 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 1100 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 1101 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 1110 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1010 1111 */ TABDECL( OP_MOV_IMM_VAL),
+/* 0011 1011 0000 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 0001 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 0010 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 0011 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 0100 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 0101 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 0110 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 0111 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 1000 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 1001 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 1010 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 1011 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 1100 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 1101 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 1110 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1011 1111 */ TABDECL( OP_MOV_S_IMM_VAL),
+/* 0011 1100 0000 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 0001 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 0010 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 0011 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 0100 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 0101 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 0110 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 0111 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 1000 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 1001 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 1010 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 1011 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 1100 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 1101 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 1110 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1100 1111 */ TABDECL( OP_BIC_IMM_VAL),
+/* 0011 1101 0000 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 0001 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 0010 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 0011 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 0100 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 0101 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 0110 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 0111 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 1000 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 1001 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 1010 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 1011 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 1100 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 1101 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 1110 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1101 1111 */ TABDECL( OP_BIC_S_IMM_VAL),
+/* 0011 1110 0000 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 0001 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 0010 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 0011 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 0100 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 0101 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 0110 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 0111 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 1000 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 1001 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 1010 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 1011 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 1100 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 1101 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 1110 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1110 1111 */ TABDECL( OP_MVN_IMM_VAL),
+/* 0011 1111 0000 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 0001 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 0010 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 0011 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 0100 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 0101 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 0110 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 0111 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 1000 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 1001 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 1010 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 1011 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 1100 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 1101 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 1110 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0011 1111 1111 */ TABDECL( OP_MVN_S_IMM_VAL),
+/* 0100 0000 0000 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 0001 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 0010 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 0011 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 0100 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 0101 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 0110 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 0111 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 1000 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 1001 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 1010 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 1011 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 1100 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 1101 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 1110 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0000 1111 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0001 0000 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 0001 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 0010 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 0011 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 0100 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 0101 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 0110 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 0111 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 1000 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 1001 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 1010 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 1011 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 1100 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 1101 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 1110 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0001 1111 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0010 0000 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 0001 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 0010 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 0011 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 0100 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 0101 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 0110 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 0111 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 1000 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 1001 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 1010 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 1011 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 1100 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 1101 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 1110 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0010 1111 */ TABDECL( OP_STR_M_IMM_OFF_POSTIND),
+/* 0100 0011 0000 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 0001 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 0010 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 0011 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 0100 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 0101 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 0110 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 0111 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 1000 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 1001 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 1010 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 1011 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 1100 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 1101 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 1110 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0011 1111 */ TABDECL( OP_LDR_M_IMM_OFF_POSTIND),
+/* 0100 0100 0000 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 0001 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 0010 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 0011 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 0100 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 0101 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 0110 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 0111 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 1000 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 1001 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 1010 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 1011 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 1100 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 1101 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 1110 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0100 1111 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 0000 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 0001 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 0010 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 0011 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 0100 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 0101 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 0110 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 0111 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 1000 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 1001 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 1010 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 1011 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 1100 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 1101 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 1110 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0101 1111 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 0000 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 0001 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 0010 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 0011 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 0100 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 0101 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 0110 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 0111 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 1000 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 1001 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 1010 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 1011 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 1100 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 1101 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 1110 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0110 1111 */ TABDECL( OP_STRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 0000 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 0001 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 0010 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 0011 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 0100 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 0101 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 0110 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 0111 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 1000 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 1001 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 1010 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 1011 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 1100 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 1101 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 1110 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 0111 1111 */ TABDECL( OP_LDRB_M_IMM_OFF_POSTIND),
+/* 0100 1000 0000 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 0001 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 0010 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 0011 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 0100 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 0101 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 0110 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 0111 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 1000 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 1001 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 1010 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 1011 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 1100 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 1101 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 1110 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1000 1111 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1001 0000 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 0001 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 0010 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 0011 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 0100 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 0101 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 0110 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 0111 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 1000 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 1001 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 1010 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 1011 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 1100 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 1101 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 1110 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1001 1111 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1010 0000 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 0001 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 0010 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 0011 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 0100 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 0101 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 0110 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 0111 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 1000 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 1001 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 1010 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 1011 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 1100 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 1101 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 1110 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1010 1111 */ TABDECL( OP_STR_P_IMM_OFF_POSTIND),
+/* 0100 1011 0000 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 0001 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 0010 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 0011 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 0100 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 0101 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 0110 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 0111 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 1000 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 1001 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 1010 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 1011 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 1100 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 1101 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 1110 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1011 1111 */ TABDECL( OP_LDR_P_IMM_OFF_POSTIND),
+/* 0100 1100 0000 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 0001 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 0010 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 0011 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 0100 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 0101 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 0110 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 0111 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 1000 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 1001 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 1010 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 1011 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 1100 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 1101 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 1110 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1100 1111 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 0000 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 0001 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 0010 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 0011 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 0100 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 0101 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 0110 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 0111 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 1000 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 1001 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 1010 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 1011 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 1100 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 1101 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 1110 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1101 1111 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 0000 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 0001 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 0010 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 0011 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 0100 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 0101 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 0110 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 0111 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 1000 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 1001 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 1010 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 1011 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 1100 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 1101 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 1110 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1110 1111 */ TABDECL( OP_STRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 0000 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 0001 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 0010 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 0011 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 0100 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 0101 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 0110 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 0111 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 1000 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 1001 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 1010 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 1011 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 1100 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 1101 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 1110 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0100 1111 1111 */ TABDECL( OP_LDRB_P_IMM_OFF_POSTIND),
+/* 0101 0000 0000 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 0001 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 0010 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 0011 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 0100 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 0101 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 0110 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 0111 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 1000 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 1001 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 1010 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 1011 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 1100 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 1101 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 1110 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0000 1111 */ TABDECL( OP_STR_M_IMM_OFF),
+/* 0101 0001 0000 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 0001 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 0010 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 0011 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 0100 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 0101 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 0110 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 0111 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 1000 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 1001 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 1010 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 1011 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 1100 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 1101 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 1110 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0001 1111 */ TABDECL( OP_LDR_M_IMM_OFF),
+/* 0101 0010 0000 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 0001 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 0010 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 0011 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 0100 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 0101 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 0110 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 0111 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 1000 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 1001 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 1010 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 1011 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 1100 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 1101 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 1110 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0010 1111 */ TABDECL( OP_STR_M_IMM_OFF_PREIND),
+/* 0101 0011 0000 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 0001 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 0010 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 0011 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 0100 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 0101 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 0110 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 0111 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 1000 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 1001 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 1010 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 1011 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 1100 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 1101 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 1110 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0011 1111 */ TABDECL( OP_LDR_M_IMM_OFF_PREIND),
+/* 0101 0100 0000 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 0001 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 0010 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 0011 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 0100 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 0101 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 0110 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 0111 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 1000 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 1001 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 1010 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 1011 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 1100 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 1101 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 1110 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0100 1111 */ TABDECL( OP_STRB_M_IMM_OFF),
+/* 0101 0101 0000 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 0001 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 0010 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 0011 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 0100 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 0101 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 0110 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 0111 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 1000 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 1001 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 1010 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 1011 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 1100 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 1101 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 1110 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0101 1111 */ TABDECL( OP_LDRB_M_IMM_OFF),
+/* 0101 0110 0000 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 0001 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 0010 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 0011 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 0100 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 0101 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 0110 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 0111 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 1000 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 1001 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 1010 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 1011 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 1100 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 1101 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 1110 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0110 1111 */ TABDECL( OP_STRB_M_IMM_OFF_PREIND),
+/* 0101 0111 0000 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 0001 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 0010 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 0011 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 0100 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 0101 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 0110 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 0111 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 1000 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 1001 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 1010 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 1011 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 1100 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 1101 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 1110 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 0111 1111 */ TABDECL( OP_LDRB_M_IMM_OFF_PREIND),
+/* 0101 1000 0000 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 0001 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 0010 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 0011 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 0100 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 0101 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 0110 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 0111 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 1000 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 1001 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 1010 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 1011 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 1100 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 1101 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 1110 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1000 1111 */ TABDECL( OP_STR_P_IMM_OFF),
+/* 0101 1001 0000 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 0001 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 0010 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 0011 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 0100 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 0101 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 0110 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 0111 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 1000 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 1001 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 1010 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 1011 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 1100 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 1101 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 1110 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1001 1111 */ TABDECL( OP_LDR_P_IMM_OFF),
+/* 0101 1010 0000 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 0001 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 0010 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 0011 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 0100 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 0101 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 0110 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 0111 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 1000 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 1001 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 1010 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 1011 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 1100 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 1101 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 1110 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1010 1111 */ TABDECL( OP_STR_P_IMM_OFF_PREIND),
+/* 0101 1011 0000 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 0001 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 0010 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 0011 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 0100 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 0101 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 0110 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 0111 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 1000 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 1001 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 1010 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 1011 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 1100 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 1101 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 1110 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1011 1111 */ TABDECL( OP_LDR_P_IMM_OFF_PREIND),
+/* 0101 1100 0000 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 0001 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 0010 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 0011 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 0100 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 0101 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 0110 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 0111 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 1000 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 1001 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 1010 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 1011 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 1100 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 1101 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 1110 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1100 1111 */ TABDECL( OP_STRB_P_IMM_OFF),
+/* 0101 1101 0000 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 0001 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 0010 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 0011 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 0100 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 0101 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 0110 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 0111 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 1000 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 1001 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 1010 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 1011 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 1100 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 1101 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 1110 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1101 1111 */ TABDECL( OP_LDRB_P_IMM_OFF),
+/* 0101 1110 0000 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 0001 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 0010 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 0011 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 0100 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 0101 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 0110 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 0111 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 1000 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 1001 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 1010 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 1011 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 1100 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 1101 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 1110 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1110 1111 */ TABDECL( OP_STRB_P_IMM_OFF_PREIND),
+/* 0101 1111 0000 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 0001 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 0010 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 0011 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 0100 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 0101 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 0110 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 0111 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 1000 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 1001 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 1010 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 1011 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 1100 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 1101 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 1110 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0101 1111 1111 */ TABDECL( OP_LDRB_P_IMM_OFF_PREIND),
+/* 0110 0000 0000 */ TABDECL( OP_STR_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0000 0001 */ TABDECL( OP_UND),
+/* 0110 0000 0010 */ TABDECL( OP_STR_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0000 0011 */ TABDECL( OP_UND),
+/* 0110 0000 0100 */ TABDECL( OP_STR_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0000 0101 */ TABDECL( OP_UND),
+/* 0110 0000 0110 */ TABDECL( OP_STR_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0000 0111 */ TABDECL( OP_UND),
+/* 0110 0000 1000 */ TABDECL( OP_STR_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0000 1001 */ TABDECL( OP_UND),
+/* 0110 0000 1010 */ TABDECL( OP_STR_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0000 1011 */ TABDECL( OP_UND),
+/* 0110 0000 1100 */ TABDECL( OP_STR_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0000 1101 */ TABDECL( OP_UND),
+/* 0110 0000 1110 */ TABDECL( OP_STR_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0000 1111 */ TABDECL( OP_UND),
+/* 0110 0001 0000 */ TABDECL( OP_LDR_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0001 0001 */ TABDECL( OP_UND),
+/* 0110 0001 0010 */ TABDECL( OP_LDR_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0001 0011 */ TABDECL( OP_UND),
+/* 0110 0001 0100 */ TABDECL( OP_LDR_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0001 0101 */ TABDECL( OP_UND),
+/* 0110 0001 0110 */ TABDECL( OP_LDR_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0001 0111 */ TABDECL( OP_UND),
+/* 0110 0001 1000 */ TABDECL( OP_LDR_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0001 1001 */ TABDECL( OP_UND),
+/* 0110 0001 1010 */ TABDECL( OP_LDR_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0001 1011 */ TABDECL( OP_UND),
+/* 0110 0001 1100 */ TABDECL( OP_LDR_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0001 1101 */ TABDECL( OP_UND),
+/* 0110 0001 1110 */ TABDECL( OP_LDR_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0001 1111 */ TABDECL( OP_UND),
+/* 0110 0010 0000 */ TABDECL( OP_STR_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0010 0001 */ TABDECL( OP_UND),
+/* 0110 0010 0010 */ TABDECL( OP_STR_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0010 0011 */ TABDECL( OP_UND),
+/* 0110 0010 0100 */ TABDECL( OP_STR_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0010 0101 */ TABDECL( OP_UND),
+/* 0110 0010 0110 */ TABDECL( OP_STR_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0010 0111 */ TABDECL( OP_UND),
+/* 0110 0010 1000 */ TABDECL( OP_STR_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0010 1001 */ TABDECL( OP_UND),
+/* 0110 0010 1010 */ TABDECL( OP_STR_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0010 1011 */ TABDECL( OP_UND),
+/* 0110 0010 1100 */ TABDECL( OP_STR_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0010 1101 */ TABDECL( OP_UND),
+/* 0110 0010 1110 */ TABDECL( OP_STR_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0010 1111 */ TABDECL( OP_UND),
+/* 0110 0011 0000 */ TABDECL( OP_LDR_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0011 0001 */ TABDECL( OP_UND),
+/* 0110 0011 0010 */ TABDECL( OP_LDR_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0011 0011 */ TABDECL( OP_UND),
+/* 0110 0011 0100 */ TABDECL( OP_LDR_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0011 0101 */ TABDECL( OP_UND),
+/* 0110 0011 0110 */ TABDECL( OP_LDR_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0011 0111 */ TABDECL( OP_UND),
+/* 0110 0011 1000 */ TABDECL( OP_LDR_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0011 1001 */ TABDECL( OP_UND),
+/* 0110 0011 1010 */ TABDECL( OP_LDR_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0011 1011 */ TABDECL( OP_UND),
+/* 0110 0011 1100 */ TABDECL( OP_LDR_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0011 1101 */ TABDECL( OP_UND),
+/* 0110 0011 1110 */ TABDECL( OP_LDR_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0011 1111 */ TABDECL( OP_UND),
+/* 0110 0100 0000 */ TABDECL( OP_STRB_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0100 0001 */ TABDECL( OP_UND),
+/* 0110 0100 0010 */ TABDECL( OP_STRB_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0100 0011 */ TABDECL( OP_UND),
+/* 0110 0100 0100 */ TABDECL( OP_STRB_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0100 0101 */ TABDECL( OP_UND),
+/* 0110 0100 0110 */ TABDECL( OP_STRB_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0100 0111 */ TABDECL( OP_UND),
+/* 0110 0100 1000 */ TABDECL( OP_STRB_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0100 1001 */ TABDECL( OP_UND),
+/* 0110 0100 1010 */ TABDECL( OP_STRB_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0100 1011 */ TABDECL( OP_UND),
+/* 0110 0100 1100 */ TABDECL( OP_STRB_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0100 1101 */ TABDECL( OP_UND),
+/* 0110 0100 1110 */ TABDECL( OP_STRB_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0100 1111 */ TABDECL( OP_UND),
+/* 0110 0101 0000 */ TABDECL( OP_LDRB_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0101 0001 */ TABDECL( OP_UND),
+/* 0110 0101 0010 */ TABDECL( OP_LDRB_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0101 0011 */ TABDECL( OP_UND),
+/* 0110 0101 0100 */ TABDECL( OP_LDRB_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0101 0101 */ TABDECL( OP_UND),
+/* 0110 0101 0110 */ TABDECL( OP_LDRB_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0101 0111 */ TABDECL( OP_UND),
+/* 0110 0101 1000 */ TABDECL( OP_LDRB_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0101 1001 */ TABDECL( OP_UND),
+/* 0110 0101 1010 */ TABDECL( OP_LDRB_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0101 1011 */ TABDECL( OP_UND),
+/* 0110 0101 1100 */ TABDECL( OP_LDRB_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0101 1101 */ TABDECL( OP_UND),
+/* 0110 0101 1110 */ TABDECL( OP_LDRB_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0101 1111 */ TABDECL( OP_UND),
+/* 0110 0110 0000 */ TABDECL( OP_STRB_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0110 0001 */ TABDECL( OP_UND),
+/* 0110 0110 0010 */ TABDECL( OP_STRB_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0110 0011 */ TABDECL( OP_UND),
+/* 0110 0110 0100 */ TABDECL( OP_STRB_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0110 0101 */ TABDECL( OP_UND),
+/* 0110 0110 0110 */ TABDECL( OP_STRB_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0110 0111 */ TABDECL( OP_UND),
+/* 0110 0110 1000 */ TABDECL( OP_STRB_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0110 1001 */ TABDECL( OP_UND),
+/* 0110 0110 1010 */ TABDECL( OP_STRB_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0110 1011 */ TABDECL( OP_UND),
+/* 0110 0110 1100 */ TABDECL( OP_STRB_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0110 1101 */ TABDECL( OP_UND),
+/* 0110 0110 1110 */ TABDECL( OP_STRB_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0110 1111 */ TABDECL( OP_UND),
+/* 0110 0111 0000 */ TABDECL( OP_LDRB_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0111 0001 */ TABDECL( OP_UND),
+/* 0110 0111 0010 */ TABDECL( OP_LDRB_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0111 0011 */ TABDECL( OP_UND),
+/* 0110 0111 0100 */ TABDECL( OP_LDRB_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0111 0101 */ TABDECL( OP_UND),
+/* 0110 0111 0110 */ TABDECL( OP_LDRB_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0111 0111 */ TABDECL( OP_UND),
+/* 0110 0111 1000 */ TABDECL( OP_LDRB_M_LSL_IMM_OFF_POSTIND),
+/* 0110 0111 1001 */ TABDECL( OP_UND),
+/* 0110 0111 1010 */ TABDECL( OP_LDRB_M_LSR_IMM_OFF_POSTIND),
+/* 0110 0111 1011 */ TABDECL( OP_UND),
+/* 0110 0111 1100 */ TABDECL( OP_LDRB_M_ASR_IMM_OFF_POSTIND),
+/* 0110 0111 1101 */ TABDECL( OP_UND),
+/* 0110 0111 1110 */ TABDECL( OP_LDRB_M_ROR_IMM_OFF_POSTIND),
+/* 0110 0111 1111 */ TABDECL( OP_UND),
+/* 0110 1000 0000 */ TABDECL( OP_STR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1000 0001 */ TABDECL( OP_UND),
+/* 0110 1000 0010 */ TABDECL( OP_STR_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1000 0011 */ TABDECL( OP_UND),
+/* 0110 1000 0100 */ TABDECL( OP_STR_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1000 0101 */ TABDECL( OP_UND),
+/* 0110 1000 0110 */ TABDECL( OP_STR_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1000 0111 */ TABDECL( OP_UND),
+/* 0110 1000 1000 */ TABDECL( OP_STR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1000 1001 */ TABDECL( OP_UND),
+/* 0110 1000 1010 */ TABDECL( OP_STR_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1000 1011 */ TABDECL( OP_UND),
+/* 0110 1000 1100 */ TABDECL( OP_STR_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1000 1101 */ TABDECL( OP_UND),
+/* 0110 1000 1110 */ TABDECL( OP_STR_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1000 1111 */ TABDECL( OP_UND),
+/* 0110 1001 0000 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1001 0001 */ TABDECL( OP_UND),
+/* 0110 1001 0010 */ TABDECL( OP_LDR_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1001 0011 */ TABDECL( OP_UND),
+/* 0110 1001 0100 */ TABDECL( OP_LDR_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1001 0101 */ TABDECL( OP_UND),
+/* 0110 1001 0110 */ TABDECL( OP_LDR_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1001 0111 */ TABDECL( OP_UND),
+/* 0110 1001 1000 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1001 1001 */ TABDECL( OP_UND),
+/* 0110 1001 1010 */ TABDECL( OP_LDR_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1001 1011 */ TABDECL( OP_UND),
+/* 0110 1001 1100 */ TABDECL( OP_LDR_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1001 1101 */ TABDECL( OP_UND),
+/* 0110 1001 1110 */ TABDECL( OP_LDR_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1001 1111 */ TABDECL( OP_UND),
+/* 0110 1010 0000 */ TABDECL( OP_STR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1010 0001 */ TABDECL( OP_UND),
+/* 0110 1010 0010 */ TABDECL( OP_STR_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1010 0011 */ TABDECL( OP_UND),
+/* 0110 1010 0100 */ TABDECL( OP_STR_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1010 0101 */ TABDECL( OP_UND),
+/* 0110 1010 0110 */ TABDECL( OP_STR_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1010 0111 */ TABDECL( OP_UND),
+/* 0110 1010 1000 */ TABDECL( OP_STR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1010 1001 */ TABDECL( OP_UND),
+/* 0110 1010 1010 */ TABDECL( OP_STR_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1010 1011 */ TABDECL( OP_UND),
+/* 0110 1010 1100 */ TABDECL( OP_STR_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1010 1101 */ TABDECL( OP_UND),
+/* 0110 1010 1110 */ TABDECL( OP_STR_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1010 1111 */ TABDECL( OP_UND),
+/* 0110 1011 0000 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1011 0001 */ TABDECL( OP_UND),
+/* 0110 1011 0010 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1011 0011 */ TABDECL( OP_UND),
+/* 0110 1011 0100 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1011 0101 */ TABDECL( OP_UND),
+/* 0110 1011 0110 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1011 0111 */ TABDECL( OP_UND),
+/* 0110 1011 1000 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1011 1001 */ TABDECL( OP_UND),
+/* 0110 1011 1010 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1011 1011 */ TABDECL( OP_UND),
+/* 0110 1011 1100 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1011 1101 */ TABDECL( OP_UND),
+/* 0110 1011 1110 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1011 1111 */ TABDECL( OP_UND),
+/* 0110 1100 0000 */ TABDECL( OP_STRB_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1100 0001 */ TABDECL( OP_UND),
+/* 0110 1100 0010 */ TABDECL( OP_STRB_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1100 0011 */ TABDECL( OP_UND),
+/* 0110 1100 0100 */ TABDECL( OP_STRB_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1100 0101 */ TABDECL( OP_UND),
+/* 0110 1100 0110 */ TABDECL( OP_STRB_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1100 0111 */ TABDECL( OP_UND),
+/* 0110 1100 1000 */ TABDECL( OP_STRB_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1100 1001 */ TABDECL( OP_UND),
+/* 0110 1100 1010 */ TABDECL( OP_STRB_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1100 1011 */ TABDECL( OP_UND),
+/* 0110 1100 1100 */ TABDECL( OP_STRB_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1100 1101 */ TABDECL( OP_UND),
+/* 0110 1100 1110 */ TABDECL( OP_STRB_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1100 1111 */ TABDECL( OP_UND),
+/* 0110 1101 0000 */ TABDECL( OP_LDRB_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1101 0001 */ TABDECL( OP_UND),
+/* 0110 1101 0010 */ TABDECL( OP_LDRB_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1101 0011 */ TABDECL( OP_UND),
+/* 0110 1101 0100 */ TABDECL( OP_LDRB_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1101 0101 */ TABDECL( OP_UND),
+/* 0110 1101 0110 */ TABDECL( OP_LDRB_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1101 0111 */ TABDECL( OP_UND),
+/* 0110 1101 1000 */ TABDECL( OP_LDRB_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1101 1001 */ TABDECL( OP_UND),
+/* 0110 1101 1010 */ TABDECL( OP_LDRB_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1101 1011 */ TABDECL( OP_UND),
+/* 0110 1101 1100 */ TABDECL( OP_LDRB_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1101 1101 */ TABDECL( OP_UND),
+/* 0110 1101 1110 */ TABDECL( OP_LDRB_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1101 1111 */ TABDECL( OP_UND),
+/* 0110 1110 0000 */ TABDECL( OP_STRB_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1110 0001 */ TABDECL( OP_UND),
+/* 0110 1110 0010 */ TABDECL( OP_STRB_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1110 0011 */ TABDECL( OP_UND),
+/* 0110 1110 0100 */ TABDECL( OP_STRB_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1110 0101 */ TABDECL( OP_UND),
+/* 0110 1110 0110 */ TABDECL( OP_STRB_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1110 0111 */ TABDECL( OP_UND),
+/* 0110 1110 1000 */ TABDECL( OP_STRB_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1110 1001 */ TABDECL( OP_UND),
+/* 0110 1110 1010 */ TABDECL( OP_STRB_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1110 1011 */ TABDECL( OP_UND),
+/* 0110 1110 1100 */ TABDECL( OP_STRB_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1110 1101 */ TABDECL( OP_UND),
+/* 0110 1110 1110 */ TABDECL( OP_STRB_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1110 1111 */ TABDECL( OP_UND),
+/* 0110 1111 0000 */ TABDECL( OP_LDRB_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1111 0001 */ TABDECL( OP_UND),
+/* 0110 1111 0010 */ TABDECL( OP_LDRB_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1111 0011 */ TABDECL( OP_UND),
+/* 0110 1111 0100 */ TABDECL( OP_LDRB_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1111 0101 */ TABDECL( OP_UND),
+/* 0110 1111 0110 */ TABDECL( OP_LDRB_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1111 0111 */ TABDECL( OP_UND),
+/* 0110 1111 1000 */ TABDECL( OP_LDRB_P_LSL_IMM_OFF_POSTIND),
+/* 0110 1111 1001 */ TABDECL( OP_UND),
+/* 0110 1111 1010 */ TABDECL( OP_LDRB_P_LSR_IMM_OFF_POSTIND),
+/* 0110 1111 1011 */ TABDECL( OP_UND),
+/* 0110 1111 1100 */ TABDECL( OP_LDRB_P_ASR_IMM_OFF_POSTIND),
+/* 0110 1111 1101 */ TABDECL( OP_UND),
+/* 0110 1111 1110 */ TABDECL( OP_LDRB_P_ROR_IMM_OFF_POSTIND),
+/* 0110 1111 1111 */ TABDECL( OP_UND),
+/* 0111 0000 0000 */ TABDECL( OP_STR_M_LSL_IMM_OFF),
+/* 0111 0000 0001 */ TABDECL( OP_UND),
+/* 0111 0000 0010 */ TABDECL( OP_STR_M_LSR_IMM_OFF),
+/* 0111 0000 0011 */ TABDECL( OP_UND),
+/* 0111 0000 0100 */ TABDECL( OP_STR_M_ASR_IMM_OFF),
+/* 0111 0000 0101 */ TABDECL( OP_UND),
+/* 0111 0000 0110 */ TABDECL( OP_STR_M_ROR_IMM_OFF),
+/* 0111 0000 0111 */ TABDECL( OP_UND),
+/* 0111 0000 1000 */ TABDECL( OP_STR_M_LSL_IMM_OFF),
+/* 0111 0000 1001 */ TABDECL( OP_UND),
+/* 0111 0000 1010 */ TABDECL( OP_STR_M_LSR_IMM_OFF),
+/* 0111 0000 1011 */ TABDECL( OP_UND),
+/* 0111 0000 1100 */ TABDECL( OP_STR_M_ASR_IMM_OFF),
+/* 0111 0000 1101 */ TABDECL( OP_UND),
+/* 0111 0000 1110 */ TABDECL( OP_STR_M_ROR_IMM_OFF),
+/* 0111 0000 1111 */ TABDECL( OP_UND),
+/* 0111 0001 0000 */ TABDECL( OP_LDR_M_LSL_IMM_OFF),
+/* 0111 0001 0001 */ TABDECL( OP_UND),
+/* 0111 0001 0010 */ TABDECL( OP_LDR_M_LSR_IMM_OFF),
+/* 0111 0001 0011 */ TABDECL( OP_UND),
+/* 0111 0001 0100 */ TABDECL( OP_LDR_M_ASR_IMM_OFF),
+/* 0111 0001 0101 */ TABDECL( OP_UND),
+/* 0111 0001 0110 */ TABDECL( OP_LDR_M_ROR_IMM_OFF),
+/* 0111 0001 0111 */ TABDECL( OP_UND),
+/* 0111 0001 1000 */ TABDECL( OP_LDR_M_LSL_IMM_OFF),
+/* 0111 0001 1001 */ TABDECL( OP_UND),
+/* 0111 0001 1010 */ TABDECL( OP_LDR_M_LSR_IMM_OFF),
+/* 0111 0001 1011 */ TABDECL( OP_UND),
+/* 0111 0001 1100 */ TABDECL( OP_LDR_M_ASR_IMM_OFF),
+/* 0111 0001 1101 */ TABDECL( OP_UND),
+/* 0111 0001 1110 */ TABDECL( OP_LDR_M_ROR_IMM_OFF),
+/* 0111 0001 1111 */ TABDECL( OP_UND),
+/* 0111 0010 0000 */ TABDECL( OP_STR_M_LSL_IMM_OFF_PREIND),
+/* 0111 0010 0001 */ TABDECL( OP_UND),
+/* 0111 0010 0010 */ TABDECL( OP_STR_M_LSR_IMM_OFF_PREIND),
+/* 0111 0010 0011 */ TABDECL( OP_UND),
+/* 0111 0010 0100 */ TABDECL( OP_STR_M_ASR_IMM_OFF_PREIND),
+/* 0111 0010 0101 */ TABDECL( OP_UND),
+/* 0111 0010 0110 */ TABDECL( OP_STR_M_ROR_IMM_OFF_PREIND),
+/* 0111 0010 0111 */ TABDECL( OP_UND),
+/* 0111 0010 1000 */ TABDECL( OP_STR_M_LSL_IMM_OFF_PREIND),
+/* 0111 0010 1001 */ TABDECL( OP_UND),
+/* 0111 0010 1010 */ TABDECL( OP_STR_M_LSR_IMM_OFF_PREIND),
+/* 0111 0010 1011 */ TABDECL( OP_UND),
+/* 0111 0010 1100 */ TABDECL( OP_STR_M_ASR_IMM_OFF_PREIND),
+/* 0111 0010 1101 */ TABDECL( OP_UND),
+/* 0111 0010 1110 */ TABDECL( OP_STR_M_ROR_IMM_OFF_PREIND),
+/* 0111 0010 1111 */ TABDECL( OP_UND),
+/* 0111 0011 0000 */ TABDECL( OP_LDR_M_LSL_IMM_OFF_PREIND),
+/* 0111 0011 0001 */ TABDECL( OP_UND),
+/* 0111 0011 0010 */ TABDECL( OP_LDR_M_LSR_IMM_OFF_PREIND),
+/* 0111 0011 0011 */ TABDECL( OP_UND),
+/* 0111 0011 0100 */ TABDECL( OP_LDR_M_ASR_IMM_OFF_PREIND),
+/* 0111 0011 0101 */ TABDECL( OP_UND),
+/* 0111 0011 0110 */ TABDECL( OP_LDR_M_ROR_IMM_OFF_PREIND),
+/* 0111 0011 0111 */ TABDECL( OP_UND),
+/* 0111 0011 1000 */ TABDECL( OP_LDR_M_LSL_IMM_OFF_PREIND),
+/* 0111 0011 1001 */ TABDECL( OP_UND),
+/* 0111 0011 1010 */ TABDECL( OP_LDR_M_LSR_IMM_OFF_PREIND),
+/* 0111 0011 1011 */ TABDECL( OP_UND),
+/* 0111 0011 1100 */ TABDECL( OP_LDR_M_ASR_IMM_OFF_PREIND),
+/* 0111 0011 1101 */ TABDECL( OP_UND),
+/* 0111 0011 1110 */ TABDECL( OP_LDR_M_ROR_IMM_OFF_PREIND),
+/* 0111 0011 1111 */ TABDECL( OP_UND),
+/* 0111 0100 0000 */ TABDECL( OP_STRB_M_LSL_IMM_OFF),
+/* 0111 0100 0001 */ TABDECL( OP_UND),
+/* 0111 0100 0010 */ TABDECL( OP_STRB_M_LSR_IMM_OFF),
+/* 0111 0100 0011 */ TABDECL( OP_UND),
+/* 0111 0100 0100 */ TABDECL( OP_STRB_M_ASR_IMM_OFF),
+/* 0111 0100 0101 */ TABDECL( OP_UND),
+/* 0111 0100 0110 */ TABDECL( OP_STRB_M_ROR_IMM_OFF),
+/* 0111 0100 0111 */ TABDECL( OP_UND),
+/* 0111 0100 1000 */ TABDECL( OP_STRB_M_LSL_IMM_OFF),
+/* 0111 0100 1001 */ TABDECL( OP_UND),
+/* 0111 0100 1010 */ TABDECL( OP_STRB_M_LSR_IMM_OFF),
+/* 0111 0100 1011 */ TABDECL( OP_UND),
+/* 0111 0100 1100 */ TABDECL( OP_STRB_M_ASR_IMM_OFF),
+/* 0111 0100 1101 */ TABDECL( OP_UND),
+/* 0111 0100 1110 */ TABDECL( OP_STRB_M_ROR_IMM_OFF),
+/* 0111 0100 1111 */ TABDECL( OP_UND),
+/* 0111 0101 0000 */ TABDECL( OP_LDRB_M_LSL_IMM_OFF),
+/* 0111 0101 0001 */ TABDECL( OP_UND),
+/* 0111 0101 0010 */ TABDECL( OP_LDRB_M_LSR_IMM_OFF),
+/* 0111 0101 0011 */ TABDECL( OP_UND),
+/* 0111 0101 0100 */ TABDECL( OP_LDRB_M_ASR_IMM_OFF),
+/* 0111 0101 0101 */ TABDECL( OP_UND),
+/* 0111 0101 0110 */ TABDECL( OP_LDRB_M_ROR_IMM_OFF),
+/* 0111 0101 0111 */ TABDECL( OP_UND),
+/* 0111 0101 1000 */ TABDECL( OP_LDRB_M_LSL_IMM_OFF),
+/* 0111 0101 1001 */ TABDECL( OP_UND),
+/* 0111 0101 1010 */ TABDECL( OP_LDRB_M_LSR_IMM_OFF),
+/* 0111 0101 1011 */ TABDECL( OP_UND),
+/* 0111 0101 1100 */ TABDECL( OP_LDRB_M_ASR_IMM_OFF),
+/* 0111 0101 1101 */ TABDECL( OP_UND),
+/* 0111 0101 1110 */ TABDECL( OP_LDRB_M_ROR_IMM_OFF),
+/* 0111 0101 1111 */ TABDECL( OP_UND),
+/* 0111 0110 0000 */ TABDECL( OP_STRB_M_LSL_IMM_OFF_PREIND),
+/* 0111 0110 0001 */ TABDECL( OP_UND),
+/* 0111 0110 0010 */ TABDECL( OP_STRB_M_LSR_IMM_OFF_PREIND),
+/* 0111 0110 0011 */ TABDECL( OP_UND),
+/* 0111 0110 0100 */ TABDECL( OP_STRB_M_ASR_IMM_OFF_PREIND),
+/* 0111 0110 0101 */ TABDECL( OP_UND),
+/* 0111 0110 0110 */ TABDECL( OP_STRB_M_ROR_IMM_OFF_PREIND),
+/* 0111 0110 0111 */ TABDECL( OP_UND),
+/* 0111 0110 1000 */ TABDECL( OP_STRB_M_LSL_IMM_OFF_PREIND),
+/* 0111 0110 1001 */ TABDECL( OP_UND),
+/* 0111 0110 1010 */ TABDECL( OP_STRB_M_LSR_IMM_OFF_PREIND),
+/* 0111 0110 1011 */ TABDECL( OP_UND),
+/* 0111 0110 1100 */ TABDECL( OP_STRB_M_ASR_IMM_OFF_PREIND),
+/* 0111 0110 1101 */ TABDECL( OP_UND),
+/* 0111 0110 1110 */ TABDECL( OP_STRB_M_ROR_IMM_OFF_PREIND),
+/* 0111 0110 1111 */ TABDECL( OP_UND),
+/* 0111 0111 0000 */ TABDECL( OP_LDRB_M_LSL_IMM_OFF_PREIND),
+/* 0111 0111 0001 */ TABDECL( OP_UND),
+/* 0111 0111 0010 */ TABDECL( OP_LDRB_M_LSR_IMM_OFF_PREIND),
+/* 0111 0111 0011 */ TABDECL( OP_UND),
+/* 0111 0111 0100 */ TABDECL( OP_LDRB_M_ASR_IMM_OFF_PREIND),
+/* 0111 0111 0101 */ TABDECL( OP_UND),
+/* 0111 0111 0110 */ TABDECL( OP_LDRB_M_ROR_IMM_OFF_PREIND),
+/* 0111 0111 0111 */ TABDECL( OP_UND),
+/* 0111 0111 1000 */ TABDECL( OP_LDRB_M_LSL_IMM_OFF_PREIND),
+/* 0111 0111 1001 */ TABDECL( OP_UND),
+/* 0111 0111 1010 */ TABDECL( OP_LDRB_M_LSR_IMM_OFF_PREIND),
+/* 0111 0111 1011 */ TABDECL( OP_UND),
+/* 0111 0111 1100 */ TABDECL( OP_LDRB_M_ASR_IMM_OFF_PREIND),
+/* 0111 0111 1101 */ TABDECL( OP_UND),
+/* 0111 0111 1110 */ TABDECL( OP_LDRB_M_ROR_IMM_OFF_PREIND),
+/* 0111 0111 1111 */ TABDECL( OP_UND),
+/* 0111 1000 0000 */ TABDECL( OP_STR_P_LSL_IMM_OFF),
+/* 0111 1000 0001 */ TABDECL( OP_UND),
+/* 0111 1000 0010 */ TABDECL( OP_STR_P_LSR_IMM_OFF),
+/* 0111 1000 0011 */ TABDECL( OP_UND),
+/* 0111 1000 0100 */ TABDECL( OP_STR_P_ASR_IMM_OFF),
+/* 0111 1000 0101 */ TABDECL( OP_UND),
+/* 0111 1000 0110 */ TABDECL( OP_STR_P_ROR_IMM_OFF),
+/* 0111 1000 0111 */ TABDECL( OP_UND),
+/* 0111 1000 1000 */ TABDECL( OP_STR_P_LSL_IMM_OFF),
+/* 0111 1000 1001 */ TABDECL( OP_UND),
+/* 0111 1000 1010 */ TABDECL( OP_STR_P_LSR_IMM_OFF),
+/* 0111 1000 1011 */ TABDECL( OP_UND),
+/* 0111 1000 1100 */ TABDECL( OP_STR_P_ASR_IMM_OFF),
+/* 0111 1000 1101 */ TABDECL( OP_UND),
+/* 0111 1000 1110 */ TABDECL( OP_STR_P_ROR_IMM_OFF),
+/* 0111 1000 1111 */ TABDECL( OP_UND),
+/* 0111 1001 0000 */ TABDECL( OP_LDR_P_LSL_IMM_OFF),
+/* 0111 1001 0001 */ TABDECL( OP_UND),
+/* 0111 1001 0010 */ TABDECL( OP_LDR_P_LSR_IMM_OFF),
+/* 0111 1001 0011 */ TABDECL( OP_UND),
+/* 0111 1001 0100 */ TABDECL( OP_LDR_P_ASR_IMM_OFF),
+/* 0111 1001 0101 */ TABDECL( OP_UND),
+/* 0111 1001 0110 */ TABDECL( OP_LDR_P_ROR_IMM_OFF),
+/* 0111 1001 0111 */ TABDECL( OP_UND),
+/* 0111 1001 1000 */ TABDECL( OP_LDR_P_LSL_IMM_OFF),
+/* 0111 1001 1001 */ TABDECL( OP_UND),
+/* 0111 1001 1010 */ TABDECL( OP_LDR_P_LSR_IMM_OFF),
+/* 0111 1001 1011 */ TABDECL( OP_UND),
+/* 0111 1001 1100 */ TABDECL( OP_LDR_P_ASR_IMM_OFF),
+/* 0111 1001 1101 */ TABDECL( OP_UND),
+/* 0111 1001 1110 */ TABDECL( OP_LDR_P_ROR_IMM_OFF),
+/* 0111 1001 1111 */ TABDECL( OP_UND),
+/* 0111 1010 0000 */ TABDECL( OP_STR_P_LSL_IMM_OFF_PREIND),
+/* 0111 1010 0001 */ TABDECL( OP_UND),
+/* 0111 1010 0010 */ TABDECL( OP_STR_P_LSR_IMM_OFF_PREIND),
+/* 0111 1010 0011 */ TABDECL( OP_UND),
+/* 0111 1010 0100 */ TABDECL( OP_STR_P_ASR_IMM_OFF_PREIND),
+/* 0111 1010 0101 */ TABDECL( OP_UND),
+/* 0111 1010 0110 */ TABDECL( OP_STR_P_ROR_IMM_OFF_PREIND),
+/* 0111 1010 0111 */ TABDECL( OP_UND),
+/* 0111 1010 1000 */ TABDECL( OP_STR_P_LSL_IMM_OFF_PREIND),
+/* 0111 1010 1001 */ TABDECL( OP_UND),
+/* 0111 1010 1010 */ TABDECL( OP_STR_P_LSR_IMM_OFF_PREIND),
+/* 0111 1010 1011 */ TABDECL( OP_UND),
+/* 0111 1010 1100 */ TABDECL( OP_STR_P_ASR_IMM_OFF_PREIND),
+/* 0111 1010 1101 */ TABDECL( OP_UND),
+/* 0111 1010 1110 */ TABDECL( OP_STR_P_ROR_IMM_OFF_PREIND),
+/* 0111 1010 1111 */ TABDECL( OP_UND),
+/* 0111 1011 0000 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_PREIND),
+/* 0111 1011 0001 */ TABDECL( OP_UND),
+/* 0111 1011 0010 */ TABDECL( OP_LDR_P_LSR_IMM_OFF_PREIND),
+/* 0111 1011 0011 */ TABDECL( OP_UND),
+/* 0111 1011 0100 */ TABDECL( OP_LDR_P_ASR_IMM_OFF_PREIND),
+/* 0111 1011 0101 */ TABDECL( OP_UND),
+/* 0111 1011 0110 */ TABDECL( OP_LDR_P_ROR_IMM_OFF_PREIND),
+/* 0111 1011 0111 */ TABDECL( OP_UND),
+/* 0111 1011 1000 */ TABDECL( OP_LDR_P_LSL_IMM_OFF_PREIND),
+/* 0111 1011 1001 */ TABDECL( OP_UND),
+/* 0111 1011 1010 */ TABDECL( OP_LDR_P_LSR_IMM_OFF_PREIND),
+/* 0111 1011 1011 */ TABDECL( OP_UND),
+/* 0111 1011 1100 */ TABDECL( OP_LDR_P_ASR_IMM_OFF_PREIND),
+/* 0111 1011 1101 */ TABDECL( OP_UND),
+/* 0111 1011 1110 */ TABDECL( OP_LDR_P_ROR_IMM_OFF_PREIND),
+/* 0111 1011 1111 */ TABDECL( OP_UND),
+/* 0111 1100 0000 */ TABDECL( OP_STRB_P_LSL_IMM_OFF),
+/* 0111 1100 0001 */ TABDECL( OP_UND),
+/* 0111 1100 0010 */ TABDECL( OP_STRB_P_LSR_IMM_OFF),
+/* 0111 1100 0011 */ TABDECL( OP_UND),
+/* 0111 1100 0100 */ TABDECL( OP_STRB_P_ASR_IMM_OFF),
+/* 0111 1100 0101 */ TABDECL( OP_UND),
+/* 0111 1100 0110 */ TABDECL( OP_STRB_P_ROR_IMM_OFF),
+/* 0111 1100 0111 */ TABDECL( OP_UND),
+/* 0111 1100 1000 */ TABDECL( OP_STRB_P_LSL_IMM_OFF),
+/* 0111 1100 1001 */ TABDECL( OP_UND),
+/* 0111 1100 1010 */ TABDECL( OP_STRB_P_LSR_IMM_OFF),
+/* 0111 1100 1011 */ TABDECL( OP_UND),
+/* 0111 1100 1100 */ TABDECL( OP_STRB_P_ASR_IMM_OFF),
+/* 0111 1100 1101 */ TABDECL( OP_UND),
+/* 0111 1100 1110 */ TABDECL( OP_STRB_P_ROR_IMM_OFF),
+/* 0111 1100 1111 */ TABDECL( OP_UND),
+/* 0111 1101 0000 */ TABDECL( OP_LDRB_P_LSL_IMM_OFF),
+/* 0111 1101 0001 */ TABDECL( OP_UND),
+/* 0111 1101 0010 */ TABDECL( OP_LDRB_P_LSR_IMM_OFF),
+/* 0111 1101 0011 */ TABDECL( OP_UND),
+/* 0111 1101 0100 */ TABDECL( OP_LDRB_P_ASR_IMM_OFF),
+/* 0111 1101 0101 */ TABDECL( OP_UND),
+/* 0111 1101 0110 */ TABDECL( OP_LDRB_P_ROR_IMM_OFF),
+/* 0111 1101 0111 */ TABDECL( OP_UND),
+/* 0111 1101 1000 */ TABDECL( OP_LDRB_P_LSL_IMM_OFF),
+/* 0111 1101 1001 */ TABDECL( OP_UND),
+/* 0111 1101 1010 */ TABDECL( OP_LDRB_P_LSR_IMM_OFF),
+/* 0111 1101 1011 */ TABDECL( OP_UND),
+/* 0111 1101 1100 */ TABDECL( OP_LDRB_P_ASR_IMM_OFF),
+/* 0111 1101 1101 */ TABDECL( OP_UND),
+/* 0111 1101 1110 */ TABDECL( OP_LDRB_P_ROR_IMM_OFF),
+/* 0111 1101 1111 */ TABDECL( OP_UND),
+/* 0111 1110 0000 */ TABDECL( OP_STRB_P_LSL_IMM_OFF_PREIND),
+/* 0111 1110 0001 */ TABDECL( OP_UND),
+/* 0111 1110 0010 */ TABDECL( OP_STRB_P_LSR_IMM_OFF_PREIND),
+/* 0111 1110 0011 */ TABDECL( OP_UND),
+/* 0111 1110 0100 */ TABDECL( OP_STRB_P_ASR_IMM_OFF_PREIND),
+/* 0111 1110 0101 */ TABDECL( OP_UND),
+/* 0111 1110 0110 */ TABDECL( OP_STRB_P_ROR_IMM_OFF_PREIND),
+/* 0111 1110 0111 */ TABDECL( OP_UND),
+/* 0111 1110 1000 */ TABDECL( OP_STRB_P_LSL_IMM_OFF_PREIND),
+/* 0111 1110 1001 */ TABDECL( OP_UND),
+/* 0111 1110 1010 */ TABDECL( OP_STRB_P_LSR_IMM_OFF_PREIND),
+/* 0111 1110 1011 */ TABDECL( OP_UND),
+/* 0111 1110 1100 */ TABDECL( OP_STRB_P_ASR_IMM_OFF_PREIND),
+/* 0111 1110 1101 */ TABDECL( OP_UND),
+/* 0111 1110 1110 */ TABDECL( OP_STRB_P_ROR_IMM_OFF_PREIND),
+/* 0111 1110 1111 */ TABDECL( OP_UND),
+/* 0111 1111 0000 */ TABDECL( OP_LDRB_P_LSL_IMM_OFF_PREIND),
+/* 0111 1111 0001 */ TABDECL( OP_UND),
+/* 0111 1111 0010 */ TABDECL( OP_LDRB_P_LSR_IMM_OFF_PREIND),
+/* 0111 1111 0011 */ TABDECL( OP_UND),
+/* 0111 1111 0100 */ TABDECL( OP_LDRB_P_ASR_IMM_OFF_PREIND),
+/* 0111 1111 0101 */ TABDECL( OP_UND),
+/* 0111 1111 0110 */ TABDECL( OP_LDRB_P_ROR_IMM_OFF_PREIND),
+/* 0111 1111 0111 */ TABDECL( OP_UND),
+/* 0111 1111 1000 */ TABDECL( OP_LDRB_P_LSL_IMM_OFF_PREIND),
+/* 0111 1111 1001 */ TABDECL( OP_UND),
+/* 0111 1111 1010 */ TABDECL( OP_LDRB_P_LSR_IMM_OFF_PREIND),
+/* 0111 1111 1011 */ TABDECL( OP_UND),
+/* 0111 1111 1100 */ TABDECL( OP_LDRB_P_ASR_IMM_OFF_PREIND),
+/* 0111 1111 1101 */ TABDECL( OP_UND),
+/* 0111 1111 1110 */ TABDECL( OP_LDRB_P_ROR_IMM_OFF_PREIND),
+/* 0111 1111 1111 */ TABDECL( OP_UND),
+/* 1000 0000 0000 */ TABDECL( OP_STMDA),
+/* 1000 0000 0001 */ TABDECL( OP_STMDA),
+/* 1000 0000 0010 */ TABDECL( OP_STMDA),
+/* 1000 0000 0011 */ TABDECL( OP_STMDA),
+/* 1000 0000 0100 */ TABDECL( OP_STMDA),
+/* 1000 0000 0101 */ TABDECL( OP_STMDA),
+/* 1000 0000 0110 */ TABDECL( OP_STMDA),
+/* 1000 0000 0111 */ TABDECL( OP_STMDA),
+/* 1000 0000 1000 */ TABDECL( OP_STMDA),
+/* 1000 0000 1001 */ TABDECL( OP_STMDA),
+/* 1000 0000 1010 */ TABDECL( OP_STMDA),
+/* 1000 0000 1011 */ TABDECL( OP_STMDA),
+/* 1000 0000 1100 */ TABDECL( OP_STMDA),
+/* 1000 0000 1101 */ TABDECL( OP_STMDA),
+/* 1000 0000 1110 */ TABDECL( OP_STMDA),
+/* 1000 0000 1111 */ TABDECL( OP_STMDA),
+/* 1000 0001 0000 */ TABDECL( OP_LDMDA),
+/* 1000 0001 0001 */ TABDECL( OP_LDMDA),
+/* 1000 0001 0010 */ TABDECL( OP_LDMDA),
+/* 1000 0001 0011 */ TABDECL( OP_LDMDA),
+/* 1000 0001 0100 */ TABDECL( OP_LDMDA),
+/* 1000 0001 0101 */ TABDECL( OP_LDMDA),
+/* 1000 0001 0110 */ TABDECL( OP_LDMDA),
+/* 1000 0001 0111 */ TABDECL( OP_LDMDA),
+/* 1000 0001 1000 */ TABDECL( OP_LDMDA),
+/* 1000 0001 1001 */ TABDECL( OP_LDMDA),
+/* 1000 0001 1010 */ TABDECL( OP_LDMDA),
+/* 1000 0001 1011 */ TABDECL( OP_LDMDA),
+/* 1000 0001 1100 */ TABDECL( OP_LDMDA),
+/* 1000 0001 1101 */ TABDECL( OP_LDMDA),
+/* 1000 0001 1110 */ TABDECL( OP_LDMDA),
+/* 1000 0001 1111 */ TABDECL( OP_LDMDA),
+/* 1000 0010 0000 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 0001 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 0010 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 0011 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 0100 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 0101 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 0110 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 0111 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 1000 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 1001 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 1010 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 1011 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 1100 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 1101 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 1110 */ TABDECL( OP_STMDA_W),
+/* 1000 0010 1111 */ TABDECL( OP_STMDA_W),
+/* 1000 0011 0000 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 0001 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 0010 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 0011 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 0100 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 0101 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 0110 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 0111 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 1000 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 1001 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 1010 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 1011 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 1100 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 1101 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 1110 */ TABDECL( OP_LDMDA_W),
+/* 1000 0011 1111 */ TABDECL( OP_LDMDA_W),
+/* 1000 0100 0000 */ TABDECL( OP_STMDA2),
+/* 1000 0100 0001 */ TABDECL( OP_STMDA2),
+/* 1000 0100 0010 */ TABDECL( OP_STMDA2),
+/* 1000 0100 0011 */ TABDECL( OP_STMDA2),
+/* 1000 0100 0100 */ TABDECL( OP_STMDA2),
+/* 1000 0100 0101 */ TABDECL( OP_STMDA2),
+/* 1000 0100 0110 */ TABDECL( OP_STMDA2),
+/* 1000 0100 0111 */ TABDECL( OP_STMDA2),
+/* 1000 0100 1000 */ TABDECL( OP_STMDA2),
+/* 1000 0100 1001 */ TABDECL( OP_STMDA2),
+/* 1000 0100 1010 */ TABDECL( OP_STMDA2),
+/* 1000 0100 1011 */ TABDECL( OP_STMDA2),
+/* 1000 0100 1100 */ TABDECL( OP_STMDA2),
+/* 1000 0100 1101 */ TABDECL( OP_STMDA2),
+/* 1000 0100 1110 */ TABDECL( OP_STMDA2),
+/* 1000 0100 1111 */ TABDECL( OP_STMDA2),
+/* 1000 0101 0000 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 0001 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 0010 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 0011 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 0100 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 0101 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 0110 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 0111 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 1000 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 1001 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 1010 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 1011 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 1100 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 1101 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 1110 */ TABDECL( OP_LDMDA2),
+/* 1000 0101 1111 */ TABDECL( OP_LDMDA2),
+/* 1000 0110 0000 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 0001 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 0010 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 0011 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 0100 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 0101 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 0110 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 0111 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 1000 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 1001 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 1010 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 1011 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 1100 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 1101 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 1110 */ TABDECL( OP_STMDA2_W),
+/* 1000 0110 1111 */ TABDECL( OP_STMDA2_W),
+/* 1000 0111 0000 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 0001 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 0010 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 0011 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 0100 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 0101 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 0110 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 0111 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 1000 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 1001 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 1010 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 1011 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 1100 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 1101 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 1110 */ TABDECL( OP_LDMDA2_W),
+/* 1000 0111 1111 */ TABDECL( OP_LDMDA2_W),
+/* 1000 1000 0000 */ TABDECL( OP_STMIA),
+/* 1000 1000 0001 */ TABDECL( OP_STMIA),
+/* 1000 1000 0010 */ TABDECL( OP_STMIA),
+/* 1000 1000 0011 */ TABDECL( OP_STMIA),
+/* 1000 1000 0100 */ TABDECL( OP_STMIA),
+/* 1000 1000 0101 */ TABDECL( OP_STMIA),
+/* 1000 1000 0110 */ TABDECL( OP_STMIA),
+/* 1000 1000 0111 */ TABDECL( OP_STMIA),
+/* 1000 1000 1000 */ TABDECL( OP_STMIA),
+/* 1000 1000 1001 */ TABDECL( OP_STMIA),
+/* 1000 1000 1010 */ TABDECL( OP_STMIA),
+/* 1000 1000 1011 */ TABDECL( OP_STMIA),
+/* 1000 1000 1100 */ TABDECL( OP_STMIA),
+/* 1000 1000 1101 */ TABDECL( OP_STMIA),
+/* 1000 1000 1110 */ TABDECL( OP_STMIA),
+/* 1000 1000 1111 */ TABDECL( OP_STMIA),
+/* 1000 1001 0000 */ TABDECL( OP_LDMIA),
+/* 1000 1001 0001 */ TABDECL( OP_LDMIA),
+/* 1000 1001 0010 */ TABDECL( OP_LDMIA),
+/* 1000 1001 0011 */ TABDECL( OP_LDMIA),
+/* 1000 1001 0100 */ TABDECL( OP_LDMIA),
+/* 1000 1001 0101 */ TABDECL( OP_LDMIA),
+/* 1000 1001 0110 */ TABDECL( OP_LDMIA),
+/* 1000 1001 0111 */ TABDECL( OP_LDMIA),
+/* 1000 1001 1000 */ TABDECL( OP_LDMIA),
+/* 1000 1001 1001 */ TABDECL( OP_LDMIA),
+/* 1000 1001 1010 */ TABDECL( OP_LDMIA),
+/* 1000 1001 1011 */ TABDECL( OP_LDMIA),
+/* 1000 1001 1100 */ TABDECL( OP_LDMIA),
+/* 1000 1001 1101 */ TABDECL( OP_LDMIA),
+/* 1000 1001 1110 */ TABDECL( OP_LDMIA),
+/* 1000 1001 1111 */ TABDECL( OP_LDMIA),
+/* 1000 1010 0000 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 0001 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 0010 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 0011 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 0100 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 0101 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 0110 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 0111 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 1000 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 1001 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 1010 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 1011 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 1100 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 1101 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 1110 */ TABDECL( OP_STMIA_W),
+/* 1000 1010 1111 */ TABDECL( OP_STMIA_W),
+/* 1000 1011 0000 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 0001 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 0010 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 0011 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 0100 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 0101 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 0110 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 0111 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 1000 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 1001 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 1010 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 1011 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 1100 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 1101 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 1110 */ TABDECL( OP_LDMIA_W),
+/* 1000 1011 1111 */ TABDECL( OP_LDMIA_W),
+/* 1000 1100 0000 */ TABDECL( OP_STMIA2),
+/* 1000 1100 0001 */ TABDECL( OP_STMIA2),
+/* 1000 1100 0010 */ TABDECL( OP_STMIA2),
+/* 1000 1100 0011 */ TABDECL( OP_STMIA2),
+/* 1000 1100 0100 */ TABDECL( OP_STMIA2),
+/* 1000 1100 0101 */ TABDECL( OP_STMIA2),
+/* 1000 1100 0110 */ TABDECL( OP_STMIA2),
+/* 1000 1100 0111 */ TABDECL( OP_STMIA2),
+/* 1000 1100 1000 */ TABDECL( OP_STMIA2),
+/* 1000 1100 1001 */ TABDECL( OP_STMIA2),
+/* 1000 1100 1010 */ TABDECL( OP_STMIA2),
+/* 1000 1100 1011 */ TABDECL( OP_STMIA2),
+/* 1000 1100 1100 */ TABDECL( OP_STMIA2),
+/* 1000 1100 1101 */ TABDECL( OP_STMIA2),
+/* 1000 1100 1110 */ TABDECL( OP_STMIA2),
+/* 1000 1100 1111 */ TABDECL( OP_STMIA2),
+/* 1000 1101 0000 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 0001 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 0010 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 0011 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 0100 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 0101 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 0110 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 0111 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 1000 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 1001 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 1010 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 1011 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 1100 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 1101 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 1110 */ TABDECL( OP_LDMIA2),
+/* 1000 1101 1111 */ TABDECL( OP_LDMIA2),
+/* 1000 1110 0000 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 0001 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 0010 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 0011 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 0100 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 0101 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 0110 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 0111 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 1000 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 1001 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 1010 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 1011 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 1100 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 1101 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 1110 */ TABDECL( OP_STMIA2_W),
+/* 1000 1110 1111 */ TABDECL( OP_STMIA2_W),
+/* 1000 1111 0000 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 0001 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 0010 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 0011 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 0100 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 0101 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 0110 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 0111 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 1000 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 1001 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 1010 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 1011 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 1100 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 1101 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 1110 */ TABDECL( OP_LDMIA2_W),
+/* 1000 1111 1111 */ TABDECL( OP_LDMIA2_W),
+/* 1001 0000 0000 */ TABDECL( OP_STMDB),
+/* 1001 0000 0001 */ TABDECL( OP_STMDB),
+/* 1001 0000 0010 */ TABDECL( OP_STMDB),
+/* 1001 0000 0011 */ TABDECL( OP_STMDB),
+/* 1001 0000 0100 */ TABDECL( OP_STMDB),
+/* 1001 0000 0101 */ TABDECL( OP_STMDB),
+/* 1001 0000 0110 */ TABDECL( OP_STMDB),
+/* 1001 0000 0111 */ TABDECL( OP_STMDB),
+/* 1001 0000 1000 */ TABDECL( OP_STMDB),
+/* 1001 0000 1001 */ TABDECL( OP_STMDB),
+/* 1001 0000 1010 */ TABDECL( OP_STMDB),
+/* 1001 0000 1011 */ TABDECL( OP_STMDB),
+/* 1001 0000 1100 */ TABDECL( OP_STMDB),
+/* 1001 0000 1101 */ TABDECL( OP_STMDB),
+/* 1001 0000 1110 */ TABDECL( OP_STMDB),
+/* 1001 0000 1111 */ TABDECL( OP_STMDB),
+/* 1001 0001 0000 */ TABDECL( OP_LDMDB),
+/* 1001 0001 0001 */ TABDECL( OP_LDMDB),
+/* 1001 0001 0010 */ TABDECL( OP_LDMDB),
+/* 1001 0001 0011 */ TABDECL( OP_LDMDB),
+/* 1001 0001 0100 */ TABDECL( OP_LDMDB),
+/* 1001 0001 0101 */ TABDECL( OP_LDMDB),
+/* 1001 0001 0110 */ TABDECL( OP_LDMDB),
+/* 1001 0001 0111 */ TABDECL( OP_LDMDB),
+/* 1001 0001 1000 */ TABDECL( OP_LDMDB),
+/* 1001 0001 1001 */ TABDECL( OP_LDMDB),
+/* 1001 0001 1010 */ TABDECL( OP_LDMDB),
+/* 1001 0001 1011 */ TABDECL( OP_LDMDB),
+/* 1001 0001 1100 */ TABDECL( OP_LDMDB),
+/* 1001 0001 1101 */ TABDECL( OP_LDMDB),
+/* 1001 0001 1110 */ TABDECL( OP_LDMDB),
+/* 1001 0001 1111 */ TABDECL( OP_LDMDB),
+/* 1001 0010 0000 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 0001 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 0010 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 0011 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 0100 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 0101 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 0110 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 0111 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 1000 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 1001 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 1010 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 1011 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 1100 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 1101 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 1110 */ TABDECL( OP_STMDB_W),
+/* 1001 0010 1111 */ TABDECL( OP_STMDB_W),
+/* 1001 0011 0000 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 0001 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 0010 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 0011 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 0100 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 0101 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 0110 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 0111 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 1000 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 1001 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 1010 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 1011 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 1100 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 1101 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 1110 */ TABDECL( OP_LDMDB_W),
+/* 1001 0011 1111 */ TABDECL( OP_LDMDB_W),
+/* 1001 0100 0000 */ TABDECL( OP_STMDB2),
+/* 1001 0100 0001 */ TABDECL( OP_STMDB2),
+/* 1001 0100 0010 */ TABDECL( OP_STMDB2),
+/* 1001 0100 0011 */ TABDECL( OP_STMDB2),
+/* 1001 0100 0100 */ TABDECL( OP_STMDB2),
+/* 1001 0100 0101 */ TABDECL( OP_STMDB2),
+/* 1001 0100 0110 */ TABDECL( OP_STMDB2),
+/* 1001 0100 0111 */ TABDECL( OP_STMDB2),
+/* 1001 0100 1000 */ TABDECL( OP_STMDB2),
+/* 1001 0100 1001 */ TABDECL( OP_STMDB2),
+/* 1001 0100 1010 */ TABDECL( OP_STMDB2),
+/* 1001 0100 1011 */ TABDECL( OP_STMDB2),
+/* 1001 0100 1100 */ TABDECL( OP_STMDB2),
+/* 1001 0100 1101 */ TABDECL( OP_STMDB2),
+/* 1001 0100 1110 */ TABDECL( OP_STMDB2),
+/* 1001 0100 1111 */ TABDECL( OP_STMDB2),
+/* 1001 0101 0000 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 0001 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 0010 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 0011 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 0100 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 0101 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 0110 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 0111 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 1000 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 1001 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 1010 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 1011 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 1100 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 1101 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 1110 */ TABDECL( OP_LDMDB2),
+/* 1001 0101 1111 */ TABDECL( OP_LDMDB2),
+/* 1001 0110 0000 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 0001 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 0010 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 0011 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 0100 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 0101 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 0110 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 0111 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 1000 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 1001 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 1010 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 1011 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 1100 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 1101 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 1110 */ TABDECL( OP_STMDB2_W),
+/* 1001 0110 1111 */ TABDECL( OP_STMDB2_W),
+/* 1001 0111 0000 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 0001 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 0010 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 0011 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 0100 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 0101 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 0110 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 0111 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 1000 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 1001 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 1010 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 1011 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 1100 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 1101 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 1110 */ TABDECL( OP_LDMDB2_W),
+/* 1001 0111 1111 */ TABDECL( OP_LDMDB2_W),
+/* 1001 1000 0000 */ TABDECL( OP_STMIB),
+/* 1001 1000 0001 */ TABDECL( OP_STMIB),
+/* 1001 1000 0010 */ TABDECL( OP_STMIB),
+/* 1001 1000 0011 */ TABDECL( OP_STMIB),
+/* 1001 1000 0100 */ TABDECL( OP_STMIB),
+/* 1001 1000 0101 */ TABDECL( OP_STMIB),
+/* 1001 1000 0110 */ TABDECL( OP_STMIB),
+/* 1001 1000 0111 */ TABDECL( OP_STMIB),
+/* 1001 1000 1000 */ TABDECL( OP_STMIB),
+/* 1001 1000 1001 */ TABDECL( OP_STMIB),
+/* 1001 1000 1010 */ TABDECL( OP_STMIB),
+/* 1001 1000 1011 */ TABDECL( OP_STMIB),
+/* 1001 1000 1100 */ TABDECL( OP_STMIB),
+/* 1001 1000 1101 */ TABDECL( OP_STMIB),
+/* 1001 1000 1110 */ TABDECL( OP_STMIB),
+/* 1001 1000 1111 */ TABDECL( OP_STMIB),
+/* 1001 1001 0000 */ TABDECL( OP_LDMIB),
+/* 1001 1001 0001 */ TABDECL( OP_LDMIB),
+/* 1001 1001 0010 */ TABDECL( OP_LDMIB),
+/* 1001 1001 0011 */ TABDECL( OP_LDMIB),
+/* 1001 1001 0100 */ TABDECL( OP_LDMIB),
+/* 1001 1001 0101 */ TABDECL( OP_LDMIB),
+/* 1001 1001 0110 */ TABDECL( OP_LDMIB),
+/* 1001 1001 0111 */ TABDECL( OP_LDMIB),
+/* 1001 1001 1000 */ TABDECL( OP_LDMIB),
+/* 1001 1001 1001 */ TABDECL( OP_LDMIB),
+/* 1001 1001 1010 */ TABDECL( OP_LDMIB),
+/* 1001 1001 1011 */ TABDECL( OP_LDMIB),
+/* 1001 1001 1100 */ TABDECL( OP_LDMIB),
+/* 1001 1001 1101 */ TABDECL( OP_LDMIB),
+/* 1001 1001 1110 */ TABDECL( OP_LDMIB),
+/* 1001 1001 1111 */ TABDECL( OP_LDMIB),
+/* 1001 1010 0000 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 0001 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 0010 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 0011 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 0100 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 0101 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 0110 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 0111 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 1000 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 1001 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 1010 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 1011 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 1100 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 1101 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 1110 */ TABDECL( OP_STMIB_W),
+/* 1001 1010 1111 */ TABDECL( OP_STMIB_W),
+/* 1001 1011 0000 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 0001 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 0010 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 0011 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 0100 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 0101 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 0110 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 0111 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 1000 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 1001 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 1010 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 1011 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 1100 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 1101 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 1110 */ TABDECL( OP_LDMIB_W),
+/* 1001 1011 1111 */ TABDECL( OP_LDMIB_W),
+/* 1001 1100 0000 */ TABDECL( OP_STMIB2),
+/* 1001 1100 0001 */ TABDECL( OP_STMIB2),
+/* 1001 1100 0010 */ TABDECL( OP_STMIB2),
+/* 1001 1100 0011 */ TABDECL( OP_STMIB2),
+/* 1001 1100 0100 */ TABDECL( OP_STMIB2),
+/* 1001 1100 0101 */ TABDECL( OP_STMIB2),
+/* 1001 1100 0110 */ TABDECL( OP_STMIB2),
+/* 1001 1100 0111 */ TABDECL( OP_STMIB2),
+/* 1001 1100 1000 */ TABDECL( OP_STMIB2),
+/* 1001 1100 1001 */ TABDECL( OP_STMIB2),
+/* 1001 1100 1010 */ TABDECL( OP_STMIB2),
+/* 1001 1100 1011 */ TABDECL( OP_STMIB2),
+/* 1001 1100 1100 */ TABDECL( OP_STMIB2),
+/* 1001 1100 1101 */ TABDECL( OP_STMIB2),
+/* 1001 1100 1110 */ TABDECL( OP_STMIB2),
+/* 1001 1100 1111 */ TABDECL( OP_STMIB2),
+/* 1001 1101 0000 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 0001 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 0010 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 0011 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 0100 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 0101 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 0110 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 0111 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 1000 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 1001 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 1010 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 1011 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 1100 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 1101 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 1110 */ TABDECL( OP_LDMIB2),
+/* 1001 1101 1111 */ TABDECL( OP_LDMIB2),
+/* 1001 1110 0000 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 0001 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 0010 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 0011 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 0100 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 0101 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 0110 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 0111 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 1000 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 1001 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 1010 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 1011 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 1100 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 1101 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 1110 */ TABDECL( OP_STMIB2_W),
+/* 1001 1110 1111 */ TABDECL( OP_STMIB2_W),
+/* 1001 1111 0000 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 0001 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 0010 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 0011 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 0100 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 0101 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 0110 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 0111 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 1000 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 1001 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 1010 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 1011 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 1100 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 1101 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 1110 */ TABDECL( OP_LDMIB2_W),
+/* 1001 1111 1111 */ TABDECL( OP_LDMIB2_W),
+/* 1010 0000 0000 */ TABDECL( OP_B),
+/* 1010 0000 0001 */ TABDECL( OP_B),
+/* 1010 0000 0010 */ TABDECL( OP_B),
+/* 1010 0000 0011 */ TABDECL( OP_B),
+/* 1010 0000 0100 */ TABDECL( OP_B),
+/* 1010 0000 0101 */ TABDECL( OP_B),
+/* 1010 0000 0110 */ TABDECL( OP_B),
+/* 1010 0000 0111 */ TABDECL( OP_B),
+/* 1010 0000 1000 */ TABDECL( OP_B),
+/* 1010 0000 1001 */ TABDECL( OP_B),
+/* 1010 0000 1010 */ TABDECL( OP_B),
+/* 1010 0000 1011 */ TABDECL( OP_B),
+/* 1010 0000 1100 */ TABDECL( OP_B),
+/* 1010 0000 1101 */ TABDECL( OP_B),
+/* 1010 0000 1110 */ TABDECL( OP_B),
+/* 1010 0000 1111 */ TABDECL( OP_B),
+/* 1010 0001 0000 */ TABDECL( OP_B),
+/* 1010 0001 0001 */ TABDECL( OP_B),
+/* 1010 0001 0010 */ TABDECL( OP_B),
+/* 1010 0001 0011 */ TABDECL( OP_B),
+/* 1010 0001 0100 */ TABDECL( OP_B),
+/* 1010 0001 0101 */ TABDECL( OP_B),
+/* 1010 0001 0110 */ TABDECL( OP_B),
+/* 1010 0001 0111 */ TABDECL( OP_B),
+/* 1010 0001 1000 */ TABDECL( OP_B),
+/* 1010 0001 1001 */ TABDECL( OP_B),
+/* 1010 0001 1010 */ TABDECL( OP_B),
+/* 1010 0001 1011 */ TABDECL( OP_B),
+/* 1010 0001 1100 */ TABDECL( OP_B),
+/* 1010 0001 1101 */ TABDECL( OP_B),
+/* 1010 0001 1110 */ TABDECL( OP_B),
+/* 1010 0001 1111 */ TABDECL( OP_B),
+/* 1010 0010 0000 */ TABDECL( OP_B),
+/* 1010 0010 0001 */ TABDECL( OP_B),
+/* 1010 0010 0010 */ TABDECL( OP_B),
+/* 1010 0010 0011 */ TABDECL( OP_B),
+/* 1010 0010 0100 */ TABDECL( OP_B),
+/* 1010 0010 0101 */ TABDECL( OP_B),
+/* 1010 0010 0110 */ TABDECL( OP_B),
+/* 1010 0010 0111 */ TABDECL( OP_B),
+/* 1010 0010 1000 */ TABDECL( OP_B),
+/* 1010 0010 1001 */ TABDECL( OP_B),
+/* 1010 0010 1010 */ TABDECL( OP_B),
+/* 1010 0010 1011 */ TABDECL( OP_B),
+/* 1010 0010 1100 */ TABDECL( OP_B),
+/* 1010 0010 1101 */ TABDECL( OP_B),
+/* 1010 0010 1110 */ TABDECL( OP_B),
+/* 1010 0010 1111 */ TABDECL( OP_B),
+/* 1010 0011 0000 */ TABDECL( OP_B),
+/* 1010 0011 0001 */ TABDECL( OP_B),
+/* 1010 0011 0010 */ TABDECL( OP_B),
+/* 1010 0011 0011 */ TABDECL( OP_B),
+/* 1010 0011 0100 */ TABDECL( OP_B),
+/* 1010 0011 0101 */ TABDECL( OP_B),
+/* 1010 0011 0110 */ TABDECL( OP_B),
+/* 1010 0011 0111 */ TABDECL( OP_B),
+/* 1010 0011 1000 */ TABDECL( OP_B),
+/* 1010 0011 1001 */ TABDECL( OP_B),
+/* 1010 0011 1010 */ TABDECL( OP_B),
+/* 1010 0011 1011 */ TABDECL( OP_B),
+/* 1010 0011 1100 */ TABDECL( OP_B),
+/* 1010 0011 1101 */ TABDECL( OP_B),
+/* 1010 0011 1110 */ TABDECL( OP_B),
+/* 1010 0011 1111 */ TABDECL( OP_B),
+/* 1010 0100 0000 */ TABDECL( OP_B),
+/* 1010 0100 0001 */ TABDECL( OP_B),
+/* 1010 0100 0010 */ TABDECL( OP_B),
+/* 1010 0100 0011 */ TABDECL( OP_B),
+/* 1010 0100 0100 */ TABDECL( OP_B),
+/* 1010 0100 0101 */ TABDECL( OP_B),
+/* 1010 0100 0110 */ TABDECL( OP_B),
+/* 1010 0100 0111 */ TABDECL( OP_B),
+/* 1010 0100 1000 */ TABDECL( OP_B),
+/* 1010 0100 1001 */ TABDECL( OP_B),
+/* 1010 0100 1010 */ TABDECL( OP_B),
+/* 1010 0100 1011 */ TABDECL( OP_B),
+/* 1010 0100 1100 */ TABDECL( OP_B),
+/* 1010 0100 1101 */ TABDECL( OP_B),
+/* 1010 0100 1110 */ TABDECL( OP_B),
+/* 1010 0100 1111 */ TABDECL( OP_B),
+/* 1010 0101 0000 */ TABDECL( OP_B),
+/* 1010 0101 0001 */ TABDECL( OP_B),
+/* 1010 0101 0010 */ TABDECL( OP_B),
+/* 1010 0101 0011 */ TABDECL( OP_B),
+/* 1010 0101 0100 */ TABDECL( OP_B),
+/* 1010 0101 0101 */ TABDECL( OP_B),
+/* 1010 0101 0110 */ TABDECL( OP_B),
+/* 1010 0101 0111 */ TABDECL( OP_B),
+/* 1010 0101 1000 */ TABDECL( OP_B),
+/* 1010 0101 1001 */ TABDECL( OP_B),
+/* 1010 0101 1010 */ TABDECL( OP_B),
+/* 1010 0101 1011 */ TABDECL( OP_B),
+/* 1010 0101 1100 */ TABDECL( OP_B),
+/* 1010 0101 1101 */ TABDECL( OP_B),
+/* 1010 0101 1110 */ TABDECL( OP_B),
+/* 1010 0101 1111 */ TABDECL( OP_B),
+/* 1010 0110 0000 */ TABDECL( OP_B),
+/* 1010 0110 0001 */ TABDECL( OP_B),
+/* 1010 0110 0010 */ TABDECL( OP_B),
+/* 1010 0110 0011 */ TABDECL( OP_B),
+/* 1010 0110 0100 */ TABDECL( OP_B),
+/* 1010 0110 0101 */ TABDECL( OP_B),
+/* 1010 0110 0110 */ TABDECL( OP_B),
+/* 1010 0110 0111 */ TABDECL( OP_B),
+/* 1010 0110 1000 */ TABDECL( OP_B),
+/* 1010 0110 1001 */ TABDECL( OP_B),
+/* 1010 0110 1010 */ TABDECL( OP_B),
+/* 1010 0110 1011 */ TABDECL( OP_B),
+/* 1010 0110 1100 */ TABDECL( OP_B),
+/* 1010 0110 1101 */ TABDECL( OP_B),
+/* 1010 0110 1110 */ TABDECL( OP_B),
+/* 1010 0110 1111 */ TABDECL( OP_B),
+/* 1010 0111 0000 */ TABDECL( OP_B),
+/* 1010 0111 0001 */ TABDECL( OP_B),
+/* 1010 0111 0010 */ TABDECL( OP_B),
+/* 1010 0111 0011 */ TABDECL( OP_B),
+/* 1010 0111 0100 */ TABDECL( OP_B),
+/* 1010 0111 0101 */ TABDECL( OP_B),
+/* 1010 0111 0110 */ TABDECL( OP_B),
+/* 1010 0111 0111 */ TABDECL( OP_B),
+/* 1010 0111 1000 */ TABDECL( OP_B),
+/* 1010 0111 1001 */ TABDECL( OP_B),
+/* 1010 0111 1010 */ TABDECL( OP_B),
+/* 1010 0111 1011 */ TABDECL( OP_B),
+/* 1010 0111 1100 */ TABDECL( OP_B),
+/* 1010 0111 1101 */ TABDECL( OP_B),
+/* 1010 0111 1110 */ TABDECL( OP_B),
+/* 1010 0111 1111 */ TABDECL( OP_B),
+/* 1010 1000 0000 */ TABDECL( OP_B),
+/* 1010 1000 0001 */ TABDECL( OP_B),
+/* 1010 1000 0010 */ TABDECL( OP_B),
+/* 1010 1000 0011 */ TABDECL( OP_B),
+/* 1010 1000 0100 */ TABDECL( OP_B),
+/* 1010 1000 0101 */ TABDECL( OP_B),
+/* 1010 1000 0110 */ TABDECL( OP_B),
+/* 1010 1000 0111 */ TABDECL( OP_B),
+/* 1010 1000 1000 */ TABDECL( OP_B),
+/* 1010 1000 1001 */ TABDECL( OP_B),
+/* 1010 1000 1010 */ TABDECL( OP_B),
+/* 1010 1000 1011 */ TABDECL( OP_B),
+/* 1010 1000 1100 */ TABDECL( OP_B),
+/* 1010 1000 1101 */ TABDECL( OP_B),
+/* 1010 1000 1110 */ TABDECL( OP_B),
+/* 1010 1000 1111 */ TABDECL( OP_B),
+/* 1010 1001 0000 */ TABDECL( OP_B),
+/* 1010 1001 0001 */ TABDECL( OP_B),
+/* 1010 1001 0010 */ TABDECL( OP_B),
+/* 1010 1001 0011 */ TABDECL( OP_B),
+/* 1010 1001 0100 */ TABDECL( OP_B),
+/* 1010 1001 0101 */ TABDECL( OP_B),
+/* 1010 1001 0110 */ TABDECL( OP_B),
+/* 1010 1001 0111 */ TABDECL( OP_B),
+/* 1010 1001 1000 */ TABDECL( OP_B),
+/* 1010 1001 1001 */ TABDECL( OP_B),
+/* 1010 1001 1010 */ TABDECL( OP_B),
+/* 1010 1001 1011 */ TABDECL( OP_B),
+/* 1010 1001 1100 */ TABDECL( OP_B),
+/* 1010 1001 1101 */ TABDECL( OP_B),
+/* 1010 1001 1110 */ TABDECL( OP_B),
+/* 1010 1001 1111 */ TABDECL( OP_B),
+/* 1010 1010 0000 */ TABDECL( OP_B),
+/* 1010 1010 0001 */ TABDECL( OP_B),
+/* 1010 1010 0010 */ TABDECL( OP_B),
+/* 1010 1010 0011 */ TABDECL( OP_B),
+/* 1010 1010 0100 */ TABDECL( OP_B),
+/* 1010 1010 0101 */ TABDECL( OP_B),
+/* 1010 1010 0110 */ TABDECL( OP_B),
+/* 1010 1010 0111 */ TABDECL( OP_B),
+/* 1010 1010 1000 */ TABDECL( OP_B),
+/* 1010 1010 1001 */ TABDECL( OP_B),
+/* 1010 1010 1010 */ TABDECL( OP_B),
+/* 1010 1010 1011 */ TABDECL( OP_B),
+/* 1010 1010 1100 */ TABDECL( OP_B),
+/* 1010 1010 1101 */ TABDECL( OP_B),
+/* 1010 1010 1110 */ TABDECL( OP_B),
+/* 1010 1010 1111 */ TABDECL( OP_B),
+/* 1010 1011 0000 */ TABDECL( OP_B),
+/* 1010 1011 0001 */ TABDECL( OP_B),
+/* 1010 1011 0010 */ TABDECL( OP_B),
+/* 1010 1011 0011 */ TABDECL( OP_B),
+/* 1010 1011 0100 */ TABDECL( OP_B),
+/* 1010 1011 0101 */ TABDECL( OP_B),
+/* 1010 1011 0110 */ TABDECL( OP_B),
+/* 1010 1011 0111 */ TABDECL( OP_B),
+/* 1010 1011 1000 */ TABDECL( OP_B),
+/* 1010 1011 1001 */ TABDECL( OP_B),
+/* 1010 1011 1010 */ TABDECL( OP_B),
+/* 1010 1011 1011 */ TABDECL( OP_B),
+/* 1010 1011 1100 */ TABDECL( OP_B),
+/* 1010 1011 1101 */ TABDECL( OP_B),
+/* 1010 1011 1110 */ TABDECL( OP_B),
+/* 1010 1011 1111 */ TABDECL( OP_B),
+/* 1010 1100 0000 */ TABDECL( OP_B),
+/* 1010 1100 0001 */ TABDECL( OP_B),
+/* 1010 1100 0010 */ TABDECL( OP_B),
+/* 1010 1100 0011 */ TABDECL( OP_B),
+/* 1010 1100 0100 */ TABDECL( OP_B),
+/* 1010 1100 0101 */ TABDECL( OP_B),
+/* 1010 1100 0110 */ TABDECL( OP_B),
+/* 1010 1100 0111 */ TABDECL( OP_B),
+/* 1010 1100 1000 */ TABDECL( OP_B),
+/* 1010 1100 1001 */ TABDECL( OP_B),
+/* 1010 1100 1010 */ TABDECL( OP_B),
+/* 1010 1100 1011 */ TABDECL( OP_B),
+/* 1010 1100 1100 */ TABDECL( OP_B),
+/* 1010 1100 1101 */ TABDECL( OP_B),
+/* 1010 1100 1110 */ TABDECL( OP_B),
+/* 1010 1100 1111 */ TABDECL( OP_B),
+/* 1010 1101 0000 */ TABDECL( OP_B),
+/* 1010 1101 0001 */ TABDECL( OP_B),
+/* 1010 1101 0010 */ TABDECL( OP_B),
+/* 1010 1101 0011 */ TABDECL( OP_B),
+/* 1010 1101 0100 */ TABDECL( OP_B),
+/* 1010 1101 0101 */ TABDECL( OP_B),
+/* 1010 1101 0110 */ TABDECL( OP_B),
+/* 1010 1101 0111 */ TABDECL( OP_B),
+/* 1010 1101 1000 */ TABDECL( OP_B),
+/* 1010 1101 1001 */ TABDECL( OP_B),
+/* 1010 1101 1010 */ TABDECL( OP_B),
+/* 1010 1101 1011 */ TABDECL( OP_B),
+/* 1010 1101 1100 */ TABDECL( OP_B),
+/* 1010 1101 1101 */ TABDECL( OP_B),
+/* 1010 1101 1110 */ TABDECL( OP_B),
+/* 1010 1101 1111 */ TABDECL( OP_B),
+/* 1010 1110 0000 */ TABDECL( OP_B),
+/* 1010 1110 0001 */ TABDECL( OP_B),
+/* 1010 1110 0010 */ TABDECL( OP_B),
+/* 1010 1110 0011 */ TABDECL( OP_B),
+/* 1010 1110 0100 */ TABDECL( OP_B),
+/* 1010 1110 0101 */ TABDECL( OP_B),
+/* 1010 1110 0110 */ TABDECL( OP_B),
+/* 1010 1110 0111 */ TABDECL( OP_B),
+/* 1010 1110 1000 */ TABDECL( OP_B),
+/* 1010 1110 1001 */ TABDECL( OP_B),
+/* 1010 1110 1010 */ TABDECL( OP_B),
+/* 1010 1110 1011 */ TABDECL( OP_B),
+/* 1010 1110 1100 */ TABDECL( OP_B),
+/* 1010 1110 1101 */ TABDECL( OP_B),
+/* 1010 1110 1110 */ TABDECL( OP_B),
+/* 1010 1110 1111 */ TABDECL( OP_B),
+/* 1010 1111 0000 */ TABDECL( OP_B),
+/* 1010 1111 0001 */ TABDECL( OP_B),
+/* 1010 1111 0010 */ TABDECL( OP_B),
+/* 1010 1111 0011 */ TABDECL( OP_B),
+/* 1010 1111 0100 */ TABDECL( OP_B),
+/* 1010 1111 0101 */ TABDECL( OP_B),
+/* 1010 1111 0110 */ TABDECL( OP_B),
+/* 1010 1111 0111 */ TABDECL( OP_B),
+/* 1010 1111 1000 */ TABDECL( OP_B),
+/* 1010 1111 1001 */ TABDECL( OP_B),
+/* 1010 1111 1010 */ TABDECL( OP_B),
+/* 1010 1111 1011 */ TABDECL( OP_B),
+/* 1010 1111 1100 */ TABDECL( OP_B),
+/* 1010 1111 1101 */ TABDECL( OP_B),
+/* 1010 1111 1110 */ TABDECL( OP_B),
+/* 1010 1111 1111 */ TABDECL( OP_B),
+/* 1011 0000 0000 */ TABDECL( OP_BL),
+/* 1011 0000 0001 */ TABDECL( OP_BL),
+/* 1011 0000 0010 */ TABDECL( OP_BL),
+/* 1011 0000 0011 */ TABDECL( OP_BL),
+/* 1011 0000 0100 */ TABDECL( OP_BL),
+/* 1011 0000 0101 */ TABDECL( OP_BL),
+/* 1011 0000 0110 */ TABDECL( OP_BL),
+/* 1011 0000 0111 */ TABDECL( OP_BL),
+/* 1011 0000 1000 */ TABDECL( OP_BL),
+/* 1011 0000 1001 */ TABDECL( OP_BL),
+/* 1011 0000 1010 */ TABDECL( OP_BL),
+/* 1011 0000 1011 */ TABDECL( OP_BL),
+/* 1011 0000 1100 */ TABDECL( OP_BL),
+/* 1011 0000 1101 */ TABDECL( OP_BL),
+/* 1011 0000 1110 */ TABDECL( OP_BL),
+/* 1011 0000 1111 */ TABDECL( OP_BL),
+/* 1011 0001 0000 */ TABDECL( OP_BL),
+/* 1011 0001 0001 */ TABDECL( OP_BL),
+/* 1011 0001 0010 */ TABDECL( OP_BL),
+/* 1011 0001 0011 */ TABDECL( OP_BL),
+/* 1011 0001 0100 */ TABDECL( OP_BL),
+/* 1011 0001 0101 */ TABDECL( OP_BL),
+/* 1011 0001 0110 */ TABDECL( OP_BL),
+/* 1011 0001 0111 */ TABDECL( OP_BL),
+/* 1011 0001 1000 */ TABDECL( OP_BL),
+/* 1011 0001 1001 */ TABDECL( OP_BL),
+/* 1011 0001 1010 */ TABDECL( OP_BL),
+/* 1011 0001 1011 */ TABDECL( OP_BL),
+/* 1011 0001 1100 */ TABDECL( OP_BL),
+/* 1011 0001 1101 */ TABDECL( OP_BL),
+/* 1011 0001 1110 */ TABDECL( OP_BL),
+/* 1011 0001 1111 */ TABDECL( OP_BL),
+/* 1011 0010 0000 */ TABDECL( OP_BL),
+/* 1011 0010 0001 */ TABDECL( OP_BL),
+/* 1011 0010 0010 */ TABDECL( OP_BL),
+/* 1011 0010 0011 */ TABDECL( OP_BL),
+/* 1011 0010 0100 */ TABDECL( OP_BL),
+/* 1011 0010 0101 */ TABDECL( OP_BL),
+/* 1011 0010 0110 */ TABDECL( OP_BL),
+/* 1011 0010 0111 */ TABDECL( OP_BL),
+/* 1011 0010 1000 */ TABDECL( OP_BL),
+/* 1011 0010 1001 */ TABDECL( OP_BL),
+/* 1011 0010 1010 */ TABDECL( OP_BL),
+/* 1011 0010 1011 */ TABDECL( OP_BL),
+/* 1011 0010 1100 */ TABDECL( OP_BL),
+/* 1011 0010 1101 */ TABDECL( OP_BL),
+/* 1011 0010 1110 */ TABDECL( OP_BL),
+/* 1011 0010 1111 */ TABDECL( OP_BL),
+/* 1011 0011 0000 */ TABDECL( OP_BL),
+/* 1011 0011 0001 */ TABDECL( OP_BL),
+/* 1011 0011 0010 */ TABDECL( OP_BL),
+/* 1011 0011 0011 */ TABDECL( OP_BL),
+/* 1011 0011 0100 */ TABDECL( OP_BL),
+/* 1011 0011 0101 */ TABDECL( OP_BL),
+/* 1011 0011 0110 */ TABDECL( OP_BL),
+/* 1011 0011 0111 */ TABDECL( OP_BL),
+/* 1011 0011 1000 */ TABDECL( OP_BL),
+/* 1011 0011 1001 */ TABDECL( OP_BL),
+/* 1011 0011 1010 */ TABDECL( OP_BL),
+/* 1011 0011 1011 */ TABDECL( OP_BL),
+/* 1011 0011 1100 */ TABDECL( OP_BL),
+/* 1011 0011 1101 */ TABDECL( OP_BL),
+/* 1011 0011 1110 */ TABDECL( OP_BL),
+/* 1011 0011 1111 */ TABDECL( OP_BL),
+/* 1011 0100 0000 */ TABDECL( OP_BL),
+/* 1011 0100 0001 */ TABDECL( OP_BL),
+/* 1011 0100 0010 */ TABDECL( OP_BL),
+/* 1011 0100 0011 */ TABDECL( OP_BL),
+/* 1011 0100 0100 */ TABDECL( OP_BL),
+/* 1011 0100 0101 */ TABDECL( OP_BL),
+/* 1011 0100 0110 */ TABDECL( OP_BL),
+/* 1011 0100 0111 */ TABDECL( OP_BL),
+/* 1011 0100 1000 */ TABDECL( OP_BL),
+/* 1011 0100 1001 */ TABDECL( OP_BL),
+/* 1011 0100 1010 */ TABDECL( OP_BL),
+/* 1011 0100 1011 */ TABDECL( OP_BL),
+/* 1011 0100 1100 */ TABDECL( OP_BL),
+/* 1011 0100 1101 */ TABDECL( OP_BL),
+/* 1011 0100 1110 */ TABDECL( OP_BL),
+/* 1011 0100 1111 */ TABDECL( OP_BL),
+/* 1011 0101 0000 */ TABDECL( OP_BL),
+/* 1011 0101 0001 */ TABDECL( OP_BL),
+/* 1011 0101 0010 */ TABDECL( OP_BL),
+/* 1011 0101 0011 */ TABDECL( OP_BL),
+/* 1011 0101 0100 */ TABDECL( OP_BL),
+/* 1011 0101 0101 */ TABDECL( OP_BL),
+/* 1011 0101 0110 */ TABDECL( OP_BL),
+/* 1011 0101 0111 */ TABDECL( OP_BL),
+/* 1011 0101 1000 */ TABDECL( OP_BL),
+/* 1011 0101 1001 */ TABDECL( OP_BL),
+/* 1011 0101 1010 */ TABDECL( OP_BL),
+/* 1011 0101 1011 */ TABDECL( OP_BL),
+/* 1011 0101 1100 */ TABDECL( OP_BL),
+/* 1011 0101 1101 */ TABDECL( OP_BL),
+/* 1011 0101 1110 */ TABDECL( OP_BL),
+/* 1011 0101 1111 */ TABDECL( OP_BL),
+/* 1011 0110 0000 */ TABDECL( OP_BL),
+/* 1011 0110 0001 */ TABDECL( OP_BL),
+/* 1011 0110 0010 */ TABDECL( OP_BL),
+/* 1011 0110 0011 */ TABDECL( OP_BL),
+/* 1011 0110 0100 */ TABDECL( OP_BL),
+/* 1011 0110 0101 */ TABDECL( OP_BL),
+/* 1011 0110 0110 */ TABDECL( OP_BL),
+/* 1011 0110 0111 */ TABDECL( OP_BL),
+/* 1011 0110 1000 */ TABDECL( OP_BL),
+/* 1011 0110 1001 */ TABDECL( OP_BL),
+/* 1011 0110 1010 */ TABDECL( OP_BL),
+/* 1011 0110 1011 */ TABDECL( OP_BL),
+/* 1011 0110 1100 */ TABDECL( OP_BL),
+/* 1011 0110 1101 */ TABDECL( OP_BL),
+/* 1011 0110 1110 */ TABDECL( OP_BL),
+/* 1011 0110 1111 */ TABDECL( OP_BL),
+/* 1011 0111 0000 */ TABDECL( OP_BL),
+/* 1011 0111 0001 */ TABDECL( OP_BL),
+/* 1011 0111 0010 */ TABDECL( OP_BL),
+/* 1011 0111 0011 */ TABDECL( OP_BL),
+/* 1011 0111 0100 */ TABDECL( OP_BL),
+/* 1011 0111 0101 */ TABDECL( OP_BL),
+/* 1011 0111 0110 */ TABDECL( OP_BL),
+/* 1011 0111 0111 */ TABDECL( OP_BL),
+/* 1011 0111 1000 */ TABDECL( OP_BL),
+/* 1011 0111 1001 */ TABDECL( OP_BL),
+/* 1011 0111 1010 */ TABDECL( OP_BL),
+/* 1011 0111 1011 */ TABDECL( OP_BL),
+/* 1011 0111 1100 */ TABDECL( OP_BL),
+/* 1011 0111 1101 */ TABDECL( OP_BL),
+/* 1011 0111 1110 */ TABDECL( OP_BL),
+/* 1011 0111 1111 */ TABDECL( OP_BL),
+/* 1011 1000 0000 */ TABDECL( OP_BL),
+/* 1011 1000 0001 */ TABDECL( OP_BL),
+/* 1011 1000 0010 */ TABDECL( OP_BL),
+/* 1011 1000 0011 */ TABDECL( OP_BL),
+/* 1011 1000 0100 */ TABDECL( OP_BL),
+/* 1011 1000 0101 */ TABDECL( OP_BL),
+/* 1011 1000 0110 */ TABDECL( OP_BL),
+/* 1011 1000 0111 */ TABDECL( OP_BL),
+/* 1011 1000 1000 */ TABDECL( OP_BL),
+/* 1011 1000 1001 */ TABDECL( OP_BL),
+/* 1011 1000 1010 */ TABDECL( OP_BL),
+/* 1011 1000 1011 */ TABDECL( OP_BL),
+/* 1011 1000 1100 */ TABDECL( OP_BL),
+/* 1011 1000 1101 */ TABDECL( OP_BL),
+/* 1011 1000 1110 */ TABDECL( OP_BL),
+/* 1011 1000 1111 */ TABDECL( OP_BL),
+/* 1011 1001 0000 */ TABDECL( OP_BL),
+/* 1011 1001 0001 */ TABDECL( OP_BL),
+/* 1011 1001 0010 */ TABDECL( OP_BL),
+/* 1011 1001 0011 */ TABDECL( OP_BL),
+/* 1011 1001 0100 */ TABDECL( OP_BL),
+/* 1011 1001 0101 */ TABDECL( OP_BL),
+/* 1011 1001 0110 */ TABDECL( OP_BL),
+/* 1011 1001 0111 */ TABDECL( OP_BL),
+/* 1011 1001 1000 */ TABDECL( OP_BL),
+/* 1011 1001 1001 */ TABDECL( OP_BL),
+/* 1011 1001 1010 */ TABDECL( OP_BL),
+/* 1011 1001 1011 */ TABDECL( OP_BL),
+/* 1011 1001 1100 */ TABDECL( OP_BL),
+/* 1011 1001 1101 */ TABDECL( OP_BL),
+/* 1011 1001 1110 */ TABDECL( OP_BL),
+/* 1011 1001 1111 */ TABDECL( OP_BL),
+/* 1011 1010 0000 */ TABDECL( OP_BL),
+/* 1011 1010 0001 */ TABDECL( OP_BL),
+/* 1011 1010 0010 */ TABDECL( OP_BL),
+/* 1011 1010 0011 */ TABDECL( OP_BL),
+/* 1011 1010 0100 */ TABDECL( OP_BL),
+/* 1011 1010 0101 */ TABDECL( OP_BL),
+/* 1011 1010 0110 */ TABDECL( OP_BL),
+/* 1011 1010 0111 */ TABDECL( OP_BL),
+/* 1011 1010 1000 */ TABDECL( OP_BL),
+/* 1011 1010 1001 */ TABDECL( OP_BL),
+/* 1011 1010 1010 */ TABDECL( OP_BL),
+/* 1011 1010 1011 */ TABDECL( OP_BL),
+/* 1011 1010 1100 */ TABDECL( OP_BL),
+/* 1011 1010 1101 */ TABDECL( OP_BL),
+/* 1011 1010 1110 */ TABDECL( OP_BL),
+/* 1011 1010 1111 */ TABDECL( OP_BL),
+/* 1011 1011 0000 */ TABDECL( OP_BL),
+/* 1011 1011 0001 */ TABDECL( OP_BL),
+/* 1011 1011 0010 */ TABDECL( OP_BL),
+/* 1011 1011 0011 */ TABDECL( OP_BL),
+/* 1011 1011 0100 */ TABDECL( OP_BL),
+/* 1011 1011 0101 */ TABDECL( OP_BL),
+/* 1011 1011 0110 */ TABDECL( OP_BL),
+/* 1011 1011 0111 */ TABDECL( OP_BL),
+/* 1011 1011 1000 */ TABDECL( OP_BL),
+/* 1011 1011 1001 */ TABDECL( OP_BL),
+/* 1011 1011 1010 */ TABDECL( OP_BL),
+/* 1011 1011 1011 */ TABDECL( OP_BL),
+/* 1011 1011 1100 */ TABDECL( OP_BL),
+/* 1011 1011 1101 */ TABDECL( OP_BL),
+/* 1011 1011 1110 */ TABDECL( OP_BL),
+/* 1011 1011 1111 */ TABDECL( OP_BL),
+/* 1011 1100 0000 */ TABDECL( OP_BL),
+/* 1011 1100 0001 */ TABDECL( OP_BL),
+/* 1011 1100 0010 */ TABDECL( OP_BL),
+/* 1011 1100 0011 */ TABDECL( OP_BL),
+/* 1011 1100 0100 */ TABDECL( OP_BL),
+/* 1011 1100 0101 */ TABDECL( OP_BL),
+/* 1011 1100 0110 */ TABDECL( OP_BL),
+/* 1011 1100 0111 */ TABDECL( OP_BL),
+/* 1011 1100 1000 */ TABDECL( OP_BL),
+/* 1011 1100 1001 */ TABDECL( OP_BL),
+/* 1011 1100 1010 */ TABDECL( OP_BL),
+/* 1011 1100 1011 */ TABDECL( OP_BL),
+/* 1011 1100 1100 */ TABDECL( OP_BL),
+/* 1011 1100 1101 */ TABDECL( OP_BL),
+/* 1011 1100 1110 */ TABDECL( OP_BL),
+/* 1011 1100 1111 */ TABDECL( OP_BL),
+/* 1011 1101 0000 */ TABDECL( OP_BL),
+/* 1011 1101 0001 */ TABDECL( OP_BL),
+/* 1011 1101 0010 */ TABDECL( OP_BL),
+/* 1011 1101 0011 */ TABDECL( OP_BL),
+/* 1011 1101 0100 */ TABDECL( OP_BL),
+/* 1011 1101 0101 */ TABDECL( OP_BL),
+/* 1011 1101 0110 */ TABDECL( OP_BL),
+/* 1011 1101 0111 */ TABDECL( OP_BL),
+/* 1011 1101 1000 */ TABDECL( OP_BL),
+/* 1011 1101 1001 */ TABDECL( OP_BL),
+/* 1011 1101 1010 */ TABDECL( OP_BL),
+/* 1011 1101 1011 */ TABDECL( OP_BL),
+/* 1011 1101 1100 */ TABDECL( OP_BL),
+/* 1011 1101 1101 */ TABDECL( OP_BL),
+/* 1011 1101 1110 */ TABDECL( OP_BL),
+/* 1011 1101 1111 */ TABDECL( OP_BL),
+/* 1011 1110 0000 */ TABDECL( OP_BL),
+/* 1011 1110 0001 */ TABDECL( OP_BL),
+/* 1011 1110 0010 */ TABDECL( OP_BL),
+/* 1011 1110 0011 */ TABDECL( OP_BL),
+/* 1011 1110 0100 */ TABDECL( OP_BL),
+/* 1011 1110 0101 */ TABDECL( OP_BL),
+/* 1011 1110 0110 */ TABDECL( OP_BL),
+/* 1011 1110 0111 */ TABDECL( OP_BL),
+/* 1011 1110 1000 */ TABDECL( OP_BL),
+/* 1011 1110 1001 */ TABDECL( OP_BL),
+/* 1011 1110 1010 */ TABDECL( OP_BL),
+/* 1011 1110 1011 */ TABDECL( OP_BL),
+/* 1011 1110 1100 */ TABDECL( OP_BL),
+/* 1011 1110 1101 */ TABDECL( OP_BL),
+/* 1011 1110 1110 */ TABDECL( OP_BL),
+/* 1011 1110 1111 */ TABDECL( OP_BL),
+/* 1011 1111 0000 */ TABDECL( OP_BL),
+/* 1011 1111 0001 */ TABDECL( OP_BL),
+/* 1011 1111 0010 */ TABDECL( OP_BL),
+/* 1011 1111 0011 */ TABDECL( OP_BL),
+/* 1011 1111 0100 */ TABDECL( OP_BL),
+/* 1011 1111 0101 */ TABDECL( OP_BL),
+/* 1011 1111 0110 */ TABDECL( OP_BL),
+/* 1011 1111 0111 */ TABDECL( OP_BL),
+/* 1011 1111 1000 */ TABDECL( OP_BL),
+/* 1011 1111 1001 */ TABDECL( OP_BL),
+/* 1011 1111 1010 */ TABDECL( OP_BL),
+/* 1011 1111 1011 */ TABDECL( OP_BL),
+/* 1011 1111 1100 */ TABDECL( OP_BL),
+/* 1011 1111 1101 */ TABDECL( OP_BL),
+/* 1011 1111 1110 */ TABDECL( OP_BL),
+/* 1011 1111 1111 */ TABDECL( OP_BL),
+/* 1100 0000 0000 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 0001 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 0010 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 0011 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 0100 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 0101 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 0110 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 0111 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 1000 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 1001 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 1010 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 1011 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 1100 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 1101 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 1110 */ TABDECL( OP_STC_OPTION),
+/* 1100 0000 1111 */ TABDECL( OP_STC_OPTION),
+/* 1100 0001 0000 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 0001 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 0010 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 0011 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 0100 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 0101 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 0110 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 0111 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 1000 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 1001 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 1010 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 1011 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 1100 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 1101 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 1110 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0001 1111 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0010 0000 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 0001 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 0010 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 0011 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 0100 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 0101 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 0110 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 0111 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 1000 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 1001 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 1010 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 1011 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 1100 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 1101 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 1110 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0010 1111 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0011 0000 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 0001 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 0010 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 0011 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 0100 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 0101 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 0110 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 0111 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 1000 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 1001 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 1010 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 1011 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 1100 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 1101 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 1110 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0011 1111 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0100 0000 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 0001 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 0010 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 0011 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 0100 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 0101 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 0110 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 0111 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 1000 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 1001 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 1010 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 1011 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 1100 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 1101 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 1110 */ TABDECL( OP_STC_OPTION),
+/* 1100 0100 1111 */ TABDECL( OP_STC_OPTION),
+/* 1100 0101 0000 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 0001 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 0010 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 0011 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 0100 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 0101 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 0110 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 0111 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 1000 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 1001 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 1010 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 1011 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 1100 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 1101 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 1110 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0101 1111 */ TABDECL( OP_LDC_OPTION),
+/* 1100 0110 0000 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 0001 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 0010 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 0011 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 0100 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 0101 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 0110 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 0111 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 1000 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 1001 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 1010 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 1011 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 1100 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 1101 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 1110 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0110 1111 */ TABDECL( OP_STC_M_POSTIND),
+/* 1100 0111 0000 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 0001 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 0010 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 0011 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 0100 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 0101 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 0110 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 0111 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 1000 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 1001 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 1010 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 1011 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 1100 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 1101 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 1110 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 0111 1111 */ TABDECL( OP_LDC_M_POSTIND),
+/* 1100 1000 0000 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 0001 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 0010 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 0011 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 0100 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 0101 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 0110 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 0111 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 1000 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 1001 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 1010 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 1011 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 1100 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 1101 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 1110 */ TABDECL( OP_STC_OPTION),
+/* 1100 1000 1111 */ TABDECL( OP_STC_OPTION),
+/* 1100 1001 0000 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 0001 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 0010 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 0011 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 0100 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 0101 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 0110 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 0111 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 1000 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 1001 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 1010 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 1011 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 1100 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 1101 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 1110 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1001 1111 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1010 0000 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 0001 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 0010 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 0011 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 0100 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 0101 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 0110 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 0111 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 1000 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 1001 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 1010 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 1011 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 1100 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 1101 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 1110 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1010 1111 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1011 0000 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 0001 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 0010 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 0011 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 0100 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 0101 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 0110 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 0111 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 1000 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 1001 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 1010 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 1011 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 1100 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 1101 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 1110 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1011 1111 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1100 0000 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 0001 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 0010 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 0011 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 0100 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 0101 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 0110 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 0111 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 1000 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 1001 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 1010 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 1011 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 1100 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 1101 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 1110 */ TABDECL( OP_STC_OPTION),
+/* 1100 1100 1111 */ TABDECL( OP_STC_OPTION),
+/* 1100 1101 0000 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 0001 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 0010 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 0011 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 0100 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 0101 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 0110 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 0111 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 1000 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 1001 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 1010 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 1011 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 1100 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 1101 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 1110 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1101 1111 */ TABDECL( OP_LDC_OPTION),
+/* 1100 1110 0000 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 0001 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 0010 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 0011 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 0100 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 0101 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 0110 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 0111 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 1000 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 1001 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 1010 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 1011 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 1100 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 1101 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 1110 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1110 1111 */ TABDECL( OP_STC_P_POSTIND),
+/* 1100 1111 0000 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 0001 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 0010 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 0011 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 0100 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 0101 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 0110 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 0111 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 1000 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 1001 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 1010 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 1011 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 1100 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 1101 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 1110 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1100 1111 1111 */ TABDECL( OP_LDC_P_POSTIND),
+/* 1101 0000 0000 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 0001 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 0010 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 0011 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 0100 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 0101 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 0110 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 0111 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 1000 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 1001 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 1010 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 1011 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 1100 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 1101 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 1110 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0000 1111 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0001 0000 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 0001 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 0010 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 0011 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 0100 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 0101 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 0110 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 0111 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 1000 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 1001 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 1010 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 1011 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 1100 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 1101 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 1110 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0001 1111 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0010 0000 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 0001 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 0010 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 0011 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 0100 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 0101 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 0110 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 0111 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 1000 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 1001 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 1010 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 1011 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 1100 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 1101 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 1110 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0010 1111 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0011 0000 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 0001 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 0010 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 0011 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 0100 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 0101 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 0110 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 0111 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 1000 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 1001 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 1010 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 1011 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 1100 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 1101 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 1110 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0011 1111 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0100 0000 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 0001 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 0010 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 0011 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 0100 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 0101 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 0110 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 0111 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 1000 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 1001 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 1010 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 1011 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 1100 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 1101 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 1110 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0100 1111 */ TABDECL( OP_STC_M_IMM_OFF),
+/* 1101 0101 0000 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 0001 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 0010 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 0011 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 0100 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 0101 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 0110 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 0111 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 1000 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 1001 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 1010 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 1011 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 1100 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 1101 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 1110 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0101 1111 */ TABDECL( OP_LDC_M_IMM_OFF),
+/* 1101 0110 0000 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 0001 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 0010 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 0011 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 0100 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 0101 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 0110 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 0111 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 1000 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 1001 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 1010 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 1011 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 1100 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 1101 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 1110 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0110 1111 */ TABDECL( OP_STC_M_PREIND),
+/* 1101 0111 0000 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 0001 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 0010 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 0011 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 0100 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 0101 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 0110 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 0111 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 1000 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 1001 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 1010 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 1011 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 1100 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 1101 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 1110 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 0111 1111 */ TABDECL( OP_LDC_M_PREIND),
+/* 1101 1000 0000 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 0001 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 0010 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 0011 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 0100 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 0101 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 0110 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 0111 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 1000 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 1001 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 1010 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 1011 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 1100 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 1101 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 1110 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1000 1111 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1001 0000 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 0001 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 0010 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 0011 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 0100 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 0101 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 0110 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 0111 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 1000 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 1001 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 1010 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 1011 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 1100 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 1101 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 1110 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1001 1111 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1010 0000 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 0001 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 0010 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 0011 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 0100 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 0101 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 0110 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 0111 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 1000 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 1001 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 1010 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 1011 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 1100 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 1101 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 1110 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1010 1111 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1011 0000 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 0001 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 0010 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 0011 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 0100 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 0101 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 0110 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 0111 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 1000 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 1001 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 1010 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 1011 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 1100 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 1101 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 1110 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1011 1111 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1100 0000 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 0001 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 0010 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 0011 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 0100 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 0101 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 0110 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 0111 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 1000 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 1001 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 1010 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 1011 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 1100 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 1101 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 1110 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1100 1111 */ TABDECL( OP_STC_P_IMM_OFF),
+/* 1101 1101 0000 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 0001 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 0010 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 0011 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 0100 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 0101 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 0110 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 0111 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 1000 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 1001 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 1010 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 1011 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 1100 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 1101 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 1110 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1101 1111 */ TABDECL( OP_LDC_P_IMM_OFF),
+/* 1101 1110 0000 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 0001 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 0010 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 0011 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 0100 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 0101 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 0110 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 0111 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 1000 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 1001 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 1010 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 1011 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 1100 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 1101 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 1110 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1110 1111 */ TABDECL( OP_STC_P_PREIND),
+/* 1101 1111 0000 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 0001 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 0010 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 0011 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 0100 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 0101 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 0110 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 0111 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 1000 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 1001 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 1010 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 1011 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 1100 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 1101 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 1110 */ TABDECL( OP_LDC_P_PREIND),
+/* 1101 1111 1111 */ TABDECL( OP_LDC_P_PREIND),
+/* 1110 0000 0000 */ TABDECL( OP_CDP),
+/* 1110 0000 0001 */ TABDECL( OP_MCR),
+/* 1110 0000 0010 */ TABDECL( OP_CDP),
+/* 1110 0000 0011 */ TABDECL( OP_MCR),
+/* 1110 0000 0100 */ TABDECL( OP_CDP),
+/* 1110 0000 0101 */ TABDECL( OP_MCR),
+/* 1110 0000 0110 */ TABDECL( OP_CDP),
+/* 1110 0000 0111 */ TABDECL( OP_MCR),
+/* 1110 0000 1000 */ TABDECL( OP_CDP),
+/* 1110 0000 1001 */ TABDECL( OP_MCR),
+/* 1110 0000 1010 */ TABDECL( OP_CDP),
+/* 1110 0000 1011 */ TABDECL( OP_MCR),
+/* 1110 0000 1100 */ TABDECL( OP_CDP),
+/* 1110 0000 1101 */ TABDECL( OP_MCR),
+/* 1110 0000 1110 */ TABDECL( OP_CDP),
+/* 1110 0000 1111 */ TABDECL( OP_MCR),
+/* 1110 0001 0000 */ TABDECL( OP_CDP),
+/* 1110 0001 0001 */ TABDECL( OP_MRC),
+/* 1110 0001 0010 */ TABDECL( OP_CDP),
+/* 1110 0001 0011 */ TABDECL( OP_MRC),
+/* 1110 0001 0100 */ TABDECL( OP_CDP),
+/* 1110 0001 0101 */ TABDECL( OP_MRC),
+/* 1110 0001 0110 */ TABDECL( OP_CDP),
+/* 1110 0001 0111 */ TABDECL( OP_MRC),
+/* 1110 0001 1000 */ TABDECL( OP_CDP),
+/* 1110 0001 1001 */ TABDECL( OP_MRC),
+/* 1110 0001 1010 */ TABDECL( OP_CDP),
+/* 1110 0001 1011 */ TABDECL( OP_MRC),
+/* 1110 0001 1100 */ TABDECL( OP_CDP),
+/* 1110 0001 1101 */ TABDECL( OP_MRC),
+/* 1110 0001 1110 */ TABDECL( OP_CDP),
+/* 1110 0001 1111 */ TABDECL( OP_MRC),
+/* 1110 0010 0000 */ TABDECL( OP_CDP),
+/* 1110 0010 0001 */ TABDECL( OP_MCR),
+/* 1110 0010 0010 */ TABDECL( OP_CDP),
+/* 1110 0010 0011 */ TABDECL( OP_MCR),
+/* 1110 0010 0100 */ TABDECL( OP_CDP),
+/* 1110 0010 0101 */ TABDECL( OP_MCR),
+/* 1110 0010 0110 */ TABDECL( OP_CDP),
+/* 1110 0010 0111 */ TABDECL( OP_MCR),
+/* 1110 0010 1000 */ TABDECL( OP_CDP),
+/* 1110 0010 1001 */ TABDECL( OP_MCR),
+/* 1110 0010 1010 */ TABDECL( OP_CDP),
+/* 1110 0010 1011 */ TABDECL( OP_MCR),
+/* 1110 0010 1100 */ TABDECL( OP_CDP),
+/* 1110 0010 1101 */ TABDECL( OP_MCR),
+/* 1110 0010 1110 */ TABDECL( OP_CDP),
+/* 1110 0010 1111 */ TABDECL( OP_MCR),
+/* 1110 0011 0000 */ TABDECL( OP_CDP),
+/* 1110 0011 0001 */ TABDECL( OP_MRC),
+/* 1110 0011 0010 */ TABDECL( OP_CDP),
+/* 1110 0011 0011 */ TABDECL( OP_MRC),
+/* 1110 0011 0100 */ TABDECL( OP_CDP),
+/* 1110 0011 0101 */ TABDECL( OP_MRC),
+/* 1110 0011 0110 */ TABDECL( OP_CDP),
+/* 1110 0011 0111 */ TABDECL( OP_MRC),
+/* 1110 0011 1000 */ TABDECL( OP_CDP),
+/* 1110 0011 1001 */ TABDECL( OP_MRC),
+/* 1110 0011 1010 */ TABDECL( OP_CDP),
+/* 1110 0011 1011 */ TABDECL( OP_MRC),
+/* 1110 0011 1100 */ TABDECL( OP_CDP),
+/* 1110 0011 1101 */ TABDECL( OP_MRC),
+/* 1110 0011 1110 */ TABDECL( OP_CDP),
+/* 1110 0011 1111 */ TABDECL( OP_MRC),
+/* 1110 0100 0000 */ TABDECL( OP_CDP),
+/* 1110 0100 0001 */ TABDECL( OP_MCR),
+/* 1110 0100 0010 */ TABDECL( OP_CDP),
+/* 1110 0100 0011 */ TABDECL( OP_MCR),
+/* 1110 0100 0100 */ TABDECL( OP_CDP),
+/* 1110 0100 0101 */ TABDECL( OP_MCR),
+/* 1110 0100 0110 */ TABDECL( OP_CDP),
+/* 1110 0100 0111 */ TABDECL( OP_MCR),
+/* 1110 0100 1000 */ TABDECL( OP_CDP),
+/* 1110 0100 1001 */ TABDECL( OP_MCR),
+/* 1110 0100 1010 */ TABDECL( OP_CDP),
+/* 1110 0100 1011 */ TABDECL( OP_MCR),
+/* 1110 0100 1100 */ TABDECL( OP_CDP),
+/* 1110 0100 1101 */ TABDECL( OP_MCR),
+/* 1110 0100 1110 */ TABDECL( OP_CDP),
+/* 1110 0100 1111 */ TABDECL( OP_MCR),
+/* 1110 0101 0000 */ TABDECL( OP_CDP),
+/* 1110 0101 0001 */ TABDECL( OP_MRC),
+/* 1110 0101 0010 */ TABDECL( OP_CDP),
+/* 1110 0101 0011 */ TABDECL( OP_MRC),
+/* 1110 0101 0100 */ TABDECL( OP_CDP),
+/* 1110 0101 0101 */ TABDECL( OP_MRC),
+/* 1110 0101 0110 */ TABDECL( OP_CDP),
+/* 1110 0101 0111 */ TABDECL( OP_MRC),
+/* 1110 0101 1000 */ TABDECL( OP_CDP),
+/* 1110 0101 1001 */ TABDECL( OP_MRC),
+/* 1110 0101 1010 */ TABDECL( OP_CDP),
+/* 1110 0101 1011 */ TABDECL( OP_MRC),
+/* 1110 0101 1100 */ TABDECL( OP_CDP),
+/* 1110 0101 1101 */ TABDECL( OP_MRC),
+/* 1110 0101 1110 */ TABDECL( OP_CDP),
+/* 1110 0101 1111 */ TABDECL( OP_MRC),
+/* 1110 0110 0000 */ TABDECL( OP_CDP),
+/* 1110 0110 0001 */ TABDECL( OP_MCR),
+/* 1110 0110 0010 */ TABDECL( OP_CDP),
+/* 1110 0110 0011 */ TABDECL( OP_MCR),
+/* 1110 0110 0100 */ TABDECL( OP_CDP),
+/* 1110 0110 0101 */ TABDECL( OP_MCR),
+/* 1110 0110 0110 */ TABDECL( OP_CDP),
+/* 1110 0110 0111 */ TABDECL( OP_MCR),
+/* 1110 0110 1000 */ TABDECL( OP_CDP),
+/* 1110 0110 1001 */ TABDECL( OP_MCR),
+/* 1110 0110 1010 */ TABDECL( OP_CDP),
+/* 1110 0110 1011 */ TABDECL( OP_MCR),
+/* 1110 0110 1100 */ TABDECL( OP_CDP),
+/* 1110 0110 1101 */ TABDECL( OP_MCR),
+/* 1110 0110 1110 */ TABDECL( OP_CDP),
+/* 1110 0110 1111 */ TABDECL( OP_MCR),
+/* 1110 0111 0000 */ TABDECL( OP_CDP),
+/* 1110 0111 0001 */ TABDECL( OP_MRC),
+/* 1110 0111 0010 */ TABDECL( OP_CDP),
+/* 1110 0111 0011 */ TABDECL( OP_MRC),
+/* 1110 0111 0100 */ TABDECL( OP_CDP),
+/* 1110 0111 0101 */ TABDECL( OP_MRC),
+/* 1110 0111 0110 */ TABDECL( OP_CDP),
+/* 1110 0111 0111 */ TABDECL( OP_MRC),
+/* 1110 0111 1000 */ TABDECL( OP_CDP),
+/* 1110 0111 1001 */ TABDECL( OP_MRC),
+/* 1110 0111 1010 */ TABDECL( OP_CDP),
+/* 1110 0111 1011 */ TABDECL( OP_MRC),
+/* 1110 0111 1100 */ TABDECL( OP_CDP),
+/* 1110 0111 1101 */ TABDECL( OP_MRC),
+/* 1110 0111 1110 */ TABDECL( OP_CDP),
+/* 1110 0111 1111 */ TABDECL( OP_MRC),
+/* 1110 1000 0000 */ TABDECL( OP_CDP),
+/* 1110 1000 0001 */ TABDECL( OP_MCR),
+/* 1110 1000 0010 */ TABDECL( OP_CDP),
+/* 1110 1000 0011 */ TABDECL( OP_MCR),
+/* 1110 1000 0100 */ TABDECL( OP_CDP),
+/* 1110 1000 0101 */ TABDECL( OP_MCR),
+/* 1110 1000 0110 */ TABDECL( OP_CDP),
+/* 1110 1000 0111 */ TABDECL( OP_MCR),
+/* 1110 1000 1000 */ TABDECL( OP_CDP),
+/* 1110 1000 1001 */ TABDECL( OP_MCR),
+/* 1110 1000 1010 */ TABDECL( OP_CDP),
+/* 1110 1000 1011 */ TABDECL( OP_MCR),
+/* 1110 1000 1100 */ TABDECL( OP_CDP),
+/* 1110 1000 1101 */ TABDECL( OP_MCR),
+/* 1110 1000 1110 */ TABDECL( OP_CDP),
+/* 1110 1000 1111 */ TABDECL( OP_MCR),
+/* 1110 1001 0000 */ TABDECL( OP_CDP),
+/* 1110 1001 0001 */ TABDECL( OP_MRC),
+/* 1110 1001 0010 */ TABDECL( OP_CDP),
+/* 1110 1001 0011 */ TABDECL( OP_MRC),
+/* 1110 1001 0100 */ TABDECL( OP_CDP),
+/* 1110 1001 0101 */ TABDECL( OP_MRC),
+/* 1110 1001 0110 */ TABDECL( OP_CDP),
+/* 1110 1001 0111 */ TABDECL( OP_MRC),
+/* 1110 1001 1000 */ TABDECL( OP_CDP),
+/* 1110 1001 1001 */ TABDECL( OP_MRC),
+/* 1110 1001 1010 */ TABDECL( OP_CDP),
+/* 1110 1001 1011 */ TABDECL( OP_MRC),
+/* 1110 1001 1100 */ TABDECL( OP_CDP),
+/* 1110 1001 1101 */ TABDECL( OP_MRC),
+/* 1110 1001 1110 */ TABDECL( OP_CDP),
+/* 1110 1001 1111 */ TABDECL( OP_MRC),
+/* 1110 1010 0000 */ TABDECL( OP_CDP),
+/* 1110 1010 0001 */ TABDECL( OP_MCR),
+/* 1110 1010 0010 */ TABDECL( OP_CDP),
+/* 1110 1010 0011 */ TABDECL( OP_MCR),
+/* 1110 1010 0100 */ TABDECL( OP_CDP),
+/* 1110 1010 0101 */ TABDECL( OP_MCR),
+/* 1110 1010 0110 */ TABDECL( OP_CDP),
+/* 1110 1010 0111 */ TABDECL( OP_MCR),
+/* 1110 1010 1000 */ TABDECL( OP_CDP),
+/* 1110 1010 1001 */ TABDECL( OP_MCR),
+/* 1110 1010 1010 */ TABDECL( OP_CDP),
+/* 1110 1010 1011 */ TABDECL( OP_MCR),
+/* 1110 1010 1100 */ TABDECL( OP_CDP),
+/* 1110 1010 1101 */ TABDECL( OP_MCR),
+/* 1110 1010 1110 */ TABDECL( OP_CDP),
+/* 1110 1010 1111 */ TABDECL( OP_MCR),
+/* 1110 1011 0000 */ TABDECL( OP_CDP),
+/* 1110 1011 0001 */ TABDECL( OP_MRC),
+/* 1110 1011 0010 */ TABDECL( OP_CDP),
+/* 1110 1011 0011 */ TABDECL( OP_MRC),
+/* 1110 1011 0100 */ TABDECL( OP_CDP),
+/* 1110 1011 0101 */ TABDECL( OP_MRC),
+/* 1110 1011 0110 */ TABDECL( OP_CDP),
+/* 1110 1011 0111 */ TABDECL( OP_MRC),
+/* 1110 1011 1000 */ TABDECL( OP_CDP),
+/* 1110 1011 1001 */ TABDECL( OP_MRC),
+/* 1110 1011 1010 */ TABDECL( OP_CDP),
+/* 1110 1011 1011 */ TABDECL( OP_MRC),
+/* 1110 1011 1100 */ TABDECL( OP_CDP),
+/* 1110 1011 1101 */ TABDECL( OP_MRC),
+/* 1110 1011 1110 */ TABDECL( OP_CDP),
+/* 1110 1011 1111 */ TABDECL( OP_MRC),
+/* 1110 1100 0000 */ TABDECL( OP_CDP),
+/* 1110 1100 0001 */ TABDECL( OP_MCR),
+/* 1110 1100 0010 */ TABDECL( OP_CDP),
+/* 1110 1100 0011 */ TABDECL( OP_MCR),
+/* 1110 1100 0100 */ TABDECL( OP_CDP),
+/* 1110 1100 0101 */ TABDECL( OP_MCR),
+/* 1110 1100 0110 */ TABDECL( OP_CDP),
+/* 1110 1100 0111 */ TABDECL( OP_MCR),
+/* 1110 1100 1000 */ TABDECL( OP_CDP),
+/* 1110 1100 1001 */ TABDECL( OP_MCR),
+/* 1110 1100 1010 */ TABDECL( OP_CDP),
+/* 1110 1100 1011 */ TABDECL( OP_MCR),
+/* 1110 1100 1100 */ TABDECL( OP_CDP),
+/* 1110 1100 1101 */ TABDECL( OP_MCR),
+/* 1110 1100 1110 */ TABDECL( OP_CDP),
+/* 1110 1100 1111 */ TABDECL( OP_MCR),
+/* 1110 1101 0000 */ TABDECL( OP_CDP),
+/* 1110 1101 0001 */ TABDECL( OP_MRC),
+/* 1110 1101 0010 */ TABDECL( OP_CDP),
+/* 1110 1101 0011 */ TABDECL( OP_MRC),
+/* 1110 1101 0100 */ TABDECL( OP_CDP),
+/* 1110 1101 0101 */ TABDECL( OP_MRC),
+/* 1110 1101 0110 */ TABDECL( OP_CDP),
+/* 1110 1101 0111 */ TABDECL( OP_MRC),
+/* 1110 1101 1000 */ TABDECL( OP_CDP),
+/* 1110 1101 1001 */ TABDECL( OP_MRC),
+/* 1110 1101 1010 */ TABDECL( OP_CDP),
+/* 1110 1101 1011 */ TABDECL( OP_MRC),
+/* 1110 1101 1100 */ TABDECL( OP_CDP),
+/* 1110 1101 1101 */ TABDECL( OP_MRC),
+/* 1110 1101 1110 */ TABDECL( OP_CDP),
+/* 1110 1101 1111 */ TABDECL( OP_MRC),
+/* 1110 1110 0000 */ TABDECL( OP_CDP),
+/* 1110 1110 0001 */ TABDECL( OP_MCR),
+/* 1110 1110 0010 */ TABDECL( OP_CDP),
+/* 1110 1110 0011 */ TABDECL( OP_MCR),
+/* 1110 1110 0100 */ TABDECL( OP_CDP),
+/* 1110 1110 0101 */ TABDECL( OP_MCR),
+/* 1110 1110 0110 */ TABDECL( OP_CDP),
+/* 1110 1110 0111 */ TABDECL( OP_MCR),
+/* 1110 1110 1000 */ TABDECL( OP_CDP),
+/* 1110 1110 1001 */ TABDECL( OP_MCR),
+/* 1110 1110 1010 */ TABDECL( OP_CDP),
+/* 1110 1110 1011 */ TABDECL( OP_MCR),
+/* 1110 1110 1100 */ TABDECL( OP_CDP),
+/* 1110 1110 1101 */ TABDECL( OP_MCR),
+/* 1110 1110 1110 */ TABDECL( OP_CDP),
+/* 1110 1110 1111 */ TABDECL( OP_MCR),
+/* 1110 1111 0000 */ TABDECL( OP_CDP),
+/* 1110 1111 0001 */ TABDECL( OP_MRC),
+/* 1110 1111 0010 */ TABDECL( OP_CDP),
+/* 1110 1111 0011 */ TABDECL( OP_MRC),
+/* 1110 1111 0100 */ TABDECL( OP_CDP),
+/* 1110 1111 0101 */ TABDECL( OP_MRC),
+/* 1110 1111 0110 */ TABDECL( OP_CDP),
+/* 1110 1111 0111 */ TABDECL( OP_MRC),
+/* 1110 1111 1000 */ TABDECL( OP_CDP),
+/* 1110 1111 1001 */ TABDECL( OP_MRC),
+/* 1110 1111 1010 */ TABDECL( OP_CDP),
+/* 1110 1111 1011 */ TABDECL( OP_MRC),
+/* 1110 1111 1100 */ TABDECL( OP_CDP),
+/* 1110 1111 1101 */ TABDECL( OP_MRC),
+/* 1110 1111 1110 */ TABDECL( OP_CDP),
+/* 1110 1111 1111 */ TABDECL( OP_MRC),
+/* 1111 0000 0000 */ TABDECL( OP_SWI),
+/* 1111 0000 0001 */ TABDECL( OP_SWI),
+/* 1111 0000 0010 */ TABDECL( OP_SWI),
+/* 1111 0000 0011 */ TABDECL( OP_SWI),
+/* 1111 0000 0100 */ TABDECL( OP_SWI),
+/* 1111 0000 0101 */ TABDECL( OP_SWI),
+/* 1111 0000 0110 */ TABDECL( OP_SWI),
+/* 1111 0000 0111 */ TABDECL( OP_SWI),
+/* 1111 0000 1000 */ TABDECL( OP_SWI),
+/* 1111 0000 1001 */ TABDECL( OP_SWI),
+/* 1111 0000 1010 */ TABDECL( OP_SWI),
+/* 1111 0000 1011 */ TABDECL( OP_SWI),
+/* 1111 0000 1100 */ TABDECL( OP_SWI),
+/* 1111 0000 1101 */ TABDECL( OP_SWI),
+/* 1111 0000 1110 */ TABDECL( OP_SWI),
+/* 1111 0000 1111 */ TABDECL( OP_SWI),
+/* 1111 0001 0000 */ TABDECL( OP_SWI),
+/* 1111 0001 0001 */ TABDECL( OP_SWI),
+/* 1111 0001 0010 */ TABDECL( OP_SWI),
+/* 1111 0001 0011 */ TABDECL( OP_SWI),
+/* 1111 0001 0100 */ TABDECL( OP_SWI),
+/* 1111 0001 0101 */ TABDECL( OP_SWI),
+/* 1111 0001 0110 */ TABDECL( OP_SWI),
+/* 1111 0001 0111 */ TABDECL( OP_SWI),
+/* 1111 0001 1000 */ TABDECL( OP_SWI),
+/* 1111 0001 1001 */ TABDECL( OP_SWI),
+/* 1111 0001 1010 */ TABDECL( OP_SWI),
+/* 1111 0001 1011 */ TABDECL( OP_SWI),
+/* 1111 0001 1100 */ TABDECL( OP_SWI),
+/* 1111 0001 1101 */ TABDECL( OP_SWI),
+/* 1111 0001 1110 */ TABDECL( OP_SWI),
+/* 1111 0001 1111 */ TABDECL( OP_SWI),
+/* 1111 0010 0000 */ TABDECL( OP_SWI),
+/* 1111 0010 0001 */ TABDECL( OP_SWI),
+/* 1111 0010 0010 */ TABDECL( OP_SWI),
+/* 1111 0010 0011 */ TABDECL( OP_SWI),
+/* 1111 0010 0100 */ TABDECL( OP_SWI),
+/* 1111 0010 0101 */ TABDECL( OP_SWI),
+/* 1111 0010 0110 */ TABDECL( OP_SWI),
+/* 1111 0010 0111 */ TABDECL( OP_SWI),
+/* 1111 0010 1000 */ TABDECL( OP_SWI),
+/* 1111 0010 1001 */ TABDECL( OP_SWI),
+/* 1111 0010 1010 */ TABDECL( OP_SWI),
+/* 1111 0010 1011 */ TABDECL( OP_SWI),
+/* 1111 0010 1100 */ TABDECL( OP_SWI),
+/* 1111 0010 1101 */ TABDECL( OP_SWI),
+/* 1111 0010 1110 */ TABDECL( OP_SWI),
+/* 1111 0010 1111 */ TABDECL( OP_SWI),
+/* 1111 0011 0000 */ TABDECL( OP_SWI),
+/* 1111 0011 0001 */ TABDECL( OP_SWI),
+/* 1111 0011 0010 */ TABDECL( OP_SWI),
+/* 1111 0011 0011 */ TABDECL( OP_SWI),
+/* 1111 0011 0100 */ TABDECL( OP_SWI),
+/* 1111 0011 0101 */ TABDECL( OP_SWI),
+/* 1111 0011 0110 */ TABDECL( OP_SWI),
+/* 1111 0011 0111 */ TABDECL( OP_SWI),
+/* 1111 0011 1000 */ TABDECL( OP_SWI),
+/* 1111 0011 1001 */ TABDECL( OP_SWI),
+/* 1111 0011 1010 */ TABDECL( OP_SWI),
+/* 1111 0011 1011 */ TABDECL( OP_SWI),
+/* 1111 0011 1100 */ TABDECL( OP_SWI),
+/* 1111 0011 1101 */ TABDECL( OP_SWI),
+/* 1111 0011 1110 */ TABDECL( OP_SWI),
+/* 1111 0011 1111 */ TABDECL( OP_SWI),
+/* 1111 0100 0000 */ TABDECL( OP_SWI),
+/* 1111 0100 0001 */ TABDECL( OP_SWI),
+/* 1111 0100 0010 */ TABDECL( OP_SWI),
+/* 1111 0100 0011 */ TABDECL( OP_SWI),
+/* 1111 0100 0100 */ TABDECL( OP_SWI),
+/* 1111 0100 0101 */ TABDECL( OP_SWI),
+/* 1111 0100 0110 */ TABDECL( OP_SWI),
+/* 1111 0100 0111 */ TABDECL( OP_SWI),
+/* 1111 0100 1000 */ TABDECL( OP_SWI),
+/* 1111 0100 1001 */ TABDECL( OP_SWI),
+/* 1111 0100 1010 */ TABDECL( OP_SWI),
+/* 1111 0100 1011 */ TABDECL( OP_SWI),
+/* 1111 0100 1100 */ TABDECL( OP_SWI),
+/* 1111 0100 1101 */ TABDECL( OP_SWI),
+/* 1111 0100 1110 */ TABDECL( OP_SWI),
+/* 1111 0100 1111 */ TABDECL( OP_SWI),
+/* 1111 0101 0000 */ TABDECL( OP_SWI),
+/* 1111 0101 0001 */ TABDECL( OP_SWI),
+/* 1111 0101 0010 */ TABDECL( OP_SWI),
+/* 1111 0101 0011 */ TABDECL( OP_SWI),
+/* 1111 0101 0100 */ TABDECL( OP_SWI),
+/* 1111 0101 0101 */ TABDECL( OP_SWI),
+/* 1111 0101 0110 */ TABDECL( OP_SWI),
+/* 1111 0101 0111 */ TABDECL( OP_SWI),
+/* 1111 0101 1000 */ TABDECL( OP_SWI),
+/* 1111 0101 1001 */ TABDECL( OP_SWI),
+/* 1111 0101 1010 */ TABDECL( OP_SWI),
+/* 1111 0101 1011 */ TABDECL( OP_SWI),
+/* 1111 0101 1100 */ TABDECL( OP_SWI),
+/* 1111 0101 1101 */ TABDECL( OP_SWI),
+/* 1111 0101 1110 */ TABDECL( OP_SWI),
+/* 1111 0101 1111 */ TABDECL( OP_SWI),
+/* 1111 0110 0000 */ TABDECL( OP_SWI),
+/* 1111 0110 0001 */ TABDECL( OP_SWI),
+/* 1111 0110 0010 */ TABDECL( OP_SWI),
+/* 1111 0110 0011 */ TABDECL( OP_SWI),
+/* 1111 0110 0100 */ TABDECL( OP_SWI),
+/* 1111 0110 0101 */ TABDECL( OP_SWI),
+/* 1111 0110 0110 */ TABDECL( OP_SWI),
+/* 1111 0110 0111 */ TABDECL( OP_SWI),
+/* 1111 0110 1000 */ TABDECL( OP_SWI),
+/* 1111 0110 1001 */ TABDECL( OP_SWI),
+/* 1111 0110 1010 */ TABDECL( OP_SWI),
+/* 1111 0110 1011 */ TABDECL( OP_SWI),
+/* 1111 0110 1100 */ TABDECL( OP_SWI),
+/* 1111 0110 1101 */ TABDECL( OP_SWI),
+/* 1111 0110 1110 */ TABDECL( OP_SWI),
+/* 1111 0110 1111 */ TABDECL( OP_SWI),
+/* 1111 0111 0000 */ TABDECL( OP_SWI),
+/* 1111 0111 0001 */ TABDECL( OP_SWI),
+/* 1111 0111 0010 */ TABDECL( OP_SWI),
+/* 1111 0111 0011 */ TABDECL( OP_SWI),
+/* 1111 0111 0100 */ TABDECL( OP_SWI),
+/* 1111 0111 0101 */ TABDECL( OP_SWI),
+/* 1111 0111 0110 */ TABDECL( OP_SWI),
+/* 1111 0111 0111 */ TABDECL( OP_SWI),
+/* 1111 0111 1000 */ TABDECL( OP_SWI),
+/* 1111 0111 1001 */ TABDECL( OP_SWI),
+/* 1111 0111 1010 */ TABDECL( OP_SWI),
+/* 1111 0111 1011 */ TABDECL( OP_SWI),
+/* 1111 0111 1100 */ TABDECL( OP_SWI),
+/* 1111 0111 1101 */ TABDECL( OP_SWI),
+/* 1111 0111 1110 */ TABDECL( OP_SWI),
+/* 1111 0111 1111 */ TABDECL( OP_SWI),
+/* 1111 1000 0000 */ TABDECL( OP_SWI),
+/* 1111 1000 0001 */ TABDECL( OP_SWI),
+/* 1111 1000 0010 */ TABDECL( OP_SWI),
+/* 1111 1000 0011 */ TABDECL( OP_SWI),
+/* 1111 1000 0100 */ TABDECL( OP_SWI),
+/* 1111 1000 0101 */ TABDECL( OP_SWI),
+/* 1111 1000 0110 */ TABDECL( OP_SWI),
+/* 1111 1000 0111 */ TABDECL( OP_SWI),
+/* 1111 1000 1000 */ TABDECL( OP_SWI),
+/* 1111 1000 1001 */ TABDECL( OP_SWI),
+/* 1111 1000 1010 */ TABDECL( OP_SWI),
+/* 1111 1000 1011 */ TABDECL( OP_SWI),
+/* 1111 1000 1100 */ TABDECL( OP_SWI),
+/* 1111 1000 1101 */ TABDECL( OP_SWI),
+/* 1111 1000 1110 */ TABDECL( OP_SWI),
+/* 1111 1000 1111 */ TABDECL( OP_SWI),
+/* 1111 1001 0000 */ TABDECL( OP_SWI),
+/* 1111 1001 0001 */ TABDECL( OP_SWI),
+/* 1111 1001 0010 */ TABDECL( OP_SWI),
+/* 1111 1001 0011 */ TABDECL( OP_SWI),
+/* 1111 1001 0100 */ TABDECL( OP_SWI),
+/* 1111 1001 0101 */ TABDECL( OP_SWI),
+/* 1111 1001 0110 */ TABDECL( OP_SWI),
+/* 1111 1001 0111 */ TABDECL( OP_SWI),
+/* 1111 1001 1000 */ TABDECL( OP_SWI),
+/* 1111 1001 1001 */ TABDECL( OP_SWI),
+/* 1111 1001 1010 */ TABDECL( OP_SWI),
+/* 1111 1001 1011 */ TABDECL( OP_SWI),
+/* 1111 1001 1100 */ TABDECL( OP_SWI),
+/* 1111 1001 1101 */ TABDECL( OP_SWI),
+/* 1111 1001 1110 */ TABDECL( OP_SWI),
+/* 1111 1001 1111 */ TABDECL( OP_SWI),
+/* 1111 1010 0000 */ TABDECL( OP_SWI),
+/* 1111 1010 0001 */ TABDECL( OP_SWI),
+/* 1111 1010 0010 */ TABDECL( OP_SWI),
+/* 1111 1010 0011 */ TABDECL( OP_SWI),
+/* 1111 1010 0100 */ TABDECL( OP_SWI),
+/* 1111 1010 0101 */ TABDECL( OP_SWI),
+/* 1111 1010 0110 */ TABDECL( OP_SWI),
+/* 1111 1010 0111 */ TABDECL( OP_SWI),
+/* 1111 1010 1000 */ TABDECL( OP_SWI),
+/* 1111 1010 1001 */ TABDECL( OP_SWI),
+/* 1111 1010 1010 */ TABDECL( OP_SWI),
+/* 1111 1010 1011 */ TABDECL( OP_SWI),
+/* 1111 1010 1100 */ TABDECL( OP_SWI),
+/* 1111 1010 1101 */ TABDECL( OP_SWI),
+/* 1111 1010 1110 */ TABDECL( OP_SWI),
+/* 1111 1010 1111 */ TABDECL( OP_SWI),
+/* 1111 1011 0000 */ TABDECL( OP_SWI),
+/* 1111 1011 0001 */ TABDECL( OP_SWI),
+/* 1111 1011 0010 */ TABDECL( OP_SWI),
+/* 1111 1011 0011 */ TABDECL( OP_SWI),
+/* 1111 1011 0100 */ TABDECL( OP_SWI),
+/* 1111 1011 0101 */ TABDECL( OP_SWI),
+/* 1111 1011 0110 */ TABDECL( OP_SWI),
+/* 1111 1011 0111 */ TABDECL( OP_SWI),
+/* 1111 1011 1000 */ TABDECL( OP_SWI),
+/* 1111 1011 1001 */ TABDECL( OP_SWI),
+/* 1111 1011 1010 */ TABDECL( OP_SWI),
+/* 1111 1011 1011 */ TABDECL( OP_SWI),
+/* 1111 1011 1100 */ TABDECL( OP_SWI),
+/* 1111 1011 1101 */ TABDECL( OP_SWI),
+/* 1111 1011 1110 */ TABDECL( OP_SWI),
+/* 1111 1011 1111 */ TABDECL( OP_SWI),
+/* 1111 1100 0000 */ TABDECL( OP_SWI),
+/* 1111 1100 0001 */ TABDECL( OP_SWI),
+/* 1111 1100 0010 */ TABDECL( OP_SWI),
+/* 1111 1100 0011 */ TABDECL( OP_SWI),
+/* 1111 1100 0100 */ TABDECL( OP_SWI),
+/* 1111 1100 0101 */ TABDECL( OP_SWI),
+/* 1111 1100 0110 */ TABDECL( OP_SWI),
+/* 1111 1100 0111 */ TABDECL( OP_SWI),
+/* 1111 1100 1000 */ TABDECL( OP_SWI),
+/* 1111 1100 1001 */ TABDECL( OP_SWI),
+/* 1111 1100 1010 */ TABDECL( OP_SWI),
+/* 1111 1100 1011 */ TABDECL( OP_SWI),
+/* 1111 1100 1100 */ TABDECL( OP_SWI),
+/* 1111 1100 1101 */ TABDECL( OP_SWI),
+/* 1111 1100 1110 */ TABDECL( OP_SWI),
+/* 1111 1100 1111 */ TABDECL( OP_SWI),
+/* 1111 1101 0000 */ TABDECL( OP_SWI),
+/* 1111 1101 0001 */ TABDECL( OP_SWI),
+/* 1111 1101 0010 */ TABDECL( OP_SWI),
+/* 1111 1101 0011 */ TABDECL( OP_SWI),
+/* 1111 1101 0100 */ TABDECL( OP_SWI),
+/* 1111 1101 0101 */ TABDECL( OP_SWI),
+/* 1111 1101 0110 */ TABDECL( OP_SWI),
+/* 1111 1101 0111 */ TABDECL( OP_SWI),
+/* 1111 1101 1000 */ TABDECL( OP_SWI),
+/* 1111 1101 1001 */ TABDECL( OP_SWI),
+/* 1111 1101 1010 */ TABDECL( OP_SWI),
+/* 1111 1101 1011 */ TABDECL( OP_SWI),
+/* 1111 1101 1100 */ TABDECL( OP_SWI),
+/* 1111 1101 1101 */ TABDECL( OP_SWI),
+/* 1111 1101 1110 */ TABDECL( OP_SWI),
+/* 1111 1101 1111 */ TABDECL( OP_SWI),
+/* 1111 1110 0000 */ TABDECL( OP_SWI),
+/* 1111 1110 0001 */ TABDECL( OP_SWI),
+/* 1111 1110 0010 */ TABDECL( OP_SWI),
+/* 1111 1110 0011 */ TABDECL( OP_SWI),
+/* 1111 1110 0100 */ TABDECL( OP_SWI),
+/* 1111 1110 0101 */ TABDECL( OP_SWI),
+/* 1111 1110 0110 */ TABDECL( OP_SWI),
+/* 1111 1110 0111 */ TABDECL( OP_SWI),
+/* 1111 1110 1000 */ TABDECL( OP_SWI),
+/* 1111 1110 1001 */ TABDECL( OP_SWI),
+/* 1111 1110 1010 */ TABDECL( OP_SWI),
+/* 1111 1110 1011 */ TABDECL( OP_SWI),
+/* 1111 1110 1100 */ TABDECL( OP_SWI),
+/* 1111 1110 1101 */ TABDECL( OP_SWI),
+/* 1111 1110 1110 */ TABDECL( OP_SWI),
+/* 1111 1110 1111 */ TABDECL( OP_SWI),
+/* 1111 1111 0000 */ TABDECL( OP_SWI),
+/* 1111 1111 0001 */ TABDECL( OP_SWI),
+/* 1111 1111 0010 */ TABDECL( OP_SWI),
+/* 1111 1111 0011 */ TABDECL( OP_SWI),
+/* 1111 1111 0100 */ TABDECL( OP_SWI),
+/* 1111 1111 0101 */ TABDECL( OP_SWI),
+/* 1111 1111 0110 */ TABDECL( OP_SWI),
+/* 1111 1111 0111 */ TABDECL( OP_SWI),
+/* 1111 1111 1000 */ TABDECL( OP_SWI),
+/* 1111 1111 1001 */ TABDECL( OP_SWI),
+/* 1111 1111 1010 */ TABDECL( OP_SWI),
+/* 1111 1111 1011 */ TABDECL( OP_SWI),
+/* 1111 1111 1100 */ TABDECL( OP_SWI),
+/* 1111 1111 1101 */ TABDECL( OP_SWI),
+/* 1111 1111 1110 */ TABDECL( OP_SWI),
+/* 1111 1111 1111 */ TABDECL( OP_SWI),
+
+
+
+
--- /dev/null
+++ b/src/in_2sf/desmume/matrix.h
@@ -1,1 +1,340 @@
-
+/*
+ Copyright (C) 2006-2007 shash
+ Copyright (C) 2007-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MATRIX_H
+#define MATRIX_H
+
+#include <cmath>
+#include <cstring>
+
+#include "types.h"
+#include "mem.h"
+
+/*#ifdef __SSE__
+#include <xmmintrin.h>
+#endif*/
+
+#ifdef __SSE2__
+#include <emmintrin.h>
+#endif
+
+/*struct MatrixStack
+{
+ MatrixStack(int size, int type);
+ int32_t *matrix;
+ int32_t position;
+ int32_t size;
+ uint8_t type;
+};*/
+
+//void MatrixInit(float *matrix);
+//void MatrixInit(int32_t *matrix);
+
+//In order to conditionally use these asm optimized functions in visual studio
+//without having to make new build types to exclude the assembly files.
+//a bit sloppy, but there aint much to it
+
+//float MatrixGetMultipliedIndex (int index, float *matrix, float *rightMatrix);
+//int32_t MatrixGetMultipliedIndex (int index, int32_t *matrix, int32_t *rightMatrix);
+//void MatrixSet (float *matrix, int x, int y, float value);
+//void MatrixCopy (float * matrixDST, const float * matrixSRC);
+//void MatrixCopy (int32_t * matrixDST, const int32_t * matrixSRC);
+//int MatrixCompare (const float * matrixDST, const float * matrixSRC);
+//void MatrixIdentity (float *matrix);
+//void MatrixIdentity (int32_t *matrix);
+
+//void MatrixTranspose (float *matrix);
+//void MatrixStackInit (MatrixStack *stack);
+//void MatrixStackSetMaxSize (MatrixStack *stack, int size);
+//void MatrixStackPushMatrix (MatrixStack *stack, const int32_t *ptr);
+//void MatrixStackPopMatrix (int32_t *mtxCurr, MatrixStack *stack, int size);
+//int32_t* MatrixStackGetPos (MatrixStack *stack, int pos);
+//int32_t* MatrixStackGet (MatrixStack *stack);
+//void MatrixStackLoadMatrix (MatrixStack *stack, int pos, const int32_t *ptr);
+
+//void Vector2Copy(float *dst, const float *src);
+//void Vector2Add(float *dst, const float *src);
+//void Vector2Subtract(float *dst, const float *src);
+//float Vector2Dot(const float *a, const float *b);
+//float Vector2Cross(const float *a, const float *b);
+
+//float Vector3Dot(const float *a, const float *b);
+//void Vector3Cross(float* dst, const float *a, const float *b);
+//float Vector3Length(const float *a);
+//void Vector3Add(float *dst, const float *src);
+//void Vector3Subtract(float *dst, const float *src);
+//void Vector3Scale(float *dst, const float scale);
+//void Vector3Copy(float *dst, const float *src);
+//void Vector3Normalize(float *dst);
+
+//void Vector4Copy(float *dst, const float *src);
+
+//these functions are an unreliable, inaccurate floor.
+//it should only be used for positive numbers
+//this isnt as fast as it could be if we used a visual c++ intrinsic, but those appear not to be universally available
+inline uint32_t u32floor(float f)
+{
+#ifdef __SSE2__
+ return (uint32_t)_mm_cvtt_ss2si(_mm_set_ss(f));
+#else
+ return (uint32_t)f;
+#endif
+}
+inline uint32_t u32floor(double d)
+{
+#ifdef __SSE2__
+ return (uint32_t)_mm_cvttsd_si32(_mm_set_sd(d));
+#else
+ return (uint32_t)d;
+#endif
+}
+
+//same as above but works for negative values too.
+//be sure that the results are the same thing as floorf!
+inline int32_t s32floor(float f)
+{
+#ifdef __SSE2__
+ return _mm_cvtss_si32( _mm_add_ss(_mm_set_ss(-0.5f),_mm_add_ss(_mm_set_ss(f), _mm_set_ss(f))) ) >> 1;
+#else
+ return (int32_t)floorf(f);
+#endif
+}
+inline int32_t s32floor(double d)
+{
+ return s32floor((float)d);
+}
+
+//switched SSE2 functions
+//-------------
+#ifdef __SSE2__
+
+/*template<int NUM>
+inline void memset_u16_le(void* dst, uint16_t val)
+{
+ uint32_t u32val;
+ //just for the endian safety
+ T1WriteWord((uint8_t*)&u32val,0,val);
+ T1WriteWord((uint8_t*)&u32val,2,val);
+ ////const __m128i temp = _mm_set_epi32(u32val,u32val,u32val,u32val);
+
+#if defined(__GNUC__) || defined(__INTEL_COMPILER)
+ const __m128i temp = _mm_set_epi32(u32val,u32val,u32val,u32val);
+ MACRODO_N(NUM/8,_mm_store_si128((__m128i*)((uint8_t*)dst+(X)*16), temp));
+#else
+ __m128 temp; temp.m128_i32[0] = u32val;
+ //MACRODO_N(NUM/8,_mm_store_si128((__m128i*)((uint8_t*)dst+(X)*16), temp));
+ MACRODO_N(NUM/8,_mm_store_ps1((float*)((uint8_t*)dst+(X)*16), temp));
+#endif
+}*/
+
+#else //no sse2
+
+/*template<int NUM>
+static inline void memset_u16_le(void* dst, uint16_t val)
+{
+ for(int i=0;i<NUM;i++)
+ T1WriteWord((uint8_t*)dst,i<<1,val);
+}*/
+
+#endif
+
+// NOSSE version always used in gfx3d.cpp
+//void _NOSSE_MatrixMultVec4x4 (const float *matrix, float *vecPtr);
+//void MatrixMultVec3x3_fixed(const int32_t *matrix, int32_t *vecPtr);
+
+//---------------------------
+//switched SSE functions
+#ifdef __SSE__
+
+/*struct SSE_MATRIX
+{
+ SSE_MATRIX(const float *matrix)
+ : row0(_mm_load_ps(matrix))
+ , row1(_mm_load_ps(matrix+4))
+ , row2(_mm_load_ps(matrix+8))
+ , row3(_mm_load_ps(matrix+12))
+ {}
+
+ union {
+ __m128 rows[4];
+ struct { __m128 row0; __m128 row1; __m128 row2; __m128 row3; };
+ };
+
+};*/
+
+/*inline __m128 _util_MatrixMultVec4x4_(const SSE_MATRIX &mat, __m128 vec)
+{
+ __m128 xmm5 = _mm_shuffle_ps(vec, vec, B8(01010101));
+ __m128 xmm6 = _mm_shuffle_ps(vec, vec, B8(10101010));
+ __m128 xmm7 = _mm_shuffle_ps(vec, vec, B8(11111111));
+ __m128 xmm4 = _mm_shuffle_ps(vec, vec, B8(00000000));
+
+ xmm4 = _mm_mul_ps(xmm4,mat.row0);
+ xmm5 = _mm_mul_ps(xmm5,mat.row1);
+ xmm6 = _mm_mul_ps(xmm6,mat.row2);
+ xmm7 = _mm_mul_ps(xmm7,mat.row3);
+ xmm4 = _mm_add_ps(xmm4,xmm5);
+ xmm4 = _mm_add_ps(xmm4,xmm6);
+ xmm4 = _mm_add_ps(xmm4,xmm7);
+ return xmm4;
+}*/
+
+/*inline void MatrixMultiply(float * matrix, const float * rightMatrix)
+{
+ //this seems to generate larger code, including many movaps, but maybe it is less harsh on the registers than the
+ //more hand-tailored approach
+ __m128 row0 = _util_MatrixMultVec4x4_((SSE_MATRIX)matrix,_mm_load_ps(rightMatrix));
+ __m128 row1 = _util_MatrixMultVec4x4_((SSE_MATRIX)matrix,_mm_load_ps(rightMatrix+4));
+ __m128 row2 = _util_MatrixMultVec4x4_((SSE_MATRIX)matrix,_mm_load_ps(rightMatrix+8));
+ __m128 row3 = _util_MatrixMultVec4x4_((SSE_MATRIX)matrix,_mm_load_ps(rightMatrix+12));
+ _mm_store_ps(matrix,row0);
+ _mm_store_ps(matrix+4,row1);
+ _mm_store_ps(matrix+8,row2);
+ _mm_store_ps(matrix+12,row3);
+}*/
+
+
+
+/*inline void MatrixMultVec4x4(const float *matrix, float *vecPtr)
+{
+ _mm_store_ps(vecPtr,_util_MatrixMultVec4x4_((SSE_MATRIX)matrix,_mm_load_ps(vecPtr)));
+}*/
+
+/*inline void MatrixMultVec4x4_M2(const float *matrix, float *vecPtr)
+{
+ //there are hardly any gains from merging these manually
+ MatrixMultVec4x4(matrix+16,vecPtr);
+ MatrixMultVec4x4(matrix,vecPtr);
+}*/
+
+/*inline void MatrixMultVec3x3(const float * matrix, float * vecPtr)
+{
+ const __m128 vec = _mm_load_ps(vecPtr);
+
+ __m128 xmm5 = _mm_shuffle_ps(vec, vec, B8(01010101));
+ __m128 xmm6 = _mm_shuffle_ps(vec, vec, B8(10101010));
+ __m128 xmm4 = _mm_shuffle_ps(vec, vec, B8(00000000));
+
+ const SSE_MATRIX mat(matrix);
+
+ xmm4 = _mm_mul_ps(xmm4,mat.row0);
+ xmm5 = _mm_mul_ps(xmm5,mat.row1);
+ xmm6 = _mm_mul_ps(xmm6,mat.row2);
+ xmm4 = _mm_add_ps(xmm4,xmm5);
+ xmm4 = _mm_add_ps(xmm4,xmm6);
+
+ _mm_store_ps(vecPtr,xmm4);
+}*/
+
+/*inline void MatrixTranslate(float *matrix, const float *ptr)
+{
+ __m128 xmm4 = _mm_load_ps(ptr);
+ __m128 xmm5 = _mm_shuffle_ps(xmm4, xmm4, B8(01010101));
+ __m128 xmm6 = _mm_shuffle_ps(xmm4, xmm4, B8(10101010));
+ xmm4 = _mm_shuffle_ps(xmm4, xmm4, B8(00000000));
+
+ xmm4 = _mm_mul_ps(xmm4,_mm_load_ps(matrix));
+ xmm5 = _mm_mul_ps(xmm5,_mm_load_ps(matrix+4));
+ xmm6 = _mm_mul_ps(xmm6,_mm_load_ps(matrix+8));
+ xmm4 = _mm_add_ps(xmm4,xmm5);
+ xmm4 = _mm_add_ps(xmm4,xmm6);
+ xmm4 = _mm_add_ps(xmm4,_mm_load_ps(matrix+12));
+ _mm_store_ps(matrix+12,xmm4);
+}*/
+
+/*inline void MatrixScale(float *matrix, const float *ptr)
+{
+ __m128 xmm4 = _mm_load_ps(ptr);
+ __m128 xmm5 = _mm_shuffle_ps(xmm4, xmm4, B8(01010101));
+ __m128 xmm6 = _mm_shuffle_ps(xmm4, xmm4, B8(10101010));
+ xmm4 = _mm_shuffle_ps(xmm4, xmm4, B8(00000000));
+
+ xmm4 = _mm_mul_ps(xmm4,_mm_load_ps(matrix));
+ xmm5 = _mm_mul_ps(xmm5,_mm_load_ps(matrix+4));
+ xmm6 = _mm_mul_ps(xmm6,_mm_load_ps(matrix+8));
+ _mm_store_ps(matrix,xmm4);
+ _mm_store_ps(matrix+4,xmm5);
+ _mm_store_ps(matrix+8,xmm6);
+}*/
+
+/*template<int NUM_ROWS>
+inline void vector_fix2float(float* matrix, const float divisor)
+{
+ CTASSERT(NUM_ROWS==3 || NUM_ROWS==4);
+
+ const __m128 val = _mm_set_ps1(divisor);
+
+ _mm_store_ps(matrix,_mm_div_ps(_mm_load_ps(matrix),val));
+ _mm_store_ps(matrix+4,_mm_div_ps(_mm_load_ps(matrix+4),val));
+ _mm_store_ps(matrix+8,_mm_div_ps(_mm_load_ps(matrix+8),val));
+ if(NUM_ROWS==4)
+ _mm_store_ps(matrix+12,_mm_div_ps(_mm_load_ps(matrix+12),val));
+}*/
+
+//WARNING: I do not think this is as fast as a memset, for some reason.
+//at least in vc2005 with sse enabled. better figure out why before using it
+/*template<int NUM>
+static inline void memset_u8(void* _dst, uint8_t val)
+{
+ memset(_dst,val,NUM);
+ //const uint8_t* dst = (uint8_t*)_dst;
+ //uint32_t u32val = (val<<24)|(val<<16)|(val<<8)|val;
+ //const __m128i temp = _mm_set_epi32(u32val,u32val,u32val,u32val);
+ //MACRODO_N(NUM/16,_mm_store_si128((__m128i*)(dst+(X)*16), temp));
+}*/
+
+#else //no sse
+
+//void MatrixMultVec4x4 (const float *matrix, float *vecPtr);
+//void MatrixMultVec3x3(const float * matrix, float * vecPtr);
+//void MatrixMultiply(float * matrix, const float * rightMatrix);
+//void MatrixTranslate(float *matrix, const float *ptr);
+//void MatrixScale(float * matrix, const float * ptr);
+
+/*inline void MatrixMultVec4x4_M2(const float *matrix, float *vecPtr)
+{
+ //there are hardly any gains from merging these manually
+ MatrixMultVec4x4(matrix+16,vecPtr);
+ MatrixMultVec4x4(matrix,vecPtr);
+}*/
+
+/*template<int NUM_ROWS>
+inline void vector_fix2float(float* matrix, const float divisor)
+{
+ for(int i=0;i<NUM_ROWS*4;i++)
+ matrix[i] /= divisor;
+}*/
+
+/*template<int NUM>
+static inline void memset_u8(void* dst, uint8_t val)
+{
+ memset(dst,val,NUM);
+}*/
+
+#endif //switched SSE functions
+
+//void MatrixMultVec4x4 (const int32_t *matrix, int32_t *vecPtr);
+
+//void MatrixMultVec4x4_M2(const int32_t *matrix, int32_t *vecPtr);
+
+//void MatrixMultiply(int32_t* matrix, const int32_t* rightMatrix);
+//void MatrixScale(int32_t *matrix, const int32_t *ptr);
+//void MatrixTranslate(int32_t *matrix, const int32_t *ptr);
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/mc.cpp
@@ -1,1 +1,1281 @@
-
+/*
+ Copyright (C) 2006 thoduv
+ Copyright (C) 2006-2007 Theo Berkau
+ Copyright (C) 2008-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cstdlib>
+#include <cstring>
+
+//#include "debug.h"
+#include "types.h"
+#include "mc.h"
+//#include "movie.h"
+#include "readwrite.h"
+#include "NDSSystem.h"
+
+#define FW_CMD_READ 0x03
+#define FW_CMD_WRITEDISABLE 0x04
+#define FW_CMD_READSTATUS 0x05
+#define FW_CMD_WRITEENABLE 0x06
+#define FW_CMD_PAGEWRITE 0x0A
+#define FW_CMD_READ_ID 0x9F
+
+#define BM_CMD_AUTODETECT 0xFF
+#define BM_CMD_WRITESTATUS 0x01
+#define BM_CMD_WRITELOW 0x02
+#define BM_CMD_READLOW 0x03
+#define BM_CMD_WRITEDISABLE 0x04
+#define BM_CMD_READSTATUS 0x05
+#define BM_CMD_WRITEENABLE 0x06
+#define BM_CMD_WRITEHIGH 0x0A
+#define BM_CMD_READHIGH 0x0B
+
+/* FLASH*/
+#define COMM_PAGE_WRITE 0x0A
+#define COMM_PAGE_ERASE 0xDB
+#define COMM_SECTOR_ERASE 0xD8
+#define COMM_CHIP_ERASE 0xC7
+#define CARDFLASH_READ_BYTES_FAST 0x0B /* Not used*/
+#define CARDFLASH_DEEP_POWDOWN 0xB9 /* Not used*/
+#define CARDFLASH_WAKEUP 0xAB /* Not used*/
+
+//since r2203 this was 0x00.
+//but baby pals proves finally that it should be 0xFF:
+//the game reads its initial sound volumes from uninitialized data, and if it is 0, the game will be silent
+//if it is 0xFF then the game starts with its sound and music at max, as presumably it is supposed to.
+//so in r3303 I finally changed it (no$ appears definitely to initialized to 0xFF)
+static const uint8_t kUninitializedSaveDataValue = 0xFF;
+
+static const char* kDesmumeSaveCookie = "|-DESMUME SAVE-|";
+
+static const uint32_t saveSizes[] = {512, // 4k
+ 8*1024, // 64k
+ 32*1024, // 512k
+ 64*1024, // 1Mbit
+ 256*1024, // 2Mbit
+ 512*1024, // 4Mbit
+ 1024*1024, // 8Mbit
+ 2048*1024, // 16Mbit
+ 4096*1024, // 32Mbit
+ 8192*1024, // 64Mbit
+ 16384*1024, // 128Mbit
+ 32768*1024, // 256Mbit
+ 65536*1024, // 512Mbit
+ 0xFFFFFFFF};
+static const uint32_t saveSizes_count = ARRAY_SIZE(saveSizes);
+
+//the lookup table from user save types to save parameters
+const int save_types[][2] = {
+ {MC_TYPE_AUTODETECT,1},
+ {MC_TYPE_EEPROM1,MC_SIZE_4KBITS},
+ {MC_TYPE_EEPROM2,MC_SIZE_64KBITS},
+ {MC_TYPE_EEPROM2,MC_SIZE_512KBITS},
+ {MC_TYPE_FRAM,MC_SIZE_256KBITS},
+ {MC_TYPE_FLASH,MC_SIZE_2MBITS},
+ {MC_TYPE_FLASH,MC_SIZE_4MBITS},
+ {MC_TYPE_FLASH,MC_SIZE_8MBITS},
+ {MC_TYPE_FLASH,MC_SIZE_16MBITS},
+ {MC_TYPE_FLASH,MC_SIZE_32MBITS},
+ {MC_TYPE_FLASH,MC_SIZE_64MBITS},
+ {MC_TYPE_FLASH,MC_SIZE_128MBITS},
+ {MC_TYPE_FLASH,MC_SIZE_256MBITS},
+ {MC_TYPE_FLASH,MC_SIZE_512MBITS}
+};
+
+/*const char *save_names[] = {
+ "EEPROM 4kbit",
+ "EEPROM 64kbit",
+ "EEPROM 512kbit",
+ "FRAM 256kbit",
+ "FLASH 2Mbit",
+ "FLASH 4Mbit",
+ "FLASH 8Mbit",
+ "FLASH 16Mbit",
+ "FLASH 32Mbit",
+ "FLASH 64Mbit",
+ "FLASH 128Mbit",
+ "FLASH 256Mbit",
+ "FLASH 512Mbit"
+};*/
+
+//forces the currently selected backup type to be current
+//(can possibly be used to repair poorly chosen save types discovered late in gameplay i.e. pokemon gamers)
+/*void backup_forceManualBackupType()
+{
+ MMU_new.backupDevice.forceManualBackupType();
+}*/
+
+/*void backup_setManualBackupType(int type)
+{
+ CommonSettings.manualBackupType = type;
+}*/
+
+void mc_init(memory_chip_t *mc, int type)
+{
+ mc->com = 0;
+ mc->addr = 0;
+ mc->addr_shift = 0;
+ mc->data.clear();
+ mc->size = 0;
+ mc->write_enable = false;
+ mc->writeable_buffer = false;
+ mc->type = type;
+ mc->autodetectsize = 0;
+
+ switch(mc->type)
+ {
+ case MC_TYPE_EEPROM1:
+ mc->addr_size = 1;
+ break;
+ case MC_TYPE_EEPROM2:
+ case MC_TYPE_FRAM:
+ mc->addr_size = 2;
+ break;
+ case MC_TYPE_FLASH:
+ mc->addr_size = 3;
+ break;
+ default: break;
+ }
+}
+
+uint8_t *mc_alloc(memory_chip_t *mc, uint32_t size)
+{
+ /*uint8_t *buffer;
+ buffer = new uint8_t[size];
+ memset(buffer,0,size);*/
+
+ //if (mc->data) delete [] mc->data;
+ mc->data.clear();
+ //mc->data = buffer;
+ //if(!buffer) { return NULL; }
+ mc->data.resize(size, 0);
+ mc->size = size;
+ mc->writeable_buffer = true;
+
+ //return buffer;
+ return NULL;
+}
+
+void mc_free(memory_chip_t *mc)
+{
+ //if(mc->data) delete[] mc->data;
+ mc->data.clear();
+ mc_init(mc, 0);
+}
+
+void fw_reset_com(memory_chip_t *mc)
+{
+ if(mc->com == FW_CMD_PAGEWRITE)
+ {
+ if (mc->fp)
+ {
+ fseek(mc->fp, 0, SEEK_SET);
+ fwrite(&mc->data[0], mc->size, 1, mc->fp);
+ }
+
+ if (mc->isFirmware&&CommonSettings.UseExtFirmware)
+ {
+ // copy User Settings 1 to User Settings 0 area
+ memcpy(&mc->data[0x3FE00], &mc->data[0x3FF00], 0x100);
+
+ printf("Firmware: save config");
+ FILE *fp = fopen(mc->userfile, "wb");
+ if (fp)
+ {
+ if (fwrite(&mc->data[0x3FF00], 1, 0x100, fp) == 0x100) // User Settings
+ {
+ if (fwrite(&mc->data[0x0002A], 1, 0x1D6, fp) == 0x1D6) // WiFi Settings
+ {
+ if (fwrite(&mc->data[0x3FA00], 1, 0x300, fp) == 0x300) // WiFi AP Settings
+ printf(" - done\n");
+ else
+ printf(" - failed\n");
+ }
+ }
+ fclose(fp);
+ }
+ else
+ printf(" - failed\n");
+ }
+
+ mc->write_enable = false;
+ }
+
+ mc->com = 0;
+}
+
+uint8_t fw_transfer(memory_chip_t *mc, uint8_t data)
+{
+ if(mc->com == FW_CMD_READ || mc->com == FW_CMD_PAGEWRITE) /* check if we are in a command that needs 3 bytes address */
+ {
+ if(mc->addr_shift > 0) /* if we got a complete address */
+ {
+ mc->addr_shift--;
+ mc->addr |= data << (mc->addr_shift * 8); /* argument is a byte of address */
+ }
+ else /* if we have received 3 bytes of address, proceed command */
+ {
+ switch(mc->com)
+ {
+ case FW_CMD_READ:
+ if(mc->addr < mc->size) /* check if we can read */
+ {
+ data = mc->data[mc->addr]; /* return byte */
+ mc->addr++; /* then increment address */
+ }
+ break;
+
+ case FW_CMD_PAGEWRITE:
+ if(mc->addr < mc->size)
+ {
+ mc->data[mc->addr] = data; /* write byte */
+ mc->addr++;
+ }
+ break;
+ }
+
+ }
+ }
+ else if(mc->com == FW_CMD_READ_ID)
+ {
+ switch(mc->addr)
+ {
+ //here is an ID string measured from an old ds fat: 62 16 00 (0x62=sanyo)
+ //but we chose to use an ST from martin's ds fat string so programs might have a clue as to the firmware size:
+ //20 40 12
+ case 0:
+ data = 0x20;
+ mc->addr=1;
+ break;
+ case 1:
+ data = 0x40; //according to gbatek this is the device ID for the flash on someone's ds fat
+ mc->addr=2;
+ break;
+ case 2:
+ data = 0x12;
+ mc->addr = 0;
+ break;
+ }
+ }
+ else if(mc->com == FW_CMD_READSTATUS)
+ {
+ return mc->write_enable ? 0x02 : 0x00;
+ }
+ else //finally, check if it's a new command
+ {
+ switch(data)
+ {
+ case 0: break; //nothing
+
+ case FW_CMD_READ_ID:
+ mc->addr = 0;
+ mc->com = FW_CMD_READ_ID;
+ break;
+
+ case FW_CMD_READ: //read command
+ mc->addr = 0;
+ mc->addr_shift = 3;
+ mc->com = FW_CMD_READ;
+ break;
+
+ case FW_CMD_WRITEENABLE: //enable writing
+ if(mc->writeable_buffer) { mc->write_enable = true; }
+ break;
+
+ case FW_CMD_WRITEDISABLE: //disable writing
+
+ mc->write_enable = false;
+ break;
+
+ case FW_CMD_PAGEWRITE: //write command
+ if(mc->write_enable)
+ {
+ mc->addr = 0;
+ mc->addr_shift = 3;
+ mc->com = FW_CMD_PAGEWRITE;
+ }
+ else { data = 0; }
+ break;
+
+ case FW_CMD_READSTATUS: //status register command
+ mc->com = FW_CMD_READSTATUS;
+ break;
+
+ default:
+ printf("Unhandled FW command: %02X\n", data);
+ break;
+ }
+ }
+
+ return data;
+}
+
+/*bool BackupDevice::save_state(EMUFILE* os)
+{
+ uint32_t version = 2;
+ //v0
+ write32le(version,os);
+ write32le(write_enable,os);
+ write32le(com,os);
+ write32le(addr_size,os);
+ write32le(addr_counter,os);
+ write32le((uint32_t)state,os);
+ writebuffer(data,os);
+ writebuffer(data_autodetect,os);
+ //v1
+ write32le(addr,os);
+ //v2
+ write8le(motionInitState,os);
+ write8le(motionFlag,os);
+ return true;
+}*/
+
+bool BackupDevice::load_state(EMUFILE* is)
+{
+ uint32_t version;
+ if(read32le(&version,is)!=1) return false;
+ //if(version>=0)
+ {
+ readbool(&write_enable,is);
+ read32le(&com,is);
+ read32le(&addr_size,is);
+ read32le(&addr_counter,is);
+ uint32_t temp;
+ read32le(&temp,is);
+ state = (STATE)temp;
+ readbuffer(data,is);
+ readbuffer(data_autodetect,is);
+ }
+ if(version>=1)
+ read32le(&addr,is);
+ if(version>=2)
+ {
+ read8le(&motionInitState,is);
+ read8le(&motionFlag,is);
+ }
+
+ return true;
+}
+
+BackupDevice::BackupDevice()
+{
+ //isMovieMode = false;
+ reset();
+}
+
+//due to unfortunate shortcomings in the emulator architecture,
+//at reset-time, we won't have a filename to the .dsv file.
+//so the only difference between load_rom (init) and reset is that
+//one of them saves the filename
+void BackupDevice::load_rom(const char* fn)
+{
+ //isMovieMode = false;
+ this->filename = fn;
+ reset();
+}
+
+/*void BackupDevice::movie_mode()
+{
+ isMovieMode = true;
+ reset();
+}*/
+
+void BackupDevice::reset_hardware()
+{
+ write_enable = false;
+ com = 0;
+ addr = addr_counter = 0;
+ motionInitState = MOTION_INIT_STATE_IDLE;
+ motionFlag = MOTION_FLAG_NONE;
+ state = DETECTING;
+ flushPending = false;
+ lazyFlushPending = false;
+}
+
+void BackupDevice::reset()
+{
+ memset(&info, 0, sizeof(info));
+ reset_hardware();
+ resize(0);
+ data_autodetect.resize(0);
+ addr_size = 0;
+ loadfile();
+
+ //if the user has requested a manual choice for backup type, and we havent imported a raw save file, then apply it now
+ if(state == DETECTING && CommonSettings.manualBackupType != MC_TYPE_AUTODETECT)
+ {
+ state = RUNNING;
+ int savetype = save_types[CommonSettings.manualBackupType][0];
+ int savesize = save_types[CommonSettings.manualBackupType][1];
+ ensure((uint32_t)savesize); //expand properly if necessary
+ resize(savesize); //truncate if necessary
+ addr_size = addr_size_for_old_save_type(savetype);
+ //flush();
+ }
+}
+
+/*void BackupDevice::close_rom()
+{
+ //flush();
+}*/
+
+/*void BackupDevice::reset_command()
+{
+ //printf("MC RESET\n");
+ //for a performance hack, save files are only flushed after each reset command
+ //(hopefully, after each page)
+ if(flushPending)
+ {
+ //flush();
+ flushPending = false;
+ lazyFlushPending = false;
+ }
+
+ if(state == DETECTING && data_autodetect.size()>0)
+ {
+ //we can now safely detect the save address size
+ uint32_t autodetect_size = data_autodetect.size();
+
+ printf("Autodetecting with autodetect_size=%d\n",autodetect_size);
+
+ const uint8_t sm64_sig[] = {0x01,0x80,0x00,0x00};
+ if(autodetect_size == 4 && !memcmp(&data_autodetect[0],sm64_sig,4))
+ {
+ addr_size = 2;
+ }
+ else //detect based on rules
+ switch(autodetect_size)
+ {
+ case 0:
+ case 1:
+ printf("Catastrophic error while autodetecting save type.\nIt will need to be specified manually\n");
+ #ifdef _WINDOWS
+ MessageBoxA(0,"Catastrophic Error Code: Camel;\nyour save type has not been autodetected correctly;\nplease report to developers",0,0);
+ #endif
+ addr_size = 1; //choose 1 just to keep the busted savefile from growing too big
+ break;
+ case 2:
+ //the modern typical case for small eeproms
+ addr_size = 1;
+ break;
+ case 3:
+ //another modern typical case..
+ //but unfortunately we select this case for spider-man 3, when what it meant to do was
+ //present the archaic 1+2 case
+ //it seems that over the hedge does this also.
+ addr_size = 2;
+ break;
+ case 4:
+ //a modern typical case
+ addr_size = 3;
+ break;
+ default:
+ //the archaic case: write the address and then some modulo-4 number of bytes
+ //why modulo 4? who knows.
+ addr_size = autodetect_size & 3;
+ break;
+ }
+
+ state = RUNNING;
+ data_autodetect.resize(0);
+ //flush();
+ }
+
+ com = 0;
+}*/
+/*uint8_t BackupDevice::data_command(uint8_t val, int cpu)
+{
+ //printf("MC CMD: %02X\n",val);
+
+ //motion: some guessing here... hope it doesn't break anything
+ if(com == BM_CMD_READLOW && motionInitState == MOTION_INIT_STATE_RECEIVED_4_B && val == 0)
+ {
+ motionInitState = MOTION_INIT_STATE_IDLE;
+ motionFlag |= MOTION_FLAG_ENABLED;
+ //return 0x04; //return 0x04 to enable motion!!!!!
+ return 0; //but we return 0 to disable it! since we don't emulate it anyway
+ }
+
+ //if the game firmly believes we have motion support, then ignore all motion commands, since theyre not emulated.
+ if(motionFlag & MOTION_FLAG_SENSORMODE)
+ {
+ return 0;
+ }
+
+ if(com == BM_CMD_READLOW || com == BM_CMD_WRITELOW)
+ {
+ //handle data or address
+ if(state == DETECTING)
+ {
+ if(com == BM_CMD_WRITELOW)
+ {
+ printf("Unexpected backup device initialization sequence using writes!\n");
+ }
+
+ //just buffer the data until we're no longer detecting
+ data_autodetect.push_back(val);
+ val = 0;
+ }
+ else
+ {
+ if(addr_counter<addr_size)
+ {
+ //continue building address
+ addr <<= 8;
+ addr |= val;
+ addr_counter++;
+ //if(addr_counter==addr_size) printf("ADR: %08X\n",addr);
+ }
+ else
+ {
+ //why does tomb raider underworld access 0x180 and go clear through to 0x280?
+ //should this wrap around at 0 or at 0x100?
+ if(addr_size == 1) addr &= 0x1FF;
+
+ //address is complete
+ ensure(addr+1);
+ if(com == BM_CMD_READLOW)
+ {
+ //printf("READ ADR: %08X\n",addr);
+ val = data[addr];
+ //flushPending = true; //is this a good idea? it may slow stuff down, but it is helpful for debugging
+ lazyFlushPending = true; //lets do this instead
+ //printf("read: %08X\n",addr);
+ }
+ else
+ {
+ if(write_enable)
+ {
+ //printf("WRITE ADR: %08X\n",addr);
+ data[addr] = val;
+ flushPending = true;
+ //printf("writ: %08X\n",addr);
+ }
+ }
+ addr++;
+
+ }
+ }
+ }
+ else if(com == BM_CMD_READSTATUS)
+ {
+ //handle request to read status
+ //LOG("Backup Memory Read Status: %02X\n", write_enable << 1);
+ return (write_enable << 1) | (3<<2);
+ }
+ else
+ {
+ //there is no current command. receive one
+ switch(val)
+ {
+ case 0: break; //??
+
+ case 0xFE:
+ if(motionInitState == MOTION_INIT_STATE_IDLE) { motionInitState = MOTION_INIT_STATE_FE; return 0; }
+ break;
+ case 0xFD:
+ if(motionInitState == MOTION_INIT_STATE_FE) { motionInitState = MOTION_INIT_STATE_FD; return 0; }
+ break;
+ case 0xFB:
+ if(motionInitState == MOTION_INIT_STATE_FD) { motionInitState = MOTION_INIT_STATE_FB; return 0; }
+ break;
+ case 0xF8:
+ //enable sensor mode
+ if(motionInitState == MOTION_INIT_STATE_FD)
+ {
+ motionInitState = MOTION_INIT_STATE_IDLE;
+ motionFlag |= MOTION_FLAG_SENSORMODE;
+ return 0;
+ }
+ break;
+ case 0xF9:
+ //disable sensor mode
+ if(motionInitState == MOTION_INIT_STATE_FD)
+ {
+ motionInitState = MOTION_INIT_STATE_IDLE;
+ motionFlag &= ~MOTION_FLAG_SENSORMODE;
+ return 0;
+ }
+ break;
+
+ case 8:
+ printf("COMMAND%c: Unverified Backup Memory command: %02X FROM %08X\n",(cpu==ARMCPU_ARM9)?'9':'7',val, (cpu==ARMCPU_ARM9)?NDS_ARM9.instruct_adr:NDS_ARM7.instruct_adr);
+ val = 0xAA;
+ break;
+
+ case BM_CMD_WRITEDISABLE:
+ switch(motionInitState)
+ {
+ case MOTION_INIT_STATE_IDLE: motionInitState = MOTION_INIT_STATE_RECEIVED_4; break;
+ case MOTION_INIT_STATE_RECEIVED_4: motionInitState = MOTION_INIT_STATE_RECEIVED_4_B; break;
+ }
+ write_enable = false;
+ break;
+
+ case BM_CMD_READSTATUS:
+ com = BM_CMD_READSTATUS;
+ val = (write_enable << 1) | (3<<2);
+ break;
+
+ case BM_CMD_WRITEENABLE:
+ write_enable = true;
+ break;
+
+ case BM_CMD_WRITELOW:
+ case BM_CMD_READLOW:
+ //printf("XLO: %08X\n",addr);
+ com = val;
+ addr_counter = 0;
+ addr = 0;
+ break;
+
+ case BM_CMD_WRITEHIGH:
+ case BM_CMD_READHIGH:
+ //printf("XHI: %08X\n",addr);
+ if(val == BM_CMD_WRITEHIGH) val = BM_CMD_WRITELOW;
+ if(val == BM_CMD_READHIGH) val = BM_CMD_READLOW;
+ com = val;
+ addr_counter = 0;
+ addr = 0;
+ if(addr_size==1) {
+ //"write command that's only available on ST M95040-W that I know of"
+ //this makes sense, since this device would only have a 256 bytes address space with writelow
+ //and writehigh would allow access to the upper 256 bytes
+ //but it was detected in pokemon diamond also during the main save process
+ addr = 0x1;
+ }
+ break;
+
+ default:
+ printf("COMMAND%c: Unhandled Backup Memory command: %02X FROM %08X\n",(cpu==ARMCPU_ARM9)?'9':'7',val, (cpu==ARMCPU_ARM9)?NDS_ARM9.instruct_adr:NDS_ARM7.instruct_adr);
+ break;
+ } //switch(val)
+
+ //motion control state machine broke, return to ground
+ motionInitState = MOTION_INIT_STATE_IDLE;
+ }
+ return val;
+}*/
+
+//guarantees that the data buffer has room enough for the specified number of bytes
+void BackupDevice::ensure(uint32_t Addr)
+{
+ uint32_t size = data.size();
+ if(size<Addr)
+ {
+ resize(Addr);
+ }
+}
+
+void BackupDevice::resize(uint32_t size)
+{
+ size_t old_size = data.size();
+ data.resize(size);
+ for(uint32_t i=old_size;i<size;i++)
+ data[i] = kUninitializedSaveDataValue;
+}
+
+uint32_t BackupDevice::addr_size_for_old_save_size(int bupmem_size)
+{
+ switch(bupmem_size) {
+ case MC_SIZE_4KBITS:
+ return 1;
+ case MC_SIZE_64KBITS:
+ case MC_SIZE_256KBITS:
+ case MC_SIZE_512KBITS:
+ return 2;
+ case MC_SIZE_1MBITS:
+ case MC_SIZE_2MBITS:
+ case MC_SIZE_4MBITS:
+ case MC_SIZE_8MBITS:
+ case MC_SIZE_16MBITS:
+ case MC_SIZE_64MBITS:
+ return 3;
+ default:
+ return 0xFFFFFFFF;
+ }
+}
+
+uint32_t BackupDevice::addr_size_for_old_save_type(int bupmem_type)
+{
+ switch(bupmem_type)
+ {
+ case MC_TYPE_EEPROM1:
+ return 1;
+ case MC_TYPE_EEPROM2:
+ case MC_TYPE_FRAM:
+ return 2;
+ case MC_TYPE_FLASH:
+ return 3;
+ default:
+ return 0xFFFFFFFF;
+ }
+}
+
+
+void BackupDevice::load_old_state(uint32_t addrSize, uint8_t* Data, uint32_t datasize)
+{
+ state = RUNNING;
+ this->addr_size = addrSize;
+ resize(datasize);
+ memcpy(&this->data[0],Data,datasize);
+
+ //dump back out as a dsv, just to keep things sane
+ //flush();
+}
+
+//======================================================================= no$GBA
+//=======================================================================
+//=======================================================================
+
+static int no_gba_unpackSAV(void *in_buf, uint32_t fsize, void *out_buf, uint32_t &size)
+{
+ const char no_GBA_HEADER_ID[] = "NocashGbaBackupMediaSavDataFile";
+ const char no_GBA_HEADER_SRAM_ID[] = "SRAM";
+ uint8_t *src = (uint8_t *)in_buf;
+ uint8_t *dst = (uint8_t *)out_buf;
+ uint32_t src_pos = 0;
+ uint32_t dst_pos = 0;
+ uint8_t cc = 0;
+ uint32_t size_unpacked = 0;
+ //uint32_t size_packed = 0;
+ uint32_t compressMethod = 0;
+
+ if (fsize < 0x50) return 1;
+
+ for (int i = 0; i < 0x1F; i++)
+ {
+ if (src[i] != no_GBA_HEADER_ID[i]) return 2;
+ }
+ if (src[0x1F] != 0x1A) return 2;
+ for (int i = 0; i < 0x4; i++)
+ {
+ if (src[i+0x40] != no_GBA_HEADER_SRAM_ID[i]) return 2;
+ }
+
+ compressMethod = *((uint32_t*)(src+0x44));
+
+ if (compressMethod == 0) // unpacked
+ {
+ size_unpacked = *((uint32_t*)(src+0x48));
+ src_pos = 0x4C;
+ for (uint32_t i = 0; i < size_unpacked; i++)
+ {
+ dst[dst_pos++] = src[src_pos++];
+ }
+ size = dst_pos;
+ return 0;
+ }
+
+ if (compressMethod == 1) // packed (method 1)
+ {
+ //size_packed = *((uint32_t*)(src+0x48));
+ size_unpacked = *((uint32_t*)(src+0x4C));
+
+ src_pos = 0x50;
+ while (true)
+ {
+ cc = src[src_pos++];
+
+ if (cc == 0)
+ {
+ size = dst_pos;
+ return 0;
+ }
+
+ if (cc == 0x80)
+ {
+ uint16_t tsize = *((uint16_t*)(src+src_pos+1));
+ for (int t = 0; t < tsize; t++)
+ dst[dst_pos++] = src[src_pos];
+ src_pos += 3;
+ continue;
+ }
+
+ if (cc > 0x80) // repeat
+ {
+ cc -= 0x80;
+ for (int t = 0; t < cc; t++)
+ dst[dst_pos++] = src[src_pos];
+ src_pos++;
+ continue;
+ }
+ // copy
+ for (int t = 0; t < cc; t++)
+ dst[dst_pos++] = src[src_pos++];
+ }
+ size = dst_pos;
+ return 0;
+ }
+ return 200;
+}
+
+static uint32_t no_gba_savTrim(void *buf, uint32_t size)
+{
+ uint32_t rows = size / 16;
+ uint32_t pos = (size - 16);
+ uint8_t *src = (uint8_t*)buf;
+
+ for (unsigned int i = 0; i < rows; i++, pos -= 16)
+ {
+ if (src[pos] == 0xFF)
+ {
+ for (int t = 0; t < 16; t++)
+ {
+ if (src[pos+t] != 0xFF) return pos+16;
+ }
+ }
+ else
+ {
+ return pos+16;
+ }
+ }
+ return size;
+}
+
+static uint32_t no_gba_fillLeft(uint32_t size)
+{
+ for (uint32_t i = 1; i < ARRAY_SIZE(save_types); i++)
+ {
+ if (size <= (uint32_t)save_types[i][1])
+ return size + (save_types[i][1] - size);
+ }
+ return size;
+}
+
+bool BackupDevice::load_no_gba(const char *fname)
+{
+ FILE *fsrc = fopen(fname, "rb");
+ uint8_t *in_buf = NULL;
+ uint8_t *out_buf = NULL;
+
+ if (fsrc)
+ {
+ uint32_t fsize = 0;
+ fseek(fsrc, 0, SEEK_END);
+ fsize = ftell(fsrc);
+ fseek(fsrc, 0, SEEK_SET);
+ //printf("Open %s file (size %i bytes)\n", fname, fsize);
+
+ in_buf = new uint8_t [fsize];
+
+ if (fread(in_buf, 1, fsize, fsrc) == fsize)
+ {
+ out_buf = new uint8_t [8 * 1024 * 1024 / 8];
+ uint32_t size = 0;
+
+ memset(out_buf, 0xFF, 8 * 1024 * 1024 / 8);
+ if (no_gba_unpackSAV(in_buf, fsize, out_buf, size) == 0)
+ {
+ //printf("New size %i byte(s)\n", size);
+ size = no_gba_savTrim(out_buf, size);
+ //printf("--- new size after trim %i byte(s)\n", size);
+ size = no_gba_fillLeft(size);
+ //printf("--- new size after fill %i byte(s)\n", size);
+ raw_applyUserSettings(size);
+ data.resize(size);
+ for (uint32_t tt = 0; tt < size; tt++)
+ data[tt] = out_buf[tt];
+
+ //dump back out as a dsv, just to keep things sane
+ //flush();
+ printf("---- Loaded no$GBA save\n");
+
+ if (in_buf) delete [] in_buf;
+ if (out_buf) delete [] out_buf;
+ fclose(fsrc);
+ return true;
+ }
+ if (out_buf) delete [] out_buf;
+ }
+ if (in_buf) delete [] in_buf;
+ fclose(fsrc);
+ }
+
+ return false;
+}
+
+/*bool BackupDevice::save_no_gba(const char* fname)
+{
+ FILE* outf = fopen(fname,"wb");
+ if(!outf) return false;
+ uint32_t size = data.size();
+ uint32_t padSize = pad_up_size(size);
+ if(data.size()>0)
+ fwrite(&data[0],1,size,outf);
+ for(uint32_t i=size;i<padSize;i++)
+ fputc(0xFF,outf);
+
+ if (padSize < 512 * 1024)
+ {
+ for(uint32_t i=padSize; i<512 * 1024; i++)
+ fputc(0xFF,outf);
+ }
+ fclose(outf);
+ return true;
+}*/
+//======================================================================= end
+//=======================================================================
+//======================================================================= no$GBA
+
+
+void BackupDevice::loadfile()
+{
+ //never use save files if we are in movie mode
+ //if(isMovieMode) return;
+ if(filename.length() ==0) return; //No sense crashing if no filename supplied
+
+ EMUFILE_FILE* inf = new EMUFILE_FILE(filename.c_str(),"rb");
+ if(inf->fail())
+ {
+ delete inf;
+ //no dsv found; we need to try auto-importing a file with .sav extension
+ printf("DeSmuME .dsv save file not found. Trying to load an old raw .sav file.\n");
+
+ //change extension to sav
+ char tmp[MAX_PATH];
+ strcpy(tmp,filename.c_str());
+ tmp[strlen(tmp)-3] = 0;
+ strcat(tmp,"sav");
+
+ inf = new EMUFILE_FILE(tmp,"rb");
+ if(inf->fail())
+ {
+ delete inf;
+ printf("Missing save file %s\n",filename.c_str());
+ return;
+ }
+ delete inf;
+
+ if (!load_no_gba(tmp))
+ load_raw(tmp);
+ }
+ else
+ {
+ //scan for desmume save footer
+ const int32_t cookieLen = (int32_t)strlen(kDesmumeSaveCookie);
+ char *sigbuf = new char[cookieLen];
+ inf->fseek(-cookieLen, SEEK_END);
+ inf->fread(sigbuf,cookieLen);
+ int cmp = memcmp(sigbuf,kDesmumeSaveCookie,cookieLen);
+ delete[] sigbuf;
+ if(cmp)
+ {
+ //maybe it is a misnamed raw save file. try loading it that way
+ printf("Not a DeSmuME .dsv save file. Trying to load as raw.\n");
+ delete inf;
+ if (!load_no_gba(filename.c_str()))
+ load_raw(filename.c_str());
+ return;
+ }
+ //desmume format
+ inf->fseek(-cookieLen, SEEK_END);
+ inf->fseek(-4, SEEK_CUR);
+ uint32_t version = 0xFFFFFFFF;
+ read32le(&version,inf);
+ if(version!=0) {
+ printf("Unknown save file format\n");
+ return;
+ }
+ inf->fseek(-24, SEEK_CUR);
+ read32le(&info.size,inf);
+ read32le(&info.padSize,inf);
+ read32le(&info.type,inf);
+ read32le(&info.addr_size,inf);
+ read32le(&info.mem_size,inf);
+
+ //uint32_t left = 0;
+ /*if (CommonSettings.autodetectBackupMethod == 1)
+ {
+ if (advsc.isLoaded())
+ {
+ info.type = advsc.getSaveType();
+ if (info.type != 0xFF || info.type != 0xFE)
+ {
+ u32 adv_size = save_types[info.type+1][1];
+ if (info.size > adv_size)
+ info.size = adv_size;
+ else
+ if (info.size < adv_size)
+ {
+ left = adv_size - info.size;
+ info.size = adv_size;
+ }
+ }
+ }
+ }*/
+ //establish the save data
+ resize(info.size);
+ inf->fseek(0, SEEK_SET);
+ if(info.size>0)
+ inf->fread(&data[0],info.size); //read all the raw data we have
+ state = RUNNING;
+ addr_size = info.addr_size;
+ //none of the other fields are used right now
+
+ /*if (CommonSettings.autodetectBackupMethod != 1 && info.type == 0)
+ {
+ info.type = searchFileSaveType(info.size);
+ if (info.type == 0xFF) info.type = 0;
+ }
+ uint32_t ss = info.size * 8 / 1024;
+ if (ss >= 1024)
+ {
+ ss /= 1024;
+ printf("Backup size: %i Mbit\n", ss);
+ }
+ else
+ printf("Backup size: %i Kbit\n", ss);*/
+
+ delete inf;
+ }
+}
+
+/*bool BackupDevice::save_raw(const char* fn)
+{
+ FILE* outf = fopen(fn,"wb");
+ if(!outf) return false;
+ uint32_t size = data.size();
+ uint32_t padSize = pad_up_size(size);
+ if(data.size()>0)
+ fwrite(&data[0],1,size,outf);
+ for(uint32_t i=size;i<padSize;i++)
+ fputc(kUninitializedSaveDataValue,outf);
+ fclose(outf);
+ return true;
+}*/
+
+/*uint32_t BackupDevice::pad_up_size(uint32_t startSize)
+{
+ uint32_t size = startSize;
+ uint32_t ctr=0;
+ while(ctr<saveSizes_count && size > saveSizes[ctr]) ctr++;
+ uint32_t padSize = saveSizes[ctr];
+ if(padSize == 0xFFFFFFFF)
+ {
+ printf("PANIC! Couldn't pad up save size. Refusing to pad.\n");
+ padSize = startSize;
+ }
+ return padSize;
+}*/
+
+/*void BackupDevice::lazy_flush()
+{
+ if(flushPending || lazyFlushPending)
+ {
+ lazyFlushPending = flushPending = false;
+ //flush();
+ }
+}*/
+
+/*void BackupDevice::flush()
+{
+ //never use save files if we are in movie mode
+ if(isMovieMode) return;
+
+ EMUFILE* outf = new EMUFILE_FILE(filename.c_str(),"wb");
+ if(!outf->fail())
+ {
+ if(data.size()>0)
+ outf->fwrite(&data[0],data.size());
+
+ //write the footer. we use a footer so that we can maximize the chance of the
+ //save file being recognized as a raw save file by other emulators etc.
+
+ //first, pad up to the next largest known save size.
+ uint32_t size = data.size();
+ uint32_t padSize = pad_up_size(size);
+
+ for(uint32_t i=size;i<padSize;i++)
+ outf->fputc(kUninitializedSaveDataValue);
+
+ //this is just for humans to read
+ outf->fprintf("|<--Snip above here to create a raw sav by excluding this DeSmuME savedata footer:");
+
+ //and now the actual footer
+ write32le(size,outf); //the size of data that has actually been written
+ write32le(padSize,outf); //the size we padded it to
+ write32le(0,outf); //save memory type
+ write32le(addr_size,outf);
+ write32le(0,outf); //save memory size
+ write32le(0,outf); //version number
+ outf->fprintf("%s", kDesmumeSaveCookie); //this is what we'll use to recognize the desmume format save
+
+ delete outf;
+ }
+ else
+ {
+ delete outf;
+ printf("Unable to open savefile %s\n",filename.c_str());
+ }
+}*/
+
+void BackupDevice::raw_applyUserSettings(uint32_t& size, bool manual)
+{
+ //respect the user's choice of backup memory type
+ if(CommonSettings.manualBackupType == MC_TYPE_AUTODETECT && !manual)
+ {
+ addr_size = addr_size_for_old_save_size(size);
+ resize(size);
+ }
+ else
+ {
+ uint32_t type = CommonSettings.manualBackupType;
+ /*if (manual)
+ {
+ uint32_t res = searchFileSaveType(size);
+ if (res != 0xFF) type = (res + 1); // +1 - skip autodetect
+ }*/
+ int savetype = save_types[type][0];
+ int savesize = save_types[type][1];
+ addr_size = addr_size_for_old_save_type(savetype);
+ if((uint32_t)savesize<size) size = savesize;
+ resize(savesize);
+ }
+
+ state = RUNNING;
+}
+
+/*uint32_t BackupDevice::get_save_raw_size(const char* fname)
+{
+ FILE* inf = fopen(fname,"rb");
+ if (!inf) return 0xFFFFFFFF;
+
+ fseek(inf, 0, SEEK_END);
+ uint32_t size = (uint32_t)ftell(inf);
+ fclose(inf);
+ return size;
+}*/
+
+bool BackupDevice::load_raw(const char* fn, uint32_t force_size)
+{
+ FILE* inf = fopen(fn,"rb");
+
+ if (!inf) return false;
+
+ fseek(inf, 0, SEEK_END);
+ uint32_t size = (uint32_t)ftell(inf);
+ uint32_t left = 0;
+
+ if (force_size > 0)
+ {
+ if (size > force_size)
+ size = force_size;
+ else if (size < force_size)
+ {
+ left = force_size - size;
+ size = force_size;
+ }
+ }
+
+ fseek(inf, 0, SEEK_SET);
+
+ raw_applyUserSettings(size, force_size > 0);
+
+ fread(&data[0],1,size - left,inf);
+ fclose(inf);
+
+ //dump back out as a dsv, just to keep things sane
+ //flush();
+
+ return true;
+}
+
+
+/*bool BackupDevice::load_duc(const char* fn)
+{
+ uint32_t size;
+ char id[16];
+ FILE* file = fopen(fn, "rb");
+ if(file == NULL)
+ return false;
+
+ fseek(file, 0, SEEK_END);
+ size = (uint32_t)ftell(file) - 500;
+ fseek(file, 0, SEEK_SET);
+
+ // Make sure we really have the right file
+ fread((void *)id, sizeof(char), 16, file);
+
+ if (memcmp(id, "ARDS000000000001", 16) != 0)
+ {
+ printf("Not recognized as a valid DUC file\n");
+ fclose(file);
+ return false;
+ }
+ // Skip the rest of the header since we don't need it
+ fseek(file, 500, SEEK_SET);
+
+ raw_applyUserSettings(size);
+
+ ensure((uint32_t)size);
+
+ fread(&data[0],1,size,file);
+ fclose(file);
+
+ //choose
+
+ //flush();
+
+ return true;
+
+}*/
+
+/*bool BackupDevice::load_movie(EMUFILE* is) {
+
+ const int32_t cookieLen = (int32_t)strlen(kDesmumeSaveCookie);
+
+ is->fseek(-cookieLen, SEEK_END);
+ is->fseek(-4, SEEK_CUR);
+
+ uint32_t version = 0xFFFFFFFF;
+ is->fread((char*)&version,4);
+ if(version!=0) {
+ printf("Unknown save file format\n");
+ return false;
+ }
+ is->fseek(-24, SEEK_CUR);
+
+ struct{
+ uint32_t size,padSize,type,addr_size,mem_size;
+ }info;
+
+ is->fread((char*)&info.size,4);
+ is->fread((char*)&info.padSize,4);
+ is->fread((char*)&info.type,4);
+ is->fread((char*)&info.addr_size,4);
+ is->fread((char*)&info.mem_size,4);
+
+ //establish the save data
+ data.resize(info.size);
+ is->fseek(0, SEEK_SET);
+ if(info.size>0)
+ is->fread((char*)&data[0],info.size);
+
+ state = RUNNING;
+ addr_size = info.addr_size;
+ //none of the other fields are used right now
+
+ return true;
+}*/
+
+/*void BackupDevice::forceManualBackupType()
+{
+ addr_size = addr_size_for_old_save_size(save_types[CommonSettings.manualBackupType][1]);
+ state = RUNNING;
+}*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/mc.h
@@ -1,1 +1,188 @@
+/*
+ Copyright (C) 2006 thoduv
+ Copyright (C) 2006 Theo Berkau
+ Copyright (C) 2008-2012 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __FW_H__
+#define __FW_H__
+
+#include <vector>
+#include <string>
+#include <cstdio>
+
+#include "types.h"
+#include "emufile.h"
+#include "windowsh_wrapper.h"
+
+#define MAX_SAVE_TYPES 13
+#define MC_TYPE_AUTODETECT 0x0
+#define MC_TYPE_EEPROM1 0x1
+#define MC_TYPE_EEPROM2 0x2
+#define MC_TYPE_FLASH 0x3
+#define MC_TYPE_FRAM 0x4
+
+#define MC_SIZE_4KBITS 0x000200
+#define MC_SIZE_64KBITS 0x002000
+#define MC_SIZE_256KBITS 0x008000
+#define MC_SIZE_512KBITS 0x010000
+#define MC_SIZE_1MBITS 0x020000
+#define MC_SIZE_2MBITS 0x040000
+#define MC_SIZE_4MBITS 0x080000
+#define MC_SIZE_8MBITS 0x100000
+#define MC_SIZE_16MBITS 0x200000
+#define MC_SIZE_32MBITS 0x400000
+#define MC_SIZE_64MBITS 0x800000
+#define MC_SIZE_128MBITS 0x1000000
+#define MC_SIZE_256MBITS 0x2000000
+#define MC_SIZE_512MBITS 0x4000000
+
+struct memory_chip_t
+{
+ uint8_t com; //persistent command actually handled
+ uint32_t addr; //current address for reading/writing
+ uint8_t addr_shift; //shift for address (since addresses are transfered by 3 bytes units)
+ uint8_t addr_size; //size of addr when writing/reading
+
+ bool write_enable; //is write enabled ?
+
+ //uint8_t *data; //memory data
+ std::vector<uint8_t> data;
+ uint32_t size; //memory size
+ bool writeable_buffer; //is "data" writeable ?
+ int type; //type of Memory
+ char *filename;
+ FILE *fp;
+ uint8_t autodetectbuf[32768];
+ int autodetectsize;
+
+ // needs only for firmware
+ bool isFirmware;
+ char userfile[MAX_PATH];
+};
+
+//the new backup system by zeromus
+class BackupDevice
+{
+public:
+ BackupDevice();
+
+ //signals the save system that we are in our regular mode, loading up a rom. initializes for that case.
+ void load_rom(const char* filename);
+ //signals the save system that we are in MOVIE mode. doesnt load up a rom, and never saves it. initializes for that case.
+ //void movie_mode();
+
+ void reset();
+ //void close_rom();
+ //void forceManualBackupType();
+ void reset_hardware();
+ std::string getFilename() { return filename; }
+
+ //bool save_state(EMUFILE* os);
+ bool load_state(EMUFILE* is);
+
+ //commands from mmu
+ //void reset_command();
+ //uint8_t data_command(uint8_t,int);
+ std::vector<uint8_t> data;
+
+ //this info was saved before the last reset (used for savestate compatibility)
+ struct SavedInfo
+ {
+ uint32_t addr_size;
+ } savedInfo;
+
+ //and these are used by old savestates
+ void load_old_state(uint32_t addr_size, uint8_t* data, uint32_t datasize);
+ static uint32_t addr_size_for_old_save_size(int bupmem_size);
+ static uint32_t addr_size_for_old_save_type(int bupmem_type);
+
+ //static uint32_t pad_up_size(uint32_t startSize);
+ void raw_applyUserSettings(uint32_t& size, bool manual = false);
+
+ //bool load_duc(const char* filename);
+ bool load_no_gba(const char *fname);
+ //bool save_no_gba(const char* fname);
+ bool load_raw(const char* filename, uint32_t force_size = 0);
+ //bool save_raw(const char* filename);
+ //bool load_movie(EMUFILE* is);
+
+ //call me once a second or so to lazy flush the save data
+ //here's the reason for this system: we want to dump save files when theyre READ
+ //so that we have a better idea earlier on how large they are. but it slows things down
+ //way too much if we flush whenever we read.
+ //void lazy_flush();
+ //void flush();
+
+ struct {
+ uint32_t size,padSize,type,addr_size,mem_size;
+ } info;
+ //bool isMovieMode;
+
+private:
+ std::string filename;
+
+ bool write_enable; //is write enabled?
+ uint32_t com; //persistent command actually handled
+ uint32_t addr_size, addr_counter;
+ uint32_t addr;
+
+ std::vector<uint8_t> data_autodetect;
+ enum STATE {
+ DETECTING = 0, RUNNING = 1
+ } state;
+
+ enum MOTION_INIT_STATE
+ {
+ MOTION_INIT_STATE_IDLE, MOTION_INIT_STATE_RECEIVED_4, MOTION_INIT_STATE_RECEIVED_4_B,
+ MOTION_INIT_STATE_FE, MOTION_INIT_STATE_FD, MOTION_INIT_STATE_FB
+ };
+ enum MOTION_FLAG
+ {
+ MOTION_FLAG_NONE=0,
+ MOTION_FLAG_ENABLED=1,
+ MOTION_FLAG_SENSORMODE=2
+ };
+ uint8_t motionInitState, motionFlag;
+
+ void loadfile();
+ bool _loadfile(const char *fname);
+ void ensure(uint32_t addr);
+
+ bool flushPending, lazyFlushPending;
+
+private:
+ void resize(uint32_t size);
+};
+
+#define NDS_FW_SIZE_V1 (256 * 1024) /* size of fw memory on nds v1 */
+#define NDS_FW_SIZE_V2 (512 * 1024) /* size of fw memory on nds v2 */
+
+void mc_init(memory_chip_t *mc, int type); /* reset and init values for memory struct */
+uint8_t *mc_alloc(memory_chip_t *mc, uint32_t size); /* alloc mc memory */
+//void mc_realloc(memory_chip_t *mc, int type, uint32_t size); /* realloc mc memory */
+//void mc_load_file(memory_chip_t *mc, const char* filename); /* load save file and setup fp */
+void mc_free(memory_chip_t *mc); /* delete mc memory */
+void fw_reset_com(memory_chip_t *mc); /* reset communication with mc */
+uint8_t fw_transfer(memory_chip_t *mc, uint8_t data);
+
+//void backup_setManualBackupType(int type);
+//void backup_forceManualBackupType();
+
+//extern const char *save_names[];
+
+#endif /*__FW_H__*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/mem.h
@@ -1,1 +1,190 @@
+/*
+ Copyright (C) 2005 Theo Berkau
+ Copyright (C) 2005-2006 Guillaume Duhamel
+ Copyright (C) 2008-2010 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MEM_H
+#define MEM_H
+
+#include <cstdlib>
+#include <cassert>
+
+#include "types.h"
+
+//this was originally declared in MMU.h but we suffered some organizational problems and had to remove it
+enum MMU_ACCESS_TYPE
+{
+ MMU_AT_CODE, //used for cpu prefetches
+ MMU_AT_DATA, //used for cpu read/write
+ MMU_AT_GPU, //used for gpu read/write
+ MMU_AT_DMA, //used for dma read/write (blocks access to TCM)
+ MMU_AT_DEBUG //used for emulator debugging functions (bypasses some debug handling)
+};
+
+static inline uint8_t T1ReadByte(uint8_t* const mem, const uint32_t addr)
+{
+ return mem[addr];
+}
+
+static inline uint16_t T1ReadWord_guaranteedAligned(void* const mem, const uint32_t addr)
+{
+ assert((addr&1)==0);
+#ifdef WORDS_BIGENDIAN
+ return (((uint8_t*)mem)[addr + 1] << 8) | ((uint8_t*)mem)[addr];
+#else
+ return *(uint16_t*)((uint8_t*)mem + addr);
+#endif
+}
+
+static inline uint16_t T1ReadWord(void* const mem, const uint32_t addr)
+{
+#ifdef WORDS_BIGENDIAN
+ return (((uint8_t*)mem)[addr + 1] << 8) | ((uint8_t*)mem)[addr];
+#else
+ return *((uint16_t *) ((uint8_t*)mem + addr));
+#endif
+}
+
+static inline uint32_t T1ReadLong_guaranteedAligned(uint8_t* const mem, const uint32_t addr)
+{
+ assert((addr&3)==0);
+#ifdef WORDS_BIGENDIAN
+ return mem[addr + 3] << 24 | mem[addr + 2] << 16 |
+ mem[addr + 1] << 8 | mem[addr];
+#else
+ return *(uint32_t*)(mem + addr);
+#endif
+}
+
+
+static inline uint32_t T1ReadLong(uint8_t* const mem, uint32_t addr)
+{
+ addr &= ~3;
+#ifdef WORDS_BIGENDIAN
+ return mem[addr + 3] << 24 | mem[addr + 2] << 16 |
+ mem[addr + 1] << 8 | mem[addr];
+#else
+ return *(uint32_t*)(mem + addr);
+#endif
+}
+
+static inline uint64_t T1ReadQuad(uint8_t* const mem, const uint32_t addr)
+{
+#ifdef WORDS_BIGENDIAN
+ return uint64_t(mem[addr + 7]) << 56 | uint64_t(mem[addr + 6]) << 48 |
+ uint64_t(mem[addr + 5]) << 40 | uint64_t(mem[addr + 4]) << 32 |
+ uint64_t(mem[addr + 3]) << 24 | uint64_t(mem[addr + 2]) << 16 |
+ uint64_t(mem[addr + 1]) << 8 | uint64_t(mem[addr ]);
+#else
+ return *((uint64_t *) (mem + addr));
+#endif
+}
+
+static inline void T1WriteByte(uint8_t* const mem, const uint32_t addr, const uint8_t val)
+{
+ mem[addr] = val;
+}
+
+static inline void T1WriteWord(uint8_t* const mem, const uint32_t addr, const uint16_t val)
+{
+#ifdef WORDS_BIGENDIAN
+ mem[addr + 1] = val >> 8;
+ mem[addr] = val & 0xFF;
+#else
+ *((uint16_t *) (mem + addr)) = val;
+#endif
+}
+
+static inline void T1WriteLong(uint8_t* const mem, const uint32_t addr, const uint32_t val)
+{
+#ifdef WORDS_BIGENDIAN
+ mem[addr + 3] = val >> 24;
+ mem[addr + 2] = (val >> 16) & 0xFF;
+ mem[addr + 1] = (val >> 8) & 0xFF;
+ mem[addr] = val & 0xFF;
+#else
+ *((uint32_t *) (mem + addr)) = val;
+#endif
+}
+
+static inline void T1WriteQuad(uint8_t* const mem, const uint32_t addr, const uint64_t val)
+{
+#ifdef WORDS_BIGENDIAN
+ mem[addr + 7] = (val >> 56);
+ mem[addr + 6] = (val >> 48) & 0xFF;
+ mem[addr + 5] = (val >> 40) & 0xFF;
+ mem[addr + 4] = (val >> 32) & 0xFF;
+ mem[addr + 3] = (val >> 24) & 0xFF;
+ mem[addr + 2] = (val >> 16) & 0xFF;
+ mem[addr + 1] = (val >> 8) & 0xFF;
+ mem[addr] = val & 0xFF;
+#else
+ *((uint64_t *) (mem + addr)) = val;
+#endif
+}
+
+//static inline uint8_t T2ReadByte(uint8_t* const mem, const uint32_t addr)
+//{
+//#ifdef WORDS_BIGENDIAN
+// return mem[addr ^ 1];
+//#else
+// return mem[addr];
+//#endif
+//}
+//
+
+/*static inline uint16_t HostReadWord(uint8_t* const mem, const uint32_t addr)
+{
+ return *((uint16_t *) (mem + addr));
+}*/
+
+//
+//static inline uint32_t T2ReadLong(uint8_t* const mem, const uint32_t addr)
+//{
+//#ifdef WORDS_BIGENDIAN
+// return *((uint16_t *) (mem + addr + 2)) << 16 | *((uint16_t *) (mem + addr));
+//#else
+// return *((uint32_t *) (mem + addr));
+//#endif
+//}
+//
+//static inline void T2WriteByte(uint8_t* const mem, const uint32_t addr, const uint8_t val)
+//{
+//#ifdef WORDS_BIGENDIAN
+// mem[addr ^ 1] = val;
+//#else
+// mem[addr] = val;
+//#endif
+//}
+
+/*static inline void HostWriteWord(uint8_t* const mem, const uint32_t addr, const uint16_t val)
+{
+ *((uint16_t *) (mem + addr)) = val;
+}*/
+
+/*static inline void HostWriteTwoWords(uint8_t* const mem, const uint32_t addr, const uint32_t val)
+{
+#ifdef WORDS_BIGENDIAN
+ *((uint16_t *) (mem + addr + 2)) = val >> 16;
+ *((uint16_t *) (mem + addr)) = val & 0xFFFF;
+#else
+ *((uint32_t *) (mem + addr)) = val;
+#endif
+}*/
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SndOut.cpp
@@ -1,1 +1,389 @@
-
+/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
+ * Developed and maintained by the Pcsx2 Development Team.
+ *
+ * Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
+ *
+ * SPU2-X 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 Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * SPU2-X 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 SPU2-X. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <cassert>
+
+//#include "Global.h"
+#include "types.h"
+#include "SndOut.h"
+
+//----------------
+int SndOutLatencyMS = 160;
+bool timeStretchDisabled = false;
+//----------------
+
+StereoOut32 StereoOut32::Empty( 0, 0 );
+
+StereoOut32::StereoOut32( const StereoOut16& src ) :
+ Left( src.Left ),
+ Right( src.Right )
+{
+}
+
+StereoOut32::StereoOut32( const StereoOutFloat& src ) :
+ Left( (int32_t)(src.Left * 2147483647.0f) ),
+ Right( (int32_t)(src.Right * 2147483647.0f) )
+{
+}
+
+StereoOut16 StereoOut32::DownSample() const
+{
+ return StereoOut16(
+ static_cast<int16_t>(Left >> SndOutVolumeShift),
+ static_cast<int16_t>(Right >> SndOutVolumeShift)
+ );
+}
+
+/*StereoOut32 StereoOut16::UpSample() const
+{
+ return StereoOut32(
+ Left << SndOutVolumeShift,
+ Right << SndOutVolumeShift
+ );
+
+}*/
+
+//class NullOutModule: public SndOutModule
+//{
+//public:
+// int32_t Init() { return 0; }
+// void Close() { }
+// int32_t Test() const { return 0; }
+// void Configure(uptr parent) { }
+// bool Is51Out() const { return false; }
+// int GetEmptySampleCount() const { return 0; }
+//
+// const wchar_t* GetIdent() const
+// {
+// return L"nullout";
+// }
+//
+// const wchar_t* GetLongName() const
+// {
+// return L"No Sound (Emulate SPU2 only)";
+// }
+//
+// void ReadSettings()
+// {
+// }
+//
+// void WriteSettings() const
+// {
+// }
+//
+//} NullOut;
+//
+//SndOutModule* mods[]=
+//{
+// &NullOut,
+//#ifdef _MSC_VER
+// XAudio2Out,
+// DSoundOut,
+// WaveOut,
+//#endif
+// NULL // signals the end of our list
+//};
+//
+//int FindOutputModuleById( const wchar_t* omodid )
+//{
+// int modcnt = 0;
+// while( mods[modcnt] != NULL )
+// {
+// if( wcscmp( mods[modcnt]->GetIdent(), omodid ) == 0 )
+// break;
+// ++modcnt;
+// }
+// return modcnt;
+//}
+
+StereoOut32 *SndBuffer::m_buffer;
+int32_t SndBuffer::m_size;
+int32_t SndBuffer::m_rpos;
+int32_t SndBuffer::m_wpos;
+int32_t SndBuffer::m_data;
+
+bool SndBuffer::m_underrun_freeze;
+StereoOut32* SndBuffer::sndTempBuffer = NULL;
+StereoOut16* SndBuffer::sndTempBuffer16 = NULL;
+int SndBuffer::sndTempProgress = 0;
+
+static int GetAlignedBufferSize( int comp )
+{
+ return (comp + SndOutPacketSize-1) & ~(SndOutPacketSize-1);
+}
+
+// Returns true if there is data to be output, or false if no data
+// is available to be copied.
+bool SndBuffer::CheckUnderrunStatus( int& nSamples, int& quietSampleCount )
+{
+ quietSampleCount = 0;
+ if( m_underrun_freeze )
+ {
+ int toFill = (int)(m_size * ( timeStretchDisabled ? 0.50f : 0.1f ) );
+ toFill = GetAlignedBufferSize( toFill );
+
+ // toFill is now aligned to a SndOutPacket
+
+ if( m_data < toFill )
+ {
+ quietSampleCount = nSamples;
+ return false;
+ }
+
+ m_underrun_freeze = false;
+ //TODO
+ //if( MsgOverruns() )
+ printf(" * SPU2 > Underrun compensation (%d packets buffered)\n", toFill / SndOutPacketSize );
+ lastPct = 0.0; // normalize timestretcher
+ }
+ else if( m_data < nSamples )
+ {
+ nSamples = m_data;
+ quietSampleCount = SndOutPacketSize - m_data;
+ m_underrun_freeze = true;
+
+ if( !timeStretchDisabled )
+ timeStretchUnderrun();
+
+ return nSamples != 0;
+ }
+
+ return true;
+}
+
+void SndBuffer::_InitFail()
+{
+ // If a failure occurs, just initialize the NoSound driver. This'll allow
+ // the game to emulate properly (hopefully), albeit without sound.
+ //OutputModule = FindOutputModuleById( NullOut.GetIdent() );
+ //mods[OutputModule]->Init();
+}
+
+void SndBuffer::_WriteSamples(StereoOut32 *bData, int nSamples)
+{
+ int free = m_size-m_data;
+ m_predictData = 0;
+
+ assert( m_data <= m_size );
+
+ // Problem:
+ // If the SPU2 gets out of sync with the SndOut device, the writepos of the
+ // circular buffer will overtake the readpos, leading to a prolonged period
+ // of hopscotching read/write accesses (ie, lots of staticy crap sound for
+ // several seconds).
+ //
+ // Compromise:
+ // When an overrun occurs, we adapt by discarding a portion of the buffer.
+ // The older portion of the buffer is discarded rather than incoming data,
+ // so that the overall audio synchronization is better.
+
+ if( free < nSamples )
+ {
+ // Buffer overrun!
+ // Dump samples from the read portion of the buffer instead of dropping
+ // the newly written stuff.
+
+ int32_t comp;
+
+ if( !timeStretchDisabled )
+ {
+ comp = timeStretchOverrun();
+ }
+ else
+ {
+ // Toss half the buffer plus whatever's being written anew:
+ comp = GetAlignedBufferSize( (m_size + nSamples ) / 2 );
+ if( comp > (m_size-SndOutPacketSize) ) comp = m_size-SndOutPacketSize;
+ }
+
+ m_data -= comp;
+ m_rpos = (m_rpos+comp) % m_size;
+ //TODO
+ //if( MsgOverruns() )
+ printf(" * SPU2 > Overrun Compensation (%d packets tossed)\n", comp / SndOutPacketSize );
+ lastPct = 0.0; // normalize the timestretcher
+ }
+
+ // copy in two phases, since there's a chance the packet
+ // wraps around the buffer (it'd be nice to deal in packets only, but
+ // the timestretcher and DSP options require flexibility).
+
+ const int endPos = m_wpos + nSamples;
+ const int secondCopyLen = endPos - m_size;
+ StereoOut32* wposbuffer = &m_buffer[m_wpos];
+
+ m_data += nSamples;
+ if( secondCopyLen > 0 )
+ {
+ nSamples -= secondCopyLen;
+ memcpy( m_buffer, &bData[nSamples], secondCopyLen * sizeof( *bData ) );
+ m_wpos = secondCopyLen;
+ }
+ else
+ m_wpos += nSamples;
+
+ memcpy( wposbuffer, bData, nSamples * sizeof( *bData ) );
+}
+
+void SndBuffer::Init()
+{
+ //if( mods[OutputModule] == NULL )
+ //{
+ // _InitFail();
+ // return;
+ //}
+
+ // initialize sound buffer
+ // Buffer actually attempts to run ~50%, so allocate near double what
+ // the requested latency is:
+
+
+ m_rpos = 0;
+ m_wpos = 0;
+ m_data = 0;
+
+ try
+ {
+ const float latencyMS = SndOutLatencyMS * (timeStretchDisabled ? 1.5f : 2.0f );
+ m_size = GetAlignedBufferSize( (int)(latencyMS * SampleRate / 1000.0f ) );
+ m_buffer = new StereoOut32[m_size];
+ m_underrun_freeze = false;
+
+ sndTempBuffer = new StereoOut32[SndOutPacketSize];
+ sndTempBuffer16 = new StereoOut16[SndOutPacketSize];
+ }
+ catch( std::bad_alloc& )
+ {
+ // out of memory exception (most likely)
+
+ printf( "Out of memory error occurred while initializing SPU2." );
+ _InitFail();
+ return;
+ }
+
+ // clear buffers!
+ // Fixes loopy sounds on emu resets.
+ memset( sndTempBuffer, 0, sizeof(StereoOut32) * SndOutPacketSize );
+ memset( sndTempBuffer16, 0, sizeof(StereoOut16) * SndOutPacketSize );
+
+ sndTempProgress = 0;
+
+ soundtouchInit(); // initializes the timestretching
+
+ // some crap
+ //spdif_set51(mods[OutputModule]->Is51Out());
+
+ // initialize module
+ //if( mods[OutputModule]->Init() == -1 ) _InitFail();
+}
+
+/*void SndBuffer::Cleanup()
+{
+ //mods[OutputModule]->Close();
+
+ soundtouchCleanup();
+
+ //safe_delete_array( m_buffer );
+ //safe_delete_array( sndTempBuffer );
+ //safe_delete_array( sndTempBuffer16 );
+ delete[] m_buffer;
+ delete[] sndTempBuffer;
+ delete[] sndTempBuffer16;
+}*/
+
+//int SndBuffer::m_dsp_progress = 0;
+
+//int SndBuffer::m_timestretch_progress = 0;
+//int SndBuffer::ssFreeze = 0;
+
+/*void SndBuffer::ClearContents()
+{
+ SndBuffer::soundtouchClearContents();
+ SndBuffer::ssFreeze = 30; //Delays sound output for about half a second.
+}*/
+
+void SndBuffer::Write( const StereoOut32& Sample )
+{
+ // Log final output to wavefile.
+ //WaveDump::WriteCore( 1, CoreSrc_External, Sample.DownSample() );
+
+ //RecordWrite( Sample.DownSample() );
+
+ //if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p
+ // return;
+
+ sndTempBuffer[sndTempProgress++] = Sample;
+
+ // If we haven't accumulated a full packet yet, do nothing more:
+ if(sndTempProgress < SndOutPacketSize) return;
+ sndTempProgress = 0;
+
+ //Don't play anything directly after loading a savestate, avoids static killing your speakers.
+// if ( ssFreeze > 0 )
+// {
+// ssFreeze--;
+// return;
+// }
+//#ifndef __LINUX__
+// else if( dspPluginEnabled )
+// {
+// // Convert in, send to winamp DSP, and convert out.
+//
+// for( int i=0; i<SndOutPacketSize; ++i ) { sndTempBuffer16[i] = sndTempBuffer[i].DownSample(); }
+// m_dsp_progress += DspProcess( (s16*)sndTempBuffer16, SndOutPacketSize );
+//
+// // Some ugly code to ensure full packet handling:
+// int ei = 0;
+// while( m_dsp_progress >= SndOutPacketSize )
+// {
+// for( int i=0; i<SndOutPacketSize; ++i, ++ei ) { sndTempBuffer[i] = sndTempBuffer16[ei].UpSample(); }
+//
+// if( !timeStretchDisabled )
+// timeStretchWrite();
+// else
+// _WriteSamples(sndTempBuffer, sndTempProgress);
+//
+// m_dsp_progress -= SndOutPacketSize;
+// }
+//
+// // copy any leftovers to the front of the dsp buffer.
+// if( m_dsp_progress > 0 )
+// {
+// memcpy( &sndTempBuffer16[ei], sndTempBuffer16,
+// sizeof(sndTempBuffer16[0]) * m_dsp_progress
+// );
+// }
+// }
+//#endif
+// else
+ {
+ if( !timeStretchDisabled )
+ timeStretchWrite();
+ else
+ _WriteSamples(sndTempBuffer, SndOutPacketSize);
+ }
+}
+
+/*int32_t SndBuffer::Test()
+{
+ //if( mods[OutputModule] == NULL )
+ // return -1;
+
+ //return mods[OutputModule]->Test();
+ return 0;
+}*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SndOut.h
@@ -1,1 +1,534 @@
-
+/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
+ * Developed and maintained by the Pcsx2 Development Team.
+ *
+ * Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
+ *
+ * SPU2-X 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 Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * SPU2-X 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 SPU2-X. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <algorithm>
+
+struct StereoOut16;
+//struct StereoOut32;
+struct StereoOutFloat;
+
+struct StereoOut32
+{
+ static StereoOut32 Empty;
+
+ int32_t Left;
+ int32_t Right;
+
+ StereoOut32() : Left(0), Right(0)
+ {
+ }
+
+ StereoOut32(int32_t left, int32_t right) : Left(left), Right(right)
+ {
+ }
+
+ StereoOut32(const StereoOut16 &src);
+ explicit StereoOut32(const StereoOutFloat &src);
+
+ StereoOut16 DownSample() const;
+
+ StereoOut32 operator+(const StereoOut32 &right) const
+ {
+ return StereoOut32(Left + right.Left, Right + right.Right);
+ }
+
+ StereoOut32 operator/(int src) const
+ {
+ return StereoOut32(Left / src, Right / src);
+ }
+};
+
+// Number of stereo samples per SndOut block.
+// All drivers must work in units of this size when communicating with
+// SndOut.
+static const int SndOutPacketSize = 512;
+
+// Overall master volume shift.
+// Converts the mixer's 32 bit value into a 16 bit value.
+//static const int SndOutVolumeShift = 13;
+
+//edit - zeromus 23-oct-2009
+//this is hardcoded differently for metaspu
+static const int SndOutVolumeShift = 0;
+
+// Samplerate of the SPU2. For accurate playback we need to match this
+// exactly. Trying to scale samplerates and maintain SPU2's Ts timing accuracy
+// is too problematic. :)
+//this is hardcoded differently for metaspu
+//edit - zeromus 23-oct-2009
+////static const int SampleRate = 48000;
+//static const int SampleRate = 44100;
+//edit - nitsuja: make it use the global sample rate define
+#include "../SPU.h"
+static const int SampleRate = DESMUME_SAMPLE_RATE;
+
+//extern int FindOutputModuleById(const wchar_t *omodid);
+
+struct StereoOut16
+{
+ int16_t Left;
+ int16_t Right;
+
+ StereoOut16() : Left(0), Right(0)
+ {
+ }
+
+ StereoOut16(const StereoOut32 &src) : Left(static_cast<int16_t>(src.Left)), Right(static_cast<int16_t>(src.Right))
+ {
+ }
+
+ StereoOut16(int16_t left, int16_t right) : Left(left), Right(right)
+ {
+ }
+
+ //StereoOut32 UpSample() const;
+
+ void ResampleFrom(const StereoOut32 &src)
+ {
+ // Use StereoOut32's built in conversion
+ *this = src.DownSample();
+ }
+};
+
+struct StereoOutFloat
+{
+ float Left;
+ float Right;
+
+ StereoOutFloat() : Left(0.0f), Right(0.0f)
+ {
+ }
+
+ explicit StereoOutFloat(const StereoOut32 &src) : Left(src.Left / 2147483647.0f), Right(src.Right / 2147483647.0f)
+ {
+ }
+
+ explicit StereoOutFloat(int32_t left, int32_t right) : Left(left / 2147483647.0f), Right(right / 2147483647.0f)
+ {
+ }
+
+ StereoOutFloat(float left, float right) : Left(left), Right(right)
+ {
+ }
+};
+
+//struct Stereo21Out16
+//{
+// int16_t Left;
+// int16_t Right;
+// int16_t LFE;
+//
+// void ResampleFrom( const StereoOut32& src )
+// {
+// Left = src.Left >> SndOutVolumeShift;
+// Right = src.Right >> SndOutVolumeShift;
+// LFE = (src.Left + src.Right) >> (SndOutVolumeShift + 1);
+// }
+//};
+//
+//struct StereoQuadOut16
+//{
+// int16_t Left;
+// int16_t Right;
+// int16_t LeftBack;
+// int16_t RightBack;
+//
+// void ResampleFrom( const StereoOut32& src )
+// {
+// Left = src.Left >> SndOutVolumeShift;
+// Right = src.Right >> SndOutVolumeShift;
+// LeftBack = src.Left >> SndOutVolumeShift;
+// RightBack = src.Right >> SndOutVolumeShift;
+// }
+//};
+//
+//struct Stereo41Out16
+//{
+// int16_t Left;
+// int16_t Right;
+// int16_t LFE;
+// int16_t LeftBack;
+// int16_t RightBack;
+//
+// void ResampleFrom( const StereoOut32& src )
+// {
+// Left = src.Left >> SndOutVolumeShift;
+// Right = src.Right >> SndOutVolumeShift;
+// LFE = (src.Left + src.Right) >> (SndOutVolumeShift + 1);
+// LeftBack = src.Left >> SndOutVolumeShift;
+// RightBack = src.Right >> SndOutVolumeShift;
+// }
+//};
+//
+//struct Stereo51Out16
+//{
+// int16_t Left;
+// int16_t Right;
+// int16_t Center;
+// int16_t LFE;
+// int16_t LeftBack;
+// int16_t RightBack;
+//
+// // Implementation Note: Center and Subwoofer/LFE -->
+// // This method is simple and sounds nice. It relies on the speaker/soundcard
+// // systems do to their own low pass / crossover. Manual lowpass is wasted effort
+// // and can't match solid state results anyway.
+//
+// void ResampleFrom( const StereoOut32& src )
+// {
+// Left = src.Left >> SndOutVolumeShift;
+// Right = src.Right >> SndOutVolumeShift;
+// Center = (src.Left + src.Right) >> (SndOutVolumeShift + 1);
+// LFE = Center;
+// LeftBack = src.Left >> SndOutVolumeShift;
+// RightBack = src.Right >> SndOutVolumeShift;
+// }
+//};
+//
+//struct Stereo51Out16DplII
+//{
+// int16_t Left;
+// int16_t Right;
+// int16_t Center;
+// int16_t LFE;
+// int16_t LeftBack;
+// int16_t RightBack;
+//
+// void ResampleFrom( const StereoOut32& src )
+// {
+// static const u8 sLogTable[256] = {
+// 0x00,0x3C,0x60,0x78,0x8C,0x9C,0xA8,0xB4,0xBE,0xC8,0xD0,0xD8,0xDE,0xE4,0xEA,0xF0,
+// 0xF6,0xFA,0xFE,0x04,0x08,0x0C,0x10,0x14,0x16,0x1A,0x1E,0x20,0x24,0x26,0x2A,0x2C,
+// 0x2E,0x32,0x34,0x36,0x38,0x3A,0x3E,0x40,0x42,0x44,0x46,0x48,0x4A,0x4C,0x4E,0x50,
+// 0x50,0x52,0x54,0x56,0x58,0x5A,0x5A,0x5C,0x5E,0x60,0x60,0x62,0x64,0x66,0x66,0x68,
+// 0x6A,0x6A,0x6C,0x6E,0x6E,0x70,0x70,0x72,0x74,0x74,0x76,0x76,0x78,0x7A,0x7A,0x7C,
+// 0x7C,0x7E,0x7E,0x80,0x80,0x82,0x82,0x84,0x84,0x86,0x86,0x88,0x88,0x8A,0x8A,0x8C,
+// 0x8C,0x8C,0x8E,0x8E,0x90,0x90,0x92,0x92,0x92,0x94,0x94,0x96,0x96,0x96,0x98,0x98,
+// 0x9A,0x9A,0x9A,0x9C,0x9C,0x9C,0x9E,0x9E,0xA0,0xA0,0xA0,0xA2,0xA2,0xA2,0xA4,0xA4,
+// 0xA4,0xA6,0xA6,0xA6,0xA8,0xA8,0xA8,0xAA,0xAA,0xAA,0xAC,0xAC,0xAC,0xAC,0xAE,0xAE,
+// 0xAE,0xB0,0xB0,0xB0,0xB2,0xB2,0xB2,0xB2,0xB4,0xB4,0xB4,0xB6,0xB6,0xB6,0xB6,0xB8,
+// 0xB8,0xB8,0xB8,0xBA,0xBA,0xBA,0xBC,0xBC,0xBC,0xBC,0xBE,0xBE,0xBE,0xBE,0xC0,0xC0,
+// 0xC0,0xC0,0xC2,0xC2,0xC2,0xC2,0xC2,0xC4,0xC4,0xC4,0xC4,0xC6,0xC6,0xC6,0xC6,0xC8,
+// 0xC8,0xC8,0xC8,0xC8,0xCA,0xCA,0xCA,0xCA,0xCC,0xCC,0xCC,0xCC,0xCC,0xCE,0xCE,0xCE,
+// 0xCE,0xCE,0xD0,0xD0,0xD0,0xD0,0xD0,0xD2,0xD2,0xD2,0xD2,0xD2,0xD4,0xD4,0xD4,0xD4,
+// 0xD4,0xD6,0xD6,0xD6,0xD6,0xD6,0xD8,0xD8,0xD8,0xD8,0xD8,0xD8,0xDA,0xDA,0xDA,0xDA,
+// 0xDA,0xDC,0xDC,0xDC,0xDC,0xDC,0xDC,0xDE,0xDE,0xDE,0xDE,0xDE,0xDE,0xE0,0xE0,0xE0,
+// };
+//
+// static int32_t Gfl=0,Gfr=0;
+// static int32_t LMax=0,RMax=0;
+//
+// static int32_t LAccum;
+// static int32_t RAccum;
+// static int32_t ANum;
+//
+// int32_t ValL = src.Left >> (SndOutVolumeShift-8);
+// int32_t ValR = src.Right >> (SndOutVolumeShift-8);
+//
+// int32_t XL = abs(ValL>>8);
+// int32_t XR = abs(ValR>>8);
+//
+// if(XL>LMax) LMax = XL;
+// if(XR>RMax) RMax = XR;
+//
+// ANum++;
+// if(ANum>=128)
+// {
+// ANum=0;
+// LAccum = 1+((LAccum * 224 + LMax * 31)>>8);
+// RAccum = 1+((RAccum * 224 + RMax * 31)>>8);
+//
+// LMax = 0;
+// RMax = 0;
+//
+// int32_t Tfl=(RAccum)*255/(LAccum);
+// int32_t Tfr=(LAccum)*255/(RAccum);
+//
+// int gMax = std::max(Tfl,Tfr);
+// Tfl = Tfl*255/gMax;
+// Tfr = Tfr*255/gMax;
+//
+// if(Tfl>255) Tfl=255;
+// if(Tfr>255) Tfr=255;
+// if(Tfl<1) Tfl=1;
+// if(Tfr<1) Tfr=1;
+//
+// Gfl = (Gfl * 200 + Tfl * 56)>>8;
+// Gfr = (Gfr * 200 + Tfr * 56)>>8;
+//
+// }
+//
+// int32_t L,R,C,SUB,SL,SR;
+//
+// C=(ValL+ValR)>>1; //16.8
+//
+// ValL-=C;//16.8
+// ValR-=C;//16.8
+//
+// L=ValL>>8; //16.0
+// R=ValR>>8; //16.0
+// C=C>>8; //16.0
+// SUB = C;
+//
+// {
+// int32_t Cfl = 1+sLogTable[Gfl];
+// int32_t Cfr = 1+sLogTable[Gfr];
+//
+// int32_t VL=(ValL>>4) * Cfl; //16.12
+// int32_t VR=(ValR>>4) * Cfr;
+//
+// //int32_t SC = (VL-VR)>>15;
+//
+// SL = (((VR/148 - VL/209)>>4)*Cfr)>>8;
+// SR = (((VR/209 - VL/148)>>4)*Cfl)>>8;
+//
+// }
+//
+// // Random-ish values to get it to compile
+// int GainL = 200;
+// int GainR = 200;
+// int GainC = 180;
+// int GainSL = 230;
+// int GainSR = 230;
+// int GainLFE = 200;
+// int AddCLR = 55;
+//
+// int AddCX = (C * AddCLR)>>8;
+//
+// Left = (((L * GainL ))>>8) + AddCX;
+// Right = (((R * GainR ))>>8) + AddCX;
+// Center = (((C * GainC ))>>8);
+// LFE = (((SUB * GainLFE))>>8);
+// LeftBack = (((SL * GainSL ))>>8);
+// RightBack = (((SR * GainSR ))>>8);
+// }
+//};
+//
+//struct Stereo71Out16
+//{
+// int16_t Left;
+// int16_t Right;
+// int16_t Center;
+// int16_t LFE;
+// int16_t LeftBack;
+// int16_t RightBack;
+// int16_t LeftSide;
+// int16_t RightSide;
+//
+// void ResampleFrom( const StereoOut32& src )
+// {
+// Left = src.Left >> SndOutVolumeShift;
+// Right = src.Right >> SndOutVolumeShift;
+// Center = (src.Left + src.Right) >> (SndOutVolumeShift + 1);
+// LFE = Center;
+// LeftBack = src.Left >> SndOutVolumeShift;
+// RightBack = src.Right >> SndOutVolumeShift;
+//
+// LeftSide = src.Left >> (SndOutVolumeShift+1);
+// RightSide = src.Right >> (SndOutVolumeShift+1);
+// }
+//};
+//
+//struct Stereo21Out32
+//{
+// int32_t Left;
+// int32_t Right;
+// int32_t LFE;
+//};
+//
+//struct Stereo41Out32
+//{
+// int32_t Left;
+// int32_t Right;
+// int32_t LFE;
+// int32_t LeftBack;
+// int32_t RightBack;
+//};
+//
+//struct Stereo51Out32
+//{
+// int32_t Left;
+// int32_t Right;
+// int32_t Center;
+// int32_t LFE;
+// int32_t LeftBack;
+// int32_t RightBack;
+//};
+
+// Developer Note: This is a static class only (all static members).
+class SndBuffer
+{
+private:
+ static bool m_underrun_freeze;
+ static int32_t m_predictData;
+ static float lastPct;
+
+ static StereoOut32 *sndTempBuffer;
+ static StereoOut16 *sndTempBuffer16;
+
+ static int sndTempProgress;
+ //static int m_dsp_progress;
+
+ //static int m_timestretch_progress;
+ static int m_timestretch_writepos;
+
+ static StereoOut32 *m_buffer;
+ static int32_t m_size;
+ static int32_t m_rpos;
+ static int32_t m_wpos;
+ static int32_t m_data;
+
+ static float lastEmergencyAdj;
+ static float cTempo;
+ static float eTempo;
+ static int freezeTempo;
+ //static int ssFreeze;
+
+ static void _InitFail();
+ static void _WriteSamples(StereoOut32 *bData, int nSamples);
+ static bool CheckUnderrunStatus(int &nSamples, int &quietSampleCount);
+
+ static void soundtouchInit();
+ static void soundtouchClearContents();
+ static void soundtouchCleanup();
+ static void timeStretchWrite();
+ static void timeStretchUnderrun();
+ static int32_t timeStretchOverrun();
+
+ static void PredictDataWrite(int samples);
+ static float GetStatusPct();
+ static void UpdateTempoChange();
+
+public:
+ static void Init();
+ //static void Cleanup();
+ static void Write(const StereoOut32 &Sample);
+ //static int32_t Test();
+ //static void ClearContents();
+
+ // Note: When using with 32 bit output buffers, the user of this function is responsible
+ // for shifting the values to where they need to be manually. The fixed point depth of
+ // the sample output is determined by the SndOutVolumeShift, which is the number of bits
+ // to shift right to get a 16 bit result.
+ template<typename T> static void ReadSamples(T *bData)
+ {
+ int nSamples = SndOutPacketSize;
+
+ // Problem:
+ // If the SPU2 gets even the least bit out of sync with the SndOut device,
+ // the readpos of the circular buffer will overtake the writepos,
+ // leading to a prolonged period of hopscotching read/write accesses (ie,
+ // lots of staticy crap sound for several seconds).
+ //
+ // Fix:
+ // If the read position overtakes the write position, abort the
+ // transfer immediately and force the SndOut driver to wait until
+ // the read buffer has filled up again before proceeding.
+ // This will cause one brief hiccup that can never exceed the user's
+ // set buffer length in duration.
+
+ int quietSamples;
+ if (CheckUnderrunStatus(nSamples, quietSamples))
+ {
+ assert(nSamples <= SndOutPacketSize);
+
+ // [Air] [TODO]: This loop is probably a candidate for SSE2 optimization.
+
+ const int endPos = m_rpos + nSamples;
+ const int secondCopyLen = endPos - m_size;
+ const StereoOut32 *rposbuffer = &m_buffer[m_rpos];
+
+ m_data -= nSamples;
+
+ if (secondCopyLen > 0)
+ {
+ nSamples -= secondCopyLen;
+ for (int i = 0; i < secondCopyLen; ++i)
+ bData[nSamples + i].ResampleFrom(m_buffer[i]);
+ m_rpos = secondCopyLen;
+ }
+ else
+ m_rpos += nSamples;
+
+ for (int i = 0; i < nSamples; ++i)
+ bData[i].ResampleFrom(rposbuffer[i]);
+ }
+
+ // If quietSamples != 0 it means we have an underrun...
+ // Let's just dull out some silence, because that's usually the least
+ // painful way of dealing with underruns:
+ memset(bData, 0, quietSamples * sizeof(T));
+ }
+};
+
+//class SndOutModule
+//{
+//public:
+// // Virtual destructor, because it helps fight C+++ funny-business.
+// virtual ~SndOutModule() {}
+//
+// // Returns a unique identification string for this driver.
+// // (usually just matches the driver's cpp filename)
+// virtual const wchar_t* GetIdent() const=0;
+//
+// // Returns the long name / description for this driver.
+// // (for use in configuration screen)
+// virtual const wchar_t* GetLongName() const=0;
+//
+// virtual int32_t Init()=0;
+// virtual void Close()=0;
+// virtual int32_t Test() const=0;
+//
+// // Gui function: Used to open the configuration box for this driver.
+// virtual void Configure(uptr parent)=0;
+//
+// // Loads settings from the INI file for this driver
+// virtual void ReadSettings()=0;
+//
+// // Saves settings to the INI file for this driver
+// virtual void WriteSettings() const=0;
+//
+// virtual bool Is51Out() const=0;
+//
+// // Returns the number of empty samples in the output buffer.
+// // (which is effectively the amount of data played since the last update)
+// virtual int GetEmptySampleCount() const=0;
+//};
+//
+//
+//#ifdef _MSC_VER
+////internal
+//extern SndOutModule* WaveOut;
+//extern SndOutModule* DSoundOut;
+//extern SndOutModule* XAudio2Out;
+//#endif
+//
+//extern SndOutModule* mods[];
+//
+//// =====================================================================================================
+//
+//extern void RecordStart();
+//extern void RecordStop();
+//extern void RecordWrite( const StereoOut16& sample );
+//
+//extern int32_t DspLoadLibrary(wchar_t *fileName, int modNum);
+//extern void DspCloseLibrary();
+//extern int DspProcess(int16_t *buffer, int samples);
+//extern void DspUpdate(); // to let the Dsp process window messages
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/AAFilter.cpp
@@ -1,1 +1,163 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// FIR low-pass (anti-alias) filter with filter coefficient design routine and
+/// MMX optimization.
+///
+/// Anti-alias filter is used to prevent folding of high frequencies when
+/// transposing the sample rate with interpolation.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.9 $
+//
+// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#include "XSFCommon.h"
+
+#include <cassert>
+#include "AAFilter.h"
+#include "FIRFilter.h"
+
+using namespace soundtouch;
+
+#define PI 3.141592655357989
+#define TWOPI (2 * PI)
+
+/*****************************************************************************
+ *
+ * Implementation of the class 'AAFilter'
+ *
+ *****************************************************************************/
+
+AAFilter::AAFilter(const uint32_t len)
+{
+ pFIR = FIRFilter::newInstance();
+ cutoffFreq = 0.5;
+ this->setLength(len);
+}
+
+AAFilter::~AAFilter()
+{
+ delete pFIR;
+}
+
+// Sets new anti-alias filter cut-off edge frequency, scaled to
+// sampling frequency (nyquist frequency = 0.5).
+// The filter will cut frequencies higher than the given frequency.
+void AAFilter::setCutoffFreq(double newCutoffFreq)
+{
+ cutoffFreq = newCutoffFreq;
+ calculateCoeffs();
+}
+
+// Sets number of FIR filter taps
+void AAFilter::setLength(uint32_t newLength)
+{
+ length = newLength;
+ calculateCoeffs();
+}
+
+// Calculates coefficients for a low-pass FIR filter using Hamming window
+void AAFilter::calculateCoeffs()
+{
+ assert(length > 0);
+ assert(!(length % 4));
+ assert(cutoffFreq >= 0);
+ assert(cutoffFreq <= 0.5);
+
+ double *work = new double[length];
+ SAMPLETYPE *coeffs = new SAMPLETYPE[length];
+
+ double fc2 = 2.0 * cutoffFreq;
+ double wc = PI * fc2;
+ double tempCoeff = TWOPI / length;
+
+ double sum = 0.0;
+ for (uint32_t i = 0; i < length; ++i)
+ {
+ double cntTemp = i - (length / 2);
+
+ double temp = cntTemp * wc, h;
+ if (!fEqual(temp, 0.0))
+ h = fc2 * sin(temp) / temp; // sinc function
+ else
+ h = 1.0;
+ double w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window
+
+ temp = w * h;
+ work[i] = temp;
+
+ // calc net sum of coefficients
+ sum += temp;
+ }
+
+ // ensure the sum of coefficients is larger than zero
+ assert(sum > 0);
+
+ // ensure we've really designed a lowpass filter...
+ assert(work[length / 2] > 0);
+ assert(work[length / 2 + 1] > -1e-6);
+ assert(work[length / 2 - 1] > -1e-6);
+
+ // Calculate a scaling coefficient in such a way that the result can be
+ // divided by 16384
+ double scaleCoeff = 16384.0 / sum;
+
+ for (uint32_t i = 0; i < length; ++i)
+ {
+ // scale & round to nearest integer
+ double temp = work[i] * scaleCoeff;
+ temp += temp >= 0 ? 0.5 : -0.5;
+ // ensure no overfloods
+ assert(temp >= -32768 && temp <= 32767);
+ coeffs[i] = static_cast<SAMPLETYPE>(temp);
+ }
+
+ // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
+ pFIR->setCoefficients(coeffs, length, 14);
+
+ delete [] work;
+ delete [] coeffs;
+}
+
+// Applies the filter to the given sequence of samples.
+// Note : The amount of outputted samples is by value of 'filter length'
+// smaller than the amount of input samples.
+uint32_t AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples, uint32_t numChannels) const
+{
+ return pFIR->evaluate(dest, src, numSamples, numChannels);
+}
+
+uint32_t AAFilter::getLength() const
+{
+ return pFIR->getLength();
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/AAFilter.h
@@ -1,1 +1,90 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
+/// while maintaining the original pitch by using a time domain WSOLA-like method
+/// with several performance-increasing tweaks.
+///
+/// Anti-alias filter is used to prevent folding of high frequencies when
+/// transposing the sample rate with interpolation.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.10 $
+//
+// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef AAFilter_H
+#define AAFilter_H
+
+#include "STTypes.h"
+
+namespace soundtouch
+{
+
+class AAFilter
+{
+protected:
+ class FIRFilter *pFIR;
+
+ /// Low-pass filter cut-off frequency, negative = invalid
+ double cutoffFreq;
+
+ /// num of filter taps
+ uint32_t length;
+
+ /// Calculate the FIR coefficients realizing the given cutoff-frequency
+ void calculateCoeffs();
+
+public:
+ AAFilter(uint32_t length);
+
+ ~AAFilter();
+
+ /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
+ /// frequency (nyquist frequency = 0.5). The filter will cut off the
+ /// frequencies than that.
+ void setCutoffFreq(double newCutoffFreq);
+
+ /// Sets number of FIR filter taps, i.e. ~filter complexity
+ void setLength(uint32_t newLength);
+
+ uint32_t getLength() const;
+
+ /// Applies the filter to the given sequence of samples.
+ /// Note : The amount of outputted samples is by value of 'filter length'
+ /// smaller than the amount of input samples.
+ uint32_t evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples, uint32_t numChannels) const;
+};
+
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/ConfigSoundtouch.cpp
@@ -1,1 +1,135 @@
+/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
+ * Developed and maintained by the Pcsx2 Development Team.
+ *
+ * Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
+ *
+ * SPU2-X 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 Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * SPU2-X 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 SPU2-X. If not, see <http://www.gnu.org/licenses/>.
+ */
+//TODO - need to make a generic way for saving these configs and add in the windows
+//rc configurator
+
+#include "types.h"
+//#include "Global.h"
+#include "Dialogs.h"
+
+#include "../metaspu.h"
+
+#include "SoundTouch.h"
+
+static int SequenceLenMS = 63;
+static int SeekWindowMS = 16;
+static int OverlapMS = 7;
+
+// Timestretch Slider Bounds, Min/Max
+static const int SequenceLen_Min = 50;
+static const int SequenceLen_Max = 90;
+
+static const int SeekWindow_Min = 10;
+static const int SeekWindow_Max = 32;
+
+static const int Overlap_Min = 3;
+static const int Overlap_Max = 25;
+
+void SoundtouchCfg::ApplySettings( soundtouch::SoundTouch& sndtouch )
+{
+ sndtouch.setSetting( soundtouch::SETTING_SEQUENCE_MS, SequenceLenMS );
+ sndtouch.setSetting( soundtouch::SETTING_SEEKWINDOW_MS, SeekWindowMS );
+ sndtouch.setSetting( soundtouch::SETTING_OVERLAP_MS, OverlapMS );
+}
+
+/*static void ClampValues()
+{
+ Clampify( SequenceLenMS, SequenceLen_Min, SequenceLen_Max );
+ Clampify( SeekWindowMS, SeekWindow_Min, SeekWindow_Max );
+ Clampify( OverlapMS, Overlap_Min, Overlap_Max );
+}*/
+
+void SoundtouchCfg::ReadSettings()
+{
+/* SequenceLenMS = CfgReadInt( L"SOUNDTOUCH", L"SequenceLengthMS", 50 );
+ SeekWindowMS = CfgReadInt( L"SOUNDTOUCH", L"SeekWindowMS", 15 );
+ OverlapMS = CfgReadInt( L"SOUNDTOUCH", L"OverlapMS", 25 );
+
+ ClampValues(); */
+}
+
+void SoundtouchCfg::WriteSettings()
+{
+ //CfgWriteInt( L"SOUNDTOUCH", L"SequenceLengthMS", SequenceLenMS );
+ //CfgWriteInt( L"SOUNDTOUCH", L"SeekWindowMS", SeekWindowMS );
+ //CfgWriteInt( L"SOUNDTOUCH", L"OverlapMS", OverlapMS );
+}
+
+//BOOL CALLBACK SoundtouchCfg::DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
+//{
+// int wmId,wmEvent;
+// wchar_t temp[384]={0};
+//
+// switch(uMsg)
+// {
+// case WM_PAINT:
+// return false;
+//
+// case WM_INITDIALOG:
+// {
+// INIT_SLIDER( IDC_SEQLEN_SLIDER, SequenceLen_Min, SequenceLen_Max, 20, 5, 1 );
+// INIT_SLIDER( IDC_SEEKWIN_SLIDER, SeekWindow_Min, SeekWindow_Max, 5, 2, 1 );
+// INIT_SLIDER( IDC_OVERLAP_SLIDER, Overlap_Min, Overlap_Max, 3, 2, 1 );
+//
+// SendDialogMsg( hWnd, IDC_SEQLEN_SLIDER, TBM_SETPOS, true, SequenceLenMS );
+// SendDialogMsg( hWnd, IDC_SEEKWIN_SLIDER, TBM_SETPOS, true, SeekWindowMS );
+// SendDialogMsg( hWnd, IDC_OVERLAP_SLIDER, TBM_SETPOS, true, OverlapMS );
+// }
+//
+// case WM_COMMAND:
+// wmId = LOWORD(wParam);
+// wmEvent = HIWORD(wParam);
+// // Parse the menu selections:
+// if( wmId == IDOK )
+// {
+// SequenceLenMS = (int)SendDialogMsg( hWnd, IDC_SEQLEN_SLIDER, TBM_GETPOS, 0, 0 );
+// SeekWindowMS = (int)SendDialogMsg( hWnd, IDC_SEEKWIN_SLIDER, TBM_GETPOS, 0, 0 );
+// OverlapMS = (int)SendDialogMsg( hWnd, IDC_OVERLAP_SLIDER, TBM_GETPOS, 0, 0 );
+//
+// ClampValues();
+// WriteSettings();
+// EndDialog(hWnd,0);
+// }
+// else if( wmId == IDCANCEL )
+// {
+// EndDialog(hWnd,0);
+// }
+// break;
+//
+// case WM_HSCROLL:
+// DoHandleScrollMessage( hWnd, wParam, lParam );
+// break;
+//
+// default:
+// return false;
+// }
+// return true;
+//}
+
+void SoundtouchCfg::OpenDialog( HWND hWnd )
+{
+ //INT_PTR ret;
+ //ret = DialogBox( hInstance, MAKEINTRESOURCE(IDD_CONFIG_SOUNDTOUCH), hWnd, (DLGPROC)DialogProc );
+ //if(ret==-1)
+ //{
+ // MessageBoxEx(GetActiveWindow(), L"Error Opening the Soundtouch advanced dialog.", L"OMG ERROR!", MB_OK, 0);
+ // return;
+ //}
+ //ReadSettings();
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/Dialogs.h
@@ -1,1 +1,83 @@
+/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
+ * Developed and maintained by the Pcsx2 Development Team.
+ *
+ * Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
+ *
+ * SPU2-X 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 Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * SPU2-X 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 SPU2-X. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+#ifdef _XBOX
+#include <xtl.h>
+#elif _WIN32
+#include "windowsh_wrapper.h"
+#endif
+
+#include "../SoundTouch/SoundTouch.h"
+
+//#ifdef _WIN32
+//# include "WinConfig.h"
+//#else
+//# include "LnxConfig.h"
+//#endif
+//
+//namespace DebugConfig
+//{
+// extern void ReadSettings();
+// extern void WriteSettings();
+// extern void OpenDialog();
+// extern void EnableControls( HWND hWnd );
+//}
+//
+namespace SoundtouchCfg
+{
+ extern void ReadSettings();
+ extern void WriteSettings();
+ extern void OpenDialog(HWND hWnd);
+ extern bool CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ extern void ApplySettings(soundtouch::SoundTouch& sndtouch);
+}
+//
+//extern int SendDialogMsg( HWND hwnd, int dlgId, UINT code, WPARAM wParam, LPARAM lParam);
+//extern HRESULT GUIDFromString( const char *str, LPGUID guid );
+//
+//extern void AssignSliderValue( HWND idcwnd, HWND hwndDisplay, int value );
+//extern void AssignSliderValue( HWND hWnd, int idc, int editbox, int value );
+//extern int GetSliderValue( HWND hWnd, int idc );
+//extern bool DoHandleScrollMessage( HWND hwndDisplay, WPARAM wParam, LPARAM lParam );
+//
+//extern bool CfgFindName( const TCHAR *Section, const TCHAR* Name);
+//
+//extern void CfgWriteBool(const TCHAR* Section, const TCHAR* Name, bool Value);
+//extern void CfgWriteInt(const TCHAR* Section, const TCHAR* Name, int Value);
+//extern void CfgWriteStr(const TCHAR* Section, const TCHAR* Name, const wstring& Data);
+//
+//extern bool CfgReadBool(const TCHAR *Section,const TCHAR* Name, bool Default);
+//extern void CfgReadStr(const TCHAR* Section, const TCHAR* Name, wstring& Data, int DataSize, const TCHAR* Default);
+//extern void CfgReadStr(const TCHAR* Section, const TCHAR* Name, TCHAR* Data, int DataSize, const TCHAR* Default);
+//extern int CfgReadInt(const TCHAR* Section, const TCHAR* Name,int Default);
+//
+//
+//// Items Specific to DirectSound
+//#define STRFY(x) #x
+//#define verifyc(x) Verifyc(x,STRFY(x))
+//
+//extern void Verifyc(HRESULT hr, const char* fn);
+//
+//struct ds_device_data
+//{
+// std::wstring name;
+// GUID guid;
+// bool hasGuid;
+//};
+//
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/FIFOSampleBuffer.cpp
@@ -1,1 +1,221 @@
-
+////////////////////////////////////////////////////////////////////////////////
+///
+/// A buffer class for temporarily storaging sound samples, operates as a
+/// first-in-first-out pipe.
+///
+/// Samples are added to the end of the sample buffer with the 'putSamples'
+/// function, and are received from the beginning of the buffer by calling
+/// the 'receiveSamples' function. The class automatically removes the
+/// outputted samples from the buffer, as well as grows the buffer size
+/// whenever necessary.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.11 $
+//
+// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <stdexcept>
+#include <cstring>
+
+#include "FIFOSampleBuffer.h"
+
+using namespace soundtouch;
+
+// Constructor
+FIFOSampleBuffer::FIFOSampleBuffer(uint32_t numChannels)
+{
+ sizeInBytes = 0; // reasonable initial value
+ buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)];
+ bufferUnaligned = NULL;
+ samplesInBuffer = 0;
+ bufferPos = 0;
+ channels = numChannels;
+}
+
+// destructor
+FIFOSampleBuffer::~FIFOSampleBuffer()
+{
+ if (bufferUnaligned)
+ delete[] bufferUnaligned;
+}
+
+// Sets number of channels, 1 = mono, 2 = stereo
+void FIFOSampleBuffer::setChannels(uint32_t numChannels)
+{
+ uint32_t usedBytes = channels * samplesInBuffer;
+ channels = numChannels;
+ samplesInBuffer = usedBytes / channels;
+}
+
+// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
+// zeroes this pointer by copying samples from the 'bufferPos' pointer
+// location on to the beginning of the buffer.
+void FIFOSampleBuffer::rewind()
+{
+ if (bufferPos)
+ {
+ memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
+ bufferPos = 0;
+ }
+}
+
+// Adds 'numSamples' pcs of samples from the 'samples' memory position to
+// the sample buffer.
+void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint32_t numsamples)
+{
+ memcpy(ptrEnd(numsamples), samples, sizeof(SAMPLETYPE) * numsamples * channels);
+ samplesInBuffer += numsamples;
+}
+
+// Increases the number of samples in the buffer without copying any actual
+// samples.
+//
+// This function is used to update the number of samples in the sample buffer
+// when accessing the buffer directly with 'ptrEnd' function. Please be
+// careful though!
+void FIFOSampleBuffer::putSamples(uint32_t numsamples)
+{
+ uint32_t req = samplesInBuffer + numsamples;
+ this->ensureCapacity(req);
+ samplesInBuffer += numsamples;
+}
+
+// Returns a pointer to the end of the used part of the sample buffer (i.e.
+// where the new samples are to be inserted). This function may be used for
+// inserting new samples into the sample buffer directly. Please be careful!
+//
+// Parameter 'slackCapacity' tells the function how much free capacity (in
+// terms of samples) there _at least_ should be, in order to the caller to
+// succesfully insert all the required samples to the buffer. When necessary,
+// the function grows the buffer size to comply with this requirement.
+//
+// When using this function as means for inserting new samples, also remember
+// to increase the sample count afterwards, by calling the
+// 'putSamples(numSamples)' function.
+SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint32_t slackCapacity)
+{
+ this->ensureCapacity(samplesInBuffer + slackCapacity);
+ return buffer + samplesInBuffer * channels;
+}
+
+// Returns a pointer to the beginning of the currently non-outputted samples.
+// This function is provided for accessing the output samples directly.
+// Please be careful!
+//
+// When using this function to output samples, also remember to 'remove' the
+// outputted samples from the buffer by calling the
+// 'receiveSamples(numSamples)' function
+SAMPLETYPE *FIFOSampleBuffer::ptrBegin() const
+{
+ return buffer + bufferPos * channels;
+}
+
+// Ensures that the buffer has enought capacity, i.e. space for _at least_
+// 'capacityRequirement' number of samples. The buffer is grown in steps of
+// 4 kilobytes to eliminate the need for frequently growing up the buffer,
+// as well as to round the buffer size up to the virtual memory page size.
+void FIFOSampleBuffer::ensureCapacity(uint32_t capacityRequirement)
+{
+ if (capacityRequirement > getCapacity())
+ {
+ // enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
+ sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096;
+ assert(!(sizeInBytes % 2));
+ SAMPLETYPE *tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
+ SAMPLETYPE *temp = reinterpret_cast<SAMPLETYPE *>((reinterpret_cast<intptr_t>(tempUnaligned) + 15) & -16);
+ memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));
+ delete[] bufferUnaligned;
+ buffer = temp;
+ bufferUnaligned = tempUnaligned;
+ bufferPos = 0;
+ }
+ else
+ // simply rewind the buffer (if necessary)
+ rewind();
+}
+
+// Returns the current buffer capacity in terms of samples
+uint32_t FIFOSampleBuffer::getCapacity() const
+{
+ return sizeInBytes / (channels * sizeof(SAMPLETYPE));
+}
+
+// Returns the number of samples currently in the buffer
+uint32_t FIFOSampleBuffer::numSamples() const
+{
+ return samplesInBuffer;
+}
+
+// Output samples from beginning of the sample buffer. Copies demanded number
+// of samples to output and removes them from the sample buffer. If there
+// are less than 'numsample' samples in the buffer, returns all available.
+//
+// Returns number of samples copied.
+uint32_t FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint32_t maxSamples)
+{
+ uint32_t num = maxSamples > samplesInBuffer ? samplesInBuffer : maxSamples;
+
+ memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);
+ return this->receiveSamples(num);
+}
+
+// Removes samples from the beginning of the sample buffer without copying them
+// anywhere. Used to reduce the number of samples in the buffer, when accessing
+// the sample buffer with the 'ptrBegin' function.
+uint32_t FIFOSampleBuffer::receiveSamples(uint32_t maxSamples)
+{
+ if (maxSamples >= samplesInBuffer)
+ {
+ uint32_t temp = samplesInBuffer;
+ samplesInBuffer = 0;
+ return temp;
+ }
+
+ samplesInBuffer -= maxSamples;
+ bufferPos += maxSamples;
+
+ return maxSamples;
+}
+
+// Returns nonzero if the sample buffer is empty
+bool FIFOSampleBuffer::isEmpty() const
+{
+ return !samplesInBuffer;
+}
+
+// Clears the sample buffer
+void FIFOSampleBuffer::clear()
+{
+ samplesInBuffer = 0;
+ bufferPos = 0;
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/FIFOSampleBuffer.h
@@ -1,1 +1,174 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// A buffer class for temporarily storaging sound samples, operates as a
+/// first-in-first-out pipe.
+///
+/// Samples are added to the end of the sample buffer with the 'putSamples'
+/// function, and are received from the beginning of the buffer by calling
+/// the 'receiveSamples' function. The class automatically removes the
+/// output samples from the buffer as well as grows the storage size
+/// whenever necessary.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.9 $
+//
+// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef FIFOSampleBuffer_H
+#define FIFOSampleBuffer_H
+
+#include "FIFOSamplePipe.h"
+
+namespace soundtouch
+{
+
+/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes
+/// care of storage size adjustment and data moving during input/output operations.
+///
+/// Notice that in case of stereo audio, one sample is considered to consist of
+/// both channel data.
+class FIFOSampleBuffer : public FIFOSamplePipe
+{
+private:
+ /// Sample buffer.
+ SAMPLETYPE *buffer;
+
+ // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first
+ // 16-byte aligned location of this buffer
+ SAMPLETYPE *bufferUnaligned;
+
+ /// Sample buffer size in bytes
+ uint32_t sizeInBytes;
+
+ /// How many samples are currently in buffer.
+ uint32_t samplesInBuffer;
+
+ /// Channels, 1=mono, 2=stereo.
+ uint32_t channels;
+
+ /// Current position pointer to the buffer. This pointer is increased when samples are
+ /// removed from the pipe so that it's necessary to actually rewind buffer (move data)
+ /// only new data when is put to the pipe.
+ uint32_t bufferPos;
+
+ /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real
+ /// beginning of the buffer.
+ void rewind();
+
+ /// Ensures that the buffer has capacity for at least this many samples.
+ void ensureCapacity(const uint32_t capacityRequirement);
+
+ /// Returns current capacity.
+ uint32_t getCapacity() const;
+
+public:
+ /// Constructor
+ FIFOSampleBuffer(uint32_t numChannels = 2 ///< Number of channels, 1=mono, 2=stereo.
+ ///< Default is stereo.
+ );
+
+ /// destructor
+ ~FIFOSampleBuffer();
+
+ /// Returns a pointer to the beginning of the output samples.
+ /// This function is provided for accessing the output samples directly.
+ /// Please be careful for not to corrupt the book-keeping!
+ ///
+ /// When using this function to output samples, also remember to 'remove' the
+ /// output samples from the buffer by calling the
+ /// 'receiveSamples(numSamples)' function
+ virtual SAMPLETYPE *ptrBegin() const;
+
+ /// Returns a pointer to the end of the used part of the sample buffer (i.e.
+ /// where the new samples are to be inserted). This function may be used for
+ /// inserting new samples into the sample buffer directly. Please be careful
+ /// not corrupt the book-keeping!
+ ///
+ /// When using this function as means for inserting new samples, also remember
+ /// to increase the sample count afterwards, by calling the
+ /// 'putSamples(numSamples)' function.
+ SAMPLETYPE *ptrEnd(
+ uint32_t slackCapacity ///< How much free capacity (in samples) there _at least_
+ ///< should be so that the caller can succesfully insert the
+ ///< desired samples to the buffer. If necessary, the function
+ ///< grows the buffer size to comply with this requirement.
+ );
+
+ /// Adds 'numSamples' pcs of samples from the 'samples' memory position to
+ /// the sample buffer.
+ virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
+ uint32_t numSamples ///< Number of samples to insert.
+ );
+
+ /// Adjusts the book-keeping to increase number of samples in the buffer without
+ /// copying any actual samples.
+ ///
+ /// This function is used to update the number of samples in the sample buffer
+ /// when accessing the buffer directly with 'ptrEnd' function. Please be
+ /// careful though!
+ virtual void putSamples(uint32_t numSamples ///< Number of samples been inserted.
+ );
+
+ /// Output samples from beginning of the sample buffer. Copies requested samples to
+ /// output buffer and removes them from the sample buffer. If there are less than
+ /// 'numsample' samples in the buffer, returns all that available.
+ ///
+ /// \return Number of samples returned.
+ virtual uint32_t receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
+ uint32_t maxSamples ///< How many samples to receive at max.
+ );
+
+ /// Adjusts book-keeping so that given number of samples are removed from beginning of the
+ /// sample buffer without copying them anywhere.
+ ///
+ /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
+ /// with 'ptrBegin' function.
+ virtual uint32_t receiveSamples(uint32_t maxSamples ///< Remove this many samples from the beginning of pipe.
+ );
+
+ /// Returns number of samples currently available.
+ virtual uint32_t numSamples() const;
+
+ /// Sets number of channels, 1 = mono, 2 = stereo.
+ void setChannels(uint32_t numChannels);
+
+ /// Returns nonzero if there aren't any samples available for outputting.
+ virtual bool isEmpty() const;
+
+ /// Clears all the samples.
+ virtual void clear();
+};
+
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/FIFOSamplePipe.h
@@ -1,1 +1,207 @@
-
+////////////////////////////////////////////////////////////////////////////////
+///
+/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound
+/// samples by operating like a first-in-first-out pipe: New samples are fed
+/// into one end of the pipe with the 'putSamples' function, and the processed
+/// samples are received from the other end with the 'receiveSamples' function.
+///
+/// 'FIFOProcessor' : A base class for classes the do signal processing with
+/// the samples while operating like a first-in-first-out pipe. When samples
+/// are input with the 'putSamples' function, the class processes them
+/// and moves the processed samples to the given 'output' pipe object, which
+/// may be either another processing stage, or a fifo sample buffer object.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.8 $
+//
+// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef FIFOSamplePipe_H
+#define FIFOSamplePipe_H
+
+#include <cassert>
+#include <cstdlib>
+#include "STTypes.h"
+
+namespace soundtouch
+{
+
+/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
+class FIFOSamplePipe
+{
+public:
+ /// Returns a pointer to the beginning of the output samples.
+ /// This function is provided for accessing the output samples directly.
+ /// Please be careful for not to corrupt the book-keeping!
+ ///
+ /// When using this function to output samples, also remember to 'remove' the
+ /// output samples from the buffer by calling the
+ /// 'receiveSamples(numSamples)' function
+ virtual SAMPLETYPE *ptrBegin() const = 0;
+
+ /// Adds 'numSamples' pcs of samples from the 'samples' memory position to
+ /// the sample buffer.
+ virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
+ uint32_t numSamples ///< Number of samples to insert.
+ ) = 0;
+
+ // Moves samples from the 'other' pipe instance to this instance.
+ void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
+ )
+ {
+ int oNumSamples = other.numSamples();
+
+ putSamples(other.ptrBegin(), oNumSamples);
+ other.receiveSamples(oNumSamples);
+ };
+
+ /// Output samples from beginning of the sample buffer. Copies requested samples to
+ /// output buffer and removes them from the sample buffer. If there are less than
+ /// 'numsample' samples in the buffer, returns all that available.
+ ///
+ /// \return Number of samples returned.
+ virtual uint32_t receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
+ uint32_t maxSamples ///< How many samples to receive at max.
+ ) = 0;
+
+ /// Adjusts book-keeping so that given number of samples are removed from beginning of the
+ /// sample buffer without copying them anywhere.
+ ///
+ /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
+ /// with 'ptrBegin' function.
+ virtual uint32_t receiveSamples(uint32_t maxSamples ///< Remove this many samples from the beginning of pipe.
+ ) = 0;
+
+ /// Returns number of samples currently available.
+ virtual uint32_t numSamples() const = 0;
+
+ // Returns nonzero if there aren't any samples available for outputting.
+ virtual bool isEmpty() const = 0;
+
+ /// Clears all the samples.
+ virtual void clear() = 0;
+};
+
+/// Base-class for sound processing routines working in FIFO principle. With this base
+/// class it's easy to implement sound processing stages that can be chained together,
+/// so that samples that are fed into beginning of the pipe automatically go through
+/// all the processing stages.
+///
+/// When samples are input to this class, they're first processed and then put to
+/// the FIFO pipe that's defined as output of this class. This output pipe can be
+/// either other processing stage or a FIFO sample buffer.
+class FIFOProcessor :public FIFOSamplePipe
+{
+protected:
+ /// Internal pipe where processed samples are put.
+ FIFOSamplePipe *output;
+
+ /// Sets output pipe.
+ void setOutPipe(FIFOSamplePipe *pOutput)
+ {
+ assert(!output);
+ assert(pOutput);
+ output = pOutput;
+ }
+
+ /// Constructor. Doesn't define output pipe; it has to be set be
+ /// 'setOutPipe' function.
+ FIFOProcessor()
+ {
+ output = NULL;
+ }
+
+ /// Constructor. Configures output pipe.
+ FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
+ )
+ {
+ output = pOutput;
+ }
+
+ /// Destructor.
+ virtual ~FIFOProcessor()
+ {
+ }
+
+ /// Returns a pointer to the beginning of the output samples.
+ /// This function is provided for accessing the output samples directly.
+ /// Please be careful for not to corrupt the book-keeping!
+ ///
+ /// When using this function to output samples, also remember to 'remove' the
+ /// output samples from the buffer by calling the
+ /// 'receiveSamples(numSamples)' function
+ virtual SAMPLETYPE *ptrBegin() const
+ {
+ return output->ptrBegin();
+ }
+
+public:
+ /// Output samples from beginning of the sample buffer. Copies requested samples to
+ /// output buffer and removes them from the sample buffer. If there are less than
+ /// 'numsample' samples in the buffer, returns all that available.
+ ///
+ /// \return Number of samples returned.
+ virtual uint32_t receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
+ uint32_t maxSamples ///< How many samples to receive at max.
+ )
+ {
+ return output->receiveSamples(outBuffer, maxSamples);
+ }
+
+ /// Adjusts book-keeping so that given number of samples are removed from beginning of the
+ /// sample buffer without copying them anywhere.
+ ///
+ /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
+ /// with 'ptrBegin' function.
+ virtual uint32_t receiveSamples(uint32_t maxSamples ///< Remove this many samples from the beginning of pipe.
+ )
+ {
+ return output->receiveSamples(maxSamples);
+ }
+
+ /// Returns number of samples currently available.
+ virtual uint32_t numSamples() const
+ {
+ return output->numSamples();
+ }
+
+ /// Returns nonzero if there aren't any samples available for outputting.
+ virtual bool isEmpty() const
+ {
+ return output->isEmpty();
+ }
+};
+
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/FIRFilter.cpp
@@ -1,1 +1,243 @@
-
+////////////////////////////////////////////////////////////////////////////////
+///
+/// General FIR digital filter routines with MMX optimization.
+///
+/// Note : MMX optimized functions reside in a separate, platform-specific file,
+/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.16 $
+//
+// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <stdexcept>
+#include <cstring>
+#include <cassert>
+#include <cmath>
+
+#include "FIRFilter.h"
+#include "cpu_detect.h"
+
+using namespace soundtouch;
+
+/*****************************************************************************
+ *
+ * Implementation of the class 'FIRFilter'
+ *
+ *****************************************************************************/
+
+FIRFilter::FIRFilter()
+{
+ resultDivFactor = 0;
+ length = 0;
+ lengthDiv8 = 0;
+ filterCoeffs = NULL;
+}
+
+FIRFilter::~FIRFilter()
+{
+ if (filterCoeffs)
+ delete[] filterCoeffs;
+}
+
+// Usual C-version of the filter routine for stereo sound
+uint32_t FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples) const
+{
+#ifdef FLOAT_SAMPLES
+ // when using floating point samples, use a scaler instead of a divider
+ // because division is much slower operation than multiplying.
+ double dScaler = 1.0 / resultDivider;
+#endif
+
+ assert(length);
+
+ uint32_t end = 2 * (numSamples - length);
+
+ for (uint32_t j = 0; j < end; j += 2)
+ {
+ LONG_SAMPLETYPE suml = 0, sumr = 0;
+ const SAMPLETYPE *ptr = src + j;
+
+ for (uint32_t i = 0; i < length; i += 4)
+ {
+ // loop is unrolled by factor of 4 here for efficiency
+ suml += ptr[2 * i] * filterCoeffs[i] +
+ ptr[2 * i + 2] * filterCoeffs[i + 1] +
+ ptr[2 * i + 4] * filterCoeffs[i + 2] +
+ ptr[2 * i + 6] * filterCoeffs[i + 3];
+ sumr += ptr[2 * i + 1] * filterCoeffs[i] +
+ ptr[2 * i + 3] * filterCoeffs[i + 1] +
+ ptr[2 * i + 5] * filterCoeffs[i + 2] +
+ ptr[2 * i + 7] * filterCoeffs[i + 3];
+ }
+
+#ifdef INTEGER_SAMPLES
+ suml >>= resultDivFactor;
+ sumr >>= resultDivFactor;
+ // saturate to 16 bit integer limits
+ suml = suml < -32768 ? -32768 : (suml > 32767 ? 32767 : suml);
+ // saturate to 16 bit integer limits
+ sumr = sumr < -32768 ? -32768 : (sumr > 32767 ? 32767 : sumr);
+#else
+ suml *= dScaler;
+ sumr *= dScaler;
+#endif // INTEGER_SAMPLES
+ dest[j] = static_cast<SAMPLETYPE>(suml);
+ dest[j + 1] = static_cast<SAMPLETYPE>(sumr);
+ }
+ return numSamples - length;
+}
+
+// Usual C-version of the filter routine for mono sound
+uint32_t FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples) const
+{
+#ifdef FLOAT_SAMPLES
+ // when using floating point samples, use a scaler instead of a divider
+ // because division is much slower operation than multiplying.
+ double dScaler = 1.0 / resultDivider;
+#endif
+
+ assert(length);
+
+ uint32_t end = numSamples - length;
+ for (uint32_t j = 0; j < end; ++j)
+ {
+ LONG_SAMPLETYPE sum = 0;
+ for (uint32_t i = 0; i < length; i += 4)
+ {
+ // loop is unrolled by factor of 4 here for efficiency
+ sum += src[i] * filterCoeffs[i] +
+ src[i + 1] * filterCoeffs[i + 1] +
+ src[i + 2] * filterCoeffs[i + 2] +
+ src[i + 3] * filterCoeffs[i + 3];
+ }
+#ifdef INTEGER_SAMPLES
+ sum >>= resultDivFactor;
+ // saturate to 16 bit integer limits
+ sum = sum < -32768 ? -32768 : (sum > 32767 ? 32767 : sum);
+#else
+ sum *= dScaler;
+#endif // INTEGER_SAMPLES
+ dest[j] = static_cast<SAMPLETYPE>(sum);
+ ++src;
+ }
+ return end;
+}
+
+// Set filter coeffiecients and length.
+//
+// Throws an exception if filter length isn't divisible by 8
+void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint32_t newLength, uint32_t uResultDivFactor)
+{
+ assert(newLength > 0);
+ if (newLength % 8)
+ throw std::runtime_error("FIR filter length not divisible by 8");
+
+ lengthDiv8 = newLength / 8;
+ length = lengthDiv8 * 8;
+ assert(length == newLength);
+
+ resultDivFactor = uResultDivFactor;
+#ifdef INTEGER_SAMPLES
+ resultDivider = static_cast<SAMPLETYPE>(1 << resultDivFactor);
+#else
+ resultDivider = static_cast<SAMPLETYPE>(pow(2, static_cast<SAMPLETYPE>(resultDivFactor)));
+#endif
+
+ delete[] filterCoeffs;
+ filterCoeffs = new SAMPLETYPE[length];
+ memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE));
+}
+
+uint32_t FIRFilter::getLength() const
+{
+ return length;
+}
+
+// Applies the filter to the given sequence of samples.
+//
+// Note : The amount of outputted samples is by value of 'filter_length'
+// smaller than the amount of input samples.
+uint32_t FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples, uint32_t numChannels) const
+{
+ assert(numChannels == 1 || numChannels == 2);
+
+ assert(length > 0);
+ assert(lengthDiv8 * 8 == length);
+ if (numSamples < length)
+ return 0;
+ //assert(resultDivFactor >= 0);
+ if (numChannels == 2)
+ return evaluateFilterStereo(dest, src, numSamples);
+ else
+ return evaluateFilterMono(dest, src, numSamples);
+}
+
+// Operator 'new' is overloaded so that it automatically creates a suitable instance
+// depending on if we've a MMX-capable CPU available or not.
+void *FIRFilter::operator new(size_t)
+{
+ // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
+ throw std::runtime_error("Don't use 'new FIRFilter', use 'newInstance' member instead!");
+}
+
+FIRFilter *FIRFilter::newInstance()
+{
+ uint32_t uExtensions = 0;
+
+#if !defined(_MSC_VER) || !defined(__x86_64__)
+ uExtensions = detectCPUextensions();
+#endif
+ // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
+
+#ifdef ALLOW_MMX
+ // MMX routines available only with integer sample types
+ if (uExtensions & SUPPORT_MMX)
+ return ::new FIRFilterMMX;
+ else
+#endif // ALLOW_MMX
+#ifdef __SSE__
+ if (uExtensions & SUPPORT_SSE)
+ // SSE support
+ return ::new FIRFilterSSE;
+ else
+#endif // ALLOW_SSE
+#ifdef ALLOW_3DNOW
+ if (uExtensions & SUPPORT_3DNOW)
+ // 3DNow! support
+ return ::new FIRFilter3DNow;
+ else
+#endif // ALLOW_3DNOW
+ // ISA optimizations not supported, use plain C version
+ return ::new FIRFilter;
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/FIRFilter.h
@@ -1,1 +1,150 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// General FIR digital filter routines with MMX optimization.
+///
+/// Note : MMX optimized functions reside in a separate, platform-specific file,
+/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.17 $
+//
+// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef FIRFilter_H
+#define FIRFilter_H
+
+#include <cstddef>
+
+#include "STTypes.h"
+
+namespace soundtouch
+{
+
+class FIRFilter
+{
+protected:
+ // Number of FIR filter taps
+ uint32_t length;
+ // Number of FIR filter taps divided by 8
+ uint32_t lengthDiv8;
+
+ // Result divider factor in 2^k format
+ uint32_t resultDivFactor;
+
+ // Result divider value.
+ SAMPLETYPE resultDivider;
+
+ // Memory for filter coefficients
+ SAMPLETYPE *filterCoeffs;
+
+ virtual uint32_t evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples) const;
+ virtual uint32_t evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples) const;
+
+public:
+ FIRFilter();
+ virtual ~FIRFilter();
+
+ /// Operator 'new' is overloaded so that it automatically creates a suitable instance
+ /// depending on if we've a MMX-capable CPU available or not.
+ void *operator new(size_t s);
+
+ static FIRFilter *newInstance();
+
+ /// Applies the filter to the given sequence of samples.
+ /// Note : The amount of outputted samples is by value of 'filter_length'
+ /// smaller than the amount of input samples.
+ ///
+ /// \return Number of samples copied to 'dest'.
+ uint32_t evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples, uint32_t numChannels) const;
+
+ uint32_t getLength() const;
+
+ virtual void setCoefficients(const SAMPLETYPE *coeffs, uint32_t newLength, uint32_t uResultDivFactor);
+};
+
+// Optional subclasses that implement CPU-specific optimizations:
+
+#ifdef ALLOW_MMX
+/// Class that implements MMX optimized functions exclusive for 16bit integer samples type.
+class FIRFilterMMX : public FIRFilter
+{
+protected:
+ short *filterCoeffsUnalign;
+ short *filterCoeffsAlign;
+
+ virtual uint32_t evaluateFilterStereo(short *dest, const short *src, uint32_t numSamples) const;
+public:
+ FIRFilterMMX();
+ ~FIRFilterMMX();
+
+ virtual void setCoefficients(const short *coeffs, uint32_t newLength, uint32_t uResultDivFactor);
+};
+#endif // ALLOW_MMX
+
+#ifdef ALLOW_3DNOW
+/// Class that implements 3DNow! optimized functions exclusive for floating point samples type.
+class FIRFilter3DNow : public FIRFilter
+{
+protected:
+ float *filterCoeffsUnalign;
+ float *filterCoeffsAlign;
+
+ virtual uint32_t evaluateFilterStereo(float *dest, const float *src, uint32_t numSamples) const;
+public:
+ FIRFilter3DNow();
+ ~FIRFilter3DNow();
+
+ virtual void setCoefficients(const float *coeffs, uint32_t newLength, uint32_t uResultDivFactor);
+};
+#endif // ALLOW_3DNOW
+
+#ifdef __SSE__
+/// Class that implements SSE optimized functions exclusive for floating point samples type.
+class FIRFilterSSE : public FIRFilter
+{
+protected:
+ float *filterCoeffsUnalign;
+ float *filterCoeffsAlign;
+
+ virtual uint32_t evaluateFilterStereo(float *dest, const float *src, uint32_t numSamples) const;
+public:
+ FIRFilterSSE();
+ ~FIRFilterSSE();
+
+ virtual void setCoefficients(const float *coeffs, uint32_t newLength, uint32_t uResultDivFactor);
+};
+#endif // ALLOW_SSE
+
+}
+
+#endif // FIRFilter_H
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/RateTransposer.cpp
@@ -1,1 +1,611 @@
-
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sample rate transposer. Changes sample rate by using linear interpolation
+/// together with anti-alias filtering (first order interpolation with anti-
+/// alias filtering should be quite adequate for this application)
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/03/19 10:05:49 $
+// File revision : $Revision: 1.13 $
+//
+// $Id: RateTransposer.cpp,v 1.13 2006/03/19 10:05:49 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include <stdexcept>
+#include "RateTransposer.h"
+#include "AAFilter.h"
+
+using namespace soundtouch;
+
+/// A linear samplerate transposer class that uses integer arithmetics.
+/// for the transposing.
+class RateTransposerInteger : public RateTransposer
+{
+protected:
+ int iSlopeCount;
+ uint32_t uRate;
+ SAMPLETYPE sPrevSampleL, sPrevSampleR;
+
+ virtual void resetRegisters();
+
+ virtual uint32_t transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples);
+ virtual uint32_t transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples);
+
+public:
+ RateTransposerInteger();
+ virtual ~RateTransposerInteger();
+
+ /// Sets new target rate. Normal rate = 1.0, smaller values represent slower
+ /// rate, larger faster rates.
+ virtual void setRate(float newRate);
+};
+
+/// A linear samplerate transposer class that uses floating point arithmetics
+/// for the transposing.
+class RateTransposerFloat : public RateTransposer
+{
+protected:
+ float fSlopeCount;
+ float fRateStep;
+ SAMPLETYPE sPrevSampleL, sPrevSampleR;
+
+ virtual void resetRegisters();
+
+ virtual uint32_t transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples);
+ virtual uint32_t transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples);
+
+public:
+ RateTransposerFloat();
+ virtual ~RateTransposerFloat();
+};
+
+/*#ifndef min
+#define min(a,b) ((a > b) ? b : a)
+#define max(a,b) ((a < b) ? b : a)
+#endif*/
+
+
+// Operator 'new' is overloaded so that it automatically creates a suitable instance
+// depending on if we've a MMX/SSE/etc-capable CPU available or not.
+void * RateTransposer::operator new(size_t)
+{
+ // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead!
+ //assert(false);
+ //return NULL;
+ throw std::runtime_error("Don't use 'new RateTransposer', use 'newInstance' member instead!");
+}
+
+
+RateTransposer *RateTransposer::newInstance()
+{
+#ifdef INTEGER_SAMPLES
+ return ::new RateTransposerInteger;
+#else
+ return ::new RateTransposerFloat;
+#endif
+}
+
+
+// Constructor
+RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
+{
+ uChannels = 2;
+ bUseAAFilter = true;
+
+ // Instantiates the anti-alias filter with default tap length
+ // of 32
+ pAAFilter = new AAFilter(32);
+}
+
+
+
+RateTransposer::~RateTransposer()
+{
+ delete pAAFilter;
+}
+
+
+
+/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
+void RateTransposer::enableAAFilter(const bool newMode)
+{
+ bUseAAFilter = newMode;
+}
+
+
+/// Returns nonzero if anti-alias filter is enabled.
+bool RateTransposer::isAAFilterEnabled() const
+{
+ return bUseAAFilter;
+}
+
+
+AAFilter *RateTransposer::getAAFilter() const
+{
+ return pAAFilter;
+}
+
+
+
+// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower
+// uRate, larger faster uRates.
+void RateTransposer::setRate(float newRate)
+{
+ float fCutoff;
+
+ fRate = newRate;
+
+ // design a new anti-alias filter
+ if (newRate > 1.0f)
+ {
+ fCutoff = 0.5f / newRate;
+ }
+ else
+ {
+ fCutoff = 0.5f * newRate;
+ }
+ pAAFilter->setCutoffFreq(fCutoff);
+}
+
+
+// Outputs as many samples of the 'outputBuffer' as possible, and if there's
+// any room left, outputs also as many of the incoming samples as possible.
+// The goal is to drive the outputBuffer empty.
+//
+// It's allowed for 'output' and 'input' parameters to point to the same
+// memory position.
+void RateTransposer::flushStoreBuffer()
+{
+ if (storeBuffer.isEmpty())
+ return;
+
+ outputBuffer.moveSamples(storeBuffer);
+}
+
+
+// Adds 'numSamples' pcs of samples from the 'samples' memory position into
+// the input of the object.
+void RateTransposer::putSamples(const SAMPLETYPE *samples, uint32_t numsamples)
+{
+ processSamples(samples, numsamples);
+}
+
+
+
+// Transposes up the sample rate, causing the observed playback 'rate' of the
+// sound to decrease
+void RateTransposer::upsample(const SAMPLETYPE *src, uint32_t numsamples)
+{
+ int count, sizeTemp, num;
+
+ // If the parameter 'uRate' value is smaller than 'SCALE', first transpose
+ // the samples and then apply the anti-alias filter to remove aliasing.
+
+ // First check that there's enough room in 'storeBuffer'
+ // (+16 is to reserve some slack in the destination buffer)
+ sizeTemp = (int)((float)numsamples / fRate + 16.0f);
+
+ // Transpose the samples, store the result into the end of "storeBuffer"
+ count = transpose(storeBuffer.ptrEnd(sizeTemp), src, numsamples);
+ storeBuffer.putSamples(count);
+
+ // Apply the anti-alias filter to samples in "store output", output the
+ // result to "dest"
+ num = storeBuffer.numSamples();
+ count = pAAFilter->evaluate(outputBuffer.ptrEnd(num),
+ storeBuffer.ptrBegin(), num, uChannels);
+ outputBuffer.putSamples(count);
+
+ // Remove the processed samples from "storeBuffer"
+ storeBuffer.receiveSamples(count);
+}
+
+
+// Transposes down the sample rate, causing the observed playback 'rate' of the
+// sound to increase
+void RateTransposer::downsample(const SAMPLETYPE *src, uint32_t numsamples)
+{
+ int count, sizeTemp;
+
+ // If the parameter 'uRate' value is larger than 'SCALE', first apply the
+ // anti-alias filter to remove high frequencies (prevent them from folding
+ // over the lover frequencies), then transpose. */
+
+ // Add the new samples to the end of the storeBuffer */
+ storeBuffer.putSamples(src, numsamples);
+
+ // Anti-alias filter the samples to prevent folding and output the filtered
+ // data to tempBuffer. Note : because of the FIR filter length, the
+ // filtering routine takes in 'filter_length' more samples than it outputs.
+ assert(tempBuffer.isEmpty());
+ sizeTemp = storeBuffer.numSamples();
+
+ count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp),
+ storeBuffer.ptrBegin(), sizeTemp, uChannels);
+
+ // Remove the filtered samples from 'storeBuffer'
+ storeBuffer.receiveSamples(count);
+
+ // Transpose the samples (+16 is to reserve some slack in the destination buffer)
+ sizeTemp = (int)((float)numsamples / fRate + 16.0f);
+ count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count);
+ outputBuffer.putSamples(count);
+}
+
+
+// Transposes sample rate by applying anti-alias filter to prevent folding.
+// Returns amount of samples returned in the "dest" buffer.
+// The maximum amount of samples that can be returned at a time is set by
+// the 'set_returnBuffer_size' function.
+void RateTransposer::processSamples(const SAMPLETYPE *src, uint32_t numsamples)
+{
+ uint32_t count;
+ uint32_t sizeReq;
+
+ if (numsamples == 0) return;
+ assert(pAAFilter);
+
+ // If anti-alias filter is turned off, simply transpose without applying
+ // the filter
+ if (bUseAAFilter == false)
+ {
+ sizeReq = (int)((float)numsamples / fRate + 1.0f);
+ count = transpose(outputBuffer.ptrEnd(sizeReq), src, numsamples);
+ outputBuffer.putSamples(count);
+ return;
+ }
+
+ // Transpose with anti-alias filter
+ if (fRate < 1.0f)
+ {
+ upsample(src, numsamples);
+ }
+ else
+ {
+ downsample(src, numsamples);
+ }
+}
+
+
+// Transposes the sample rate of the given samples using linear interpolation.
+// Returns the number of samples returned in the "dest" buffer
+inline uint32_t RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numsamples)
+{
+ if (uChannels == 2)
+ {
+ return transposeStereo(dest, src, numsamples);
+ }
+ else
+ {
+ return transposeMono(dest, src, numsamples);
+ }
+}
+
+
+// Sets the number of channels, 1 = mono, 2 = stereo
+void RateTransposer::setChannels(uint32_t numchannels)
+{
+ if (uChannels == numchannels) return;
+
+ assert(numchannels == 1 || numchannels == 2);
+ uChannels = numchannels;
+
+ storeBuffer.setChannels(uChannels);
+ tempBuffer.setChannels(uChannels);
+ outputBuffer.setChannels(uChannels);
+
+ // Inits the linear interpolation registers
+ resetRegisters();
+}
+
+
+// Clears all the samples in the object
+void RateTransposer::clear()
+{
+ outputBuffer.clear();
+ storeBuffer.clear();
+}
+
+
+// Returns nonzero if there aren't any samples available for outputting.
+bool RateTransposer::isEmpty() const
+{
+ bool res = FIFOProcessor::isEmpty();
+ if (!res)
+ return false;
+ return storeBuffer.isEmpty();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// RateTransposerInteger - integer arithmetic implementation
+//
+
+/// fixed-point interpolation routine precision
+#define SCALE 65536
+
+// Constructor
+RateTransposerInteger::RateTransposerInteger() : RateTransposer()
+{
+ // call these here as these are virtual functions; calling these
+ // from the base class constructor wouldn't execute the overloaded
+ // versions (<master yoda>peculiar C++ can be</my>).
+ resetRegisters();
+ setRate(1.0f);
+}
+
+
+RateTransposerInteger::~RateTransposerInteger()
+{
+}
+
+
+void RateTransposerInteger::resetRegisters()
+{
+ iSlopeCount = 0;
+ sPrevSampleL =
+ sPrevSampleR = 0;
+}
+
+
+
+// Transposes the sample rate of the given samples using linear interpolation.
+// 'Mono' version of the routine. Returns the number of samples returned in
+// the "dest" buffer
+uint32_t RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numsamples)
+{
+ unsigned int i, used;
+ LONG_SAMPLETYPE temp, vol1;
+
+ used = 0;
+ i = 0;
+
+ // Process the last sample saved from the previous call first...
+ while (iSlopeCount <= SCALE)
+ {
+ vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
+ temp = vol1 * sPrevSampleL + iSlopeCount * src[0];
+ dest[i] = (SAMPLETYPE)(temp / SCALE);
+ i++;
+ iSlopeCount += uRate;
+ }
+ // now always (iSlopeCount > SCALE)
+ iSlopeCount -= SCALE;
+
+ while (1)
+ {
+ while (iSlopeCount > SCALE)
+ {
+ iSlopeCount -= SCALE;
+ used ++;
+ if (used >= numsamples - 1) goto end;
+ }
+ vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
+ temp = src[used] * vol1 + iSlopeCount * src[used + 1];
+ dest[i] = (SAMPLETYPE)(temp / SCALE);
+
+ i++;
+ iSlopeCount += uRate;
+ }
+end:
+ // Store the last sample for the next round
+ sPrevSampleL = src[numsamples - 1];
+
+ return i;
+}
+
+
+// Transposes the sample rate of the given samples using linear interpolation.
+// 'Stereo' version of the routine. Returns the number of samples returned in
+// the "dest" buffer
+uint32_t RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numsamples)
+{
+ unsigned int srcPos, i, used;
+ LONG_SAMPLETYPE temp, vol1;
+
+ if (numsamples == 0) return 0; // no samples, no work
+
+ used = 0;
+ i = 0;
+
+ // Process the last sample saved from the sPrevSampleLious call first...
+ while (iSlopeCount <= SCALE)
+ {
+ vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
+ temp = vol1 * sPrevSampleL + iSlopeCount * src[0];
+ dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
+ temp = vol1 * sPrevSampleR + iSlopeCount * src[1];
+ dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
+ i++;
+ iSlopeCount += uRate;
+ }
+ // now always (iSlopeCount > SCALE)
+ iSlopeCount -= SCALE;
+
+ while (1)
+ {
+ while (iSlopeCount > SCALE)
+ {
+ iSlopeCount -= SCALE;
+ used ++;
+ if (used >= numsamples - 1) goto end;
+ }
+ srcPos = 2 * used;
+ vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
+ temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2];
+ dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
+ temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3];
+ dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
+
+ i++;
+ iSlopeCount += uRate;
+ }
+end:
+ // Store the last sample for the next round
+ sPrevSampleL = src[2 * numsamples - 2];
+ sPrevSampleR = src[2 * numsamples - 1];
+
+ return i;
+}
+
+
+// Sets new target uRate. Normal uRate = 1.0, smaller values represent slower
+// uRate, larger faster uRates.
+void RateTransposerInteger::setRate(float newRate)
+{
+ uRate = (int)(newRate * SCALE + 0.5f);
+ RateTransposer::setRate(newRate);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// RateTransposerFloat - floating point arithmetic implementation
+//
+//////////////////////////////////////////////////////////////////////////////
+
+// Constructor
+RateTransposerFloat::RateTransposerFloat() : RateTransposer()
+{
+ // call these here as these are virtual functions; calling these
+ // from the base class constructor wouldn't execute the overloaded
+ // versions (<master yoda>peculiar C++ can be</my>).
+ resetRegisters();
+ setRate(1.0f);
+}
+
+
+RateTransposerFloat::~RateTransposerFloat()
+{
+}
+
+
+void RateTransposerFloat::resetRegisters()
+{
+ fSlopeCount = 0;
+ sPrevSampleL =
+ sPrevSampleR = 0;
+}
+
+
+
+// Transposes the sample rate of the given samples using linear interpolation.
+// 'Mono' version of the routine. Returns the number of samples returned in
+// the "dest" buffer
+uint32_t RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numsamples)
+{
+ unsigned int i, used;
+
+ used = 0;
+ i = 0;
+
+ // Process the last sample saved from the previous call first...
+ while (fSlopeCount <= 1.0f)
+ {
+ dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]);
+ i++;
+ fSlopeCount += fRate;
+ }
+ fSlopeCount -= 1.0f;
+
+ if (numsamples == 1) goto end;
+
+ while (1)
+ {
+ while (fSlopeCount > 1.0f)
+ {
+ fSlopeCount -= 1.0f;
+ used ++;
+ if (used >= numsamples - 1) goto end;
+ }
+ dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]);
+ i++;
+ fSlopeCount += fRate;
+ }
+end:
+ // Store the last sample for the next round
+ sPrevSampleL = src[numsamples - 1];
+
+ return i;
+}
+
+
+// Transposes the sample rate of the given samples using linear interpolation.
+// 'Mono' version of the routine. Returns the number of samples returned in
+// the "dest" buffer
+uint32_t RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numsamples)
+{
+ unsigned int srcPos, i, used;
+
+ if (numsamples == 0) return 0; // no samples, no work
+
+ used = 0;
+ i = 0;
+
+ // Process the last sample saved from the sPrevSampleLious call first...
+ while (fSlopeCount <= 1.0f)
+ {
+ dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]);
+ dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]);
+ i++;
+ fSlopeCount += fRate;
+ }
+ // now always (iSlopeCount > 1.0f)
+ fSlopeCount -= 1.0f;
+
+ if (numsamples == 1) goto end;
+
+ while (1)
+ {
+ while (fSlopeCount > 1.0f)
+ {
+ fSlopeCount -= 1.0f;
+ used ++;
+ if (used >= numsamples - 1) goto end;
+ }
+ srcPos = 2 * used;
+
+ dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos]
+ + fSlopeCount * src[srcPos + 2]);
+ dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1]
+ + fSlopeCount * src[srcPos + 3]);
+
+ i++;
+ fSlopeCount += fRate;
+ }
+end:
+ // Store the last sample for the next round
+ sPrevSampleL = src[2 * numsamples - 2];
+ sPrevSampleR = src[2 * numsamples - 1];
+
+ return i;
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/RateTransposer.h
@@ -1,1 +1,153 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sample rate transposer. Changes sample rate by using linear interpolation
+/// together with anti-alias filtering (first order interpolation with anti-
+/// alias filtering should be quite adequate for this application).
+///
+/// Use either of the derived classes of 'RateTransposerInteger' or
+/// 'RateTransposerFloat' for corresponding integer/floating point tranposing
+/// algorithm implementation.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.10 $
+//
+// $Id: RateTransposer.h,v 1.10 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef RateTransposer_H
+#define RateTransposer_H
+
+#include "AAFilter.h"
+#include "FIFOSamplePipe.h"
+#include "FIFOSampleBuffer.h"
+
+#include "STTypes.h"
+
+namespace soundtouch
+{
+
+/// A common linear samplerate transposer class.
+///
+/// Note: Use function "RateTransposer::newInstance()" to create a new class
+/// instance instead of the "new" operator; that function automatically
+/// chooses a correct implementation depending on if integer or floating
+/// arithmetics are to be used.
+class RateTransposer : public FIFOProcessor
+{
+protected:
+ /// Anti-alias filter object
+ AAFilter *pAAFilter;
+
+ float fRate;
+
+ uint32_t uChannels;
+
+ /// Buffer for collecting samples to feed the anti-alias filter between
+ /// two batches
+ FIFOSampleBuffer storeBuffer;
+
+ /// Buffer for keeping samples between transposing & anti-alias filter
+ FIFOSampleBuffer tempBuffer;
+
+ /// Output sample buffer
+ FIFOSampleBuffer outputBuffer;
+
+ bool bUseAAFilter;
+
+ void init();
+
+ virtual void resetRegisters() = 0;
+
+ virtual uint32_t transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples) = 0;
+ virtual uint32_t transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples) = 0;
+ uint32_t transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint32_t numSamples);
+
+ void flushStoreBuffer();
+
+ void downsample(const SAMPLETYPE *src, uint32_t numSamples);
+ void upsample(const SAMPLETYPE *src, uint32_t numSamples);
+
+ /// Transposes sample rate by applying anti-alias filter to prevent folding.
+ /// Returns amount of samples returned in the "dest" buffer.
+ /// The maximum amount of samples that can be returned at a time is set by
+ /// the 'set_returnBuffer_size' function.
+ void processSamples(const SAMPLETYPE *src, uint32_t numSamples);
+
+public:
+ RateTransposer();
+ virtual ~RateTransposer();
+
+ /// Operator 'new' is overloaded so that it automatically creates a suitable instance
+ /// depending on if we're to use integer or floating point arithmetics.
+ void *operator new(size_t s);
+
+ /// Use this function instead of "new" operator to create a new instance of this class.
+ /// This function automatically chooses a correct implementation, depending on if
+ /// integer ot floating point arithmetics are to be used.
+ static RateTransposer *newInstance();
+
+ /// Returns the output buffer object
+ FIFOSamplePipe *getOutput() { return &outputBuffer; };
+
+ /// Returns the store buffer object
+ FIFOSamplePipe *getStore() { return &storeBuffer; };
+
+ /// Return anti-alias filter object
+ AAFilter *getAAFilter() const;
+
+ /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
+ void enableAAFilter(bool newMode);
+
+ /// Returns nonzero if anti-alias filter is enabled.
+ bool isAAFilterEnabled() const;
+
+ /// Sets new target rate. Normal rate = 1.0, smaller values represent slower
+ /// rate, larger faster rates.
+ virtual void setRate(float newRate);
+
+ /// Sets the number of channels, 1 = mono, 2 = stereo
+ void setChannels(uint32_t channels);
+
+ /// Adds 'numSamples' pcs of samples from the 'samples' memory position into
+ /// the input of the object.
+ void putSamples(const SAMPLETYPE *samples, uint32_t numSamples);
+
+ /// Clears all the samples in the object
+ void clear();
+
+ /// Returns nonzero if there aren't any samples available for outputting.
+ bool isEmpty() const;
+};
+
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/STTypes.h
@@ -1,1 +1,178 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Common type definitions for SoundTouch audio processing library.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.16 $
+//
+// $Id: STTypes.h,v 1.16 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef STTypes_H
+#define STTypes_H
+
+#include "pstdint.h"
+
+//#define INTEGER_SAMPLES 1
+
+#ifdef __GNUC__
+ // In GCC, include soundtouch_config.h made by config scritps
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Use Integer as Sample type */
+//#define INTEGER_SAMPLES 1
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+#endif
+
+namespace soundtouch
+{
+/// Activate these undef's to overrule the possible sampletype
+/// setting inherited from some other header file:
+//#undef INTEGER_SAMPLES
+//#undef FLOAT_SAMPLES
+
+#if !(INTEGER_SAMPLES || FLOAT_SAMPLES)
+
+ /// Choose either 32bit floating point or 16bit integer sampletype
+ /// by choosing one of the following defines, unless this selection
+ /// has already been done in some other file.
+ ////
+ /// Notes:
+ /// - In Windows environment, choose the sample format with the
+ /// following defines.
+ /// - In GNU environment, the floating point samples are used by
+ /// default, but integer samples can be chosen by giving the
+ /// following switch to the configure script:
+ /// ./configure --enable-integer-samples
+ /// However, if you still prefer to select the sample format here
+ /// also in GNU environment, then please #undef the INTEGER_SAMPLE
+ /// and FLOAT_SAMPLE defines first as in comments above.
+ //#define INTEGER_SAMPLES 1 //< 16bit integer samples
+ #define FLOAT_SAMPLES 1 //< 32bit float samples
+
+ #endif
+
+ /// Define this to allow CPU-specific assembler optimizations. Notice that
+ /// having this enabled on non-x86 platforms doesn't matter; the compiler can
+ /// drop unsupported extensions on different platforms automatically.
+ /// However, if you're having difficulties getting the optimized routines
+ /// compiled with your compler (e.g. some gcc compiler versions may be picky),
+ /// you may wish to disable the optimizations to make the library compile.
+ #if !defined(_MSC_VER) || !defined(__x86_64__)
+ #define ALLOW_OPTIMIZATIONS 1
+ #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1
+ #endif
+
+
+ // If defined, allows the SIMD-optimized routines to take minor shortcuts
+ // for improved performance. Undefine to require faithfully similar SIMD
+ // calculations as in normal C implementation.
+
+
+
+ #ifdef INTEGER_SAMPLES
+ // 16bit integer sample type
+ typedef short SAMPLETYPE;
+ // data type for sample accumulation: Use 32bit integer to prevent overflows
+ typedef long LONG_SAMPLETYPE;
+
+ #ifdef FLOAT_SAMPLES
+ // check that only one sample type is defined
+ #error "conflicting sample types defined"
+ #endif // FLOAT_SAMPLES
+
+ #ifdef ALLOW_OPTIMIZATIONS
+ #if (_WIN32 || __i386__ || __x86_64__)
+ // Allow MMX optimizations
+ #define ALLOW_MMX 1
+ #endif
+ #endif
+
+ #else
+
+ // floating point samples
+ typedef float SAMPLETYPE;
+ // data type for sample accumulation: Use double to utilize full precision.
+ typedef double LONG_SAMPLETYPE;
+
+ #ifdef ALLOW_OPTIMIZATIONS
+ // Allow 3DNow! and SSE optimizations
+ #if _WIN32
+ // #define ALLOW_3DNOW 1
+ #endif
+ #if (_WIN32 || __i386__ || __x86_64__)
+ #define ALLOW_SSE 1
+ #endif
+ #endif
+
+ #endif // INTEGER_SAMPLES
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/SoundTouch.cpp
@@ -1,1 +1,476 @@
-
+//////////////////////////////////////////////////////////////////////////////
+///
+/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
+///
+/// Notes:
+/// - Initialize the SoundTouch object instance by setting up the sound stream
+/// parameters with functions 'setSampleRate' and 'setChannels', then set
+/// desired tempo/pitch/rate settings with the corresponding functions.
+///
+/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
+/// samples that are to be processed are fed into one of the pipe by calling
+/// function 'putSamples', while the ready processed samples can be read
+/// from the other end of the pipeline with function 'receiveSamples'.
+///
+/// - The SoundTouch processing classes require certain sized 'batches' of
+/// samples in order to process the sound. For this reason the classes buffer
+/// incoming samples until there are enough of samples available for
+/// processing, then they carry out the processing step and consequently
+/// make the processed samples available for outputting.
+///
+/// - For the above reason, the processing routines introduce a certain
+/// 'latency' between the input and output, so that the samples input to
+/// SoundTouch may not be immediately available in the output, and neither
+/// the amount of outputtable samples may not immediately be in direct
+/// relationship with the amount of previously input samples.
+///
+/// - The tempo/pitch/rate control parameters can be altered during processing.
+/// Please notice though that they aren't currently protected by semaphores,
+/// so in multi-thread application external semaphore protection may be
+/// required.
+///
+/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
+/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
+/// tempo and pitch in the same ratio) of the sound. The third available control
+/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
+/// combining the two other controls.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.13 $
+//
+// $Id: SoundTouch.cpp,v 1.13 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "XSFCommon.h"
+
+#include <stdexcept>
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
+
+#include "SoundTouch.h"
+#include "TDStretch.h"
+#include "RateTransposer.h"
+#include "cpu_detect.h"
+
+using namespace soundtouch;
+
+/// Print library version string
+extern "C" void soundtouch_ac_test()
+{
+ printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);
+}
+
+
+SoundTouch::SoundTouch()
+{
+ // Initialize rate transposer and tempo changer instances
+
+ pRateTransposer = RateTransposer::newInstance();
+ pTDStretch = TDStretch::newInstance();
+
+ setOutPipe(pTDStretch);
+
+ rate = tempo = 0;
+
+ virtualPitch =
+ virtualRate =
+ virtualTempo = 1.0;
+
+ calcEffectiveRateAndTempo();
+
+ channels = 0;
+ bSrateSet = false;
+}
+
+
+
+SoundTouch::~SoundTouch()
+{
+ delete pRateTransposer;
+ delete pTDStretch;
+}
+
+
+
+/// Get SoundTouch library version string
+const char *SoundTouch::getVersionString()
+{
+ static const char *_version = SOUNDTOUCH_VERSION;
+
+ return _version;
+}
+
+
+/// Get SoundTouch library version Id
+uint32_t SoundTouch::getVersionId()
+{
+ return SOUNDTOUCH_VERSION_ID;
+}
+
+
+// Sets the number of channels, 1 = mono, 2 = stereo
+void SoundTouch::setChannels(uint32_t numChannels)
+{
+ if (numChannels != 1 && numChannels != 2)
+ {
+ throw std::runtime_error("Illegal number of channels");
+ }
+ channels = numChannels;
+ pRateTransposer->setChannels(numChannels);
+ pTDStretch->setChannels(numChannels);
+}
+
+
+
+// Sets new rate control value. Normal rate = 1.0, smaller values
+// represent slower rate, larger faster rates.
+void SoundTouch::setRate(float newRate)
+{
+ virtualRate = newRate;
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets new rate control value as a difference in percents compared
+// to the original rate (-50 .. +100 %)
+void SoundTouch::setRateChange(float newRate)
+{
+ virtualRate = 1.0f + 0.01f * newRate;
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets new tempo control value. Normal tempo = 1.0, smaller values
+// represent slower tempo, larger faster tempo.
+void SoundTouch::setTempo(float newTempo)
+{
+ virtualTempo = newTempo;
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets new tempo control value as a difference in percents compared
+// to the original tempo (-50 .. +100 %)
+void SoundTouch::setTempoChange(float newTempo)
+{
+ virtualTempo = 1.0f + 0.01f * newTempo;
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets new pitch control value. Original pitch = 1.0, smaller values
+// represent lower pitches, larger values higher pitch.
+void SoundTouch::setPitch(float newPitch)
+{
+ virtualPitch = newPitch;
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets pitch change in octaves compared to the original pitch
+// (-1.00 .. +1.00)
+void SoundTouch::setPitchOctaves(float newPitch)
+{
+ virtualPitch = (float)exp(0.69314718056f * newPitch);
+ calcEffectiveRateAndTempo();
+}
+
+
+
+// Sets pitch change in semi-tones compared to the original pitch
+// (-12 .. +12)
+void SoundTouch::setPitchSemiTones(int newPitch)
+{
+ setPitchOctaves((float)newPitch / 12.0f);
+}
+
+
+
+void SoundTouch::setPitchSemiTones(float newPitch)
+{
+ setPitchOctaves(newPitch / 12.0f);
+}
+
+
+// Calculates 'effective' rate and tempo values from the
+// nominal control values.
+void SoundTouch::calcEffectiveRateAndTempo()
+{
+ float oldTempo = tempo;
+ float oldRate = rate;
+
+ tempo = virtualTempo / virtualPitch;
+ rate = virtualPitch * virtualRate;
+
+ if (!fEqual(rate, oldRate)) pRateTransposer->setRate(rate);
+ if (!fEqual(tempo, oldTempo)) pTDStretch->setTempo(tempo);
+
+ if (rate > 1.0f)
+ {
+ if (output != pRateTransposer)
+ {
+ FIFOSamplePipe *transOut;
+
+ assert(output == pTDStretch);
+ // move samples in the current output buffer to the output of pRateTransposer
+ transOut = pRateTransposer->getOutput();
+ transOut->moveSamples(*output);
+ // move samples in tempo changer's input to pitch transposer's input
+ pRateTransposer->moveSamples(*pTDStretch->getInput());
+
+ output = pRateTransposer;
+ }
+ }
+ else
+ {
+ if (output != pTDStretch)
+ {
+ FIFOSamplePipe *tempoOut;
+
+ assert(output == pRateTransposer);
+ // move samples in the current output buffer to the output of pTDStretch
+ tempoOut = pTDStretch->getOutput();
+ tempoOut->moveSamples(*output);
+ // move samples in pitch transposer's store buffer to tempo changer's input
+ pTDStretch->moveSamples(*pRateTransposer->getStore());
+
+ output = pTDStretch;
+
+ }
+ }
+}
+
+
+// Sets sample rate.
+void SoundTouch::setSampleRate(uint32_t srate)
+{
+ bSrateSet = true;
+ // set sample rate, leave other tempo changer parameters as they are.
+ pTDStretch->setParameters(srate);
+}
+
+
+// Adds 'numSamples' pcs of samples from the 'samples' memory position into
+// the input of the object.
+void SoundTouch::putSamples(const SAMPLETYPE *samples, uint32_t numsamples)
+{
+ if (bSrateSet == false)
+ {
+ throw std::runtime_error("SoundTouch : Sample rate not defined");
+ }
+ else if (channels == 0)
+ {
+ throw std::runtime_error("SoundTouch : Number of channels not defined");
+ }
+
+ // Transpose the rate of the new samples if necessary
+ /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value...
+ if (rate == 1.0f)
+ {
+ // The rate value is same as the original, simply evaluate the tempo changer.
+ assert(output == pTDStretch);
+ if (pRateTransposer->isEmpty() == 0)
+ {
+ // yet flush the last samples in the pitch transposer buffer
+ // (may happen if 'rate' changes from a non-zero value to zero)
+ pTDStretch->moveSamples(*pRateTransposer);
+ }
+ pTDStretch->putSamples(samples, numSamples);
+ }
+ */
+ else if (rate <= 1.0f)
+ {
+ // transpose the rate down, output the transposed sound to tempo changer buffer
+ assert(output == pTDStretch);
+ pRateTransposer->putSamples(samples, numsamples);
+ pTDStretch->moveSamples(*pRateTransposer);
+ }
+ else
+ {
+ assert(rate > 1.0f);
+ // evaluate the tempo changer, then transpose the rate up,
+ assert(output == pRateTransposer);
+ pTDStretch->putSamples(samples, numsamples);
+ pRateTransposer->moveSamples(*pTDStretch);
+ }
+}
+
+
+// Flushes the last samples from the processing pipeline to the output.
+// Clears also the internal processing buffers.
+//
+// Note: This function is meant for extracting the last samples of a sound
+// stream. This function may introduce additional blank samples in the end
+// of the sound stream, and thus it's not recommended to call this function
+// in the middle of a sound stream.
+void SoundTouch::flush()
+{
+ int i;
+ uint32_t nOut;
+ SAMPLETYPE buff[128];
+
+ nOut = numSamples();
+
+ memset(buff, 0, 128 * sizeof(SAMPLETYPE));
+ // "Push" the last active samples out from the processing pipeline by
+ // feeding blank samples into the processing pipeline until new,
+ // processed samples appear in the output (not however, more than
+ // 8ksamples in any case)
+ for (i = 0; i < 128; i ++)
+ {
+ putSamples(buff, 64);
+ if (numSamples() != nOut) break; // new samples have appeared in the output!
+ }
+
+ // Clear working buffers
+ pRateTransposer->clear();
+ pTDStretch->clearInput();
+ // yet leave the 'tempoChanger' output intouched as that's where the
+ // flushed samples are!
+}
+
+
+// Changes a setting controlling the processing system behaviour. See the
+// 'SETTING_...' defines for available setting ID's.
+bool SoundTouch::setSetting(uint32_t settingId, uint32_t value)
+{
+ uint32_t sampleRate, sequenceMs, seekWindowMs, overlapMs;
+
+ // read current tdstretch routine parameters
+ pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
+
+ switch (settingId)
+ {
+ case SETTING_USE_AA_FILTER :
+ // enables / disabless anti-alias filter
+ pRateTransposer->enableAAFilter((value != 0) ? true : false);
+ return true;
+
+ case SETTING_AA_FILTER_LENGTH :
+ // sets anti-alias filter length
+ pRateTransposer->getAAFilter()->setLength(value);
+ return true;
+
+ case SETTING_USE_QUICKSEEK :
+ // enables / disables tempo routine quick seeking algorithm
+ pTDStretch->enableQuickSeek((value != 0) ? true : false);
+ return true;
+
+ case SETTING_SEQUENCE_MS:
+ // change time-stretch sequence duration parameter
+ pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);
+ return true;
+
+ case SETTING_SEEKWINDOW_MS:
+ // change time-stretch seek window length parameter
+ pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);
+ return true;
+
+ case SETTING_OVERLAP_MS:
+ // change time-stretch overlap length parameter
+ pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);
+ return true;
+
+ default :
+ return false;
+ }
+}
+
+
+// Reads a setting controlling the processing system behaviour. See the
+// 'SETTING_...' defines for available setting ID's.
+//
+// Returns the setting value.
+uint32_t SoundTouch::getSetting(uint32_t settingId) const
+{
+ uint32_t temp;
+
+ switch (settingId)
+ {
+ case SETTING_USE_AA_FILTER :
+ return pRateTransposer->isAAFilterEnabled();
+
+ case SETTING_AA_FILTER_LENGTH :
+ return pRateTransposer->getAAFilter()->getLength();
+
+ case SETTING_USE_QUICKSEEK :
+ return pTDStretch->isQuickSeekEnabled();
+
+ case SETTING_SEQUENCE_MS:
+ pTDStretch->getParameters(NULL, &temp, NULL, NULL);
+ return temp;
+
+ case SETTING_SEEKWINDOW_MS:
+ pTDStretch->getParameters(NULL, NULL, &temp, NULL);
+ return temp;
+
+ case SETTING_OVERLAP_MS:
+ pTDStretch->getParameters(NULL, NULL, NULL, &temp);
+ return temp;
+
+ default :
+ return 0;
+ }
+}
+
+
+// Clears all the samples in the object's output and internal processing
+// buffers.
+void SoundTouch::clear()
+{
+ pRateTransposer->clear();
+ pTDStretch->clear();
+}
+
+
+
+/// Returns number of samples currently unprocessed.
+uint32_t SoundTouch::numUnprocessedSamples() const
+{
+ FIFOSamplePipe * psp;
+ if (pTDStretch)
+ {
+ psp = pTDStretch->getInput();
+ if (psp)
+ {
+ return psp->numSamples();
+ }
+ }
+ return 0;
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/SoundTouch.h
@@ -1,1 +1,252 @@
-
+//////////////////////////////////////////////////////////////////////////////
+///
+/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
+///
+/// Notes:
+/// - Initialize the SoundTouch object instance by setting up the sound stream
+/// parameters with functions 'setSampleRate' and 'setChannels', then set
+/// desired tempo/pitch/rate settings with the corresponding functions.
+///
+/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
+/// samples that are to be processed are fed into one of the pipe by calling
+/// function 'putSamples', while the ready processed samples can be read
+/// from the other end of the pipeline with function 'receiveSamples'.
+///
+/// - The SoundTouch processing classes require certain sized 'batches' of
+/// samples in order to process the sound. For this reason the classes buffer
+/// incoming samples until there are enough of samples available for
+/// processing, then they carry out the processing step and consequently
+/// make the processed samples available for outputting.
+///
+/// - For the above reason, the processing routines introduce a certain
+/// 'latency' between the input and output, so that the samples input to
+/// SoundTouch may not be immediately available in the output, and neither
+/// the amount of outputtable samples may not immediately be in direct
+/// relationship with the amount of previously input samples.
+///
+/// - The tempo/pitch/rate control parameters can be altered during processing.
+/// Please notice though that they aren't currently protected by semaphores,
+/// so in multi-thread application external semaphore protection may be
+/// required.
+///
+/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
+/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
+/// tempo and pitch in the same ratio) of the sound. The third available control
+/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
+/// combining the two other controls.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.14 $
+//
+// $Id: SoundTouch.h,v 1.14 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SoundTouch_H
+#define SoundTouch_H
+
+#include "FIFOSamplePipe.h"
+#include "STTypes.h"
+
+namespace soundtouch
+{
+
+/// Soundtouch library version string
+static const char *const SOUNDTOUCH_VERSION = "1.3.1";
+
+/// SoundTouch library version id
+static const uint32_t SOUNDTOUCH_VERSION_ID = 010301;
+
+//
+// Available setting IDs for the 'setSetting' & 'get_setting' functions:
+
+/// Enable/disable anti-alias filter in pitch transposer (0 = disable)
+static const uint32_t SETTING_USE_AA_FILTER = 0;
+
+/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)
+static const uint32_t SETTING_AA_FILTER_LENGTH = 1;
+
+/// Enable/disable quick seeking algorithm in tempo changer routine
+/// (enabling quick seeking lowers CPU utilization but causes a minor sound
+/// quality compromising)
+static const uint32_t SETTING_USE_QUICKSEEK = 2;
+
+/// Time-stretch algorithm single processing sequence length in milliseconds. This determines
+/// to how long sequences the original sound is chopped in the time-stretch algorithm.
+/// See "STTypes.h" or README for more information.
+static const uint32_t SETTING_SEQUENCE_MS = 3;
+
+/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the
+/// best possible overlapping location. This determines from how wide window the algorithm
+/// may look for an optimal joining location when mixing the sound sequences back together.
+/// See "STTypes.h" or README for more information.
+static const uint32_t SETTING_SEEKWINDOW_MS = 4;
+
+/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences
+/// are mixed back together, to form a continuous sound stream, this parameter defines over
+/// how long period the two consecutive sequences are let to overlap each other.
+/// See "STTypes.h" or README for more information.
+static const uint32_t SETTING_OVERLAP_MS = 5;
+
+class SoundTouch : public FIFOProcessor
+{
+private:
+ /// Rate transposer class instance
+ class RateTransposer *pRateTransposer;
+
+ /// Time-stretch class instance
+ class TDStretch *pTDStretch;
+
+ /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
+ float virtualRate;
+
+ /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
+ float virtualTempo;
+
+ /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
+ float virtualPitch;
+
+ /// Flag: Has sample rate been set?
+ bool bSrateSet;
+
+ /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
+ /// 'virtualPitch' parameters.
+ void calcEffectiveRateAndTempo();
+
+protected :
+ /// Number of channels
+ uint32_t channels;
+
+ /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
+ float rate;
+
+ /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
+ float tempo;
+
+public:
+ SoundTouch();
+ virtual ~SoundTouch();
+
+ /// Get SoundTouch library version string
+ static const char *getVersionString();
+
+ /// Get SoundTouch library version Id
+ static uint32_t getVersionId();
+
+ /// Sets new rate control value. Normal rate = 1.0, smaller values
+ /// represent slower rate, larger faster rates.
+ void setRate(float newRate);
+
+ /// Sets new tempo control value. Normal tempo = 1.0, smaller values
+ /// represent slower tempo, larger faster tempo.
+ void setTempo(float newTempo);
+
+ /// Sets new rate control value as a difference in percents compared
+ /// to the original rate (-50 .. +100 %)
+ void setRateChange(float newRate);
+
+ /// Sets new tempo control value as a difference in percents compared
+ /// to the original tempo (-50 .. +100 %)
+ void setTempoChange(float newTempo);
+
+ /// Sets new pitch control value. Original pitch = 1.0, smaller values
+ /// represent lower pitches, larger values higher pitch.
+ void setPitch(float newPitch);
+
+ /// Sets pitch change in octaves compared to the original pitch
+ /// (-1.00 .. +1.00)
+ void setPitchOctaves(float newPitch);
+
+ /// Sets pitch change in semi-tones compared to the original pitch
+ /// (-12 .. +12)
+ void setPitchSemiTones(int newPitch);
+ void setPitchSemiTones(float newPitch);
+
+ /// Sets the number of channels, 1 = mono, 2 = stereo
+ void setChannels(uint32_t numChannels);
+
+ /// Sets sample rate.
+ void setSampleRate(uint32_t srate);
+
+ /// Flushes the last samples from the processing pipeline to the output.
+ /// Clears also the internal processing buffers.
+ //
+ /// Note: This function is meant for extracting the last samples of a sound
+ /// stream. This function may introduce additional blank samples in the end
+ /// of the sound stream, and thus it's not recommended to call this function
+ /// in the middle of a sound stream.
+ void flush();
+
+ /// Adds 'numSamples' pcs of samples from the 'samples' memory position into
+ /// the input of the object. Notice that sample rate _has_to_ be set before
+ /// calling this function, otherwise throws a runtime_error exception.
+ virtual void putSamples(
+ const SAMPLETYPE *samples, ///< Pointer to sample buffer.
+ uint32_t numSamples ///< Number of samples in buffer. Notice
+ ///< that in case of stereo-sound a single sample
+ ///< contains data for both channels.
+ );
+
+ /// Clears all the samples in the object's output and internal processing
+ /// buffers.
+ virtual void clear();
+
+ /// Changes a setting controlling the processing system behaviour. See the
+ /// 'SETTING_...' defines for available setting ID's.
+ ///
+ /// \return 'true' if the setting was succesfully changed
+ bool setSetting(uint32_t settingId, ///< Setting ID number. see SETTING_... defines.
+ uint32_t value ///< New setting value.
+ );
+
+ /// Reads a setting controlling the processing system behaviour. See the
+ /// 'SETTING_...' defines for available setting ID's.
+ ///
+ /// \return the setting value.
+ uint32_t getSetting(uint32_t settingId ///< Setting ID number, see SETTING_... defines.
+ ) const;
+
+ /// Returns number of samples currently unprocessed.
+ virtual uint32_t numUnprocessedSamples() const;
+
+ /// Other handy functions that are implemented in the ancestor classes (see
+ /// classes 'FIFOProcessor' and 'FIFOSamplePipe')
+ ///
+ /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.
+ /// - numSamples() : Get number of 'ready' samples that can be received with
+ /// function 'receiveSamples()'
+ /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples.
+ /// - clear() : Clears all samples from ready/processing buffers.
+};
+
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/TDStretch.cpp
@@ -1,1 +1,937 @@
-
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
+/// while maintaining the original pitch by using a time domain WSOLA-like
+/// method with several performance-increasing tweaks.
+///
+/// Note : MMX optimized functions reside in a separate, platform-specific
+/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.24 $
+//
+// $Id: TDStretch.cpp,v 1.24 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "XSFCommon.h"
+
+#include <stdexcept>
+#include <cstring>
+#include <cstdlib>
+#include <climits>
+#include <cassert>
+
+#include "STTypes.h"
+#include "cpu_detect.h"
+#include "TDStretch.h"
+
+using namespace soundtouch;
+
+/*****************************************************************************
+ *
+ * Constant definitions
+ *
+ *****************************************************************************/
+
+
+// Table for the hierarchical mixing position seeking algorithm
+int scanOffsets[4][24]={
+ { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806,
+ 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0},
+ {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+
+/*****************************************************************************
+ *
+ * Implementation of the class 'TDStretch'
+ *
+ *****************************************************************************/
+
+
+TDStretch::TDStretch() : FIFOProcessor(&outputBuffer)
+{
+ bQuickseek = false;
+ channels = 2;
+ bMidBufferDirty = false;
+
+ pMidBuffer = NULL;
+ pRefMidBufferUnaligned = NULL;
+ overlapLength = 0;
+
+ setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS);
+
+ setTempo(1.0f);
+}
+
+
+
+
+TDStretch::~TDStretch()
+{
+ delete[] pMidBuffer;
+ delete[] pRefMidBufferUnaligned;
+}
+
+
+
+// Calculates the x having the closest 2^x value for the given value
+#ifdef INTEGER_SAMPLES
+
+static int _getClosest2Power(double value)
+{
+ return (int)(log(value) / log(2.0) + 0.5);
+}
+
+#endif
+
+// Sets routine control parameters. These control are certain time constants
+// defining how the sound is stretched to the desired duration.
+//
+// 'sampleRate' = sample rate of the sound
+// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms)
+// 'seekwindowMS' = seeking window length for scanning the best overlapping
+// position (default = 28 ms)
+// 'overlapMS' = overlapping length (default = 12 ms)
+
+void TDStretch::setParameters(uint32_t aSampleRate, uint32_t aSequenceMS,
+ uint32_t aSeekWindowMS, uint32_t aOverlapMS)
+{
+ this->sampleRate = aSampleRate;
+ this->sequenceMs = aSequenceMS;
+ this->seekWindowMs = aSeekWindowMS;
+ this->overlapMs = aOverlapMS;
+
+ seekLength = (sampleRate * seekWindowMs) / 1000;
+ seekWindowLength = (sampleRate * sequenceMs) / 1000;
+
+ maxOffset = seekLength;
+
+ calculateOverlapLength(overlapMs);
+
+ // set tempo to recalculate 'sampleReq'
+ setTempo(tempo);
+
+}
+
+
+
+/// Get routine control parameters, see setParameters() function.
+/// Any of the parameters to this function can be NULL, in such case corresponding parameter
+/// value isn't returned.
+void TDStretch::getParameters(uint32_t *pSampleRate, uint32_t *pSequenceMs, uint32_t *pSeekWindowMs, uint32_t *pOverlapMs)
+{
+ if (pSampleRate)
+ {
+ *pSampleRate = sampleRate;
+ }
+
+ if (pSequenceMs)
+ {
+ *pSequenceMs = sequenceMs;
+ }
+
+ if (pSeekWindowMs)
+ {
+ *pSeekWindowMs = seekWindowMs;
+ }
+
+ if (pOverlapMs)
+ {
+ *pOverlapMs = overlapMs;
+ }
+}
+
+
+// Overlaps samples in 'midBuffer' with the samples in 'input'
+void TDStretch::overlapMono(SAMPLETYPE *out, const SAMPLETYPE *in) const
+{
+ int i, itemp;
+
+ for (i = 0; i < (int)overlapLength ; i ++)
+ {
+ itemp = overlapLength - i;
+ out[i] = (in[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits;
+ }
+}
+
+
+
+void TDStretch::clearMidBuffer()
+{
+ if (bMidBufferDirty)
+ {
+ memset(pMidBuffer, 0, 2 * sizeof(SAMPLETYPE) * overlapLength);
+ bMidBufferDirty = false;
+ }
+}
+
+
+void TDStretch::clearInput()
+{
+ inputBuffer.clear();
+ clearMidBuffer();
+}
+
+
+// Clears the sample buffers
+void TDStretch::clear()
+{
+ outputBuffer.clear();
+ inputBuffer.clear();
+ clearMidBuffer();
+}
+
+
+
+// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero
+// to enable
+void TDStretch::enableQuickSeek(bool enable)
+{
+ bQuickseek = enable;
+}
+
+
+// Returns nonzero if the quick seeking algorithm is enabled.
+bool TDStretch::isQuickSeekEnabled() const
+{
+ return bQuickseek;
+}
+
+
+// Seeks for the optimal overlap-mixing position.
+uint32_t TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos)
+{
+ if (channels == 2)
+ {
+ // stereo sound
+ if (bQuickseek)
+ {
+ return seekBestOverlapPositionStereoQuick(refPos);
+ }
+ else
+ {
+ return seekBestOverlapPositionStereo(refPos);
+ }
+ }
+ else
+ {
+ // mono sound
+ if (bQuickseek)
+ {
+ return seekBestOverlapPositionMonoQuick(refPos);
+ }
+ else
+ {
+ return seekBestOverlapPositionMono(refPos);
+ }
+ }
+}
+
+
+
+
+// Overlaps samples in 'midBuffer' with the samples in 'inputBuffer' at position
+// of 'ovlPos'.
+inline void TDStretch::overlap(SAMPLETYPE *out, const SAMPLETYPE *in, uint32_t ovlPos) const
+{
+ if (channels == 2)
+ {
+ // stereo sound
+ overlapStereo(out, in + 2 * ovlPos);
+ } else {
+ // mono sound.
+ overlapMono(out, in + ovlPos);
+ }
+}
+
+
+
+
+// Seeks for the optimal overlap-mixing position. The 'stereo' version of the
+// routine
+//
+// The best position is determined as the position where the two overlapped
+// sample sequences are 'most alike', in terms of the highest cross-correlation
+// value over the overlapping period
+uint32_t TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos)
+{
+ uint32_t bestOffs;
+ LONG_SAMPLETYPE bestCorr, corr;
+ uint32_t i;
+
+ // Slopes the amplitudes of the 'midBuffer' samples
+ precalcCorrReferenceStereo();
+
+ bestCorr = INT_MIN;
+ bestOffs = 0;
+
+ // Scans for the best correlation value by testing each possible position
+ // over the permitted range.
+ for (i = 0; i < seekLength; i ++)
+ {
+ // Calculates correlation value for the mixing position corresponding
+ // to 'i'
+ corr = calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer);
+
+ // Checks for the highest correlation value
+ if (corr > bestCorr)
+ {
+ bestCorr = corr;
+ bestOffs = i;
+ }
+ }
+ // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+ clearCrossCorrState();
+
+ return bestOffs;
+}
+
+
+// Seeks for the optimal overlap-mixing position. The 'stereo' version of the
+// routine
+//
+// The best position is determined as the position where the two overlapped
+// sample sequences are 'most alike', in terms of the highest cross-correlation
+// value over the overlapping period
+uint32_t TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos)
+{
+ uint32_t j;
+ uint32_t bestOffs;
+ LONG_SAMPLETYPE bestCorr, corr;
+ uint32_t scanCount, corrOffset, tempOffset;
+
+ // Slopes the amplitude of the 'midBuffer' samples
+ precalcCorrReferenceStereo();
+
+ bestCorr = INT_MIN;
+ bestOffs = 0;
+ corrOffset = 0;
+ tempOffset = 0;
+
+ // Scans for the best correlation value using four-pass hierarchical search.
+ //
+ // The look-up table 'scans' has hierarchical position adjusting steps.
+ // In first pass the routine searhes for the highest correlation with
+ // relatively coarse steps, then rescans the neighbourhood of the highest
+ // correlation with better resolution and so on.
+ for (scanCount = 0;scanCount < 4; scanCount ++)
+ {
+ j = 0;
+ while (scanOffsets[scanCount][j])
+ {
+ tempOffset = corrOffset + scanOffsets[scanCount][j];
+ if (tempOffset >= seekLength) break;
+
+ // Calculates correlation value for the mixing position corresponding
+ // to 'tempOffset'
+ corr = calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer);
+
+ // Checks for the highest correlation value
+ if (corr > bestCorr)
+ {
+ bestCorr = corr;
+ bestOffs = tempOffset;
+ }
+ j ++;
+ }
+ corrOffset = bestOffs;
+ }
+ // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+ clearCrossCorrState();
+
+ return bestOffs;
+}
+
+
+
+// Seeks for the optimal overlap-mixing position. The 'mono' version of the
+// routine
+//
+// The best position is determined as the position where the two overlapped
+// sample sequences are 'most alike', in terms of the highest cross-correlation
+// value over the overlapping period
+uint32_t TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos)
+{
+ uint32_t bestOffs;
+ LONG_SAMPLETYPE bestCorr, corr;
+ uint32_t tempOffset;
+ const SAMPLETYPE *compare;
+
+ // Slopes the amplitude of the 'midBuffer' samples
+ precalcCorrReferenceMono();
+
+ bestCorr = INT_MIN;
+ bestOffs = 0;
+
+ // Scans for the best correlation value by testing each possible position
+ // over the permitted range.
+ for (tempOffset = 0; tempOffset < seekLength; tempOffset ++)
+ {
+ compare = refPos + tempOffset;
+
+ // Calculates correlation value for the mixing position corresponding
+ // to 'tempOffset'
+ corr = calcCrossCorrMono(pRefMidBuffer, compare);
+
+ // Checks for the highest correlation value
+ if (corr > bestCorr)
+ {
+ bestCorr = corr;
+ bestOffs = tempOffset;
+ }
+ }
+ // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+ clearCrossCorrState();
+
+ return bestOffs;
+}
+
+
+// Seeks for the optimal overlap-mixing position. The 'mono' version of the
+// routine
+//
+// The best position is determined as the position where the two overlapped
+// sample sequences are 'most alike', in terms of the highest cross-correlation
+// value over the overlapping period
+uint32_t TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos)
+{
+ uint32_t j;
+ uint32_t bestOffs;
+ LONG_SAMPLETYPE bestCorr, corr;
+ uint32_t scanCount, corrOffset, tempOffset;
+
+ // Slopes the amplitude of the 'midBuffer' samples
+ precalcCorrReferenceMono();
+
+ bestCorr = INT_MIN;
+ bestOffs = 0;
+ corrOffset = 0;
+ tempOffset = 0;
+
+ // Scans for the best correlation value using four-pass hierarchical search.
+ //
+ // The look-up table 'scans' has hierarchical position adjusting steps.
+ // In first pass the routine searhes for the highest correlation with
+ // relatively coarse steps, then rescans the neighbourhood of the highest
+ // correlation with better resolution and so on.
+ for (scanCount = 0;scanCount < 4; scanCount ++)
+ {
+ j = 0;
+ while (scanOffsets[scanCount][j])
+ {
+ tempOffset = corrOffset + scanOffsets[scanCount][j];
+ if (tempOffset >= seekLength) break;
+
+ // Calculates correlation value for the mixing position corresponding
+ // to 'tempOffset'
+ corr = calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer);
+
+ // Checks for the highest correlation value
+ if (corr > bestCorr)
+ {
+ bestCorr = corr;
+ bestOffs = tempOffset;
+ }
+ j ++;
+ }
+ corrOffset = bestOffs;
+ }
+ // clear cross correlation routine state if necessary (is so e.g. in MMX routines).
+ clearCrossCorrState();
+
+ return bestOffs;
+}
+
+
+/// clear cross correlation routine state if necessary
+void TDStretch::clearCrossCorrState()
+{
+ // default implementation is empty.
+}
+
+
+// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
+// tempo, larger faster tempo.
+void TDStretch::setTempo(float newTempo)
+{
+ uint32_t intskip;
+
+ tempo = newTempo;
+
+ // Calculate ideal skip length (according to tempo value)
+ nominalSkip = tempo * (seekWindowLength - overlapLength);
+ skipFract = 0;
+ intskip = (int)(nominalSkip + 0.5f);
+
+ // Calculate how many samples are needed in the 'inputBuffer' to
+ // process another batch of samples
+ sampleReq = std::max(intskip + overlapLength, seekWindowLength) + maxOffset;
+}
+
+
+
+// Sets the number of channels, 1 = mono, 2 = stereo
+void TDStretch::setChannels(uint32_t numChannels)
+{
+ if (channels == numChannels) return;
+ assert(numChannels == 1 || numChannels == 2);
+
+ channels = numChannels;
+ inputBuffer.setChannels(channels);
+ outputBuffer.setChannels(channels);
+}
+
+
+// nominal tempo, no need for processing, just pass the samples through
+// to outputBuffer
+void TDStretch::processNominalTempo()
+{
+ assert(fEqual(tempo, 1.0f));
+
+ if (bMidBufferDirty)
+ {
+ // If there are samples in pMidBuffer waiting for overlapping,
+ // do a single sliding overlapping with them in order to prevent a
+ // clicking distortion in the output sound
+ if (inputBuffer.numSamples() < overlapLength)
+ {
+ // wait until we've got overlapLength input samples
+ return;
+ }
+ // Mix the samples in the beginning of 'inputBuffer' with the
+ // samples in 'midBuffer' using sliding overlapping
+ overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0);
+ outputBuffer.putSamples(overlapLength);
+ inputBuffer.receiveSamples(overlapLength);
+ clearMidBuffer();
+ // now we've caught the nominal sample flow and may switch to
+ // bypass mode
+ }
+
+ // Simply bypass samples from input to output
+ outputBuffer.moveSamples(inputBuffer);
+}
+
+
+
+// Processes as many processing frames of the samples 'inputBuffer', store
+// the result into 'outputBuffer'
+void TDStretch::processSamples()
+{
+ uint32_t ovlSkip, offset;
+ int temp;
+
+ /* Removed this small optimization - can introduce a click to sound when tempo setting
+ crosses the nominal value
+ if (tempo == 1.0f)
+ {
+ // tempo not changed from the original, so bypass the processing
+ processNominalTempo();
+ return;
+ }
+ */
+
+ if (bMidBufferDirty == false)
+ {
+ // if midBuffer is empty, move the first samples of the input stream
+ // into it
+ if (inputBuffer.numSamples() < overlapLength)
+ {
+ // wait until we've got overlapLength samples
+ return;
+ }
+ memcpy(pMidBuffer, inputBuffer.ptrBegin(), channels * overlapLength * sizeof(SAMPLETYPE));
+ inputBuffer.receiveSamples(overlapLength);
+ bMidBufferDirty = true;
+ }
+
+ // Process samples as long as there are enough samples in 'inputBuffer'
+ // to form a processing frame.
+ while (inputBuffer.numSamples() >= sampleReq)
+ {
+ // If tempo differs from the normal ('SCALE'), scan for the best overlapping
+ // position
+ offset = seekBestOverlapPosition(inputBuffer.ptrBegin());
+
+ // Mix the samples in the 'inputBuffer' at position of 'offset' with the
+ // samples in 'midBuffer' using sliding overlapping
+ // ... first partially overlap with the end of the previous sequence
+ // (that's in 'midBuffer')
+ overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), offset);
+ outputBuffer.putSamples(overlapLength);
+
+ // ... then copy sequence samples from 'inputBuffer' to output
+ temp = (seekWindowLength - 2 * overlapLength);// & 0xfffffffe;
+ if (temp > 0)
+ {
+ outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), temp);
+ }
+
+ // Copies the end of the current sequence from 'inputBuffer' to
+ // 'midBuffer' for being mixed with the beginning of the next
+ // processing sequence and so on
+ assert(offset + seekWindowLength <= inputBuffer.numSamples());
+ memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + seekWindowLength - overlapLength),
+ channels * sizeof(SAMPLETYPE) * overlapLength);
+ bMidBufferDirty = true;
+
+ // Remove the processed samples from the input buffer. Update
+ // the difference between integer & nominal skip step to 'skipFract'
+ // in order to prevent the error from accumulating over time.
+ skipFract += nominalSkip; // real skip size
+ ovlSkip = (int)skipFract; // rounded to integer skip
+ skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip
+ inputBuffer.receiveSamples(ovlSkip);
+ }
+}
+
+
+// Adds 'numsamples' pcs of samples from the 'samples' memory position into
+// the input of the object.
+void TDStretch::putSamples(const SAMPLETYPE *samples, uint32_t numsamples)
+{
+ // Add the samples into the input buffer
+ inputBuffer.putSamples(samples, numsamples);
+ // Process the samples in input buffer
+ processSamples();
+}
+
+
+
+/// Set new overlap length parameter & reallocate RefMidBuffer if necessary.
+void TDStretch::acceptNewOverlapLength(uint32_t newOverlapLength)
+{
+ uint32_t prevOvl;
+
+ prevOvl = overlapLength;
+ overlapLength = newOverlapLength;
+
+ if (overlapLength > prevOvl)
+ {
+ delete[] pMidBuffer;
+ delete[] pRefMidBufferUnaligned;
+
+ pMidBuffer = new SAMPLETYPE[overlapLength * 2];
+ bMidBufferDirty = true;
+ clearMidBuffer();
+
+ pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)];
+ // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency
+ pRefMidBuffer = (SAMPLETYPE *)((((intptr_t)pRefMidBufferUnaligned) + 15) & -16);
+ }
+}
+
+
+// Operator 'new' is overloaded so that it automatically creates a suitable instance
+// depending on if we've a MMX/SSE/etc-capable CPU available or not.
+void * TDStretch::operator new(size_t s)
+{
+ // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead!
+ //assert(false);
+ //return NULL;
+ throw std::runtime_error("Don't use 'new TDStretch', use 'newInstance' member instead!");
+}
+
+
+TDStretch * TDStretch::newInstance()
+{
+ uint32_t uExtensions = 0;
+#if !defined(_MSC_VER) || !defined(__x86_64__)
+ uExtensions = detectCPUextensions();
+#endif
+ // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
+
+#ifdef ALLOW_MMX
+ // MMX routines available only with integer sample types
+ if (uExtensions & SUPPORT_MMX)
+ {
+ return ::new TDStretchMMX;
+ }
+ else
+#endif // ALLOW_MMX
+
+
+#ifdef __SSE__
+ if (uExtensions & SUPPORT_SSE)
+ {
+ // SSE support
+ return ::new TDStretchSSE;
+ }
+ else
+#endif // ALLOW_SSE
+
+
+#ifdef ALLOW_3DNOW
+ if (uExtensions & SUPPORT_3DNOW)
+ {
+ // 3DNow! support
+ return ::new TDStretch3DNow;
+ }
+ else
+#endif // ALLOW_3DNOW
+
+ {
+ // ISA optimizations not supported, use plain C version
+ return ::new TDStretch;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Integer arithmetics specific algorithm implementations.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifdef INTEGER_SAMPLES
+
+// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
+// is faster to calculate
+void TDStretch::precalcCorrReferenceStereo()
+{
+ int i, cnt2;
+ int temp, temp2;
+
+ for (i=0 ; i < (int)overlapLength ;i ++)
+ {
+ temp = i * (overlapLength - i);
+ cnt2 = i * 2;
+
+ temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider;
+ pRefMidBuffer[cnt2] = (short)(temp2);
+ temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider;
+ pRefMidBuffer[cnt2 + 1] = (short)(temp2);
+ }
+}
+
+
+// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
+// is faster to calculate
+void TDStretch::precalcCorrReferenceMono()
+{
+ int i;
+ long temp;
+ long temp2;
+
+ for (i=0 ; i < (int)overlapLength ;i ++)
+ {
+ temp = i * (overlapLength - i);
+ temp2 = (pMidBuffer[i] * temp) / slopingDivider;
+ pRefMidBuffer[i] = (short)temp2;
+ }
+}
+
+
+// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo'
+// version of the routine.
+void TDStretch::overlapStereo(short *out, const short *in) const
+{
+ int i;
+ short temp;
+ uint32_t cnt2;
+
+ for (i = 0; i < (int)overlapLength ; i ++)
+ {
+ temp = (short)(overlapLength - i);
+ cnt2 = 2 * i;
+ out[cnt2] = (in[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength;
+ out[cnt2 + 1] = (in[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength;
+ }
+}
+
+
+/// Calculates overlap period length in samples.
+/// Integer version rounds overlap length to closest power of 2
+/// for a divide scaling operation.
+void TDStretch::calculateOverlapLength(uint32_t overlapMS)
+{
+ uint32_t newOvl;
+
+ overlapDividerBits = _getClosest2Power((sampleRate * overlapMS) / 1000.0);
+ if (overlapDividerBits > 9) overlapDividerBits = 9;
+ if (overlapDividerBits < 4) overlapDividerBits = 4;
+ newOvl = 1<<overlapDividerBits;
+
+ acceptNewOverlapLength(newOvl);
+
+ // calculate sloping divider so that crosscorrelation operation won't
+ // overflow 32-bit register. Max. sum of the crosscorrelation sum without
+ // divider would be 2^30*(N^3-N)/3, where N = overlap length
+ slopingDivider = (newOvl * newOvl - 1) / 3;
+}
+
+
+long TDStretch::calcCrossCorrMono(const short *mixingPos, const short *compare) const
+{
+ long corr;
+ uint32_t i;
+
+ corr = 0;
+ for (i = 1; i < overlapLength; i ++)
+ {
+ corr += (mixingPos[i] * compare[i]) >> overlapDividerBits;
+ }
+
+ return corr;
+}
+
+
+long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const
+{
+ long corr;
+ uint32_t i;
+
+ corr = 0;
+ for (i = 2; i < 2 * overlapLength; i += 2)
+ {
+ corr += (mixingPos[i] * compare[i] +
+ mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits;
+ }
+
+ return corr;
+}
+
+#endif // INTEGER_SAMPLES
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Floating point arithmetics specific algorithm implementations.
+//
+
+#ifdef FLOAT_SAMPLES
+
+
+// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
+// is faster to calculate
+void TDStretch::precalcCorrReferenceStereo()
+{
+ int i, cnt2;
+ float temp;
+
+ for (i=0 ; i < (int)overlapLength ;i ++)
+ {
+ temp = (float)i * (float)(overlapLength - i);
+ cnt2 = i * 2;
+ pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp);
+ pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp);
+ }
+}
+
+
+// Slopes the amplitude of the 'midBuffer' samples so that cross correlation
+// is faster to calculate
+void TDStretch::precalcCorrReferenceMono()
+{
+ int i;
+ float temp;
+
+ for (i=0 ; i < (int)overlapLength ;i ++)
+ {
+ temp = (float)i * (float)(overlapLength - i);
+ pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp);
+ }
+}
+
+
+// SSE-optimized version of the function overlapStereo
+void TDStretch::overlapStereo(float *out, const float *in) const
+{
+ int i;
+ uint32_t cnt2;
+ float fTemp;
+ float fScale;
+ float fi;
+
+ fScale = 1.0f / (float)overlapLength;
+
+ for (i = 0; i < (int)overlapLength ; i ++)
+ {
+ fTemp = (float)(overlapLength - i) * fScale;
+ fi = (float)i * fScale;
+ cnt2 = 2 * i;
+ out[cnt2 + 0] = in[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp;
+ out[cnt2 + 1] = in[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp;
+ }
+}
+
+
+/// Calculates overlap period length in samples.
+void TDStretch::calculateOverlapLength(uint32_t overlapMS)
+{
+ uint32_t newOvl;
+
+ newOvl = (sampleRate * overlapMS) / 1000;
+ if (newOvl < 16) newOvl = 16;
+
+ // must be divisible by 8
+ newOvl -= newOvl % 8;
+
+ acceptNewOverlapLength(newOvl);
+}
+
+
+
+double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const
+{
+ double corr;
+ uint32_t i;
+
+ corr = 0;
+ for (i = 1; i < overlapLength; i ++)
+ {
+ corr += mixingPos[i] * compare[i];
+ }
+
+ return corr;
+}
+
+
+double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const
+{
+ double corr;
+ uint32_t i;
+
+ corr = 0;
+ for (i = 2; i < 2 * overlapLength; i += 2)
+ {
+ corr += mixingPos[i] * compare[i] +
+ mixingPos[i + 1] * compare[i + 1];
+ }
+
+ return corr;
+}
+
+#endif // FLOAT_SAMPLES
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/TDStretch.h
@@ -1,1 +1,234 @@
-
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
+/// while maintaining the original pitch by using a time domain WSOLA-like method
+/// with several performance-increasing tweaks.
+///
+/// Note : MMX optimized functions reside in a separate, platform-specific file,
+/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.16 $
+//
+// $Id: TDStretch.h,v 1.16 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef TDStretch_H
+#define TDStretch_H
+
+#include "STTypes.h"
+#include "RateTransposer.h"
+#include "FIFOSamplePipe.h"
+
+namespace soundtouch
+{
+
+// Default values for sound processing parameters:
+
+/// Default length of a single processing sequence, in milliseconds. This determines to how
+/// long sequences the original sound is chopped in the time-stretch algorithm.
+///
+/// The larger this value is, the lesser sequences are used in processing. In principle
+/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo
+/// and vice versa.
+///
+/// Increasing this value reduces computational burden & vice versa.
+static const uint32_t DEFAULT_SEQUENCE_MS = 63;
+
+static const uint32_t DEFAULT_SEEKWINDOW_MS = 17;
+
+static const uint32_t DEFAULT_OVERLAP_MS = 7;
+
+/// Class that does the time-stretch (tempo change) effect for the processed
+/// sound.
+class TDStretch : public FIFOProcessor
+{
+protected:
+ uint32_t channels;
+ uint32_t sampleReq;
+ float tempo;
+
+ SAMPLETYPE *pMidBuffer;
+ SAMPLETYPE *pRefMidBuffer;
+ SAMPLETYPE *pRefMidBufferUnaligned;
+ uint32_t overlapLength;
+ uint32_t overlapDividerBits;
+ uint32_t slopingDivider;
+ uint32_t seekLength;
+ uint32_t seekWindowLength;
+ uint32_t maxOffset;
+ float nominalSkip;
+ float skipFract;
+ FIFOSampleBuffer outputBuffer;
+ FIFOSampleBuffer inputBuffer;
+ bool bQuickseek;
+ bool bMidBufferDirty;
+
+ uint32_t sampleRate;
+ uint32_t sequenceMs;
+ uint32_t seekWindowMs;
+ uint32_t overlapMs;
+
+ void acceptNewOverlapLength(uint32_t newOverlapLength);
+
+ virtual void clearCrossCorrState();
+ void calculateOverlapLength(uint32_t overlapMs);
+
+ virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
+ virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
+
+ virtual uint32_t seekBestOverlapPositionStereo(const SAMPLETYPE *refPos);
+ virtual uint32_t seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos);
+ virtual uint32_t seekBestOverlapPositionMono(const SAMPLETYPE *refPos);
+ virtual uint32_t seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos);
+ uint32_t seekBestOverlapPosition(const SAMPLETYPE *refPos);
+
+ virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;
+ virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;
+
+ void clearMidBuffer();
+ void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint32_t ovlPos) const;
+
+ void precalcCorrReferenceMono();
+ void precalcCorrReferenceStereo();
+
+ void processNominalTempo();
+
+ /// Changes the tempo of the given sound samples.
+ /// Returns amount of samples returned in the "output" buffer.
+ /// The maximum amount of samples that can be returned at a time is set by
+ /// the 'set_returnBuffer_size' function.
+ void processSamples();
+
+public:
+ TDStretch();
+ virtual ~TDStretch();
+
+ /// Operator 'new' is overloaded so that it automatically creates a suitable instance
+ /// depending on if we've a MMX/SSE/etc-capable CPU available or not.
+ void *operator new(size_t s);
+
+ /// Use this function instead of "new" operator to create a new instance of this class.
+ /// This function automatically chooses a correct feature set depending on if the CPU
+ /// supports MMX/SSE/etc extensions.
+ static TDStretch *newInstance();
+
+ /// Returns the output buffer object
+ FIFOSamplePipe *getOutput() { return &outputBuffer; };
+
+ /// Returns the input buffer object
+ FIFOSamplePipe *getInput() { return &inputBuffer; };
+
+ /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
+ /// tempo, larger faster tempo.
+ void setTempo(float newTempo);
+
+ /// Returns nonzero if there aren't any samples available for outputting.
+ virtual void clear();
+
+ /// Clears the input buffer
+ void clearInput();
+
+ /// Sets the number of channels, 1 = mono, 2 = stereo
+ void setChannels(uint32_t numChannels);
+
+ /// Enables/disables the quick position seeking algorithm. Zero to disable,
+ /// nonzero to enable
+ void enableQuickSeek(bool enable);
+
+ /// Returns nonzero if the quick seeking algorithm is enabled.
+ bool isQuickSeekEnabled() const;
+
+ /// Sets routine control parameters. These control are certain time constants
+ /// defining how the sound is stretched to the desired duration.
+ //
+ /// 'sampleRate' = sample rate of the sound
+ /// 'sequenceMS' = one processing sequence length in milliseconds
+ /// 'seekwindowMS' = seeking window length for scanning the best overlapping
+ /// position
+ /// 'overlapMS' = overlapping length
+ void setParameters(uint32_t sampleRate, ///< Samplerate of sound being processed (Hz)
+ uint32_t sequenceMS = DEFAULT_SEQUENCE_MS, ///< Single processing sequence length (ms)
+ uint32_t seekwindowMS = DEFAULT_SEEKWINDOW_MS, ///< Offset seeking window length (ms)
+ uint32_t overlapMS = DEFAULT_OVERLAP_MS ///< Sequence overlapping length (ms)
+ );
+
+ /// Get routine control parameters, see setParameters() function.
+ /// Any of the parameters to this function can be NULL, in such case corresponding parameter
+ /// value isn't returned.
+ void getParameters(uint32_t *pSampleRate, uint32_t *pSequenceMs, uint32_t *pSeekWindowMs, uint32_t *pOverlapMs);
+
+ /// Adds 'numsamples' pcs of samples from the 'samples' memory position into
+ /// the input of the object.
+ virtual void putSamples(
+ const SAMPLETYPE *samples, ///< Input sample data
+ uint32_t numSamples ///< Number of samples in 'samples' so that one sample
+ ///< contains both channels if stereo
+ );
+};
+
+
+// Implementation-specific class declarations:
+
+//#ifdef ALLOW_MMX
+// /// Class that implements MMX optimized routines for 16bit integer samples type.
+// class TDStretchMMX : public TDStretch
+// {
+// protected:
+// long calcCrossCorrStereo(const short *mixingPos, const short *compare) const;
+// virtual void overlapStereo(short *output, const short *input) const;
+// virtual void clearCrossCorrState();
+// };
+//#endif /// ALLOW_MMX
+//
+//
+//#ifdef ALLOW_3DNOW
+// /// Class that implements 3DNow! optimized routines for floating point samples type.
+// class TDStretch3DNow : public TDStretch
+// {
+// protected:
+// double calcCrossCorrStereo(const float *mixingPos, const float *compare) const;
+// };
+//#endif /// ALLOW_3DNOW
+
+#ifdef __SSE__
+/// Class that implements SSE optimized routines for floating point samples type.
+class TDStretchSSE : public TDStretch
+{
+protected:
+ double calcCrossCorrStereo(const float *mixingPos, const float *compare) const;
+};
+#endif /// ALLOW_SSE
+
+}
+
+#endif /// TDStretch_H
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/cpu_detect.h
@@ -1,1 +1,63 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// A header file for detecting the Intel MMX instructions set extension.
+///
+/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the
+/// routine implementations for x86 Windows, x86 gnu version and non-x86
+/// platforms, respectively.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.4 $
+//
+// $Id: cpu_detect.h,v 1.4 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#ifndef _CPU_DETECT_H_
+#define _CPU_DETECT_H_
+
+#include "STTypes.h"
+
+#define SUPPORT_MMX 0x0001
+#define SUPPORT_3DNOW 0x0002
+#define SUPPORT_ALTIVEC 0x0004
+#define SUPPORT_SSE 0x0008
+#define SUPPORT_SSE2 0x0010
+
+/// Checks which instruction set extensions are supported by the CPU.
+///
+/// \return A bitmask of supported extensions, see SUPPORT_... defines.
+uint32_t detectCPUextensions();
+
+/// Disables given set of instruction extensions. See SUPPORT_... defines.
+void disableExtensions(uint32_t wDisableMask);
+
+#endif // _CPU_DETECT_H_
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/cpu_detect_x86_gcc.cpp
@@ -1,1 +1,139 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// gcc version of the x86 CPU detect routine.
+///
+/// This file is to be compiled on any platform with the GNU C compiler.
+/// Compiler. Please see 'cpu_detect_x86_win.cpp' for the x86 Windows version
+/// of this file.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.6 $
+//
+// $Id: cpu_detect_x86_gcc.cpp,v 1.6 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#include <stdexcept>
+#include <string>
+#include "cpu_detect.h"
+
+#ifndef __GNUC__
+#error wrong platform - this source code file is for the GNU C compiler.
+#endif
+
+using namespace std;
+
+#include <stdio.h>
+//////////////////////////////////////////////////////////////////////////////
+//
+// processor instructions extension detection routines
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+// Flag variable indicating whick ISA extensions are disabled (for debugging)
+static uint32_t _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
+
+// Disables given set of instruction extensions. See SUPPORT_... defines.
+void disableExtensions(uint32_t dwDisableMask)
+{
+ _dwDisabledISA = dwDisableMask;
+}
+
+
+
+/// Checks which instruction set extensions are supported by the CPU.
+uint32_t detectCPUextensions(void)
+{
+#ifndef __i386__
+ return 0; // always disable extensions on non-x86 platforms.
+#else
+ uint32_t res = 0;
+
+ if (_dwDisabledISA == 0xffffffff) return 0;
+
+ asm volatile(
+ "\n\txor %%esi, %%esi" // clear %%esi = result register
+ // check if 'cpuid' instructions is available by toggling eflags bit 21
+
+ "\n\tpushf" // save eflags to stack
+ "\n\tpop %%eax" // load eax from stack (with eflags)
+ "\n\tmovl %%eax, %%ecx" // save the original eflags values to ecx
+ "\n\txor $0x00200000, %%eax" // toggle bit 21
+ "\n\tpush %%eax" // store toggled eflags to stack
+ "\n\tpopf" // load eflags from stack
+ "\n\tpushf" // save updated eflags to stack
+ "\n\tpop %%eax" // load from stack
+ "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx
+ "\n\tcmp %%ecx, %%eax" // compare to original eflags values
+ "\n\tjz end" // jumps to 'end' if cpuid not present
+
+ // cpuid instruction available, test for presence of mmx instructions
+
+ "\n\tmovl $1, %%eax"
+ "\n\tcpuid"
+// movl $0x00800000, %edx // force enable MMX
+ "\n\ttest $0x00800000, %%edx"
+ "\n\tjz end" // branch if MMX not available
+
+ "\n\tor $0x01, %%esi" // otherwise add MMX support bit
+
+ "\n\ttest $0x02000000, %%edx"
+ "\n\tjz test3DNow" // branch if SSE not available
+
+ "\n\tor $0x08, %%esi" // otherwise add SSE support bit
+
+ "\n\ttest3DNow:"
+ // test for precense of AMD extensions
+ "\n\tmov $0x80000000, %%eax"
+ "\n\tcpuid"
+ "\n\tcmp $0x80000000, %%eax"
+ "\n\tjbe end" // branch if no AMD extensions detected
+
+ // test for precense of 3DNow! extension
+ "\n\tmov $0x80000001, %%eax"
+ "\n\tcpuid"
+ "\n\ttest $0x80000000, %%edx"
+ "\n\tjz end" // branch if 3DNow! not detected
+
+ "\n\tor $0x02, %%esi" // otherwise add 3DNow support bit
+
+ "\n\tend:"
+
+ "\n\tmov %%esi, %0"
+
+ : "=r" (res)
+ : /* no inputs */
+ : "%edx", "%eax", "%ecx", "%esi" );
+
+ return res & ~_dwDisabledISA;
+#endif
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/cpu_detect_x86_win.cpp
@@ -1,1 +1,130 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Win32 version of the x86 CPU detect routine.
+///
+/// This file is to be compiled in Windows platform with Microsoft Visual C++
+/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version
+/// for all GNU platforms.
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.10 $
+//
+// $Id: cpu_detect_x86_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+#include "cpu_detect.h"
+
+#ifndef _WIN32
+#error wrong platform - this source code file is exclusively for Win32 platform
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// processor instructions extension detection routines
+//
+//////////////////////////////////////////////////////////////////////////////
+
+// Flag variable indicating whick ISA extensions are disabled (for debugging)
+static uint32_t _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
+
+
+// Disables given set of instruction extensions. See SUPPORT_... defines.
+void disableExtensions(uint32_t dwDisableMask)
+{
+ _dwDisabledISA = dwDisableMask;
+}
+
+/// Checks which instruction set extensions are supported by the CPU.
+uint32_t detectCPUextensions()
+{
+ uint32_t res = 0;
+
+ if (_dwDisabledISA == 0xffffffff) return 0;
+
+ //zeromus 28-oct-2009 - changed to compile on 64bits msvc
+#if (defined(_MSC_VER) && !defined(_M_X64)) || !defined(_MSC_VER)
+
+ _asm
+ {
+ ; check if 'cpuid' instructions is available by toggling eflags bit 21
+ ;
+ xor esi, esi ; clear esi = result register
+
+ pushfd ; save eflags to stack
+ pop eax ; load eax from stack (with eflags)
+ mov ecx, eax ; save the original eflags values to ecx
+ xor eax, 0x00200000 ; toggle bit 21
+ push eax ; store toggled eflags to stack
+ popfd ; load eflags from stack
+ pushfd ; save updated eflags to stack
+ pop eax ; load from stack
+ xor edx, edx ; clear edx for defaulting no mmx
+ cmp eax, ecx ; compare to original eflags values
+ jz end ; jumps to 'end' if cpuid not present
+
+ ; cpuid instruction available, test for presence of mmx instructions
+ mov eax, 1
+ cpuid
+ test edx, 0x00800000
+ jz end ; branch if MMX not available
+
+ or esi, SUPPORT_MMX ; otherwise add MMX support bit
+
+ test edx, 0x02000000
+ jz test3DNow ; branch if SSE not available
+
+ or esi, SUPPORT_SSE ; otherwise add SSE support bit
+
+ test3DNow:
+ ; test for precense of AMD extensions
+ mov eax, 0x80000000
+ cpuid
+ cmp eax, 0x80000000
+ jbe end ; branch if no AMD extensions detected
+
+ ; test for precense of 3DNow! extension
+ mov eax, 0x80000001
+ cpuid
+ test edx, 0x80000000
+ jz end ; branch if 3DNow! not detected
+
+ or esi, SUPPORT_3DNOW ; otherwise add 3DNow support bit
+
+ end:
+
+ mov res, esi
+ }
+
+#endif
+
+ return res & ~_dwDisabledISA;
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/SoundTouch/sse_optimized.cpp
@@ -1,1 +1,485 @@
-
+////////////////////////////////////////////////////////////////////////////////
+///
+/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE
+/// optimized functions have been gathered into this single source
+/// code file, regardless to their class or original source code file, in order
+/// to ease porting the library to other compiler and processor platforms.
+///
+/// The SSE-optimizations are programmed using SSE compiler intrinsics that
+/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
+/// should compile with both toolsets.
+///
+/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
+/// 6.0 processor pack" update to support SSE instruction set. The update is
+/// available for download at Microsoft Developers Network, see here:
+/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx
+///
+/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
+/// perform a search with keywords "processor pack".
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// Last changed : $Date: 2006/02/05 16:44:06 $
+// File revision : $Revision: 1.2 $
+//
+// $Id: sse_optimized.cpp,v 1.2 2006/02/05 16:44:06 Olli Exp $
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// License :
+//
+// SoundTouch audio processing library
+// Copyright (c) Olli Parviainen
+//
+// This library 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 library 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 library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "cpu_detect.h"
+#include "STTypes.h"
+
+using namespace soundtouch;
+
+#ifdef __SSE__
+
+// SSE routines available only with float sample type
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// implementation of SSE optimized functions of class 'TDStretchSSE'
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include "TDStretch.h"
+#include <xmmintrin.h>
+
+// Calculates cross correlation of two buffers
+double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const
+{
+ uint32_t i;
+ __m128 vSum, *pVec2;
+
+ // Note. It means a major slow-down if the routine needs to tolerate
+ // unaligned __m128 memory accesses. It's way faster if we can skip
+ // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps.
+ // This can mean up to ~ 10-fold difference (incl. part of which is
+ // due to skipping every second round for stereo sound though).
+ //
+ // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided
+ // for choosing if this little cheating is allowed.
+
+#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION
+ // Little cheating allowed, return valid correlation only for
+ // aligned locations, meaning every second round for stereo sound.
+
+ #define _MM_LOAD _mm_load_ps
+
+ if (((uint64_t)pV1) & 15) return -1e50; // skip unaligned locations
+
+#else
+ // No cheating allowed, use unaligned load & take the resulting
+ // performance hit.
+ #define _MM_LOAD _mm_loadu_ps
+#endif
+
+ // ensure overlapLength is divisible by 8
+ assert((overlapLength % 8) == 0);
+
+ // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
+ // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not.
+ pVec2 = (__m128*)pV2;
+ vSum = _mm_setzero_ps();
+
+ // Unroll the loop by factor of 4 * 4 operations
+ for (i = 0; i < overlapLength / 8; i ++)
+ {
+ // vSum += pV1[0..3] * pV2[0..3]
+ vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1),pVec2[0]));
+
+ // vSum += pV1[4..7] * pV2[4..7]
+ vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 4), pVec2[1]));
+
+ // vSum += pV1[8..11] * pV2[8..11]
+ vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 8), pVec2[2]));
+
+ // vSum += pV1[12..15] * pV2[12..15]
+ vSum = _mm_add_ps(vSum, _mm_mul_ps(_MM_LOAD(pV1 + 12), pVec2[3]));
+
+ pV1 += 16;
+ pVec2 += 4;
+ }
+
+ // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3]
+ float *pvSum = (float*)&vSum;
+ return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]);
+
+ /* This is approximately corresponding routine in C-language:
+ double corr;
+ uint32_t i;
+
+ // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
+ corr = 0.0;
+ for (i = 0; i < overlapLength / 8; i ++)
+ {
+ corr += pV1[0] * pV2[0] +
+ pV1[1] * pV2[1] +
+ pV1[2] * pV2[2] +
+ pV1[3] * pV2[3] +
+ pV1[4] * pV2[4] +
+ pV1[5] * pV2[5] +
+ pV1[6] * pV2[6] +
+ pV1[7] * pV2[7] +
+ pV1[8] * pV2[8] +
+ pV1[9] * pV2[9] +
+ pV1[10] * pV2[10] +
+ pV1[11] * pV2[11] +
+ pV1[12] * pV2[12] +
+ pV1[13] * pV2[13] +
+ pV1[14] * pV2[14] +
+ pV1[15] * pV2[15];
+
+ pV1 += 16;
+ pV2 += 16;
+ }
+ */
+
+ /* This is corresponding routine in assembler. This may be teeny-weeny bit faster
+ than intrinsic version, but more difficult to maintain & get compiled on multiple
+ platforms.
+
+ uint32_t overlapLengthLocal = overlapLength;
+ float corr;
+
+ _asm
+ {
+ // Very important note: data in 'pV2' _must_ be aligned to
+ // 16-byte boundary!
+
+ // give prefetch hints to CPU of what data are to be needed soonish
+ // give more aggressive hints on pV1 as that changes while pV2 stays
+ // same between runs
+ prefetcht0 [pV1]
+ prefetcht0 [pV2]
+ prefetcht0 [pV1 + 32]
+
+ mov eax, dword ptr pV1
+ mov ebx, dword ptr pV2
+
+ xorps xmm0, xmm0
+
+ mov ecx, overlapLengthLocal
+ shr ecx, 3 // div by eight
+
+ loop1:
+ prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish
+ prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish
+ movups xmm1, [eax]
+ mulps xmm1, [ebx]
+ addps xmm0, xmm1
+
+ movups xmm2, [eax + 16]
+ mulps xmm2, [ebx + 16]
+ addps xmm0, xmm2
+
+ prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish
+ prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish
+
+ movups xmm3, [eax + 32]
+ mulps xmm3, [ebx + 32]
+ addps xmm0, xmm3
+
+ movups xmm4, [eax + 48]
+ mulps xmm4, [ebx + 48]
+ addps xmm0, xmm4
+
+ add eax, 64
+ add ebx, 64
+
+ dec ecx
+ jnz loop1
+
+ // add the four floats of xmm0 together and return the result.
+
+ movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1
+ addps xmm1, xmm0
+ movaps xmm2, xmm1
+ shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2
+ addss xmm2, xmm1
+ movss corr, xmm2
+ }
+
+ return (double)corr;
+ */
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// implementation of SSE optimized functions of class 'FIRFilter'
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include "FIRFilter.h"
+
+FIRFilterSSE::FIRFilterSSE() : FIRFilter()
+{
+ filterCoeffsUnalign = NULL;
+}
+
+
+FIRFilterSSE::~FIRFilterSSE()
+{
+ delete[] filterCoeffsUnalign;
+}
+
+
+// (overloaded) Calculates filter coefficients for SSE routine
+void FIRFilterSSE::setCoefficients(const float *coeffs, uint32_t newLength, uint32_t uResultDivFactor)
+{
+ uint32_t i;
+ float fDivider;
+
+ FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
+
+ // Scale the filter coefficients so that it won't be necessary to scale the filtering result
+ // also rearrange coefficients suitably for 3DNow!
+ // Ensure that filter coeffs array is aligned to 16-byte boundary
+ delete[] filterCoeffsUnalign;
+ filterCoeffsUnalign = new float[2 * newLength + 4];
+ filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & -16);
+
+ fDivider = (float)resultDivider;
+
+ // rearrange the filter coefficients for mmx routines
+ for (i = 0; i < newLength; i ++)
+ {
+ filterCoeffsAlign[2 * i + 0] =
+ filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider;
+ }
+}
+
+
+
+// SSE-optimized version of the filter routine for stereo sound
+uint32_t FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint32_t numSamples) const
+{
+ int count = (numSamples - length) & -2;
+ int j;
+
+ assert(count % 2 == 0);
+
+ if (count < 2) return 0;
+
+ assert((length % 8) == 0);
+ assert(((unsigned long)filterCoeffsAlign) % 16 == 0);
+
+ // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2'
+ for (j = 0; j < count; j += 2)
+ {
+ const float *pSrc;
+ const __m128 *pFil;
+ __m128 sum1, sum2;
+ uint32_t i;
+
+ pSrc = source; // source audio data
+ pFil = (__m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients
+ // are aligned to 16-byte boundary
+ sum1 = sum2 = _mm_setzero_ps();
+
+ for (i = 0; i < length / 8; i ++)
+ {
+ // Unroll loop for efficiency & calculate filter for 2*2 stereo samples
+ // at each pass
+
+ // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset
+ // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset.
+
+ sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0]));
+ sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0]));
+
+ sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1]));
+ sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1]));
+
+ sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2]));
+ sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2]));
+
+ sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3]));
+ sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3]));
+
+ pSrc += 16;
+ pFil += 4;
+ }
+
+ // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need
+ // to sum the two hi- and lo-floats of these registers together.
+
+ // post-shuffle & add the filtered values and store to dest.
+ _mm_storeu_ps(dest, _mm_add_ps(
+ _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2
+ _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0
+ ));
+ source += 4;
+ dest += 4;
+ }
+
+ // Ideas for further improvement:
+ // 1. If it could be guaranteed that 'source' were always aligned to 16-byte
+ // boundary, a faster aligned '_mm_load_ps' instruction could be used.
+ // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte
+ // boundary, a faster '_mm_store_ps' instruction could be used.
+
+ return (uint32_t)count;
+
+ /* original routine in C-language. please notice the C-version has differently
+ organized coefficients though.
+ double suml1, suml2;
+ double sumr1, sumr2;
+ uint32_t i, j;
+
+ for (j = 0; j < count; j += 2)
+ {
+ const float *ptr;
+ const float *pFil;
+
+ suml1 = sumr1 = 0.0;
+ suml2 = sumr2 = 0.0;
+ ptr = src;
+ pFil = filterCoeffs;
+ for (i = 0; i < lengthLocal; i ++)
+ {
+ // unroll loop for efficiency.
+
+ suml1 += ptr[0] * pFil[0] +
+ ptr[2] * pFil[2] +
+ ptr[4] * pFil[4] +
+ ptr[6] * pFil[6];
+
+ sumr1 += ptr[1] * pFil[1] +
+ ptr[3] * pFil[3] +
+ ptr[5] * pFil[5] +
+ ptr[7] * pFil[7];
+
+ suml2 += ptr[8] * pFil[0] +
+ ptr[10] * pFil[2] +
+ ptr[12] * pFil[4] +
+ ptr[14] * pFil[6];
+
+ sumr2 += ptr[9] * pFil[1] +
+ ptr[11] * pFil[3] +
+ ptr[13] * pFil[5] +
+ ptr[15] * pFil[7];
+
+ ptr += 16;
+ pFil += 8;
+ }
+ dest[0] = (float)suml1;
+ dest[1] = (float)sumr1;
+ dest[2] = (float)suml2;
+ dest[3] = (float)sumr2;
+
+ src += 4;
+ dest += 4;
+ }
+ */
+
+
+ /* Similar routine in assembly, again obsoleted due to maintainability
+ _asm
+ {
+ // Very important note: data in 'src' _must_ be aligned to
+ // 16-byte boundary!
+ mov edx, count
+ mov ebx, dword ptr src
+ mov eax, dword ptr dest
+ shr edx, 1
+
+ loop1:
+ // "outer loop" : during each round 2*2 output samples are calculated
+
+ // give prefetch hints to CPU of what data are to be needed soonish
+ prefetcht0 [ebx]
+ prefetcht0 [filterCoeffsLocal]
+
+ mov esi, ebx
+ mov edi, filterCoeffsLocal
+ xorps xmm0, xmm0
+ xorps xmm1, xmm1
+ mov ecx, lengthLocal
+
+ loop2:
+ // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples
+ prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish
+ prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish
+
+ movups xmm2, [esi] // possibly unaligned load
+ movups xmm3, [esi + 8] // possibly unaligned load
+ mulps xmm2, [edi]
+ mulps xmm3, [edi]
+ addps xmm0, xmm2
+ addps xmm1, xmm3
+
+ movups xmm4, [esi + 16] // possibly unaligned load
+ movups xmm5, [esi + 24] // possibly unaligned load
+ mulps xmm4, [edi + 16]
+ mulps xmm5, [edi + 16]
+ addps xmm0, xmm4
+ addps xmm1, xmm5
+
+ prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish
+ prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish
+
+ movups xmm6, [esi + 32] // possibly unaligned load
+ movups xmm7, [esi + 40] // possibly unaligned load
+ mulps xmm6, [edi + 32]
+ mulps xmm7, [edi + 32]
+ addps xmm0, xmm6
+ addps xmm1, xmm7
+
+ movups xmm4, [esi + 48] // possibly unaligned load
+ movups xmm5, [esi + 56] // possibly unaligned load
+ mulps xmm4, [edi + 48]
+ mulps xmm5, [edi + 48]
+ addps xmm0, xmm4
+ addps xmm1, xmm5
+
+ add esi, 64
+ add edi, 64
+ dec ecx
+ jnz loop2
+
+ // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need
+ // to sum the two hi- and lo-floats of these registers together.
+
+ movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2
+ movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2
+ shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0
+ addps xmm0, xmm2
+
+ movaps [eax], xmm0
+ add ebx, 16
+ add eax, 16
+
+ dec edx
+ jnz loop1
+ }
+ */
+}
+
+#endif // ALLOW_SSE
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/Timestretcher.cpp
@@ -1,1 +1,353 @@
-
+/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
+* Developed and maintained by the Pcsx2 Development Team.
+*
+* Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
+*
+* SPU2-X 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 Found-
+* ation, either version 3 of the License, or (at your option) any later version.
+*
+* SPU2-X 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 SPU2-X. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "XSFCommon.h"
+
+//#include "Global.h"
+#include "types.h"
+#include "SoundTouch/SoundTouch.h"
+#include "SndOut.h"
+//#include "SoundTouch/WavFile.h"
+
+#include "SoundTouch/Dialogs.h"
+
+static soundtouch::SoundTouch* pSoundTouch = NULL;
+static int ts_stats_stretchblocks = 0;
+static int ts_stats_normalblocks = 0;
+static int ts_stats_logcounter = 0;
+
+// data prediction amount, used to "commit" data that hasn't
+// finished timestretch processing.
+int32_t SndBuffer::m_predictData;
+
+// records last buffer status (fill %, range -100 to 100, with 0 being 50% full)
+float SndBuffer::lastPct;
+float SndBuffer::lastEmergencyAdj;
+
+float SndBuffer::cTempo = 1;
+float SndBuffer::eTempo = 1;
+int SndBuffer::freezeTempo = 0;
+
+void SndBuffer::PredictDataWrite( int samples )
+{
+ m_predictData += samples;
+}
+
+// Calculate the buffer status percentage.
+// Returns range from -1.0 to 1.0
+// 1.0 = buffer overflow!
+// 0.0 = buffer nominal (50% full)
+// -1.0 = buffer underflow!
+float SndBuffer::GetStatusPct()
+{
+ // Get the buffer status of the output driver too, so that we can
+ // obtain a more accurate overall buffer status.
+
+ int drvempty = 0;
+ //int drvempty = mods[OutputModule]->GetEmptySampleCount(); // / 2;
+ //TODO
+
+ //ConLog( "Data %d >>> driver: %d predict: %d\n", data, drvempty, predictData );
+
+ float result = (float)(m_data + m_predictData - drvempty) - (m_size/2);
+ result /= (m_size/2);
+ return result;
+}
+
+void SndBuffer::UpdateTempoChange()
+{
+ if( --freezeTempo > 0 )
+ {
+ return;
+ }
+
+ float statusPct = GetStatusPct();
+ float pctChange = statusPct - lastPct;
+
+ float tempoChange;
+ float emergencyAdj = 0;
+ float newcee = cTempo; // workspace var. for cTempo
+
+ // IMPORTANT!
+ // If you plan to tweak these values, make sure you're using a release build
+ // OUTSIDE THE DEBUGGER to test it! The Visual Studio debugger can really cause
+ // erratic behavior in the audio buffers, and makes the timestretcher seem a
+ // lot more inconsistent than it really is.
+
+ // We have two factors.
+ // * Distance from nominal buffer status (50% full)
+ // * The change from previous update to this update.
+
+ // Prediction based on the buffer change:
+ // (linear seems to work better here)
+
+ tempoChange = pctChange * 0.75f;
+
+ if( statusPct * tempoChange < 0.0f )
+ {
+ // only apply tempo change if it is in synch with the buffer status.
+ // In other words, if the buffer is high (over 0%), and is decreasing,
+ // ignore it. It'll just muck things up.
+
+ tempoChange = 0;
+ }
+
+ // Sudden spikes in framerate can cause the nominal buffer status
+ // to go critical, in which case we have to enact an emergency
+ // stretch. The following cubic formulas do that. Values near
+ // the extremeites give much larger results than those near 0.
+ // And the value is added only this time, and does not accumulate.
+ // (otherwise a large value like this would cause problems down the road)
+
+ // Constants:
+ // Weight - weights the statusPct's "emergency" consideration.
+ // higher values here will make the buffer perform more drastic
+ // compensations at the outer edges of the buffer (at -75 or +75%
+ // or beyond, for example).
+
+ // Range - scales the adjustment to the given range (more or less).
+ // The actual range is dependent on the weight used, so if you increase
+ // Weight you'll usually want to decrease Range somewhat to compensate.
+
+ // Prediction based on the buffer fill status:
+
+ const float statusWeight = 2.99f;
+ const float statusRange = 0.068f;
+
+ // "non-emergency" deadzone: In this area stretching will be strongly discouraged.
+ // Note: due tot he nature of timestretch latency, it's always a wee bit harder to
+ // cope with low fps (underruns) than it is high fps (overruns). So to help out a
+ // little, the low-end portions of this check are less forgiving than the high-sides.
+
+ if( cTempo < 0.965f || cTempo > 1.060f ||
+ pctChange < -0.38f || pctChange > 0.54f ||
+ statusPct < -0.32f || statusPct > 0.39f ||
+ eTempo < 0.89f || eTempo > 1.19f )
+ {
+ emergencyAdj = ( pow( statusPct*statusWeight, 3.0f ) * statusRange);
+ }
+
+ // Smooth things out by factoring our previous adjustment into this one.
+ // It helps make the system 'feel' a little smarter by giving it at least
+ // one packet worth of history to help work off of:
+
+ emergencyAdj = (emergencyAdj * 0.75f) + (lastEmergencyAdj * 0.25f );
+
+ lastEmergencyAdj = emergencyAdj;
+ lastPct = statusPct;
+
+ // Accumulate a fraction of the tempo change into the tempo itself.
+ // This helps the system run "smarter" to games that run consistently
+ // fast or slow by altering the base tempo to something closer to the
+ // game's active speed. In tests most games normalize within 2 seconds
+ // at 100ms latency, which is pretty good (larger buffers normalize even
+ // quicker).
+
+ newcee += newcee * (tempoChange+emergencyAdj) * 0.03f;
+
+ // Apply tempoChange as a scale of cTempo. That way the effect is proportional
+ // to the current tempo. (otherwise tempos rate of change at the extremes would
+ // be too drastic)
+
+ float newTempo = newcee + ( emergencyAdj * cTempo );
+
+ // ... and as a final optimization, only stretch if the new tempo is outside
+ // a nominal threshold. Keep this threshold check small, because it could
+ // cause some serious side effects otherwise. (enlarging the cTempo check above
+ // is usually better/safer)
+ if( newTempo < 0.970f || newTempo > 1.045f )
+ {
+ cTempo = (float)newcee;
+
+ if( newTempo < 0.10f ) newTempo = 0.10f;
+ else if( newTempo > 10.0f ) newTempo = 10.0f;
+
+ if( cTempo < 0.15f ) cTempo = 0.15f;
+ else if( cTempo > 7.5f ) cTempo = 7.5f;
+
+ pSoundTouch->setTempo( eTempo = (float)newTempo );
+ ts_stats_stretchblocks++;
+
+ /*ConLog(" * SPU2: [Nominal %d%%] [Emergency: %d%%] (baseTempo: %d%% ) (newTempo: %d%%) (buffer: %d%%)\n",
+ //(relation < 0.0) ? "Normalize" : "",
+ (int)(tempoChange * 100.0 * 0.03),
+ (int)(emergencyAdj * 100.0),
+ (int)(cTempo * 100.0),
+ (int)(newTempo * 100.0),
+ (int)(statusPct * 100.0)
+ );*/
+ }
+ else
+ {
+ // Nominal operation -- turn off stretching.
+ // note: eTempo 'slides' toward 1.0 for smoother audio and better
+ // protection against spikes.
+ if (!fEqual(cTempo, 1.0f))
+ {
+ cTempo = 1.0f;
+ eTempo = ( 1.0f + eTempo ) * 0.5f;
+ pSoundTouch->setTempo( eTempo );
+ }
+ else
+ {
+ if (!fEqual(eTempo, cTempo))
+ pSoundTouch->setTempo( eTempo=cTempo );
+ ts_stats_normalblocks++;
+ }
+ }
+}
+
+void SndBuffer::timeStretchUnderrun()
+{
+ // timeStretcher failed it's job. We need to slow down the audio some.
+
+ cTempo -= (cTempo * 0.12f);
+ eTempo -= (eTempo * 0.30f);
+ if( eTempo < 0.1f ) eTempo = 0.1f;
+ pSoundTouch->setTempo( eTempo );
+}
+
+int32_t SndBuffer::timeStretchOverrun()
+{
+ // If we overran it means the timestretcher failed. We need to speed
+ // up audio playback.
+ cTempo += cTempo * 0.12f;
+ eTempo += eTempo * 0.40f;
+ if( eTempo > 7.5f ) eTempo = 7.5f;
+ pSoundTouch->setTempo( eTempo );
+
+ // Throw out just a little bit (two packets worth) to help
+ // give the TS some room to work:
+
+ return SndOutPacketSize*2;
+}
+
+static void CvtPacketToFloat( StereoOut32* srcdest )
+{
+ StereoOutFloat* dest = (StereoOutFloat*)srcdest;
+ const StereoOut32* src = (StereoOut32*)srcdest;
+ for( int i=0; i<SndOutPacketSize; ++i, ++dest, ++src )
+ *dest = (StereoOutFloat)*src;
+}
+
+// Parameter note: Size should always be a multiple of 128, thanks!
+static void CvtPacketToInt( StereoOut32* srcdest, uint32_t size )
+{
+ //jASSUME( (size & 127) == 0 );
+
+ const StereoOutFloat* src = (StereoOutFloat*)srcdest;
+ StereoOut32* dest = srcdest;
+
+ for( uint32_t i=0; i<size; ++i, ++dest, ++src )
+ *dest = (StereoOut32)*src;
+}
+
+void SndBuffer::timeStretchWrite()
+{
+ bool progress = false;
+
+ // data prediction helps keep the tempo adjustments more accurate.
+ // The timestretcher returns packets in belated "clump" form.
+ // Meaning that most of the time we'll get nothing back, and then
+ // suddenly we'll get several chunks back at once. Thus we use
+ // data prediction to make the timestretcher more responsive.
+
+ PredictDataWrite( (int)( SndOutPacketSize / eTempo ) );
+ CvtPacketToFloat( sndTempBuffer );
+
+ pSoundTouch->putSamples( (float*)sndTempBuffer, SndOutPacketSize );
+
+ int tempProgress;
+ while( tempProgress = pSoundTouch->receiveSamples( (float*)sndTempBuffer, SndOutPacketSize),
+ tempProgress != 0 )
+ {
+ // Hint: It's assumed that pSoundTouch will return chunks of 128 bytes (it always does as
+ // long as the SSE optimizations are enabled), which means we can do our own SSE opts here.
+
+ CvtPacketToInt( sndTempBuffer, tempProgress );
+ _WriteSamples( sndTempBuffer, tempProgress );
+ progress = true;
+ }
+
+ UpdateTempoChange();
+
+ //TODO
+ //if( MsgOverruns() )
+ {
+ if( progress )
+ {
+ if( ++ts_stats_logcounter > 300 )
+ {
+ ts_stats_logcounter = 0;
+ printf( " * SPU2 > Timestretch Stats > %d%% of packets stretched.\n",
+ ( ts_stats_stretchblocks * 100 ) / ( ts_stats_normalblocks + ts_stats_stretchblocks ) );
+ ts_stats_normalblocks = 0;
+ ts_stats_stretchblocks = 0;
+ }
+ }
+ }
+}
+
+void SndBuffer::soundtouchInit()
+{
+ pSoundTouch = new soundtouch::SoundTouch();
+ pSoundTouch->setSampleRate(SampleRate);
+ pSoundTouch->setChannels(2);
+
+ pSoundTouch->setSetting( soundtouch::SETTING_USE_QUICKSEEK, 0 );
+ pSoundTouch->setSetting( soundtouch::SETTING_USE_AA_FILTER, 0 );
+
+ SoundtouchCfg::ApplySettings( *pSoundTouch );
+
+ pSoundTouch->setTempo(1);
+
+ // some timestretch management vars:
+
+ cTempo = 1.0;
+ eTempo = 1.0;
+ lastPct = 0;
+ lastEmergencyAdj = 0;
+
+ // just freeze tempo changes for a while at startup.
+ // the driver buffers are bogus anyway.
+ freezeTempo = 16;
+ m_predictData = 0;
+}
+
+// reset timestretch management vars, and delay updates a bit:
+void SndBuffer::soundtouchClearContents()
+{
+ if( pSoundTouch == NULL ) return;
+
+ pSoundTouch->clear();
+ pSoundTouch->setTempo(1);
+
+ cTempo = 1.0;
+ eTempo = 1.0;
+ lastPct = 0;
+ lastEmergencyAdj = 0;
+
+ freezeTempo = 16;
+ m_predictData = 0;
+}
+
+void SndBuffer::soundtouchCleanup()
+{
+ //safe_delete( pSoundTouch );
+ delete pSoundTouch;
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/metaspu.cpp
@@ -1,1 +1,519 @@
-
+/* Copyright 2009 DeSmuME team
+
+ This file is part of DeSmuME
+
+ DeSmuME is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DeSmuME 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DeSmuME; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <queue>
+#include <vector>
+#include <cassert>
+
+#include "types.h"
+#include "metaspu.h"
+
+//for pcsx2 method
+//(havent bothered to get it compiling in gcc yet)
+#ifdef _MSC_VER
+#include "SndOut.h"
+#endif
+
+/*template<typename T> inline T _abs(T val)
+{
+ if(val<0) return -val;
+ else return val;
+}*/
+
+/*template<typename T> inline T moveValueTowards(T val, T target, T incr)
+{
+ incr = _abs(incr);
+ T delta = _abs(target-val);
+ if(val<target) val += incr;
+ else if(val>target) val -= incr;
+ T newDelta = _abs(target-val);
+ if(newDelta >= delta)
+ val = target;
+ return val;
+}*/
+
+class ZeromusSynchronizer : public ISynchronizingAudioBuffer
+{
+public:
+ ZeromusSynchronizer()
+ : mixqueue_go(false)
+ ,
+ #ifdef NDEBUG
+ adjustobuf(200,1000)
+ #else
+ adjustobuf(22000,44000)
+ #endif
+ {
+
+ }
+
+ bool mixqueue_go;
+
+ virtual void enqueue_samples(int16_t* buf, int samples_provided)
+ {
+ for(int i=0;i<samples_provided;i++) {
+ int16_t left = *buf++;
+ int16_t right = *buf++;
+ adjustobuf.enqueue(left,right);
+ }
+ }
+
+ //returns the number of samples actually supplied, which may not match the number requested
+ virtual int output_samples(int16_t* buf, int samples_requested)
+ {
+ int done = 0;
+ if(!mixqueue_go) {
+ if(adjustobuf.size > 200)
+ mixqueue_go = true;
+ }
+ else
+ {
+ for(int i=0;i<samples_requested;i++) {
+ if(adjustobuf.size==0) {
+ mixqueue_go = false;
+ break;
+ }
+ done++;
+ int16_t left, right;
+ adjustobuf.dequeue(left,right);
+ *buf++ = left;
+ *buf++ = right;
+ }
+ }
+
+ return done;
+ }
+
+private:
+ class Adjustobuf
+ {
+ public:
+ Adjustobuf(int _minLatency, int _maxLatency)
+ : minLatency(_minLatency)
+ , maxLatency(_maxLatency)
+ , size(0)
+ {
+ rollingTotalSize = 0;
+ targetLatency = (maxLatency + minLatency)/2;
+ rate = 1.0f;
+ cursor = 0.0f;
+ curr[0] = curr[1] = 0;
+ kAverageSize = 80000;
+ }
+
+ float rate, cursor;
+ int minLatency, targetLatency, maxLatency;
+ std::queue<int16_t> buffer;
+ int size;
+ int16_t curr[2];
+
+ std::queue<int> statsHistory;
+
+ void enqueue(int16_t left, int16_t right)
+ {
+ buffer.push(left);
+ buffer.push(right);
+ size++;
+ }
+
+ int64_t rollingTotalSize;
+
+ uint32_t kAverageSize;
+
+ void addStatistic()
+ {
+ statsHistory.push(size);
+ rollingTotalSize += size;
+ if(statsHistory.size()>kAverageSize)
+ {
+ rollingTotalSize -= statsHistory.front();
+ statsHistory.pop();
+
+ float averageSize = (float)(rollingTotalSize / kAverageSize);
+ //static int ctr=0; ctr++; if((ctr&127)==0) printf("avg size: %f curr size: %d rate: %f\n",averageSize,size,rate);
+ {
+ float targetRate;
+ if(averageSize < targetLatency)
+ {
+ targetRate = 1.0f - (targetLatency-averageSize)/kAverageSize;
+ }
+ else if(averageSize > targetLatency) {
+ targetRate = 1.0f + (averageSize-targetLatency)/kAverageSize;
+ } else targetRate = 1.0f;
+
+ //rate = moveValueTowards(rate,targetRate,0.001f);
+ rate = targetRate;
+ }
+
+ }
+
+
+ }
+
+ void dequeue(int16_t& left, int16_t& right)
+ {
+ left = right = 0;
+ addStatistic();
+ if(size==0) { return; }
+ cursor += rate;
+ while(cursor>1.0f) {
+ cursor -= 1.0f;
+ if(size>0) {
+ curr[0] = buffer.front(); buffer.pop();
+ curr[1] = buffer.front(); buffer.pop();
+ size--;
+ }
+ }
+ left = curr[0];
+ right = curr[1];
+ }
+ } adjustobuf;
+};
+
+class NitsujaSynchronizer : public ISynchronizingAudioBuffer
+{
+private:
+ struct ssamp
+ {
+ int16_t l, r;
+ ssamp() {}
+ ssamp(int16_t ll, int16_t rr) : l(ll), r(rr) {}
+ };
+
+ std::vector<ssamp> sampleQueue;
+
+ // returns values going between 0 and y-1 in a saw wave pattern, based on x
+ static inline int pingpong(int x, int y)
+ {
+ x %= 2*y;
+ if(x >= y)
+ x = 2*y - x - 1;
+ return x;
+
+ // in case we want to switch to odd buffer sizes for more sharpness
+ //x %= 2*(y-1);
+ //if(x >= y)
+ // x = 2*(y-1) - x;
+ //return x;
+ }
+
+ static inline ssamp crossfade (ssamp lhs, ssamp rhs, int cur, int start, int end)
+ {
+ if(cur <= start)
+ return lhs;
+ if(cur >= end)
+ return rhs;
+
+ // in case we want sine wave interpolation instead of linear here
+ //float ang = 3.14159f * (float)(cur - start) / (float)(end - start);
+ //cur = start + (int)((1-cosf(ang))*0.5f * (end - start));
+
+ int inNum = cur - start;
+ int outNum = end - cur;
+ int denom = end - start;
+
+ int lrv = ((int)lhs.l * outNum + (int)rhs.l * inNum) / denom;
+ int rrv = ((int)lhs.r * outNum + (int)rhs.r * inNum) / denom;
+
+ return ssamp(lrv,rrv);
+ }
+
+ static inline void emit_sample(int16_t*& outbuf, ssamp sample)
+ {
+ *outbuf++ = sample.l;
+ *outbuf++ = sample.r;
+ }
+
+ static inline void emit_samples(int16_t*& outbuf, const ssamp* samplebuf, int samples)
+ {
+ for(int i=0;i<samples;i++)
+ emit_sample(outbuf,samplebuf[i]);
+ }
+
+public:
+ NitsujaSynchronizer()
+ {}
+
+ virtual void enqueue_samples(int16_t* buf, int samples_provided)
+ {
+ for(int i=0;i<samples_provided;i++)
+ {
+ sampleQueue.push_back(ssamp(buf[0],buf[1]));
+ buf += 2;
+ }
+ }
+
+ virtual int output_samples(int16_t* buf, int samples_requested)
+ {
+ int audiosize = samples_requested;
+ int queued = sampleQueue.size();
+
+ // I am too lazy to deal with odd numbers
+ audiosize &= ~1;
+ queued &= ~1;
+
+ if(queued > 0x200 && audiosize > 0) // is there any work to do?
+ {
+ // are we going at normal speed?
+ // or more precisely, are the input and output queues/buffers of similar size?
+ if(queued > 900 || audiosize > queued * 2)
+ {
+ // not normal speed. we have to resample it somehow in this case.
+ if(audiosize <= queued)
+ {
+ // fast forward speed
+ // this is the easy case, just crossfade it and it sounds ok
+ for(int i = 0; i < audiosize; i++)
+ {
+ int j = i + queued - audiosize;
+ ssamp outsamp = crossfade(sampleQueue[i],sampleQueue[j], i,0,audiosize);
+ emit_sample(buf,outsamp);
+ }
+ }
+ else
+ {
+ // slow motion speed
+ // here we take a very different approach,
+ // instead of crossfading it, we select a single sample from the queue
+ // and make sure that the index we use to select a sample is constantly moving
+ // and that it starts at the first sample in the queue and ends on the last one.
+ //
+ // hopefully the index doesn't move discontinuously or we'll get slight crackling
+ // (there might still be a minor bug here that causes this occasionally)
+ //
+ // here's a diagram of how the index we sample from moves:
+ //
+ // queued (this axis represents the index we sample from. the top means the end of the queue)
+ // ^
+ // | --> audiosize (this axis represents the output index we write to, right meaning forward in output time/position)
+ // | A C C end
+ // A A B C C C
+ // A A A B C C C
+ // A A A B C C
+ // A A C
+ // start
+ //
+ // yes, this means we are spending some stretches of time playing the sound backwards,
+ // but the stretches are short enough that this doesn't sound weird.
+ // this lets us avoid most crackling problems due to the endpoints matching up.
+
+ // first calculate a shorter-than-full window
+ // that has minimal slope at the endpoints
+ // (to further reduce crackling, especially in sine waves)
+ int beststart = 0, extraAtEnd = 0;
+ {
+ int bestend = queued;
+ static const int worstdiff = 99999999;
+ int beststartdiff = worstdiff;
+ int bestenddiff = worstdiff;
+ for(int i = 0; i < 128; i+=2)
+ {
+ int diff = abs(sampleQueue[i].l - sampleQueue[i+1].l) + abs(sampleQueue[i].r - sampleQueue[i+1].r);
+ if(diff < beststartdiff)
+ {
+ beststartdiff = diff;
+ beststart = i;
+ }
+ }
+ for(int i = queued-3; i > queued-3-128; i-=2)
+ {
+ int diff = abs(sampleQueue[i].l - sampleQueue[i+1].l) + abs(sampleQueue[i].r - sampleQueue[i+1].r);
+ if(diff < bestenddiff)
+ {
+ bestenddiff = diff;
+ bestend = i+1;
+ }
+ }
+
+ extraAtEnd = queued - bestend;
+ queued = bestend - beststart;
+
+ int oksize = queued;
+ while(oksize + queued*2 + beststart + extraAtEnd <= samples_requested)
+ oksize += queued*2;
+ audiosize = oksize;
+
+ for(int x = 0; x < beststart; x++)
+ {
+ emit_sample(buf,sampleQueue[x]);
+ }
+ sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin() + beststart);
+ }
+
+
+ int midpointX = audiosize >> 1;
+ int midpointY = queued >> 1;
+
+ // all we need to do here is calculate the X position of the leftmost "B" in the above diagram.
+ // TODO: we should calculate it with a simple equation like
+ // midpointXOffset = min(something,somethingElse);
+ // but it's a little difficult to work it out exactly
+ // so here's a stupid search for the value for now:
+
+ int prevA = 999999;
+ int midpointXOffset = queued/2;
+ while(true)
+ {
+ int a = abs(pingpong(midpointX - midpointXOffset, queued) - midpointY) - midpointXOffset;
+ if(((a > 0) != (prevA > 0) || (a < 0) != (prevA < 0)) && prevA != 999999)
+ {
+ if((a + prevA)&1) // there's some sort of off-by-one problem with this search since we're moving diagonally...
+ midpointXOffset++; // but this fixes it most of the time...
+ break; // found it
+ }
+ prevA = a;
+ midpointXOffset--;
+ if(midpointXOffset < 0)
+ {
+ midpointXOffset = 0;
+ break; // failed to find it. the two sides probably meet exactly in the center.
+ }
+ }
+
+ int leftMidpointX = midpointX - midpointXOffset;
+ int rightMidpointX = midpointX + midpointXOffset;
+ int leftMidpointY = pingpong(leftMidpointX, queued);
+ int rightMidpointY = (queued-1) - pingpong((int)audiosize-1 - rightMidpointX + queued*2, queued);
+
+ // output the left almost-half of the sound (section "A")
+ for(int x = 0; x < leftMidpointX; x++)
+ {
+ int i = pingpong(x, queued);
+ emit_sample(buf,sampleQueue[i]);
+ }
+
+ // output the middle stretch (section "B")
+ int y = leftMidpointY;
+ int dyMidLeft = (leftMidpointY < midpointY) ? 1 : -1;
+ int dyMidRight = (rightMidpointY > midpointY) ? 1 : -1;
+ for(int x = leftMidpointX; x < midpointX; x++, y+=dyMidLeft)
+ emit_sample(buf,sampleQueue[y]);
+ for(int x = midpointX; x < rightMidpointX; x++, y+=dyMidRight)
+ emit_sample(buf,sampleQueue[y]);
+
+ // output the end of the queued sound (section "C")
+ for(int x = rightMidpointX; x < audiosize; x++)
+ {
+ int i = (queued-1) - pingpong((int)audiosize-1 - x + queued*2, queued);
+ emit_sample(buf,sampleQueue[i]);
+ }
+
+ for(int x = 0; x < extraAtEnd; x++)
+ {
+ int i = queued + x;
+ emit_sample(buf,sampleQueue[i]);
+ }
+ queued += extraAtEnd;
+ audiosize += beststart + extraAtEnd;
+ } //end else
+
+ sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin() + queued);
+ return audiosize;
+ }
+ else
+ {
+ // normal speed
+ // just output the samples straightforwardly.
+ //
+ // at almost-full speeds (like 50/60 FPS)
+ // what will happen is that we rapidly fluctuate between entering this branch
+ // and entering the "slow motion speed" branch above.
+ // but that's ok! because all of these branches sound similar enough that we can get away with it.
+ // so the two cases actually complement each other.
+
+ if(audiosize >= queued)
+ {
+ emit_samples(buf,&sampleQueue[0],queued);
+ sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin() + queued);
+ return queued;
+ }
+ else
+ {
+ emit_samples(buf,&sampleQueue[0],audiosize);
+ sampleQueue.erase(sampleQueue.begin(), sampleQueue.begin()+audiosize);
+ return audiosize;
+ }
+
+ } //end normal speed
+
+ } //end if there is any work to do
+ else
+ {
+ return 0;
+ }
+
+ } //output_samples
+
+private:
+
+}; //NitsujaSynchronizer
+
+#ifdef _MSC_VER
+class PCSX2Synchronizer : public ISynchronizingAudioBuffer
+{
+public:
+ std::queue<int16_t> readySamples;
+ PCSX2Synchronizer()
+ {
+ SndBuffer::Init();
+ }
+ virtual void enqueue_samples(int16_t* buf, int samples_provided)
+ {
+ for(int i=0;i<samples_provided;i++)
+ {
+ StereoOut32 so32(buf[0],buf[1]);
+ SndBuffer::Write(so32);
+ buf++;
+ buf++;
+ }
+ }
+
+ virtual int output_samples(int16_t* buf, int samples_requested)
+ {
+ for(int i=0;i<samples_requested;i++) {
+ if(readySamples.size()==0) {
+ //SndOutPacketSize
+ StereoOut16 temp[SndOutPacketSize*2];
+ SndBuffer::ReadSamples( temp );
+ for(int i=0;i<SndOutPacketSize;i++) {
+ readySamples.push(temp[i].Left);
+ readySamples.push(temp[i].Right);
+ }
+ }
+ *buf++ = readySamples.front(); readySamples.pop();
+ *buf++ = readySamples.front(); readySamples.pop();
+ }
+ return samples_requested;
+ }
+};
+#endif
+
+ISynchronizingAudioBuffer* metaspu_construct(ESynchMethod method)
+{
+ switch(method)
+ {
+ case ESynchMethod_N: return new NitsujaSynchronizer();
+ case ESynchMethod_Z: return new ZeromusSynchronizer();
+ #ifdef _MSC_VER
+ case ESynchMethod_P: return new PCSX2Synchronizer();
+ #endif
+ default: return NULL;
+ }
+}
+
--- /dev/null
+++ b/src/in_2sf/desmume/metaspu/metaspu.h
@@ -1,1 +1,64 @@
+/* Copyright 2009-2010 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+//-------------------------
+//this file contains the METASPU system
+//which is designed to handle the task of audio synchronization
+//and is designed to be as portable between multiple emulators
+//-------------------------
+
+#ifndef _METASPU_H_
+#define _METASPU_H_
+
+#include <algorithm>
+#include <cmath>
+
+/*template<typename T> static inline void Clampify(T &src, T min, T max)
+{
+ src = std::min(std::max(src, min), max);
+}*/
+
+/*template<typename T> static inline T GetClamped(T src, T min, T max)
+{
+ return std::min(std::max( src, min ), max);
+}*/
+
+class ISynchronizingAudioBuffer
+{
+public:
+ virtual void enqueue_samples(int16_t *buf, int samples_provided) = 0;
+
+ // returns the number of samples actually supplied, which may not match the number requested
+ virtual int output_samples(int16_t *buf, int samples_requested) = 0;
+};
+
+enum ESynchMode
+{
+ ESynchMode_DualSynchAsynch,
+ ESynchMode_Synchronous
+};
+
+enum ESynchMethod
+{
+ ESynchMethod_N, //nitsuja's
+ ESynchMethod_Z, //zero's
+ ESynchMethod_P //PCSX2 spu2-x
+};
+
+ISynchronizingAudioBuffer *metaspu_construct(ESynchMethod method);
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/path.cpp
@@ -1,1 +1,158 @@
+/*
+ Copyright (C) 2009-2011 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "types.h"
+
+#include "path.h"
+#include <cstdio>
+
+//-----------------------------------
+//This is taken from mono Path.cs
+static const char InvalidPathChars[] = {
+ '\x22', '\x3C', '\x3E', '\x7C', '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+ '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12',
+ '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D',
+ '\x1E', '\x1F'
+};
+
+//but it is sort of windows-specific. Does it work in linux? Maybe we'll have to make it smarter
+static const char VolumeSeparatorChar = ':';
+static const char AltDirectorySeparatorChar = '/';
+static bool dirEqualsVolume = (DIRECTORY_DELIMITER_CHAR == VolumeSeparatorChar);
+
+
+bool Path::IsPathRooted (const std::string &pth)
+{
+ if (pth.empty()) {
+ return false;
+ }
+
+ if (pth.find_first_of(InvalidPathChars) != std::string::npos) {
+ return false;
+ }
+
+ char c = pth[0];
+ return c == DIRECTORY_DELIMITER_CHAR ||
+ c == AltDirectorySeparatorChar ||
+ (!dirEqualsVolume && pth.size() > 1 && pth[1] == VolumeSeparatorChar);
+}
+
+std::string Path::GetFileDirectoryPath(std::string filePath)
+{
+ if (filePath.empty()) {
+ return "";
+ }
+
+ size_t i = filePath.find_last_of(DIRECTORY_DELIMITER_CHAR);
+ if (i == std::string::npos) {
+ return filePath;
+ }
+
+ return filePath.substr(0, i);
+}
+
+std::string Path::GetFileNameFromPath(std::string filePath)
+{
+ if (filePath.empty()) {
+ return "";
+ }
+
+ size_t i = filePath.find_last_of(DIRECTORY_DELIMITER_CHAR);
+ if (i == std::string::npos) {
+ return filePath;
+ }
+
+ return filePath.substr(i + 1);
+}
+
+std::string Path::GetFileNameWithoutExt(std::string fileName)
+{
+ if (fileName.empty()) {
+ return "";
+ }
+
+ size_t i = fileName.find_last_of(FILE_EXT_DELIMITER_CHAR);
+ if (i == std::string::npos) {
+ return fileName;
+ }
+
+ return fileName.substr(0, i);
+}
+
+std::string Path::GetFileNameFromPathWithoutExt(std::string filePath)
+{
+ if (filePath.empty()) {
+ return "";
+ }
+
+ std::string fileName = GetFileNameFromPath(filePath);
+
+ return GetFileNameWithoutExt(fileName);
+}
+
+std::string Path::GetFileExt(std::string fileName)
+{
+ if (fileName.empty()) {
+ return "";
+ }
+
+ size_t i = fileName.find_last_of(FILE_EXT_DELIMITER_CHAR);
+ if (i == std::string::npos) {
+ return fileName;
+ }
+
+ return fileName.substr(i + 1);
+}
+
+//-----------------------------------
+#ifdef _WINDOWS
+void FCEUD_MakePathDirs(const char *fname)
+{
+ char Path[MAX_PATH];
+ const char* div = fname;
+
+ do
+ {
+ const char* fptr = strchr(div, '\\');
+
+ if(!fptr)
+ {
+ fptr = strchr(div, '/');
+ }
+
+ if(!fptr)
+ {
+ break;
+ }
+
+ int off = fptr - fname;
+ strncpy(Path, fname, off);
+ Path[off] = '\0';
+ mkdir(Path);
+
+ div = fptr + 1;
+
+ while(div[0] == '\\' || div[0] == '/')
+ {
+ div++;
+ }
+
+ } while(1);
+}
+#endif
+//------------------------------
+
--- /dev/null
+++ b/src/in_2sf/desmume/path.h
@@ -1,1 +1,427 @@
-
+/* Copyright 2009-2010 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string>
+
+#ifdef _MSC_VER
+#define mkdir _mkdir
+#endif
+
+#if defined(_WINDOWS)
+//#define WIN32_LEAN_AND_MEAN
+//#include <WinSock2.h>
+#include "windowsh_wrapper.h"
+#include <direct.h>
+#if !defined(WXPORT)
+#include "resource.h"
+#else
+#include <glib.h>
+#endif /* !WXPORT */
+#else
+#include <glib.h>
+#endif /* _WINDOWS */
+
+#include <cstdlib>
+#include <ctime>
+#include <cstdio>
+#include "utils/xstring.h"
+
+#ifdef _WINDOWS
+#define FILE_EXT_DELIMITER_CHAR '.'
+#define DIRECTORY_DELIMITER_CHAR '\\'
+#else
+#define FILE_EXT_DELIMITER_CHAR '.'
+#define DIRECTORY_DELIMITER_CHAR '/'
+#endif
+
+#ifdef _WINDOWS
+void FCEUD_MakePathDirs(const char *fname);
+#endif
+
+class Path
+{
+public:
+ static bool IsPathRooted (const std::string &path);
+ static std::string GetFileDirectoryPath(std::string filePath);
+ static std::string GetFileNameFromPath(std::string filePath);
+ static std::string GetFileNameWithoutExt(std::string fileName);
+ static std::string GetFileNameFromPathWithoutExt(std::string filePath);
+ static std::string GetFileExt(std::string fileName);
+};
+
+class PathInfo
+{
+public:
+
+ std::string path;
+ std::string RomName;
+ std::string RomDirectory;
+
+ #define MAX_FORMAT 20
+ #define SECTION "PathSettings"
+
+ #define ROMKEY "Roms"
+ #define BATTERYKEY "Battery"
+ #define STATEKEY "States"
+ #define SCREENSHOTKEY "Screenshots"
+ #define AVIKEY "AviFiles"
+ #define CHEATKEY "Cheats"
+ #define SOUNDKEY "SoundSamples"
+ #define FIRMWAREKEY "Firmware"
+ #define FORMATKEY "format"
+ #define DEFAULTFORMATKEY "defaultFormat"
+ #define NEEDSSAVINGKEY "needsSaving"
+ #define LASTVISITKEY "lastVisit"
+ #define LUAKEY "Lua"
+ char screenshotFormat[MAX_FORMAT];
+ bool savelastromvisit;
+
+ enum KnownPath
+ {
+ FIRSTKNOWNPATH = 0,
+ ROMS = 0,
+ BATTERY,
+ STATES,
+ SCREENSHOTS,
+ AVI_FILES,
+ CHEATS,
+ SOUNDS,
+ FIRMWARE,
+ MODULE,
+ MAXKNOWNPATH = MODULE
+ };
+
+ char pathToRoms[MAX_PATH];
+ char pathToBattery[MAX_PATH];
+ char pathToStates[MAX_PATH];
+ char pathToScreenshots[MAX_PATH];
+ char pathToAviFiles[MAX_PATH];
+ char pathToCheats[MAX_PATH];
+ char pathToSounds[MAX_PATH];
+ char pathToFirmware[MAX_PATH];
+ char pathToModule[MAX_PATH];
+ char pathToLua[MAX_PATH];
+
+ void init(const char * filename) {
+
+ path = std::string(filename);
+
+ //extract the internal part of the logical rom name
+ std::vector<std::string> parts = tokenize_str(filename,"|");
+ SetRomName(parts[parts.size()-1].c_str());
+ LoadModulePath();
+#ifndef WIN32
+ //ReadPathSettings();
+#endif
+
+ }
+
+ void LoadModulePath()
+ {
+#if defined(_WINDOWS)
+
+ char *p;
+ ZeroMemory(pathToModule, sizeof(pathToModule));
+
+ GetModuleFileNameA(NULL, pathToModule, sizeof(pathToModule));
+ p = pathToModule + strlen(pathToModule);
+ while (p >= pathToModule && *p != DIRECTORY_DELIMITER_CHAR) p--;
+ if (++p >= pathToModule) *p = 0;
+#else
+ char *cwd = g_build_filename(g_get_user_config_dir(), "desmume", NULL);
+ g_mkdir_with_parents(cwd, 0755);
+ strncpy(pathToModule, cwd, MAX_PATH);
+ g_free(cwd);
+#endif
+ }
+
+ enum Action
+ {
+ GET,
+ SET
+ };
+
+ void GetDefaultPath(char *pathToDefault, const char *, int maxCount)
+ {
+#ifdef _WINDOWS
+ std::string temp = (std::string)"." + DIRECTORY_DELIMITER_CHAR + pathToDefault;
+ strncpy(pathToDefault, temp.c_str(), maxCount);
+#else
+ strncpy(pathToDefault, pathToModule, maxCount);
+#endif
+ }
+
+ /*void ReadKey(char *pathToRead, const char *key)
+ {
+#ifdef _WINDOWS
+ GetPrivateProfileString(SECTION, key, key, pathToRead, MAX_PATH, IniName);
+ if(strcmp(pathToRead, key) == 0) {
+ //since the variables are all intialized in this file they all use MAX_PATH
+ GetDefaultPath(pathToRead, key, MAX_PATH);
+ }
+#else
+ //since the variables are all intialized in this file they all use MAX_PATH
+ GetDefaultPath(pathToRead, key, MAX_PATH);
+#endif
+ }*/
+
+ /*void ReadPathSettings()
+ {
+ if( ( strcmp(pathToModule, "") == 0) || !pathToModule)
+ LoadModulePath();
+
+ ReadKey(pathToRoms, ROMKEY);
+ ReadKey(pathToBattery, BATTERYKEY);
+ ReadKey(pathToStates, STATEKEY);
+ ReadKey(pathToScreenshots, SCREENSHOTKEY);
+ ReadKey(pathToAviFiles, AVIKEY);
+ ReadKey(pathToCheats, CHEATKEY);
+ ReadKey(pathToSounds, SOUNDKEY);
+ ReadKey(pathToFirmware, FIRMWAREKEY);
+ ReadKey(pathToLua, LUAKEY);
+#ifdef _WINDOWS
+ GetPrivateProfileString(SECTION, FORMATKEY, "%f_%s_%r", screenshotFormat, MAX_FORMAT, IniName);
+ savelastromvisit = GetPrivateProfileBool(SECTION, LASTVISITKEY, true, IniName);
+ currentimageformat = (ImageFormat)GetPrivateProfileInt(SECTION, DEFAULTFORMATKEY, PNG, IniName);
+#endif*/
+ /*
+ needsSaving = GetPrivateProfileInt(SECTION, NEEDSSAVINGKEY, true, IniName);
+ if(needsSaving)
+ {
+ needsSaving = false;
+ WritePathSettings();
+ }*/
+ /*}*/
+
+ void SwitchPath(Action action, KnownPath knownPath, char * buffer)
+ {
+ char *pathToCopy = 0;
+ switch(knownPath)
+ {
+ case ROMS:
+ pathToCopy = pathToRoms;
+ break;
+ case BATTERY:
+ pathToCopy = pathToBattery;
+ break;
+ case STATES:
+ pathToCopy = pathToStates;
+ break;
+ case SCREENSHOTS:
+ pathToCopy = pathToScreenshots;
+ break;
+ case AVI_FILES:
+ pathToCopy = pathToAviFiles;
+ break;
+ case CHEATS:
+ pathToCopy = pathToCheats;
+ break;
+ case SOUNDS:
+ pathToCopy = pathToSounds;
+ break;
+ case FIRMWARE:
+ pathToCopy = pathToFirmware;
+ break;
+ case MODULE:
+ pathToCopy = pathToModule;
+ break;
+ }
+
+ if(action == GET)
+ {
+ std::string thePath = pathToCopy;
+ std::string relativePath = (std::string)"." + DIRECTORY_DELIMITER_CHAR;
+
+ int len = (int)thePath.size()-1;
+
+ if(len == -1)
+ thePath = relativePath;
+ else
+ if(thePath[len] != DIRECTORY_DELIMITER_CHAR)
+ thePath += DIRECTORY_DELIMITER_CHAR;
+
+ if(!Path::IsPathRooted(thePath))
+ {
+ thePath = (std::string)pathToModule + thePath;
+ }
+
+ strncpy(buffer, thePath.c_str(), MAX_PATH);
+ #ifdef _WINDOWS
+ FCEUD_MakePathDirs(buffer);
+ #endif
+ }
+ else if(action == SET)
+ {
+ int len = strlen(buffer)-1;
+ if(buffer[len] == DIRECTORY_DELIMITER_CHAR)
+ buffer[len] = '\0';
+
+ strncpy(pathToCopy, buffer, MAX_PATH);
+ }
+ }
+
+ std::string getpath(KnownPath knownPath)
+ {
+ char temp[MAX_PATH];
+ SwitchPath(GET, knownPath, temp);
+ return temp;
+ }
+
+ void getpath(KnownPath knownPath, char *buffer)
+ {
+ SwitchPath(GET, knownPath, buffer);
+ }
+
+ void setpath(KnownPath knownPath, char *buffer)
+ {
+ SwitchPath(SET, knownPath, buffer);
+ }
+
+ void getfilename(char *buffer, int)
+ {
+ strcpy(buffer,noextension().c_str());
+ }
+
+ void getpathnoext(KnownPath knownPath, char *buffer)
+ {
+ getpath(knownPath, buffer);
+ strcat(buffer, GetRomNameWithoutExtension().c_str());
+ }
+
+ std::string extension()
+ {
+ return Path::GetFileExt(path);
+ }
+
+ std::string noextension()
+ {
+ std::string romNameWithPath = Path::GetFileDirectoryPath(path) + DIRECTORY_DELIMITER_CHAR + Path::GetFileNameWithoutExt(RomName);
+
+ return romNameWithPath;
+ }
+
+ void formatname(char *output)
+ {
+ std::string file;
+ time_t now = time(NULL);
+ tm *time_struct = localtime(&now);
+ srand((unsigned int)now);
+
+ for(int i = 0; i < MAX_FORMAT;i++)
+ {
+ char *c = &screenshotFormat[i];
+ char tmp[MAX_PATH] = {0};
+
+ if(*c == '%')
+ {
+ c = &screenshotFormat[++i];
+ switch(*c)
+ {
+ case 'f':
+
+ strcat(tmp, GetRomNameWithoutExtension().c_str());
+ break;
+ case 'D':
+ strftime(tmp, MAX_PATH, "%d", time_struct);
+ break;
+ case 'M':
+ strftime(tmp, MAX_PATH, "%m", time_struct);
+ break;
+ case 'Y':
+ strftime(tmp, MAX_PATH, "%Y", time_struct);
+ break;
+ case 'h':
+ strftime(tmp, MAX_PATH, "%H", time_struct);
+ break;
+ case 'm':
+ strftime(tmp, MAX_PATH, "%M", time_struct);
+ break;
+ case 's':
+ strftime(tmp, MAX_PATH, "%S", time_struct);
+ break;
+ case 'r':
+ sprintf(tmp, "%d", rand() % RAND_MAX);
+ break;
+ }
+ }
+ else
+ {
+ int j;
+ for(j=i;j<MAX_FORMAT-i;j++)
+ if(screenshotFormat[j] != '%')
+ tmp[j-i]=screenshotFormat[j];
+ else
+ break;
+ tmp[j-i]='\0';
+ }
+ file += tmp;
+ }
+ strncpy(output, file.c_str(), MAX_PATH);
+ }
+
+ enum ImageFormat
+ {
+#if defined(_WINDOWS) && !defined(WXPORT)
+ PNG = IDC_PNG,
+ BMP = IDC_BMP
+#else
+ PNG,
+ BMP
+#endif
+ };
+
+ ImageFormat currentimageformat;
+
+ ImageFormat imageformat() {
+ return currentimageformat;
+ }
+
+ void SetRomName(const char *filename)
+ {
+ std::string romPath = filename;
+
+ RomName = Path::GetFileNameFromPath(romPath);
+ RomDirectory = Path::GetFileDirectoryPath(romPath);
+ }
+
+ const char *GetRomName()
+ {
+ return RomName.c_str();
+ }
+
+ std::string GetRomNameWithoutExtension()
+ {
+ return Path::GetFileNameWithoutExt(RomName);
+ }
+
+ bool isdsgba(std::string fileName)
+ {
+ size_t i = fileName.find_last_of(FILE_EXT_DELIMITER_CHAR);
+
+ if (i != std::string::npos) {
+ fileName = fileName.substr(i - 2);
+ }
+
+ if(fileName == "ds.gba") {
+ return true;
+ }
+
+ return false;
+ }
+};
+
+extern PathInfo path;
+
--- /dev/null
+++ b/src/in_2sf/desmume/pathsettings.h
@@ -1,1 +1,30 @@
+/*
+ Copyright (C) 2007 Hicoder
+ This file is part of DeSmuME
+
+ DeSmuME is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DeSmuME 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DeSmuME; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _PATHSETTINGS_H_
+#define _PATHSETTINGS_H_
+
+void WritePathSettings();
+//void ReadPathSettings();
+
+LRESULT CALLBACK PathSettingsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/readwrite.cpp
@@ -1,1 +1,153 @@
+/*
+ Copyright (C) 2006-2009 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "readwrite.h"
+#include "types.h"
+
+//well. just for the sake of consistency
+/*int write8le(uint8_t b, EMUFILE*os)
+{
+ os->fwrite((char*)&b,1);
+ return 1;
+}*/
+
+//well. just for the sake of consistency
+int read8le(uint8_t *Bufo, EMUFILE*is)
+{
+ if(is->_fread((char*)Bufo,1) != 1)
+ return 0;
+ return 1;
+}
+
+///writes a little endian 16bit value to the specified file
+/*int write16le(uint16_t b, EMUFILE *fp)
+{
+ uint8_t s[2];
+ s[0]=(uint8_t)b;
+ s[1]=(uint8_t)(b>>8);
+ fp->fwrite(s,2);
+ return 2;
+}*/
+
+
+///writes a little endian 32bit value to the specified file
+/*int write32le(uint32_t b, EMUFILE *fp)
+{
+ uint8_t s[4];
+ s[0]=(uint8_t)b;
+ s[1]=(uint8_t)(b>>8);
+ s[2]=(uint8_t)(b>>16);
+ s[3]=(uint8_t)(b>>24);
+ fp->fwrite(s,4);
+ return 4;
+}*/
+
+//void writebool(bool b, EMUFILE* os) { write32le(b?1:0,os); }
+
+/*int write64le(uint64_t b, EMUFILE* os)
+{
+ uint8_t s[8];
+ s[0]=(uint8_t)b;
+ s[1]=(uint8_t)(b>>8);
+ s[2]=(uint8_t)(b>>16);
+ s[3]=(uint8_t)(b>>24);
+ s[4]=(uint8_t)(b>>32);
+ s[5]=(uint8_t)(b>>40);
+ s[6]=(uint8_t)(b>>48);
+ s[7]=(uint8_t)(b>>56);
+ os->fwrite((char*)&s,8);
+ return 8;
+}*/
+
+
+int read32le(uint32_t *Bufo, EMUFILE *fp)
+{
+ uint32_t buf;
+ if(fp->_fread(&buf,4)<4)
+ return 0;
+#ifdef LOCAL_LE
+ *(uint32_t*)Bufo=buf;
+#else
+ *(uint32_t*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
+#endif
+ return 1;
+}
+
+int read16le(uint16_t *Bufo, EMUFILE *is)
+{
+ uint16_t buf;
+ if(is->_fread((char*)&buf,2) != 2)
+ return 0;
+#ifdef LOCAL_LE
+ *Bufo=buf;
+#else
+ *Bufo = LE_TO_LOCAL_16(buf);
+#endif
+ return 1;
+}
+
+int read64le(uint64_t *Bufo, EMUFILE *is)
+{
+ uint64_t buf;
+ if(is->_fread((char*)&buf,8) != 8)
+ return 0;
+#ifdef LOCAL_LE
+ *Bufo=buf;
+#else
+ *Bufo = LE_TO_LOCAL_64(buf);
+#endif
+ return 1;
+}
+
+/*static int read32le(uint32_t *Bufo, std::istream *is)
+{
+ uint32_t buf;
+ if(is->read((char*)&buf,4).gcount() != 4)
+ return 0;
+#ifdef LOCAL_LE
+ *(uint32_t*)Bufo=buf;
+#else
+ *(uint32_t*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
+#endif
+ return 1;
+}*/
+
+int readbool(bool *b, EMUFILE* is)
+{
+ uint32_t temp = 0;
+ int ret = read32le(&temp,is);
+ *b = temp!=0;
+ return ret;
+}
+
+int readbuffer(std::vector<uint8_t> &vec, EMUFILE* is)
+{
+ uint32_t size;
+ if(read32le(&size,is) != 1) return 0;
+ vec.resize(size);
+ if(size>0) is->fread((char*)&vec[0],size);
+ return 1;
+}
+
+/*int writebuffer(std::vector<uint8_t>& vec, EMUFILE* os)
+{
+ uint32_t size = vec.size();
+ write32le(size,os);
+ if(size>0) os->fwrite((char*)&vec[0],size);
+ return 1;
+}*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/readwrite.h
@@ -1,1 +1,67 @@
+/*
+ Copyright (C) 2008-2009 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _READWRITE_H_
+#define _READWRITE_H_
+
+#include <iostream>
+#include <vector>
+#include <cstdio>
+
+#include "types.h"
+#include "emufile.h"
+
+//well. just for the sake of consistency
+//int write8le(uint8_t b, EMUFILE *fp);
+//inline int write8le(uint8_t* b, EMUFILE *fp) { return write8le(*b,fp); }
+//int write16le(uint16_t b, EMUFILE* os);
+//int write32le(uint32_t b, EMUFILE* os);
+//int write64le(uint64_t b, EMUFILE* os);
+//inline int write_double_le(double b, EMUFILE*is) { uint64_t temp = double_to_u64(b); int ret = write64le(temp,is); return ret; }
+
+int read8le(uint8_t *Bufo, EMUFILE*is);
+int read16le(uint16_t *Bufo, EMUFILE*is);
+inline int read16le(int16_t *Bufo, EMUFILE*is) { return read16le((uint16_t*)Bufo,is); }
+int read32le(uint32_t *Bufo, EMUFILE*is);
+inline int read32le(int32_t *Bufo, EMUFILE*is) { return read32le((uint32_t*)Bufo,is); }
+int read64le(uint64_t *Bufo, EMUFILE*is);
+inline int read_double_le(double *Bufo, EMUFILE*is) { uint64_t temp; int ret = read64le(&temp,is); *Bufo = u64_to_double(temp); return ret; }
+int read16le(uint16_t *Bufo, std::istream *is);
+
+
+/*template<typename T>
+int readle(T *Bufo, EMUFILE*is)
+{
+ CTASSERT(sizeof(T)==1||sizeof(T)==2||sizeof(T)==4||sizeof(T)==8);
+ switch(sizeof(T)) {
+ case 1: return read8le((uint8_t*)Bufo,is);
+ case 2: return read16le((uint16_t*)Bufo,is);
+ case 4: return read32le((uint32_t*)Bufo,is);
+ case 8: return read64le((uint64_t*)Bufo,is);
+ default:
+ return 0;
+ }
+}*/
+
+int readbool(bool *b, EMUFILE* is);
+//void writebool(bool b, EMUFILE* os);
+
+int readbuffer(std::vector<uint8_t> &vec, EMUFILE* is);
+//int writebuffer(std::vector<uint8_t>& vec, EMUFILE* os);
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/registers.h
@@ -1,1 +1,432 @@
-
+/*
+ Copyright (C) 2006 Theo Berkau
+ Copyright (C) 2006-2011 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef REGISTERS_H
+#define REGISTERS_H
+
+#define REG_REGION_MASK 0x0FFFEF80
+#define REG_BASE_DISPx 0x04000000
+#define REG_BASE_DISPA 0x04000000
+#define REG_BASE_DISPB 0x04001000
+#define REG_BASE_DMA 0x04000080
+#define REG_BASE_SIORTCTIMERS 0x04000100
+#define REG_BASE_ROMIPC 0x04000180
+#define REG_BASE_MEMIRQ 0x04000200
+#define REG_BASE_MATH 0x04000280
+#define REG_BASE_OTHER 0x04000300
+#define REG_BASE_RCVPORTS 0x04100000
+
+// Display Engine A
+#define REG_DISPA_DISPCNT 0x04000000
+#define REG_DISPA_VCOUNT 0x04000006
+#define REG_DISPA_BG0CNT 0x04000008
+#define REG_DISPA_BG1CNT 0x0400000A
+#define REG_DISPA_BG2CNT 0x0400000C
+#define REG_DISPA_BG3CNT 0x0400000E
+#define REG_DISPA_BG0HOFS 0x04000010
+#define REG_DISPA_BG0VOFS 0x04000012
+#define REG_DISPA_BG1HOFS 0x04000014
+#define REG_DISPA_BG1VOFS 0x04000016
+#define REG_DISPA_BG2HOFS 0x04000018
+#define REG_DISPA_BG2VOFS 0x0400001A
+#define REG_DISPA_BG3HOFS 0x0400001C
+#define REG_DISPA_BG3VOFS 0x0400001E
+#define REG_DISPA_BG2PA 0x04000020
+#define REG_DISPA_BG2PB 0x04000022
+#define REG_DISPA_BG2PC 0x04000024
+#define REG_DISPA_BG2PD 0x04000026
+#define REG_DISPA_BG2XL 0x04000028
+#define REG_DISPA_BG2XH 0x0400002A
+#define REG_DISPA_BG2YL 0x0400002C
+#define REG_DISPA_BG2YH 0x0400002E
+#define REG_DISPA_BG3PA 0x04000030
+#define REG_DISPA_BG3PB 0x04000032
+#define REG_DISPA_BG3PC 0x04000034
+#define REG_DISPA_BG3PD 0x04000036
+#define REG_DISPA_BG3XL 0x04000038
+#define REG_DISPA_BG3XH 0x0400003A
+#define REG_DISPA_BG3YL 0x0400003C
+#define REG_DISPA_BG3YH 0x0400003E
+#define REG_DISPA_WIN0H 0x04000040
+#define REG_DISPA_WIN1H 0x04000042
+#define REG_DISPA_WIN0V 0x04000044
+#define REG_DISPA_WIN1V 0x04000046
+#define REG_DISPA_WININ 0x04000048
+#define REG_DISPA_WINOUT 0x0400004A
+#define REG_DISPA_MOSAIC 0x0400004C
+#define REG_DISPA_BLDCNT 0x04000050
+#define REG_DISPA_BLDALPHA 0x04000052
+#define REG_DISPA_BLDY 0x04000054
+#define REG_DISPA_MASTERBRIGHT 0x0400006C
+
+// DMA
+#define _REG_DMA_CONTROL_MIN 0x040000B0
+#define REG_DMA0SAD 0x040000B0
+#define REG_DMA0SADL 0x040000B0
+#define REG_DMA0SADH 0x040000B2
+#define REG_DMA0DAD 0x040000B4
+#define REG_DMA0DADL 0x040000B4
+#define REG_DMA0DADH 0x040000B6
+#define REG_DMA0CNTL 0x040000B8
+#define REG_DMA0CNTH 0x040000BA
+#define REG_DMA1SAD 0x040000BC
+#define REG_DMA1SADL 0x040000BC
+#define REG_DMA1SADH 0x040000BE
+#define REG_DMA1DAD 0x040000C0
+#define REG_DMA1DADL 0x040000C0
+#define REG_DMA1DADH 0x040000C2
+#define REG_DMA1CNTL 0x040000C4
+#define REG_DMA1CNTH 0x040000C6
+#define REG_DMA2SAD 0x040000C8
+#define REG_DMA2SADL 0x040000C8
+#define REG_DMA2SADH 0x040000CA
+#define REG_DMA2DAD 0x040000CC
+#define REG_DMA2DADL 0x040000CC
+#define REG_DMA2DADH 0x040000CE
+#define REG_DMA2CNTL 0x040000D0
+#define REG_DMA2CNTH 0x040000D2
+#define REG_DMA3SAD 0x040000D4
+#define REG_DMA3SADL 0x040000D4
+#define REG_DMA3SADH 0x040000D6
+#define REG_DMA3DAD 0x040000D8
+#define REG_DMA3DADL 0x040000D8
+#define REG_DMA3DADH 0x040000DA
+#define REG_DMA3CNTL 0x040000DC
+#define REG_DMA3CNTH 0x040000DE
+#define _REG_DMA_CONTROL_MAX 0x040000DF
+#define REG_DMA0FILL 0x040000E0
+#define REG_DMA1FILL 0x040000E4
+#define REG_DMA2FILL 0x040000E8
+#define REG_DMA3FILL 0x040000EC
+
+// Timers
+#define REG_TM0CNTL 0x04000100
+#define REG_TM0CNTH 0x04000102
+#define REG_TM1CNTL 0x04000104
+#define REG_TM1CNTH 0x04000106
+#define REG_TM2CNTL 0x04000108
+#define REG_TM2CNTH 0x0400010A
+#define REG_TM3CNTL 0x0400010C
+#define REG_TM3CNTH 0x0400010E
+
+// SIO/Keypad Input/RTC
+#define REG_SIODATA32 0x04000120
+#define REG_SIOCNT 0x04000128
+#define REG_KEYINPUT 0x04000130
+#define REG_KEYCNT 0x04000132
+#define REG_RCNT 0x04000134
+#define REG_EXTKEYIN 0x04000136
+#define REG_RTC 0x04000138
+
+// IPC
+#define REG_IPCSYNC 0x04000180
+#define REG_IPCFIFOCNT 0x04000184
+#define REG_IPCFIFOSEND 0x04000188
+
+// ROM
+#define REG_AUXSPICNT 0x040001A0
+#define REG_AUXSPIDATA 0x040001A2
+#define REG_GCROMCTRL 0x040001A4
+#define REG_GCCMDOUT 0x040001A8
+#define REG_ENCSEED0L 0x040001B0
+#define REG_ENCSEED1L 0x040001B4
+#define REG_ENCSEED0H 0x040001B8
+#define REG_ENCSEED1H 0x040001BC
+#define REG_SPICNT 0x040001C0
+#define REG_SPIDATA 0x040001C2
+
+// Memory/IRQ
+#define REG_EXMEMCNT 0x04000204
+#define REG_WIFIWAITCNT 0x04000206
+#define REG_IME 0x04000208
+#define REG_IE 0x04000210
+#define REG_IF 0x04000214
+#define REG_VRAMCNTA 0x04000240
+#define REG_VRAMSTAT 0x04000240
+#define REG_VRAMCNTB 0x04000241
+#define REG_WRAMSTAT 0x04000241
+#define REG_VRAMCNTC 0x04000242
+#define REG_VRAMCNTD 0x04000243
+#define REG_VRAMCNTE 0x04000244
+#define REG_VRAMCNTF 0x04000245
+#define REG_VRAMCNTG 0x04000246
+#define REG_WRAMCNT 0x04000247
+#define REG_VRAMCNTH 0x04000248
+#define REG_VRAMCNTI 0x04000249
+
+// Math
+#define REG_DIVCNT 0x04000280
+#define REG_DIVNUMER 0x04000290
+#define REG_DIVDENOM 0x04000298
+#define REG_DIVRESULT 0x040002A0
+#define REG_DIVREMRESULT 0x040002A8
+#define REG_SQRTCNT 0x040002B0
+#define REG_SQRTRESULT 0x040002B4
+#define REG_SQRTPARAM 0x040002B8
+
+// Other
+#define REG_POSTFLG 0x04000300
+#define REG_HALTCNT 0x04000301
+#define REG_POWCNT1 0x04000304
+#define REG_POWCNT2 0x04000304
+#define REG_BIOSPROT 0x04000308
+
+#define REG_DISPB_DISPCNT 0x04001000
+#define REG_DISPB_BG0CNT 0x04001008
+#define REG_DISPB_BG1CNT 0x0400100A
+#define REG_DISPB_BG2CNT 0x0400100C
+#define REG_DISPB_BG3CNT 0x0400100E
+#define REG_DISPB_BG0HOFS 0x04001010
+#define REG_DISPB_BG0VOFS 0x04001012
+#define REG_DISPB_BG1HOFS 0x04001014
+#define REG_DISPB_BG1VOFS 0x04001016
+#define REG_DISPB_BG2HOFS 0x04001018
+#define REG_DISPB_BG2VOFS 0x0400101A
+#define REG_DISPB_BG3HOFS 0x0400101C
+#define REG_DISPB_BG3VOFS 0x0400101E
+#define REG_DISPB_BG2PA 0x04001020
+#define REG_DISPB_BG2PB 0x04001022
+#define REG_DISPB_BG2PC 0x04001024
+#define REG_DISPB_BG2PD 0x04001026
+#define REG_DISPB_BG2XL 0x04001028
+#define REG_DISPB_BG2XH 0x0400102A
+#define REG_DISPB_BG2YL 0x0400102C
+#define REG_DISPB_BG2YH 0x0400102E
+#define REG_DISPB_BG3PA 0x04001030
+#define REG_DISPB_BG3PB 0x04001032
+#define REG_DISPB_BG3PC 0x04001034
+#define REG_DISPB_BG3PD 0x04001036
+#define REG_DISPB_BG3XL 0x04001038
+#define REG_DISPB_BG3XH 0x0400103A
+#define REG_DISPB_BG3YL 0x0400103C
+#define REG_DISPB_BG3YH 0x0400103E
+#define REG_DISPB_WIN0H 0x04001040
+#define REG_DISPB_WIN1H 0x04001042
+#define REG_DISPB_WIN0V 0x04001044
+#define REG_DISPB_WIN1V 0x04001046
+#define REG_DISPB_WININ 0x04001048
+#define REG_DISPB_WINOUT 0x0400104A
+#define REG_DISPB_MOSAIC 0x0400104C
+#define REG_DISPB_BLDCNT 0x04001050
+#define REG_DISPB_BLDALPHA 0x04001052
+#define REG_DISPB_BLDY 0x04001054
+#define REG_DISPB_MASTERBRIGHT 0x0400106C
+
+// Receive ports
+#define REG_IPCFIFORECV 0x04100000
+#define REG_GCDATAIN 0x04100010
+
+
+
+
+
+#define REG_DISPB 0x00001000
+// core A and B specific
+#define REG_DISPx_DISPCNT 0x04000000
+#define REG_DISPx_VCOUNT 0x04000006
+#define REG_DISPx_BG0CNT 0x04000008
+#define REG_DISPx_BG1CNT 0x0400000A
+#define REG_DISPx_BG2CNT 0x0400000C
+#define REG_DISPx_BG3CNT 0x0400000E
+#define REG_DISPx_BG0HOFS 0x04000010
+#define REG_DISPx_BG0VOFS 0x04000012
+#define REG_DISPx_BG1HOFS 0x04000014
+#define REG_DISPx_BG1VOFS 0x04000016
+#define REG_DISPx_BG2HOFS 0x04000018
+#define REG_DISPx_BG2VOFS 0x0400001A
+#define REG_DISPx_BG3HOFS 0x0400001C
+#define REG_DISPx_BG3VOFS 0x0400001E
+#define REG_DISPx_BG2PA 0x04000020
+#define REG_DISPx_BG2PB 0x04000022
+#define REG_DISPx_BG2PC 0x04000024
+#define REG_DISPx_BG2PD 0x04000026
+#define REG_DISPx_BG2XL 0x04000028
+#define REG_DISPx_BG2XH 0x0400002A
+#define REG_DISPx_BG2YL 0x0400002C
+#define REG_DISPx_BG2YH 0x0400002E
+#define REG_DISPx_BG3PA 0x04000030
+#define REG_DISPx_BG3PB 0x04000032
+#define REG_DISPx_BG3PC 0x04000034
+#define REG_DISPx_BG3PD 0x04000036
+#define REG_DISPx_BG3XL 0x04000038
+#define REG_DISPx_BG3XH 0x0400003A
+#define REG_DISPx_BG3YL 0x0400003C
+#define REG_DISPx_BG3YH 0x0400003E
+#define REG_DISPx_WIN0H 0x04000040
+#define REG_DISPx_WIN1H 0x04000042
+#define REG_DISPx_WIN0V 0x04000044
+#define REG_DISPx_WIN1V 0x04000046
+#define REG_DISPx_WININ 0x04000048
+#define REG_DISPx_WINOUT 0x0400004A
+#define REG_DISPx_MOSAIC 0x0400004C
+#define REG_DISPx_BLDCNT 0x04000050
+#define REG_DISPx_BLDALPHA 0x04000052
+#define REG_DISPx_BLDY 0x04000054
+#define REG_DISPx_MASTERBRIGHT 0x0400006C
+// core A specific
+#define REG_DISPA_DISPSTAT 0x04000004
+#define REG_DISPA_DISP3DCNT 0x04000060
+#define REG_DISPA_DISPCAPCNT 0x04000064
+#define REG_DISPA_DISPMMEMFIFO 0x04000068
+
+#define REG_DISPA_DISP3DCNT_BIT_RDLINES_UNDERFLOW 0x1000
+#define REG_DISPA_DISP3DCNT_BIT_RAM_OVERFLOW 0x2000
+#define REG_DISPA_DISP3DCNT_BITS_ACK (REG_DISPA_DISP3DCNT_BIT_RDLINES_UNDERFLOW|REG_DISPA_DISP3DCNT_BIT_RAM_OVERFLOW)
+
+
+#define eng_3D_RDLINES_COUNT 0x04000320
+#define eng_3D_EDGE_COLOR 0x04000330
+#define eng_3D_ALPHA_TEST_REF 0x04000340
+#define eng_3D_CLEAR_COLOR 0x04000350
+#define eng_3D_CLEAR_DEPTH 0x04000354
+#define eng_3D_CLRIMAGE_OFFSET 0x04000356
+#define eng_3D_FOG_COLOR 0x04000358
+#define eng_3D_FOG_OFFSET 0x0400035C
+#define eng_3D_FOG_TABLE 0x04000360
+#define eng_3D_TOON_TABLE 0x04000380
+#define eng_3D_GXFIFO 0x04000400
+
+//DSI
+#define REG_DSIMODE 0x04004000
+
+// 3d commands
+#define cmd_3D_MTX_MODE 0x04000440
+#define cmd_3D_MTX_PUSH 0x04000444
+#define cmd_3D_MTX_POP 0x04000448
+#define cmd_3D_MTX_STORE 0x0400044C
+#define cmd_3D_MTX_RESTORE 0x04000450
+#define cmd_3D_MTX_IDENTITY 0x04000454
+#define cmd_3D_MTX_LOAD_4x4 0x04000458
+#define cmd_3D_MTX_LOAD_4x3 0x0400045C
+#define cmd_3D_MTX_MULT_4x4 0x04000460
+#define cmd_3D_MTX_MULT_4x3 0x04000464
+#define cmd_3D_MTX_MULT_3x3 0x04000468
+#define cmd_3D_MTX_SCALE 0x0400046C
+#define cmd_3D_MTX_TRANS 0x04000470
+#define cmd_3D_COLOR 0x04000480
+#define cmd_3D_NORMA 0x04000484
+#define cmd_3D_TEXCOORD 0x04000488
+#define cmd_3D_VTX_16 0x0400048C
+#define cmd_3D_VTX_10 0x04000490
+#define cmd_3D_VTX_XY 0x04000494
+#define cmd_3D_VTX_XZ 0x04000498
+#define cmd_3D_VTX_YZ 0x0400049C
+#define cmd_3D_VTX_DIFF 0x040004A0
+#define cmd_3D_POLYGON_ATTR 0x040004A4
+#define cmd_3D_TEXIMAGE_PARAM 0x040004A8
+#define cmd_3D_PLTT_BASE 0x040004AC
+#define cmd_3D_DIF_AMB 0x040004C0
+#define cmd_3D_SPE_EMI 0x040004C4
+#define cmd_3D_LIGHT_VECTOR 0x040004C8
+#define cmd_3D_LIGHT_COLOR 0x040004CC
+#define cmd_3D_SHININESS 0x040004D0
+#define cmd_3D_BEGIN_VTXS 0x04000500
+#define cmd_3D_END_VTXS 0x04000504
+#define cmd_3D_SWAP_BUFFERS 0x04000540
+#define cmd_3D_VIEWPORT 0x04000580
+#define cmd_3D_BOX_TEST 0x040005C0
+#define cmd_3D_POS_TEST 0x040005C4
+#define cmd_3D_VEC_TEST 0x040005C8
+
+#define eng_3D_GXSTAT 0x04000600
+#define eng_3D_RAM_COUNT 0x04000604
+#define eng_3D_DISP_1DOT_DEPTH 0x04000610
+#define eng_3D_POS_RESULT 0x04000620
+#define eng_3D_VEC_RESULT 0x04000630
+#define eng_3D_CLIPMTX_RESULT 0x04000640
+#define eng_3D_VECMTX_RESULT 0x04000680
+
+#define IPCFIFOCNT_SENDEMPTY 0x0001
+#define IPCFIFOCNT_SENDFULL 0x0002
+#define IPCFIFOCNT_SENDIRQEN 0x0004
+#define IPCFIFOCNT_SENDCLEAR 0x0008
+#define IPCFIFOCNT_RECVEMPTY 0x0100
+#define IPCFIFOCNT_RECVFULL 0x0200
+#define IPCFIFOCNT_RECVIRQEN 0x0400
+#define IPCFIFOCNT_FIFOERROR 0x4000
+#define IPCFIFOCNT_FIFOENABLE 0x8000
+#define IPCFIFOCNT_WRITEABLE (IPCFIFOCNT_SENDIRQEN | IPCFIFOCNT_RECVIRQEN | IPCFIFOCNT_FIFOENABLE)
+
+#define IPCSYNC_IRQ_SEND 0x2000
+#define IPCSYNC_IRQ_RECV 0x4000
+
+#define IRQ_BIT_LCD_VBLANK 0
+#define IRQ_BIT_LCD_HBLANK 1
+#define IRQ_BIT_LCD_VMATCH 2
+#define IRQ_BIT_TIMER_0 3
+#define IRQ_BIT_TIMER_1 4
+#define IRQ_BIT_TIMER_2 5
+#define IRQ_BIT_TIMER_3 6
+#define IRQ_BIT_ARM7_SIO 7
+#define IRQ_BIT_DMA_0 8
+#define IRQ_BIT_DMA_2 9
+#define IRQ_BIT_DMA_3 10
+#define IRQ_BIT_DMA_4 11
+#define IRQ_BIT_KEYPAD 12
+#define IRQ_BIT_GAMEPAK 13
+#define IRQ_BIT_IPCSYNC 16
+#define IRQ_BIT_IPCFIFO_SENDEMPTY 17
+#define IRQ_BIT_IPCFIFO_RECVNONEMPTY 18
+#define IRQ_BIT_GC_TRANSFER_COMPLETE 19
+#define IRQ_BIT_GC_IREQ_MC 20
+#define IRQ_BIT_ARM9_GXFIFO 21
+#define IRQ_BIT_ARM7_FOLD 22
+#define IRQ_BIT_ARM7_SPI 23
+#define IRQ_BIT_ARM7_WIFI 24
+
+#define IRQ_MASK_LCD_VBLANK (1<<0)
+#define IRQ_MASK_LCD_HBLANK (1<<1)
+#define IRQ_MASK_LCD_VMATCH (1<<2)
+#define IRQ_MASK_TIMER_0 (1<<3)
+#define IRQ_MASK_TIMER_1 (1<<4)
+#define IRQ_MASK_TIMER_2 (1<<5)
+#define IRQ_MASK_TIMER_3 (1<<6)
+#define IRQ_MASK_ARM7_SIO (1<<7)
+#define IRQ_MASK_DMA_0 (1<<8)
+#define IRQ_MASK_DMA_2 (1<<9)
+#define IRQ_MASK_DMA_3 (1<<10)
+#define IRQ_MASK_DMA_4 (1<<11)
+#define IRQ_MASK_KEYPAD (1<<12)
+#define IRQ_MASK_GAMEPAK (1<<13)
+#define IRQ_MASK_IPCSYNC (1<<16)
+#define IRQ_MASK_IPCFIFO_SENDEMPTY (1<<17)
+#define IRQ_MASK_IPCFIFO_RECVNONEMPTY (1<<18)
+#define IRQ_MASK_GC_TRANSFER_COMPLETE (1<<19)
+#define IRQ_MASK_GC_IREQ_MC (1<<20)
+#define IRQ_MASK_ARM9_GXFIFO (1<<21)
+#define IRQ_MASK_ARM7_FOLD (1<<22)
+#define IRQ_MASK_ARM7_SPI (1<<23)
+#define IRQ_MASK_ARM7_WIFI (1<<24)
+
+#define TSC_MEASURE_TEMP1 0
+#define TSC_MEASURE_Y 1
+#define TSC_MEASURE_BATTERY 2
+#define TSC_MEASURE_Z1 3
+#define TSC_MEASURE_Z2 4
+#define TSC_MEASURE_X 5
+#define TSC_MEASURE_AUX 6
+#define TSC_MEASURE_TEMP2 7
+
+#define EXMEMCNT_MASK_SLOT2_ARM7 (1<<7)
+#define EXMEMCNT_MASK_SLOT2_SRAM_TIME (3)
+#define EXMEMCNT_MASK_SLOT2_ROM_1ST_TIME (3<<2)
+#define EXMEMCNT_MASK_SLOT2_ROM_2ND_TIME (1<<4)
+#define EXMEMCNT_MASK_SLOT2_CLOCKRATE (3<<5)
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/resource.h
@@ -1,1 +1,962 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by resources.rc
+//
+#define IDD_RECORDMOVIE 101
+#define IDM_OPEN 101
+#define IDM_QUIT 102
+#define IDC_FERMER 103
+#define IDD_DESASSEMBLEUR_VIEWER7 103
+#define IDC_STEP 104
+#define IDC_SETPNUM 105
+#define IDC_SCROLLER 106
+#define IDD_SOUNDSETTINGS 106
+#define IDB_FRAMEADVANCE 106
+#define IDC_GO 107
+#define IDC_AUTO_UPDATE 108
+#define IDB_OPEN 108
+#define IDM_MEMORY 109
+#define IDC_CONTINUE 109
+#define IDM_DISASSEMBLER 110
+#define IDB_PAUSE 110
+#define IDD_3DSETTINGS 111
+#define IDM_GAME_INFO 111
+#define IDB_PLAY 112
+#define IDD_GBASLOT 113
+#define IDM_PAUSE 113
+#define IDD_GBASLOT_CFLASH 114
+#define IDM_RESET 114
+#define IDB_RESET 114
+#define IDD_CHEAT_SEARCH_VIEW 115
+#define IDM_IOREG 115
+#define IDD_CHEAT_LIST 116
+#define IDB_STOP 116
+#define IDD_CHEAT_ADD 117
+#define IDM_PAL 117
+#define IDM_TILE 118
+#define IDM_MAP 119
+#define IDB_ROTATECCW 119
+#define IDM_MBG0 120
+#define IDB_BITMAP2 120
+#define IDB_ROTATECW 120
+#define IDM_MBG1 121
+#define IDM_MBG2 122
+#define IDD_CHEAT_EXPORT 122
+#define IDM_MBG3 123
+#define IDM_SBG0 124
+#define IDM_SBG1 125
+#define IDM_SBG2 126
+#define IDM_SBG3 127
+#define IDM_OAM 128
+#define IDM_PRINTSCREEN 129
+#define IDM_QUICK_PRINTSCREEN 130
+#define IDM_SOUNDSETTINGS 131
+#define IDM_WEBSITE 132
+#define IDM_FORUM 133
+#define IDM_SUBMITBUGREPORT 134
+#define IDM_STATE_LOAD 135
+#define IDM_STATE_SAVE 136
+#define IDM_STATE_SAVE_F10 139
+#define IDM_STATE_SAVE_F1 140
+#define IDM_STATE_SAVE_F2 141
+#define IDM_STATE_SAVE_F3 142
+#define IDM_STATE_SAVE_F4 143
+#define IDM_STATE_SAVE_F5 144
+#define IDM_STATE_SAVE_F6 145
+#define IDM_STATE_SAVE_F7 146
+#define IDM_STATE_SAVE_F8 147
+#define IDM_STATE_SAVE_F9 148
+#define IDM_STATE_LOAD_F10 149
+#define IDM_STATE_LOAD_F1 150
+#define IDM_STATE_LOAD_F2 151
+#define IDM_STATE_LOAD_F3 152
+#define IDM_STATE_LOAD_F4 153
+#define IDM_STATE_LOAD_F5 154
+#define IDM_STATE_LOAD_F6 155
+#define IDM_STATE_LOAD_F7 156
+#define IDM_STATE_LOAD_F8 157
+#define IDM_STATE_LOAD_F9 158
+#define IDC_COMBO1 160
+#define IDC_COMBO2 161
+#define IDC_COMBO3 162
+#define IDC_COMBO4 163
+#define IDM_CONFIG 180
+#define IDC_FRAMESKIP0 191
+#define IDC_FRAMESKIP1 192
+#define IDC_FRAMESKIP2 193
+#define IDC_FRAMESKIP3 194
+#define IDC_FRAMESKIP4 195
+#define IDC_FRAMESKIP5 196
+#define IDC_FRAMESKIP6 197
+#define IDC_FRAMESKIP7 198
+#define IDC_FRAMESKIP8 199
+#define IDC_EDIT_FILENAME 200
+#define IDC_FRAMESKIP9 200
+#define IDC_BUTTON_BROWSEFILE 201
+#define IDC_CHECK_READONLY 201
+#define IDM_IMPORTBACKUPMEMORY 201
+#define IDC_LANGENGLISH 210
+#define IDC_LANGFRENCH 211
+#define IDC_LANG_CHINESE_SIMPLIFIED 213
+#define IDC_LANGITALIAN 214
+#define IDC_LANGJAPANESE 215
+#define IDM_MGPU 219
+#define IDM_SGPU 220
+#define IDC_FRAMESKIPAUTO 221
+#define IDC_8_BIT 302
+#define IDC_16_BIT 303
+#define IDC_32_BIT 304
+#define IDC_BACKGROUNDPAUSE 305
+#define IDC_BACKGROUNDINPUT 306
+#define IDC_LUACONSOLE 309
+#define IDC_EDIT_LUAPATH 310
+#define IDC_BUTTON_LUARUN 311
+#define IDC_BUTTON_LUASTOP 312
+#define IDC_BUTTON_LUABROWSE 313
+#define IDC_BUTTON_LUAEDIT 314
+#define IDC_NOTIFY_SUBSERVIENT 315
+#define IDD_ARCHIVEFILECHOOSER 316
+#define IDD_LUA 317
+#define IDC_NEW_LUA_SCRIPT 318
+#define IDC_PATHEDIT 319
+#define IDC_BROWSE 320
+#define IDC_USELASTVISIT 321
+#define IDC_FORMATEDIT 322
+#define IDC_PATHLIST 323
+#define IDC_SAVEAS 324
+#define IDC_PNG 325
+#define IDC_BMP 326
+#define IDC_FORMATSTATIC 327
+#define IDM_CLOSEROM 328
+#define IDM_PATHSETTINGS 350
+#define IDC_ROMPATHEDIT 351
+#define IDC_BROWSEROMS 352
+#define IDC_PATHDEFAULTS 353
+#define IDC_SAVERAMPATHEDIT 354
+#define IDC_BROWSESRAM 355
+#define IDC_STATEPATHEDIT 356
+#define IDC_BROWSESTATES 357
+#define IDC_SCREENSHOTPATHEDIT 358
+#define IDC_BROWSESCREENSHOTS 359
+#define IDC_AVIPATHEDIT 360
+#define IDC_BROWSEAVI 361
+#define IDC_CHEATPATHEDIT 362
+#define IDC_BROWSECHEATS 363
+#define IDC_LUAPATHEDIT 364
+#define IDC_BROWSELUA 365
+#define IDD_PATHSETTINGS 366
+#define IDC_STATEREWINDING 367
+#define IDC_CLOSE_LUA_SCRIPTS 368
+#define IDC_DES_BOX 402
+#define IDC_R0 403
+#define IDC_R1 404
+#define IDC_R2 405
+#define IDC_R3 406
+#define IDC_R4 407
+#define IDC_R5 408
+#define IDC_R6 409
+#define IDC_R7 410
+#define IDC_R8 411
+#define IDC_R9 412
+#define IDC_R10 413
+#define IDC_R11 414
+#define IDC_R12 415
+#define IDC_R13 416
+#define IDC_R14 417
+#define IDC_R15 418
+#define IDC_MODE 419
+#define IDC_AUTO_DES 420
+#define IDC_ARM 421
+#define IDC_THUMB 422
+#define IDC_GOTODES 423
+#define IDC_TMP 424
+#define IDD_GAME_INFO 501
+#define ID_RAM_WATCH 550
+#define IDM_RENDER_NORMAL 551
+#define IDM_RENDER_HQ2X 552
+#define IDM_RENDER_2XSAI 553
+#define IDM_RENDER_SUPER2XSAI 554
+#define IDM_RENDER_SUPEREAGLE 555
+#define IDM_RENDER_SCANLINE 556
+#define IDM_RENDER_BILINEAR 557
+#define IDM_RENDER_NEAREST2X 558
+#define IDM_RENDER_EPX 559
+#define IDM_RENDER_EPXPLUS 560
+#define IDM_RENDER_EPX1POINT5 561
+#define IDM_RENDER_EPXPLUS1POINT5 562
+#define IDM_RENDER_NEAREST1POINT5 563
+#define IDM_RENDER_NEARESTPLUS1POINT5 564
+#define IDD_IO_REG 601
+#define IDM_RECORD_MOVIE 602
+#define IDM_PLAY_MOVIE 603
+#define IDD_PAL 703
+#define IDD_TILE 704
+#define IDC_PAL_SELECT 705
+#define IDC_PALNUM 706
+#define IDC_MEM_SELECT 707
+#define IDC_Tile_BOX 708
+#define IDC_BITMAP 709
+#define IDC_256COUL 710
+#define IDC_16COUL 711
+#define IDC_MINI_TILE 712
+#define IDC_TILENUM 713
+#define IDD_MAP 800
+#define IDC_BG_SELECT 801
+#define IDC_PAL 803
+#define IDC_PRIO 804
+#define IDC_CHAR 805
+#define IDC_SCR 806
+#define IDC_MSIZE 807
+#define IDC_SCROLL 808
+#define IDD_OAM 900
+#define IDC_SCR_SELECT 901
+#define IDC_TILE 902
+#define IDC_OAMNUM 903
+#define IDC_COOR 904
+#define IDC_DIM 905
+#define IDC_ROT 906
+#define IDC_MOS 907
+#define IDC_PROP0 908
+#define IDC_PROP1 909
+#define IDD_EMULATIONSETTINGS 916
+#define IDD_WIFISETTINGS 918
+#define IDD_MEM_VIEW 920
+#define IDC_DIFFERENTFROM 921
+#define IDC_DIFFERENTBY 922
+#define IDC_MODULO 923
+#define IDC_EDIT_DIFFBY 924
+#define IDC_EDIT_MODBY 925
+#define IDC_PREVIOUSVALUE 926
+#define IDC_SPECIFICVALUE 927
+#define IDC_NUMBEROFCHANGES 928
+#define IDC_EDIT_COMPAREVALUE 929
+#define IDC_EDIT_COMPARECHANGES 930
+#define IDC_C_AUTOSEARCH 931
+#define IDC_MISALIGN 932
+#define IDC_C_RESET_CHANGES 933
+#define IDC_C_UNDO 934
+#define ID_RAM_SEARCH 935
+#define IDD_RAMSEARCH 945
+#define IDC_SPECIFICADDRESS 950
+#define IDC_EDIT_COMPAREADDRESS 951
+#define IDC_PROMPT_TEXT 952
+#define IDC_PROMPT_EDIT 953
+#define IDC_SIGNED 954
+#define IDC_UNSIGNED 955
+#define IDC_HEX 956
+#define IDC_1_BYTE 957
+#define IDC_2_BYTES 958
+#define IDC_4_BYTES 959
+#define IDC_WATCHLIST 960
+#define IDC_HEX2 960
+#define IDC_C_WATCH_EDIT 961
+#define IDC_C_WATCH_REMOVE 962
+#define IDC_C_WATCH 963
+#define IDC_C_WATCH_DUPLICATE 964
+#define IDC_C_ADDCHEAT 965
+#define ID_WATCHES_UPDOWN 966
+#define IDD_RAMWATCH 967
+#define IDC_C_WATCH_DUPLICATE2 967
+#define IDC_C_WATCH_SEPARATE 967
+#define IDR_ACCELERATOR1 968
+#define IDD_PROMPT 969
+#define ID_VIEW_DISPLAYGRAPHICALINPUT 971
+#define IDD_SOUND_VIEW 977
+#define IDC_START_FROM_SRAM 978
+#define IDC_EDIT_SRAMFILENAME 979
+#define IDC_BUTTON_BROWSESRAM 980
+#define IDC_C_WATCH_UP 980
+#define IDD_EDITWATCH 980
+#define IDC_C_WATCH_DOWN 981
+#define RAMMENU_FILE_AUTOLOAD 982
+#define RAMMENU_FILE_SAVEWINDOW 983
+#define RAMMENU_FILE_SAVE 984
+#define RAMMENU_FILE_SAVEAS 985
+#define RAMMENU_FILE_OPEN 986
+#define RAMMENU_FILE_APPEND 987
+#define RAMMENU_FILE_NEW 988
+#define RAMMENU_FILE_RECENT 990
+#define IDC_RAMLIST 991
+#define IDC_C_SEARCH 992
+#define IDC_C_RESET 993
+#define IDC_C_ELIMINATE 994
+#define IDC_LESSTHAN 995
+#define IDC_MORETHAN 996
+#define IDC_NOMORETHAN 997
+#define IDC_NOLESSTHAN 998
+#define IDC_EQUALTO 999
+#define IDC_BRIDGEADAPTER 1000
+#define IDC_SOUNDCORECB 1000
+#define IDC_USEEXTBIOS 1000
+#define ID_BROWSE 1000
+#define IDC_CHECKBOX_DEBUGGERMODE 1001
+#define IDC_SOUNDBUFFERET 1001
+#define IDC_SOUNDVIEW_CHANSWITCH 1001
+#define PM_FILENAME 1001
+#define IDC_ARM9BIOS 1002
+#define IDC_MLENGTH 1002
+#define IDC_SLVOLUME 1002
+#define IDC_GI_GAMETITLE 1003
+#define IDC_MFRAMES 1003
+#define IDC_ROTATE0 1003
+#define IDC_BUTTON2 1003
+#define IDC_CHECKBOX_ENSATAEMULATION 1003
+#define IDC_ARM9BIOSBROWSE 1004
+#define IDC_GI_GAMECODE 1004
+#define IDC_MRERECORDCOUNT 1004
+#define IDC_ROTATE90 1004
+#define IDC_SPU_INTERPOLATION_CB 1004
+#define IDC_BUTTON_VOLMODE 1004
+#define IDC_ARM7BIOS 1005
+#define IDC_MROM 1005
+#define IDC_ROTATE180 1005
+#define IDC_GGREEN 1005
+#define IDC_ROTATE270 1006
+#define IDC_GRED 1006
+#define IDC_WIFIMODE0 1006
+#define IDC_ARM7BIOSBROWSE 1007
+#define IDC_GYELLOW 1007
+#define IDC_WIFIMODE1 1007
+#define IDC_MEMVIEWBOX 1008
+#define IDC_GBLUE 1008
+#define IDC_ADHOC_SERVER 1008
+#define IDC_ADDRESS 1009
+#define IDC_BIOSSWIS 1009
+#define IDC_FORCERATIO 1009
+#define IDC_ADHOC_CLIENT 1009
+#define IDC_AUTO_UPDATE_SPIN 1010
+#define IDC_TEXTDUMP 1010
+#define IDC_WINDOW1X 1010
+#define IDC_ADHOC_SERVERNAME 1010
+#define IDC_AUTO_UPDATE_SECS 1011
+#define IDC_USEEXTFIRMWARE 1011
+#define IDC_WINDOW2X 1011
+#define IDC_FIRMWARE 1012
+#define IDC_RAWDUMP 1012
+#define IDC_REFRESH 1012
+#define IDC_WINDOW3X 1012
+#define IDC_SYNCHMODE_DUAL 1012
+#define IDC_WINDOW4X 1013
+#define IDC_VIEWMODE 1013
+#define IDC_SYNCHMODE_SYNCH 1013
+#define IDC_FIRMWAREBROWSE 1014
+#define IDC_VOLUME 1014
+#define IDC_DUMPALL 1014
+#define IDC_SYNCHMETHOD_N 1015
+#define IDC_FIRMWAREBOOT 1016
+#define IDC_SYNCHMETHOD_Z 1016
+#define IDC_GROUP_SYNCHMETHOD 1017
+#define IDC_AUTOUPDATE_ASM 1018
+#define IDC_SYNCHMETHOD_P 1018
+#define IDC_VISIBLE 1019
+#define IDC_USEPHYSICAL 1019
+#define IDC_SPLIT1 1021
+#define IDC_PATCHSWI3 1022
+#define IDC_CAP0_ADD 1023
+#define IDC_CAP0_CURDAD 1024
+#define IDC_CAP1_ADD 1025
+#define IDC_SPU_ADVANCED 1025
+#define IDC_CAP1_CURDAD 1026
+#define IDC_CHECBOX_ADVANCEDTIMING 1026
+#define IDC_DEFAULT 1027
+#define IDC_DTP_DATE 1027
+#define IDC_3DCORE 1028
+#define IDC_SNDCTRL_ENABLE 1028
+#define IDC_DTP_TIME 1028
+#define IDC_TXT_COMPILED 1029
+#define IDC_SNDCTRL_CH1NOMIX 1029
+#define IDC_TXT_VERSION 1030
+#define IDC_SNDCTRL_CH3NOMIX 1030
+#define IDC_SOUND_CAPTURE_MUTED 1031
+#define IDC_SOUND_ANALYZE_CAP 1032
+#define IDC_ADDONS_LIST 1033
+#define IDC_BUTTON3 1033
+#define IDC_SOUND_UNMUTE_ALL 1033
+#define IDC_PIANO_C 1033
+#define IDC_ADDONS_INFO 1034
+#define IDC_BORDER 1034
+#define IDC_PIANO_CS 1034
+#define IDC_BBROWSE 1035
+#define IDC_PIANO_D 1035
+#define IDC_PATHIMG 1036
+#define IDC_PIANO_DS 1036
+#define IDC_PATH 1037
+#define IDC_PATHGAME 1037
+#define IDC_PIANO_E 1037
+#define IDC_LIST_CHEATS 1037
+#define IDC_RFILE 1038
+#define IDC_EXPORT 1038
+#define IDC_RFOLDER 1039
+#define IDC_2012 1039
+#define IDC_BBROWSE2 1040
+#define IDC_PATHDESMUME 1041
+#define IDC_BRESTART 1042
+#define IDC_BVIEW 1043
+#define IDC_BSEARCH 1044
+#define IDC_PIANO_F 1044
+#define IDC_RADIO1 1045
+#define IDC_PIANO_FS 1045
+#define IDC_RADIO2 1046
+#define IDC_PIANO_GS 1046
+#define IDC_RADIO3 1047
+#define IDC_PIANO_B 1047
+#define IDC_RADIO4 1048
+#define IDC_PIANO_A 1048
+#define IDC_RADIO5 1049
+#define IDC_PIANO_AS 1049
+#define IDC_RADIO6 1050
+#define IDC_PIANO_G 1050
+#define IDC_RADIO7 1051
+#define IDC_PIANO_DS3 1051
+#define IDC_PIANO_HIC 1051
+#define IDC_RADIO8 1052
+#define IDC_LIST1 1056
+#define IDC_BADD_AR 1057
+#define IDC_BADD_CB 1058
+#define IDC_BREMOVE 1060
+#define IDC_BEDIT 1061
+#define IDC_STATIC_S1 1061
+#define IDC_STATIC_S2 1062
+#define IDC_STATIC_S3 1063
+#define IDC_STATIC_S4 1064
+#define IDC_EVALUE 1065
+#define IDC_STATIC_RANGE 1066
+#define IDC_BADD 1068
+#define IDC_LIST 1069
+#define IDC_SNUMBER 1071
+#define IDC_CHECK1 1074
+#define IDC_CHECK2 1075
+#define IDC_CAP0_SRC 1075
+#define IDC_CHECK3 1076
+#define IDC_CAP0_ONESHOT 1076
+#define IDC_CHECK4 1077
+#define IDC_CAP0_TYPE 1077
+#define IDC_CAP0_ACTIVE 1078
+#define IDC_CHECK10 1079
+#define IDC_CAP0_RUNNING 1079
+#define IDC_CHECK6 1080
+#define IDC_CAP1_SRC 1080
+#define IDC_CAP1_ONESHOT 1081
+#define IDC_CHECK7 1082
+#define IDC_CAP1_TYPE 1082
+#define IDC_CHECK8 1083
+#define IDC_CAP1_ACTIVE 1083
+#define IDC_CAP1_RUNNING 1084
+#define IDC_CHECK9 1088
+#define IDC_S2X 1090
+#define IDC_S4X 1091
+#define IDC_S8X 1092
+#define IDC_S16X 1093
+#define IDM_FIRMSETTINGS 1100
+#define IDD_FIRMSETTINGS 1101
+#define IDC_EDIT1 1102
+#define IDC_EDIT2 1103
+#define IDC_EDIT3 1104
+#define IDC_EDIT_AUTHOR 1180
+#define IDD_MATRIX_VIEWER 1200
+#define IDM_MATRIX_VIEWER 1200
+#define IDC_MATRIX_VIEWER_COORD_GROUP 1201
+#define IDC_MATRIX_VIEWER_COORD_COMBO 1202
+#define IDC_MATRIX_VIEWER_COORD_11_EDIT 1203
+#define IDC_MATRIX_VIEWER_COORD_12_EDIT 1204
+#define IDC_MATRIX_VIEWER_COORD_13_EDIT 1205
+#define IDC_MATRIX_VIEWER_COORD_14_EDIT 1206
+#define IDC_MATRIX_VIEWER_COORD_21_EDIT 1207
+#define IDC_MATRIX_VIEWER_COORD_22_EDIT 1208
+#define IDC_MATRIX_VIEWER_COORD_23_EDIT 1209
+#define IDC_MATRIX_VIEWER_COORD_24_EDIT 1210
+#define IDC_MATRIX_VIEWER_COORD_31_EDIT 1211
+#define IDC_MATRIX_VIEWER_COORD_32_EDIT 1212
+#define IDC_MATRIX_VIEWER_COORD_33_EDIT 1213
+#define IDC_MATRIX_VIEWER_COORD_34_EDIT 1214
+#define IDC_MATRIX_VIEWER_COORD_41_EDIT 1215
+#define IDC_MATRIX_VIEWER_COORD_42_EDIT 1216
+#define IDC_MATRIX_VIEWER_COORD_43_EDIT 1217
+#define IDC_MATRIX_VIEWER_COORD_44_EDIT 1218
+#define IDC_MATRIX_VIEWER_DIR_GROUP 1221
+#define IDC_MATRIX_VIEWER_DIR_COMBO 1222
+#define IDC_MATRIX_VIEWER_DIR_11_EDIT 1223
+#define IDC_MATRIX_VIEWER_DIR_12_EDIT 1224
+#define IDC_MATRIX_VIEWER_DIR_13_EDIT 1225
+#define IDC_MATRIX_VIEWER_DIR_14_EDIT 1226
+#define IDC_MATRIX_VIEWER_DIR_21_EDIT 1227
+#define IDC_MATRIX_VIEWER_DIR_22_EDIT 1228
+#define IDC_MATRIX_VIEWER_DIR_23_EDIT 1229
+#define IDC_MATRIX_VIEWER_DIR_24_EDIT 1230
+#define IDC_MATRIX_VIEWER_DIR_31_EDIT 1231
+#define IDC_MATRIX_VIEWER_DIR_32_EDIT 1232
+#define IDC_MATRIX_VIEWER_DIR_33_EDIT 1233
+#define IDC_MATRIX_VIEWER_DIR_34_EDIT 1234
+#define IDC_MATRIX_VIEWER_DIR_41_EDIT 1235
+#define IDC_MATRIX_VIEWER_DIR_42_EDIT 1236
+#define IDC_MATRIX_VIEWER_DIR_43_EDIT 1237
+#define IDC_MATRIX_VIEWER_DIR_44_EDIT 1238
+#define IDC_MATRIX_VIEWER_PROJ_GROUP 1241
+#define IDC_MATRIX_VIEWER_PROJ_11_EDIT 1243
+#define IDC_MATRIX_VIEWER_PROJ_12_EDIT 1244
+#define IDC_MATRIX_VIEWER_PROJ_13_EDIT 1245
+#define IDC_MATRIX_VIEWER_PROJ_14_EDIT 1246
+#define IDC_MATRIX_VIEWER_PROJ_21_EDIT 1247
+#define IDC_MATRIX_VIEWER_PROJ_22_EDIT 1248
+#define IDC_MATRIX_VIEWER_PROJ_23_EDIT 1249
+#define IDC_MATRIX_VIEWER_PROJ_24_EDIT 1250
+#define IDC_MATRIX_VIEWER_PROJ_31_EDIT 1251
+#define IDC_MATRIX_VIEWER_PROJ_32_EDIT 1252
+#define IDC_MATRIX_VIEWER_PROJ_33_EDIT 1253
+#define IDC_MATRIX_VIEWER_PROJ_34_EDIT 1254
+#define IDC_MATRIX_VIEWER_PROJ_41_EDIT 1255
+#define IDC_MATRIX_VIEWER_PROJ_42_EDIT 1256
+#define IDC_MATRIX_VIEWER_PROJ_43_EDIT 1257
+#define IDC_MATRIX_VIEWER_PROJ_44_EDIT 1258
+#define IDC_MATRIX_VIEWER_TEX_GROUP 1261
+#define IDC_MATRIX_VIEWER_TEX_11_EDIT 1263
+#define IDC_MATRIX_VIEWER_TEX_12_EDIT 1264
+#define IDC_MATRIX_VIEWER_TEX_13_EDIT 1265
+#define IDC_MATRIX_VIEWER_TEX_14_EDIT 1266
+#define IDC_MATRIX_VIEWER_TEX_21_EDIT 1267
+#define IDC_MATRIX_VIEWER_TEX_22_EDIT 1268
+#define IDC_MATRIX_VIEWER_TEX_23_EDIT 1269
+#define IDC_MATRIX_VIEWER_TEX_24_EDIT 1270
+#define IDC_MATRIX_VIEWER_TEX_31_EDIT 1271
+#define IDC_MATRIX_VIEWER_TEX_32_EDIT 1272
+#define IDC_MATRIX_VIEWER_TEX_33_EDIT 1273
+#define IDC_MATRIX_VIEWER_TEX_34_EDIT 1274
+#define IDC_MATRIX_VIEWER_TEX_41_EDIT 1275
+#define IDC_MATRIX_VIEWER_TEX_42_EDIT 1276
+#define IDC_MATRIX_VIEWER_TEX_43_EDIT 1277
+#define IDC_MATRIX_VIEWER_TEX_44_EDIT 1278
+#define IDD_LIGHT_VIEWER 1300
+#define IDM_LIGHT_VIEWER 1300
+#define IDC_LIGHT_VIWER_LIGHT0_GROUP 1301
+#define IDD_ABOUT_BOX 1301
+#define IDC_AUTHORS_LIST 1302
+#define IDC_LIGHT_VIEWER_LIGHT0COLOR_COLORCTRL 1302
+#define IDD_DESASSEMBLEUR_VIEWER9 1302
+#define IDC_LIGHT_VIEWER_LIGHT0COLOR_EDIT 1303
+#define IDC_LIGHT_VIEWER_LIGHT0VECTOR_EDIT 1304
+#define IDD_GBASLOT_NONE 1304
+#define IDD_GBASLOT_RUMBLEPAK 1305
+#define IDD_GBASLOT_GBAGAME 1306
+#define IDD_CHEAT_SEARCH_COMP 1307
+#define IDD_CHEAT_SEARCH_MAIN 1308
+#define IDD_CHEAT_SEARCH_RESULT 1310
+#define IDC_LIGHT_VIWER_LIGHT1_GROUP 1311
+#define IDD_CHEAT_SEARCH_EXACT 1311
+#define IDC_LIGHT_VIEWER_LIGHT1COLOR_COLORCTRL 1312
+#define IDD_CHEAT_SEARCH 1312
+#define IDC_LIGHT_VIEWER_LIGHT1COLOR_EDIT 1313
+#define IDC_LIGHT_VIEWER_LIGHT1VECTOR_EDIT 1314
+#define IDC_LIGHT_VIWER_LIGHT2_GROUP 1321
+#define IDC_LIGHT_VIEWER_LIGHT2COLOR_COLORCTRL 1322
+#define IDC_LIGHT_VIEWER_LIGHT2COLOR_EDIT 1323
+#define IDC_LIGHT_VIEWER_LIGHT2VECTOR_EDIT 1324
+#define IDC_LIGHT_VIWER_LIGHT3_GROUP 1331
+#define IDC_LIGHT_VIEWER_LIGHT3COLOR_COLORCTRL 1332
+#define IDC_LIGHT_VIEWER_LIGHT3COLOR_EDIT 1333
+#define IDC_LIGHT_VIEWER_LIGHT3VECTOR_EDIT 1334
+#define IDC_SOUND0ID 1350
+#define IDC_SOUND1ID 1351
+#define IDC_SOUND2ID 1352
+#define IDC_SOUND3ID 1353
+#define IDC_SOUND4ID 1354
+#define IDC_SOUND5ID 1355
+#define IDC_SOUND6ID 1356
+#define IDC_SOUND7ID 1357
+#define IDC_SOUND0VOL 1358
+#define IDC_SOUND1VOL 1359
+#define IDC_SOUND2VOL 1360
+#define IDC_SOUND3VOL 1361
+#define IDC_SOUND4VOL 1362
+#define IDC_SOUND5VOL 1363
+#define IDC_SOUND6VOL 1364
+#define IDC_SOUND7VOL 1365
+#define IDC_SOUND0VOLBAR 1366
+#define IDC_SOUND1VOLBAR 1367
+#define IDC_SOUND2VOLBAR 1368
+#define IDC_SOUND3VOLBAR 1369
+#define IDC_SOUND4VOLBAR 1370
+#define IDC_SOUND5VOLBAR 1371
+#define IDC_SOUND6VOLBAR 1372
+#define IDC_SOUND7VOLBAR 1373
+#define IDC_SOUND0PAN 1374
+#define IDC_SOUND1PAN 1375
+#define IDC_SOUND2PAN 1376
+#define IDC_SOUND3PAN 1377
+#define IDC_SOUND4PAN 1378
+#define IDC_SOUND5PAN 1379
+#define IDC_SOUND6PAN 1380
+#define IDC_SOUND7PAN 1381
+#define IDC_SOUND0PANBAR 1382
+#define IDC_SOUND1PANBAR 1383
+#define IDC_SOUND2PANBAR 1384
+#define IDC_SOUND3PANBAR 1385
+#define IDC_SOUND4PANBAR 1386
+#define IDC_SOUND5PANBAR 1387
+#define IDC_SOUND6PANBAR 1388
+#define IDC_SOUND7PANBAR 1389
+#define IDC_SOUND0HOLD 1390
+#define IDC_SOUND1HOLD 1391
+#define IDC_SOUND2HOLD 1392
+#define IDC_SOUND3HOLD 1393
+#define IDC_SOUND4HOLD 1394
+#define IDC_SOUND5HOLD 1395
+#define IDC_SOUND6HOLD 1396
+#define IDC_SOUND7HOLD 1397
+#define IDC_SOUND0BUSY 1398
+#define IDC_SOUND1BUSY 1399
+#define IDC_SOUND2BUSY 1400
+#define IDC_SOUND3BUSY 1401
+#define IDC_SOUND4BUSY 1402
+#define IDC_SOUND5BUSY 1403
+#define IDC_SOUND6BUSY 1404
+#define IDC_SOUND7BUSY 1405
+#define IDC_SOUND0REPEATMODE 1406
+#define IDC_SOUND1REPEATMODE 1407
+#define IDC_SOUND2REPEATMODE 1408
+#define IDC_SOUND3REPEATMODE 1409
+#define IDC_SOUND4REPEATMODE 1410
+#define IDC_SOUND5REPEATMODE 1411
+#define IDC_SOUND6REPEATMODE 1412
+#define IDC_SOUND7REPEATMODE 1413
+#define IDC_SOUND0FORMAT 1414
+#define IDC_SOUND1FORMAT 1415
+#define IDC_SOUND2FORMAT 1416
+#define IDC_SOUND3FORMAT 1417
+#define IDC_SOUND4FORMAT 1418
+#define IDC_SOUND5FORMAT 1419
+#define IDC_SOUND6FORMAT 1420
+#define IDC_SOUND7FORMAT 1421
+#define IDC_SOUND0SAD 1422
+#define IDC_SOUND1SAD 1423
+#define IDC_SOUND2SAD 1424
+#define IDC_SOUND3SAD 1425
+#define IDC_SOUND4SAD 1426
+#define IDC_SOUND5SAD 1427
+#define IDC_SOUND6SAD 1428
+#define IDC_SOUND7SAD 1429
+#define IDC_SOUND0PNT 1430
+#define IDC_SOUND1PNT 1431
+#define IDC_SOUND2PNT 1432
+#define IDC_SOUND3PNT 1433
+#define IDC_SOUND4PNT 1434
+#define IDC_SOUND5PNT 1435
+#define IDC_SOUND6PNT 1436
+#define IDC_SOUND7PNT 1437
+#define IDC_SOUND0TMR 1438
+#define IDC_SOUND1TMR 1439
+#define IDC_SOUND2TMR 1440
+#define IDC_SOUND3TMR 1441
+#define IDC_SOUND4TMR 1442
+#define IDC_SOUND5TMR 1443
+#define IDC_SOUND6TMR 1444
+#define IDC_SOUND7TMR 1445
+#define IDC_SOUND0POSLEN 1446
+#define IDC_SOUND1POSLEN 1447
+#define IDC_SOUND2POSLEN 1448
+#define IDC_SOUND3POSLEN 1449
+#define IDC_SOUND4POSLEN 1450
+#define IDC_SOUND5POSLEN 1451
+#define IDC_SOUND6POSLEN 1452
+#define IDC_SOUND7POSLEN 1453
+#define IDC_CAP0_DAD 1454
+#define IDC_CAP0_CTRL 1455
+#define IDC_CAP0_SRCTEXT 1456
+#define IDC_CAP0_TYPETEXT 1457
+#define IDC_CAP0_LEN 1458
+#define IDC_SOUND0POSLEN7 1459
+#define IDC_CAP1_DAD 1459
+#define IDC_CAP1_CTRL 1460
+#define IDC_CAP1_SRCTEXT 1461
+#define IDC_CAP1_TYPETEXT 1462
+#define IDC_CAP1_LEN 1463
+#define IDC_SNDCTRL_CTRL 1464
+#define IDC_SNDCTRL_VOL 1465
+#define IDC_SNDCTRL_BIAS 1466
+#define IDC_SNDCTRL_LEFTOUT 1467
+#define IDC_SNDCTRL_LEFTOUTTEXT 1468
+#define IDC_SNDCTRL_RIGHTOUT 1469
+#define IDC_SNDCTRL_RIGHTOUTTEXT 1470
+#define IDC_SOUND0MUTE 2001
+#define IDC_SOUND1MUTE 2002
+#define IDC_SOUND2MUTE 2003
+#define IDC_SOUND3MUTE 2004
+#define IDC_SOUND4MUTE 2005
+#define IDC_SOUND5MUTE 2006
+#define IDC_SOUND6MUTE 2007
+#define IDC_SOUND7MUTE 2008
+#define ICONDESMUME 2009
+#define IDD_REPLAYINP 2010
+#define IDD_REPLAY_METADATA 2011
+#define MENU_PRINCIPAL 2012
+#define RAMWATCH_MENU 2013
+#define RECENTROMS 2014
+#define IDC_GI_FATOFS 4464
+#define IDC_INTERPOLATECOLOR 4464
+#define IDC_GI_FATSIZE 4465
+#define IDC_3DSETTINGS_EDGEMARK 4465
+#define ID_LABEL_HK1 4465
+#define IDC_GI_ICONTITLEOFS 4466
+#define IDC_3DSETTINGS_FOG 4466
+#define ID_LABEL_HK2 4466
+#define IDC_GI_USEDROMSIZE 4467
+#define ID_LABEL_HK3 4467
+#define IDC_3DSETTINGS_FOG2 4467
+#define IDC_3DSETTINGS_TEXTURE 4467
+#define ID_LABEL_HK4 4468
+#define IDC_GI_ICON 4469
+#define ID_LABEL_HK5 4469
+#define IDC_GI_TITLE 4470
+#define ID_LABEL_HK6 4470
+#define IDC_GI_TITLEEN 4471
+#define ID_LABEL_HK7 4471
+#define IDC_GI_TITLEFR 4472
+#define ID_LABEL_HK8 4472
+#define IDC_GI_TITLEGE 4473
+#define ID_LABEL_HK9 4473
+#define IDC_GI_TITLEIT 4474
+#define ID_LABEL_HK10 4474
+#define IDC_GI_TITLESP 4475
+#define ID_LABEL_HK11 4475
+#define IDC_GI_MAKERCODE 4476
+#define ID_LABEL_HK12 4476
+#define IDC_GI_TITLEJP 4477
+#define ID_LABEL_HK13 4477
+#define IDC_GI_CHIPSIZE 4478
+#define ID_LABEL_HK14 4478
+#define IDC_GI_ARM9START 4479
+#define ID_LABEL_HK15 4479
+#define IDC_GI_ARM9ENTRY 4480
+#define ID_LABEL_HK16 4480
+#define IDC_GI_ARM9ROM 4481
+#define ID_LABEL_HK17 4481
+#define IDC_GI_ARM9SIZE 4482
+#define ID_LABEL_HK18 4482
+#define IDC_GI_ARM7ROM 4483
+#define ID_LABEL_HK19 4483
+#define IDC_GI_ARM7ENTRY 4484
+#define ID_LABEL_HK20 4484
+#define IDC_GI_ARM7START 4485
+#define ID_LABEL_HK21 4485
+#define IDC_GI_ARM7SIZE 4486
+#define ID_LABEL_HK22 4486
+#define IDC_GI_FNTOFS 4487
+#define ID_LABEL_HK23 4487
+#define IDC_GI_FNTSIZE 4488
+#define ID_LABEL_HK24 4488
+#define ID_LABEL_HK25 4489
+#define ID_LABEL_HK26 4490
+#define ID_LABEL_HK27 4491
+#define ID_LABEL_HK28 4492
+#define ID_LABEL_HK29 4493
+#define ID_LABEL_HK30 4494
+#define ID_LABEL_HK31 4495
+#define ID_LABEL_HK32 4496
+#define ID_LABEL_HK33 4497
+#define ID_LABEL_HK34 4498
+#define ID_LABEL_HK35 4499
+#define ID_LABEL_HK36 4500
+#define ID_LABEL_HK37 4501
+#define ID_LABEL_HK38 4502
+#define ID_LABEL_HK39 4503
+#define ID_LABEL_HK40 4504
+#define ID_LABEL_HK41 4505
+#define ID_LABEL_HK42 4506
+#define ID_LABEL_HK43 4507
+#define ID_LABEL_HK44 4508
+#define ID_LABEL_HK45 4509
+#define ID_LABEL_HK46 4510
+#define ID_LABEL_HK47 4511
+#define ID_LABEL_HK48 4512
+#define ID_LABEL_HK49 4513
+#define ID_LABEL_HK50 4514
+#define ID_LABEL_HK51 4515
+#define ID_LABEL_HK52 4516
+#define ID_LABEL_HK53 4517
+#define ID_LABEL_HK13b 4518
+#define ID_LABEL_HK54 4519
+#define IDD_MICROPHONE 5000
+#define IDM_MICROPHONESETTINGS 5001
+#define IDC_MICSAMPLEBROWSE 5003
+#define IDC_MICSAMPLE 5004
+#define IDC_USEMICSAMPLE 5005
+#define IDC_USEMICRAND 5009
+#define IDC_USENOISE 5010
+#define IDC_CPU 6000
+#define IDC_IOREG 6001
+#define ID_LABEL_ZELDA_SHADOW_DEPTH_HACK 9000
+#define IDC_ZELDA_SHADOW_DEPTH_HACK 9001
+#define IDD_CHEAT_ADD_XX_CODE 10005
+#define IDD_GBASLOT_GUITARGRIP 10009
+#define IDD_GBASLOT_PIANO 10010
+#define IDM_FILE_STOPAVI 40000
+#define IDM_SCREENSEP_NONE 40000
+#define IDM_FILE_STOPWAV 40001
+#define IDM_SCREENSEP_BORDER 40001
+#define IDM_SCREENSEP_NDSGAP 40002
+#define IDM_ABOUT 40003
+#define IDM_EMULATIONSETTINGS 40004
+#define IDC_FRAMELIMIT 40005
+#define ID_CONFIG_PAUSEWHENFOCUSLOST 40005
+#define IDC_WINDOW1_5X 40006
+#define IDM_WIFISETTINGS 40007
+#define IDM_ALWAYS_ON_TOP 40008
+#define ID_VIEW_FRAMECOUNTER 40009
+#define ID_VIEW_DISPLAYFPS 40010
+#define ID_VIEW_DISPLAYINPUT 40011
+#define ID_VIEW_DISPLAYLAG 40012
+#define ID_VIEW_HUDEDITOR 40013
+#define ID_VIEW_DISPLAYMICROPHONE 40014
+#define IDM_FILE_RECORDAVI 40015
+#define IDM_SOUND_VIEW 40016
+#define IDM_FILE_RECORDWAV 40017
+#define IDM_EXPORTBACKUPMEMORY 40018
+#define IDM_STOPMOVIE 40019
+#define IDM_SCREENSEP_NDSGAP2 40021
+#define IDM_SCREENSEP_DRAGEDIT 40022
+#define IDM_SCREENSEP_COLORWHITE 40023
+#define IDM_SCREENSEP_COLORGRAY 40024
+#define IDM_SCREENSEP_COLORBLACK 40025
+#define IDM_FILE_RECORDUSERSPUWAV 40026
+#define ID_FILE_RECENTROM 40034
+#define IDM_DEFSIZE 40038
+#define IDM_3DCONFIG 40040
+#define IDM_GBASLOT 40042
+#define IDM_CHEATS_LIST 40050
+#define IDM_SHUT_UP 40053
+#define IDC_WINDOW2_5X 40054
+#define ID_LCDS_VERTICAL 40055
+#define ID_LCDS_HORIZONTAL 40056
+#define ID_LCDS_ONE 40057
+#define ID_LCDS_SWAP 40058
+#define ID_LCDS_NOSWAP 40059
+#define ID_LCDS_MAINGPU 40060
+#define ID_LCDS_SUBGPU 40061
+#define IDM_CHEATS_DISABLE 40062
+#define IDM_CHEATS_SEARCH 40063
+#define ID_RAMSEARCH_CAPTIONTEXT 40064
+#define IDM_VIEW3D 40065
+#define IDM_LOCKDOWN 40066
+#define IDM_EJECTCARD 40068
+#define IDM_SHOWTOOLBAR 40069
+#define ID_CONFIG_DISPLAYMETHOD 40070
+#define ID_DISPLAYMETHOD_DIRECTDRAWHW 40071
+#define ID_DISPLAYMETHOD_DIRECTDRAWSW 40072
+#define ID_HOTKEYS_TITLE 40073
+#define ID_VIEWLAYERS_SUBOBJ 40074
+#define ID_VIEWLAYERS_MAINOBJ 40075
+#define IDM_MOBJ 40076
+#define IDM_SOBJ 40077
+#define ID_VIEW_DISPLAYRTC 40078
+#define ID_CONFIG_ADVANCED 40079
+#define ID_ADVANCED_ADVANCED 40080
+#define ID_ADVANCED 40081
+#define ID_SAVETYPE_FORCEASCURRENT 40082
+#define IDC_SAVETYPE_FORCE 40083
+#define ID_DISPLAYMETHOD_VSYNC 40084
+#define IDC_LABEL_UP 50000
+#define IDC_LABEL_RIGHT 50001
+#define IDC_LABEL_LEFT 50002
+#define IDC_LABEL_DOWN 50003
+#define IDC_LABEL_A 50004
+#define IDC_LABEL_X 50005
+#define IDC_LABEL_B 50006
+#define IDC_LABEL_Y 50007
+#define IDC_LABEL_L 50008
+#define IDC_LABEL_START 50009
+#define IDC_LABEL_R 50010
+#define IDC_LABEL_SELECT 50011
+#define IDC_LABEL_UPLEFT 50012
+#define IDC_LABEL_DOWNRIGHT 50013
+#define IDC_LABEL_UPRIGHT 50014
+#define IDC_LABEL_DOWNLEFT 50015
+#define IDC_ALLOWLEFTRIGHT 50016
+#define IDC_LABEL_X3 50017
+#define IDC_LABEL_X2 50018
+#define IDC_DEBUG 50019
+#define IDC_UP 50020
+#define IDC_LEFT 50021
+#define IDC_DOWN 50022
+#define IDC_RIGHT 50023
+#define IDC_B 50024
+#define IDC_A 50025
+#define IDC_Y 50026
+#define IDC_X 50027
+#define IDC_START 50028
+#define IDC_SELECT 50029
+#define IDC_L 50030
+#define IDC_R 50031
+#define IDC_UPLEFT 50032
+#define IDC_UPRIGHT 50033
+#define IDC_DWNRIGHT 50034
+#define IDC_DWNLEFT 50035
+#define IDC_LABEL_BLUE 50036
+#define IDC_LID 50037
+#define IDD_INPUTCONFIG 50038
+#define IDC_LABEL_BLUE1 50039
+#define IDC_LUASCRIPT_RESERVE_START 58000
+#define IDC_LUASCRIPT_RESERVE_END 58099
+#define IDD_LUARECENT_RESERVE_START 58100
+#define IDD_LUARECENT_RESERVE_END 58199
+#define IDC_LUAMENU_RESERVE_START 58200
+#define IDC_LUAMENU_RESERVE_END 58399
+#define IDC_FRAMEADVANCE 58400
+#define IDC_LABEL_HK1 60001
+#define IDC_LABEL_HK2 60002
+#define IDC_LABEL_HK3 60003
+#define IDC_LABEL_HK4 60004
+#define IDC_LABEL_HK5 60005
+#define IDC_LABEL_HK6 60006
+#define IDC_LABEL_HK7 60007
+#define IDC_LABEL_HK8 60008
+#define IDC_LABEL_HK9 60009
+#define IDC_HOTKEY1 60011
+#define IDC_HOTKEY2 60012
+#define IDC_HOTKEY3 60013
+#define IDC_HOTKEY4 60014
+#define IDC_HOTKEY5 60015
+#define IDC_HOTKEY6 60016
+#define IDC_HOTKEY7 60017
+#define IDC_HOTKEY8 60018
+#define IDC_HOTKEY9 60019
+#define IDC_HOTKEY10 60020
+#define IDC_HOTKEY11 60021
+#define IDC_HOTKEY12 60022
+#define IDC_HOTKEY13 60023
+#define IDC_HOTKEY14 60024
+#define IDC_HOTKEY15 60025
+#define IDC_HOTKEY16 60026
+#define IDC_HOTKEY17 60027
+#define IDC_HOTKEY18 60028
+#define IDC_HOTKEY19 60029
+#define IDC_HOTKEY20 60030
+#define IDC_LABEL_HK10 60031
+#define IDC_LABEL_HK11 60032
+#define IDC_LABEL_HK12 60033
+#define IDC_LABEL_HK13 60034
+#define IDC_LABEL_HK14 60035
+#define IDC_LABEL_HK15 60036
+#define IDC_LABEL_HK16 60037
+#define IDC_LABEL_HK17 60038
+#define IDC_LABEL_HK19 60040
+#define IDC_LABEL_HK20 60041
+#define IDC_LABEL_HK18 60049
+#define IDC_HKCOMBO 60077
+#define IDD_KEYCUSTOM 60078
+#define IDM_HOTKEY_CONFIG 60079
+#define IDM_RENDER_HQ2XS 60081
+#define IDM_RENDER_LQ2X 60082
+#define IDM_RENDER_LQ2XS 60083
+#define IDC_SAVETYPE 64000
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 123
+#define _APS_NEXT_COMMAND_VALUE 40085
+#define _APS_NEXT_CONTROL_VALUE 1040
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/saves.cpp
@@ -1,1 +1,1857 @@
-
+/*
+ Copyright (C) 2006 Normmatt
+ Copyright (C) 2006 Theo Berkau
+ Copyright (C) 2007 Pascal Giard
+ Copyright (C) 2008-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stack>
+#include <set>
+#include <fstream>
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+#include <sys/stat.h>
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+#include "saves.h"
+#include "MMU.h"
+#include "NDSSystem.h"
+//#include "render3D.h"
+#include "cp15.h"
+//#include "GPU_osd.h"
+#include "version.h"
+
+#include "readwrite.h"
+//#include "gfx3d.h"
+//#include "movie.h"
+//#include "mic.h"
+#include "MMU_timing.h"
+
+#include "path.h"
+
+#ifdef _WINDOWS
+//#include "main.h"
+#endif
+
+//int lastSaveState = 0; //Keeps track of last savestate used for quick save/load functions
+
+//void*v is actually a void** which will be indirected before reading
+//since this isnt supported right now, it is declared in here to make things compile
+//#define SS_INDIRECT 0x80000000
+
+//savestates_t savestates[NB_STATES];
+
+#define SAVESTATE_VERSION 12
+static const char* magic = "DeSmuME SState\0";
+
+//a savestate chunk loader can set this if it wants to permit a silent failure (for compatibility)
+static bool SAV_silent_fail_flag;
+
+SFORMAT SF_ARM7[]={
+ { "7INS", 4, 1, &NDS_ARM7.instruction },
+ { "7INA", 4, 1, &NDS_ARM7.instruct_adr },
+ { "7INN", 4, 1, &NDS_ARM7.next_instruction },
+ { "7REG", 4,16, NDS_ARM7.R },
+ { "7CPS", 4, 1, &NDS_ARM7.CPSR },
+ { "7SPS", 4, 1, &NDS_ARM7.SPSR },
+ { "7DUS", 4, 1, &NDS_ARM7.R13_usr },
+ { "7EUS", 4, 1, &NDS_ARM7.R14_usr },
+ { "7DSV", 4, 1, &NDS_ARM7.R13_svc },
+ { "7ESV", 4, 1, &NDS_ARM7.R14_svc },
+ { "7DAB", 4, 1, &NDS_ARM7.R13_abt },
+ { "7EAB", 4, 1, &NDS_ARM7.R14_abt },
+ { "7DUN", 4, 1, &NDS_ARM7.R13_und },
+ { "7EUN", 4, 1, &NDS_ARM7.R14_und },
+ { "7DIR", 4, 1, &NDS_ARM7.R13_irq },
+ { "7EIR", 4, 1, &NDS_ARM7.R14_irq },
+ { "78FI", 4, 1, &NDS_ARM7.R8_fiq },
+ { "79FI", 4, 1, &NDS_ARM7.R9_fiq },
+ { "7AFI", 4, 1, &NDS_ARM7.R10_fiq },
+ { "7BFI", 4, 1, &NDS_ARM7.R11_fiq },
+ { "7CFI", 4, 1, &NDS_ARM7.R12_fiq },
+ { "7DFI", 4, 1, &NDS_ARM7.R13_fiq },
+ { "7EFI", 4, 1, &NDS_ARM7.R14_fiq },
+ { "7SVC", 4, 1, &NDS_ARM7.SPSR_svc },
+ { "7ABT", 4, 1, &NDS_ARM7.SPSR_abt },
+ { "7UND", 4, 1, &NDS_ARM7.SPSR_und },
+ { "7IRQ", 4, 1, &NDS_ARM7.SPSR_irq },
+ { "7FIQ", 4, 1, &NDS_ARM7.SPSR_fiq },
+ { "7int", 4, 1, &NDS_ARM7.intVector },
+ { "7LDT", 1, 1, &NDS_ARM7.LDTBit },
+ { "7Wai", 4, 1, &NDS_ARM7.waitIRQ },
+ { "7hef", 4, 1, &NDS_ARM7.halt_IE_and_IF },
+ { "7iws", 1, 1, &NDS_ARM7.intrWaitARM_state },
+ { NULL, 0, 0, NULL }
+};
+
+SFORMAT SF_ARM9[]={
+ { "9INS", 4, 1, &NDS_ARM9.instruction},
+ { "9INA", 4, 1, &NDS_ARM9.instruct_adr},
+ { "9INN", 4, 1, &NDS_ARM9.next_instruction},
+ { "9REG", 4,16, NDS_ARM9.R},
+ { "9CPS", 4, 1, &NDS_ARM9.CPSR},
+ { "9SPS", 4, 1, &NDS_ARM9.SPSR},
+ { "9DUS", 4, 1, &NDS_ARM9.R13_usr},
+ { "9EUS", 4, 1, &NDS_ARM9.R14_usr},
+ { "9DSV", 4, 1, &NDS_ARM9.R13_svc},
+ { "9ESV", 4, 1, &NDS_ARM9.R14_svc},
+ { "9DAB", 4, 1, &NDS_ARM9.R13_abt},
+ { "9EAB", 4, 1, &NDS_ARM9.R14_abt},
+ { "9DUN", 4, 1, &NDS_ARM9.R13_und},
+ { "9EUN", 4, 1, &NDS_ARM9.R14_und},
+ { "9DIR", 4, 1, &NDS_ARM9.R13_irq},
+ { "9EIR", 4, 1, &NDS_ARM9.R14_irq},
+ { "98FI", 4, 1, &NDS_ARM9.R8_fiq},
+ { "99FI", 4, 1, &NDS_ARM9.R9_fiq},
+ { "9AFI", 4, 1, &NDS_ARM9.R10_fiq},
+ { "9BFI", 4, 1, &NDS_ARM9.R11_fiq},
+ { "9CFI", 4, 1, &NDS_ARM9.R12_fiq},
+ { "9DFI", 4, 1, &NDS_ARM9.R13_fiq},
+ { "9EFI", 4, 1, &NDS_ARM9.R14_fiq},
+ { "9SVC", 4, 1, &NDS_ARM9.SPSR_svc},
+ { "9ABT", 4, 1, &NDS_ARM9.SPSR_abt},
+ { "9UND", 4, 1, &NDS_ARM9.SPSR_und},
+ { "9IRQ", 4, 1, &NDS_ARM9.SPSR_irq},
+ { "9FIQ", 4, 1, &NDS_ARM9.SPSR_fiq},
+ { "9int", 4, 1, &NDS_ARM9.intVector},
+ { "9LDT", 1, 1, &NDS_ARM9.LDTBit},
+ { "9Wai", 4, 1, &NDS_ARM9.waitIRQ},
+ { "9hef", 4, 1, &NDS_ARM9.halt_IE_and_IF },
+ { "9iws", 1, 1, &NDS_ARM7.intrWaitARM_state },
+ { NULL, 0, 0, NULL }
+};
+
+SFORMAT SF_MEM[]={
+ { "ITCM", 1, sizeof(MMU.ARM9_ITCM), MMU.ARM9_ITCM},
+ { "DTCM", 1, sizeof(MMU.ARM9_DTCM), MMU.ARM9_DTCM},
+
+ //for legacy purposes, WRAX is a separate variable. shouldnt be a problem.
+ { "WRAM", 1, 0x400000, MMU.MAIN_MEM},
+ { "WRAX", 1, 0x400000, MMU.MAIN_MEM+0x400000},
+
+ //NOTE - this is not as large as the allocated memory.
+ //the memory is overlarge due to the way our memory map system is setup
+ //but there are actually no more registers than this
+ { "9REG", 1, 0x2000, MMU.ARM9_REG},
+
+ { "VMEM", 1, sizeof(MMU.ARM9_VMEM), MMU.ARM9_VMEM},
+ { "OAMS", 1, sizeof(MMU.ARM9_OAM), MMU.ARM9_OAM},
+
+ //this size is specially chosen to avoid saving the blank space at the end
+ { "LCDM", 1, 0xA4000, MMU.ARM9_LCD},
+ { NULL, 0, 0, NULL }
+};
+
+SFORMAT SF_NDS[]={
+ //{ "_WCY", 4, 1, &nds.wifiCycle},
+ { "_TCY", 8, 8, nds.timerCycle},
+ { "_VCT", 4, 1, &nds.VCount},
+ { "_OLD", 4, 1, &nds.old},
+ { "_TPX", 2, 1, NULL},
+ { "_TPY", 2, 1, NULL},
+ { "_TPB", 4, 1, NULL},
+ { "_DBG", 4, 1, NULL},
+ { "_ENS", 4, 1, NULL},
+ { "_ENH", 4, 1, NULL},
+ { "_ENI", 4, 1, NULL},
+ { "_SLP", 4, 1, &nds.sleeping},
+ { "_FBS", 4, 1, &nds.freezeBus},
+ { "_CEJ", 4, 1, &nds.cardEjected},
+ { "_P00", 1, 1, NULL},
+ { "_P01", 1, 1, NULL},
+ //{ "_P02", 1, 1, &nds.power1.gfx3d_render},
+ //{ "_P03", 1, 1, &nds.power1.gfx3d_geometry},
+ { "_P04", 1, 1, NULL},
+ { "_P05", 1, 1, NULL},
+ { "_P06", 1, 1, NULL},
+ //{ "_P07", 1, 1, &nds.power2.wifi},
+ { NULL, 0, 0, NULL }
+};
+
+SFORMAT SF_MMU[]={
+ { "M7BI", 1, sizeof(MMU.ARM7_BIOS), MMU.ARM7_BIOS},
+ { "M7ER", 1, sizeof(MMU.ARM7_ERAM), MMU.ARM7_ERAM},
+ { "M7RG", 1, sizeof(MMU.ARM7_REG), MMU.ARM7_REG},
+ { "M7WI", 1, sizeof(MMU.ARM7_WIRAM), MMU.ARM7_WIRAM},
+ { "MSWI", 1, sizeof(MMU.SWIRAM), MMU.SWIRAM},
+ { "M9RW", 1, 1, &MMU.ARM9_RW_MODE},
+ { "MDTC", 4, 1, &MMU.DTCMRegion},
+ { "MITC", 4, 1, &MMU.ITCMRegion},
+ { "MTIM", 2, 8, MMU.timer},
+ { "MTMO", 4, 8, MMU.timerMODE},
+ { "MTON", 4, 8, MMU.timerON},
+ { "MTRN", 4, 8, MMU.timerRUN},
+ { "MTRL", 2, 8, MMU.timerReload},
+ { "MIME", 4, 2, MMU.reg_IME},
+ { "MIE_", 4, 2, MMU.reg_IE},
+ { "MIF_", 4, 2, MMU.reg_IF_bits},
+
+ //{ "MGXC", 8, 1, &MMU.gfx3dCycles},
+
+ { "M_SX", 1, 2, &MMU.SPI_CNT},
+ { "M_SC", 1, 2, &MMU.SPI_CMD},
+ { "MASX", 1, 2, &MMU.AUX_SPI_CNT},
+ { "MASC", 1, 2, &MMU.AUX_SPI_CMD},
+
+ { "MDV1", 4, 1, &MMU.divRunning},
+ { "MDV2", 8, 1, &MMU.divResult},
+ { "MDV3", 8, 1, &MMU.divMod},
+ { "MDV5", 8, 1, &MMU.divCycles},
+
+ { "MSQ1", 4, 1, &MMU.sqrtRunning},
+ { "MSQ2", 4, 1, &MMU.sqrtResult},
+ { "MSQ4", 8, 1, &MMU.sqrtCycles},
+
+ //begin memory chips
+ { "BUCO", 1, 1, &MMU.fw.com},
+ { "BUAD", 4, 1, &MMU.fw.addr},
+ { "BUAS", 1, 1, &MMU.fw.addr_shift},
+ { "BUAZ", 1, 1, &MMU.fw.addr_size},
+ { "BUWE", 4, 1, &MMU.fw.write_enable},
+ { "BUWR", 4, 1, &MMU.fw.writeable_buffer},
+ //end memory chips
+
+ { "MC0A", 4, 1, &MMU.dscard[0].address},
+ { "MC0T", 4, 1, &MMU.dscard[0].transfer_count},
+ { "MC1A", 4, 1, &MMU.dscard[1].address},
+ { "MC1T", 4, 1, &MMU.dscard[1].transfer_count},
+ //{ "MCHT", 4, 1, &MMU.CheckTimers},
+ //{ "MCHD", 4, 1, &MMU.CheckDMAs},
+
+ //fifos
+ { "F0TH", 1, 1, &ipc_fifo[0].head},
+ { "F0TL", 1, 1, &ipc_fifo[0].tail},
+ { "F0SZ", 1, 1, &ipc_fifo[0].size},
+ { "F0BF", 4, 16, ipc_fifo[0].buf},
+ { "F1TH", 1, 1, &ipc_fifo[1].head},
+ { "F1TL", 1, 1, &ipc_fifo[1].tail},
+ { "F1SZ", 1, 1, &ipc_fifo[1].size},
+ { "F1BF", 4, 16, ipc_fifo[1].buf},
+
+ { "FDHD", 4, 1, NULL},
+ { "FDTL", 4, 1, NULL},
+ { "FDBF", 4, 0x6000, NULL},
+
+ { "PMCN", 1, 1, &MMU.powerMan_CntReg},
+ { "PMCW", 4, 1, &MMU.powerMan_CntRegWritten},
+ { "PMCR", 1, 5, &MMU.powerMan_Reg},
+
+ { "MR3D", 4, 1, NULL},
+
+ { NULL, 0, 0, NULL }
+};
+
+/*static uint32_t tmpu32;
+SFORMAT SF_MOVIE[]={
+ { "FRAC", 4, 1, &tmpu32},
+ { "LAGC", 4, 1, &tmpu32},
+ { NULL, 0, 0, NULL }
+};*/
+
+/*static void mmu_savestate(EMUFILE* os)
+{
+ uint32_t version = 5;
+ write32le(version,os);
+
+ //version 2:
+ MMU_new.backupDevice.save_state(os);
+
+ //version 3:
+ MMU_new.gxstat.savestate(os);
+ for(int i=0;i<2;i++)
+ for(int j=0;j<4;j++)
+ MMU_new.dma[i][j].savestate(os);
+
+ MMU_timing.arm9codeFetch.savestate(os, version);
+ MMU_timing.arm9dataFetch.savestate(os, version);
+ MMU_timing.arm7codeFetch.savestate(os, version);
+ MMU_timing.arm7dataFetch.savestate(os, version);
+ MMU_timing.arm9codeCache.savestate(os, version);
+ MMU_timing.arm9dataCache.savestate(os, version);
+
+ //version 4:
+ MMU_new.sqrt.savestate(os);
+ MMU_new.div.savestate(os);
+}*/
+
+/*static uint16_t tmpu16;
+static uint16_t tmpu16_array3[3];
+static uint8_t tmpu8;
+static uint8_t tmpu8_array3[3];
+static uint32_t tmpu32_array3[3];
+static uint8_t tmpu8_array6[6];
+static uint64_t tmpu64;
+static uint8_t tmpu8_array105[105];
+static uint16_t tmpu16_array4096[0x1000];
+static uint16_t tmpu16_array2048[0x800];
+static uint8_t tmpu8_array4096[4096];
+SFORMAT SF_WIFI[]={
+ { "W000", 4, 1, &tmpu32},
+ { "W010", 4, 1, &tmpu32},
+
+ { "W020", 2, 1, &tmpu16},
+ { "W030", 2, 1, &tmpu16},
+
+ { "W040", 2, 1, &tmpu16},
+ { "W050", 2, 1, &tmpu16},
+
+ { "W060", 2, 1, &tmpu16},
+ { "W070", 2, 1, &tmpu16},
+ { "W080", 4, 1, &tmpu32},
+
+ { "W090", 2, 3, tmpu16_array3},
+ { "W100", 2, 1, &tmpu16},
+ { "W110", 2, 1, &tmpu16},
+ { "W120", 2, 1, &tmpu16},
+ { "W130", 2, 1, &tmpu16},
+ { "W140", 4, 1, &tmpu32},
+ { "W150", 1, 1, &tmpu8},
+ { "W160", 1, 3, tmpu8_array3},
+ { "W170", 4, 3, tmpu32_array3},
+ { "W180", 4, 3, tmpu32_array3},
+ { "W190", 4, 3, tmpu32_array3},
+
+ { "W200", 2, 1, &tmpu16},
+ { "W210", 2, 1, &tmpu16},
+
+ { "W220", 1, 6, tmpu8_array6},
+ { "W230", 1, 6, tmpu8_array6},
+
+ { "W240", 2, 1, &tmpu16},
+ { "W250", 2, 1, &tmpu16},
+ { "W260", 2, 1, &tmpu16},
+
+ { "W270", 4, 1, &tmpu32},
+ { "W280", 8, 1, &tmpu64},
+ { "W290", 4, 1, &tmpu32},
+ { "W300", 8, 1, &tmpu64},
+ { "W310", 4, 1, &tmpu32},
+ { "W320", 2, 1, &tmpu16},
+ { "W330", 4, 1, &tmpu32},
+
+ { "WR00", 4, 1, &tmpu32},
+ { "WR01", 4, 1, &tmpu32},
+ { "WR02", 4, 1, &tmpu32},
+ { "WR03", 4, 1, &tmpu32},
+ { "WR04", 4, 1, &tmpu32},
+ { "WR05", 4, 1, &tmpu32},
+ { "WR06", 4, 1, &tmpu32},
+ { "WR07", 4, 1, &tmpu32},
+ { "WR08", 4, 1, &tmpu32},
+ { "WR09", 4, 1, &tmpu32},
+ { "WR10", 4, 1, &tmpu32},
+ { "WR11", 4, 1, &tmpu32},
+ { "WR12", 4, 1, &tmpu32},
+
+ { "W340", 1, 105, tmpu8_array105},
+
+ { "W350", 2, 1, &tmpu16},
+ { "W360", 2, 1, &tmpu16},
+ { "W370", 4, 1, &tmpu32},
+ { "W380", 2, 1, &tmpu16},
+
+ { "W400", 2, 0x1000, tmpu16_array4096},
+ { "W410", 2, 1, &tmpu16},
+ { "W420", 2, 1, &tmpu16},
+ { "W430", 2, 1, &tmpu16},
+ { "W460", 2, 1, &tmpu16},
+ { "W470", 2, 1, &tmpu16},
+ { "W480", 2, 1, &tmpu16},
+ { "W490", 2, 1, &tmpu16},
+ { "W500", 2, 1, &tmpu16},
+ { "W510", 2, 1, &tmpu16},
+ { "W520", 2, 1, &tmpu16},
+ { "W530", 2, 1, &tmpu16},
+ { "W540", 2, 1, &tmpu16},
+
+ { "W550", 4, 1, &tmpu32},
+ { "W560", 4, 1, &tmpu32},
+ { "W570", 4, 1, &tmpu32},
+
+ { "W580", 2, 0x800, tmpu16_array2048},
+ { "W590", 2, 1, &tmpu16},
+
+ { "WX00", 8, 1, &tmpu64},
+ { "WX10", 1, 4096, tmpu8_array4096},
+ { "WX20", 4, 1, &tmpu32},
+ { "WX30", 4, 1, &tmpu32},
+ { "WX40", 4, 1, &tmpu32},
+
+ { NULL, 0, 0, NULL }
+};*/
+
+static bool mmu_loadstate(EMUFILE* is, int)
+{
+ //read version
+ uint32_t version;
+ if(read32le(&version,is) != 1) return false;
+
+ if(version == 0 || version == 1)
+ {
+ uint32_t bupmem_size;
+ uint32_t addr_size;
+
+ if(version == 0)
+ {
+ //version 0 was buggy and didnt save the type.
+ //it would silently fail if there was a size mismatch
+ SAV_silent_fail_flag = true;
+ if(read32le(&bupmem_size,is) != 1) return false;
+ //if(bupmem_size != MMU.bupmem.size) return false; //mismatch between current initialized and saved size
+ addr_size = BackupDevice::addr_size_for_old_save_size(bupmem_size);
+ }
+ else if(version == 1)
+ {
+ //version 1 reinitializes the save system with the type that was saved
+ uint32_t bupmem_type;
+ if(read32le(&bupmem_type,is) != 1) return false;
+ if(read32le(&bupmem_size,is) != 1) return false;
+ addr_size = BackupDevice::addr_size_for_old_save_type(bupmem_type);
+ if(addr_size == 0xFFFFFFFF)
+ addr_size = BackupDevice::addr_size_for_old_save_size(bupmem_size);
+ }
+
+ if(addr_size == 0xFFFFFFFF)
+ return false;
+
+ uint8_t* temp = new uint8_t[bupmem_size];
+ is->fread((char*)temp,bupmem_size);
+ MMU_new.backupDevice.load_old_state(addr_size,temp,bupmem_size);
+ delete[] temp;
+ if(is->fail()) return false;
+ }
+
+ if(version < 2) return true;
+
+ bool ok = MMU_new.backupDevice.load_state(is);
+
+ if(version < 3) return true;
+
+ ok &= MMU_new.gxstat.loadstate(is);
+
+ for(int i=0;i<2;i++)
+ for(int j=0;j<4;j++)
+ ok &= MMU_new.dma[i][j].loadstate(is);
+
+ ok &= MMU_timing.arm9codeFetch.loadstate(is, version);
+ ok &= MMU_timing.arm9dataFetch.loadstate(is, version);
+ ok &= MMU_timing.arm7codeFetch.loadstate(is, version);
+ ok &= MMU_timing.arm7dataFetch.loadstate(is, version);
+ ok &= MMU_timing.arm9codeCache.loadstate(is, version);
+ ok &= MMU_timing.arm9dataCache.loadstate(is, version);
+
+ if(version < 4) return true;
+
+ ok &= MMU_new.sqrt.loadstate(is,version);
+ ok &= MMU_new.div.loadstate(is,version);
+
+ //to prevent old savestates from confusing IF bits, mask out ones which had been stored but should have been generated
+ MMU.reg_IF_bits[0] &= ~0x00200000;
+ MMU.reg_IF_bits[1] &= ~0x00000000;
+
+ //MMU_new.gxstat.fifo_low = gxFIFO.size <= 127;
+ //MMU_new.gxstat.fifo_empty = gxFIFO.size == 0;
+
+ /*if(version < 5)
+ MMU.reg_DISP3DCNT_bits = T1ReadWord(MMU.ARM9_REG,0x60);*/
+
+ return ok;
+}
+
+/*static void cp15_saveone(armcp15_t *cp15, EMUFILE* os)
+{
+ write32le(cp15->IDCode,os);
+ write32le(cp15->cacheType,os);
+ write32le(cp15->TCMSize,os);
+ write32le(cp15->ctrl,os);
+ write32le(cp15->DCConfig,os);
+ write32le(cp15->ICConfig,os);
+ write32le(cp15->writeBuffCtrl,os);
+ write32le(cp15->und,os);
+ write32le(cp15->DaccessPerm,os);
+ write32le(cp15->IaccessPerm,os);
+ write32le(cp15->protectBaseSize0,os);
+ write32le(cp15->protectBaseSize1,os);
+ write32le(cp15->protectBaseSize2,os);
+ write32le(cp15->protectBaseSize3,os);
+ write32le(cp15->protectBaseSize4,os);
+ write32le(cp15->protectBaseSize5,os);
+ write32le(cp15->protectBaseSize6,os);
+ write32le(cp15->protectBaseSize7,os);
+ write32le(cp15->cacheOp,os);
+ write32le(cp15->DcacheLock,os);
+ write32le(cp15->IcacheLock,os);
+ write32le(cp15->ITCMRegion,os);
+ write32le(cp15->DTCMRegion,os);
+ write32le(cp15->processID,os);
+ write32le(cp15->RAM_TAG,os);
+ write32le(cp15->testState,os);
+ write32le(cp15->cacheDbg,os);
+ for(int i=0;i<8;i++) write32le(cp15->regionWriteMask_USR[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionWriteMask_SYS[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionReadMask_USR[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionReadMask_SYS[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionExecuteMask_USR[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionExecuteMask_SYS[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionWriteSet_USR[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionWriteSet_SYS[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionReadSet_USR[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionReadSet_SYS[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionExecuteSet_USR[i],os);
+ for(int i=0;i<8;i++) write32le(cp15->regionExecuteSet_SYS[i],os);
+}*/
+
+/*static void cp15_savestate(EMUFILE* os)
+{
+ //version
+ write32le(1,os);
+
+ cp15_saveone((armcp15_t *)NDS_ARM9.coproc[15],os);
+ //ARM7 not have coprocessor
+ //cp15_saveone((armcp15_t *)NDS_ARM7.coproc[15],os);
+}*/
+
+static bool cp15_loadone(armcp15_t *cp15, EMUFILE* is)
+{
+ if(!read32le(&cp15->IDCode,is)) return false;
+ if(!read32le(&cp15->cacheType,is)) return false;
+ if(!read32le(&cp15->TCMSize,is)) return false;
+ if(!read32le(&cp15->ctrl,is)) return false;
+ if(!read32le(&cp15->DCConfig,is)) return false;
+ if(!read32le(&cp15->ICConfig,is)) return false;
+ if(!read32le(&cp15->writeBuffCtrl,is)) return false;
+ if(!read32le(&cp15->und,is)) return false;
+ if(!read32le(&cp15->DaccessPerm,is)) return false;
+ if(!read32le(&cp15->IaccessPerm,is)) return false;
+ if(!read32le(&cp15->protectBaseSize0,is)) return false;
+ if(!read32le(&cp15->protectBaseSize1,is)) return false;
+ if(!read32le(&cp15->protectBaseSize2,is)) return false;
+ if(!read32le(&cp15->protectBaseSize3,is)) return false;
+ if(!read32le(&cp15->protectBaseSize4,is)) return false;
+ if(!read32le(&cp15->protectBaseSize5,is)) return false;
+ if(!read32le(&cp15->protectBaseSize6,is)) return false;
+ if(!read32le(&cp15->protectBaseSize7,is)) return false;
+ if(!read32le(&cp15->cacheOp,is)) return false;
+ if(!read32le(&cp15->DcacheLock,is)) return false;
+ if(!read32le(&cp15->IcacheLock,is)) return false;
+ if(!read32le(&cp15->ITCMRegion,is)) return false;
+ if(!read32le(&cp15->DTCMRegion,is)) return false;
+ if(!read32le(&cp15->processID,is)) return false;
+ if(!read32le(&cp15->RAM_TAG,is)) return false;
+ if(!read32le(&cp15->testState,is)) return false;
+ if(!read32le(&cp15->cacheDbg,is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionWriteMask_USR[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionWriteMask_SYS[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionReadMask_USR[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionReadMask_SYS[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionExecuteMask_USR[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionExecuteMask_SYS[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionWriteSet_USR[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionWriteSet_SYS[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionReadSet_USR[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionReadSet_SYS[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionExecuteSet_USR[i],is)) return false;
+ for(int i=0;i<8;i++) if(!read32le(&cp15->regionExecuteSet_SYS[i],is)) return false;
+
+ return true;
+}
+
+static bool cp15_loadstate(EMUFILE* is, int)
+{
+ //read version
+ uint32_t version;
+ if(read32le(&version,is) != 1) return false;
+ if(version > 1) return false;
+
+ if(!cp15_loadone((armcp15_t *)NDS_ARM9.coproc[15],is)) return false;
+
+ if(version == 0)
+ {
+ //ARM7 not have coprocessor
+ uint8_t *tmp_buf = new uint8_t [sizeof(armcp15_t)];
+ if (!tmp_buf) return false;
+ if(!cp15_loadone((armcp15_t *)tmp_buf,is)) return false;
+ delete [] tmp_buf;
+ tmp_buf = NULL;
+ }
+
+ return true;
+}
+
+
+
+/* Format time and convert to string */
+/*static char * format_time(time_t cal_time)
+{
+ struct tm *time_struct;
+ static char str[64];
+
+ time_struct=localtime(&cal_time);
+ strftime(str, sizeof str, "%d-%b-%Y %H:%M:%S", time_struct);
+
+ return str;
+}*/
+
+/*void clear_savestates()
+{
+ uint8_t i;
+ for( i = 0; i < NB_STATES; i++ )
+ savestates[i].exists = false;
+}*/
+
+// Scan for existing savestates and update struct
+/*void scan_savestates()
+{
+ struct stat sbuf;
+ char filename[MAX_PATH+1];
+
+ clear_savestates();
+
+ for(int i = 0; i < NB_STATES; i++ )
+ {
+ path.getpathnoext(path.STATES, filename);
+
+ if (strlen(filename) + strlen(".dst") + strlen("-2147483648")*/ /* = biggest string for i */ /*>MAX_PATH) return ;
+ sprintf(filename+strlen(filename), ".ds%d", i);
+ if( stat(filename,&sbuf) == -1 ) continue;
+ savestates[i].exists = true;
+ strncpy(savestates[i].date, format_time(sbuf.st_mtime),40);
+ savestates[i].date[40-1] = '\0';
+ }
+
+ return ;
+}*/
+
+/*void savestate_slot(int num)
+{
+ struct stat sbuf;
+ char filename[MAX_PATH+1];
+
+ lastSaveState = num; //Set last savestate used
+
+ path.getpathnoext(path.STATES, filename);
+
+ if (strlen(filename) + strlen(".dsx") + strlen("-2147483648")*/ /* = biggest string for num *//* >MAX_PATH) return ;
+ sprintf(filename+strlen(filename), ".ds%d", num);*/
+
+ /*if (savestate_save(filename))
+ {
+ osd->setLineColor(255, 255, 255);
+ osd->addLine("Saved to %i slot", num);
+ }
+ else
+ {
+ osd->setLineColor(255, 0, 0);
+ osd->addLine("Error saving %i slot", num);
+ return;
+ }*/
+
+ /*if (num >= 0 && num < NB_STATES)
+ {
+ if (stat(filename,&sbuf) != -1)
+ {
+ savestates[num].exists = true;
+ strncpy(savestates[num].date, format_time(sbuf.st_mtime),40);
+ savestates[num].date[40-1] = '\0';
+ }
+ }
+}*/
+
+/*void loadstate_slot(int num)
+{
+ char filename[MAX_PATH];
+
+ lastSaveState = num; //Set last savestate used
+
+ path.getpathnoext(path.STATES, filename);
+
+ if (strlen(filename) + strlen(".dsx") + strlen("-2147483648")*/ /* = biggest string for num *//* >MAX_PATH) return ;
+ sprintf(filename+strlen(filename), ".ds%d", num);*/
+ /*if (savestate_load(filename))
+ {
+ osd->setLineColor(255, 255, 255);
+ osd->addLine("Loaded from %i slot", num);
+ }
+ else
+ {
+ osd->setLineColor(255, 0, 0);
+ osd->addLine("Error loading %i slot", num);
+ }*/
+//}
+
+
+// note: guessSF is so we don't have to do a linear search through the SFORMAT array every time
+// in the (most common) case that we already know where the next entry is.
+static const SFORMAT *CheckS(const SFORMAT *guessSF, const SFORMAT *firstSF, uint32_t size, uint32_t count, char *desc)
+{
+ const SFORMAT *sf = guessSF ? guessSF : firstSF;
+ while(sf->v)
+ {
+ //NOT SUPPORTED RIGHT NOW
+ //if(sf->size==~0) // Link to another SFORMAT structure.
+ //{
+ // SFORMAT *tmp;
+ // if((tmp= CheckS((SFORMAT *)sf->v, tsize, desc) ))
+ // return tmp;
+ // sf++;
+ // continue;
+ //}
+ if(!memcmp(desc,sf->desc,4))
+ {
+ if(sf->size != size || sf->count != count)
+ return 0;
+ return sf;
+ }
+
+ // failed to find it, have to keep iterating
+ if(guessSF)
+ {
+ sf = firstSF;
+ guessSF = NULL;
+ }
+ else
+ {
+ sf++;
+ }
+ }
+ return 0;
+}
+
+
+static bool ReadStateChunk(EMUFILE* is, const SFORMAT *sf, int size)
+{
+ const SFORMAT *tmp = NULL;
+ const SFORMAT *guessSF = NULL;
+ size_t temp = is->ftell();
+
+ while(is->ftell()<temp+size)
+ {
+ uint32_t sz, count;
+
+ char toa[4];
+ is->fread(toa,4);
+ if(is->fail())
+ return false;
+
+ if(!read32le(&sz,is)) return false;
+ if(!read32le(&count,is)) return false;
+
+ if((tmp=CheckS(guessSF,sf,sz,count,toa)))
+ {
+ #ifdef LOCAL_LE
+ // no need to ever loop one at a time if not flipping byte order
+ is->fread((char *)tmp->v,sz*count);
+ #else
+ if(sz == 1) {
+ //special case: read a huge byte array
+ is->fread((char *)tmp->v,count);
+ } else {
+ for(unsigned int i=0;i<count;i++)
+ {
+ is->fread((char *)tmp->v + i*sz,sz);
+ FlipByteOrder((uint8_t*)tmp->v + i*sz,sz);
+ }
+ }
+ #endif
+ guessSF = tmp + 1;
+ }
+ else
+ {
+ is->fseek(sz*count,SEEK_CUR);
+ guessSF = NULL;
+ }
+ } // while(...)
+ return true;
+}
+
+
+
+/*static int SubWrite(EMUFILE* os, const SFORMAT *sf)
+{
+ uint32_t acc=0;
+
+#ifdef DEBUG
+ std::set<std::string> keyset;
+#endif
+
+ const SFORMAT* temp = sf;
+ while(temp->v) {
+ const SFORMAT* seek = sf;
+ while(seek->v && seek != temp) {
+ if(!strcmp(seek->desc,temp->desc)) {
+ printf("ERROR! duplicated chunk name: %s\n", temp->desc);
+ }
+ seek++;
+ }
+ temp++;
+ }
+
+ while(sf->v)
+ {
+ //not supported right now
+ //if(sf->size==~0) //Link to another struct
+ //{
+ // uint32_t tmp;
+
+ // if(!(tmp=SubWrite(os,(SFORMAT *)sf->v)))
+ // return 0;
+ // acc+=tmp;
+ // sf++;
+ // continue;
+ //}
+
+ int count = sf->count;
+ int size = sf->size;
+
+ //add size of current node to the accumulator
+ acc += 4 + sizeof(sf->size) + sizeof(sf->count);
+ acc += count * size;
+
+ if(os) //Are we writing or calculating the size of this block?
+ {
+ os->fwrite(sf->desc,4);
+ write32le(sf->size,os);
+ write32le(sf->count,os);
+
+ #ifdef DEBUG
+ //make sure we dont dup any keys
+ if(keyset.find(sf->desc) != keyset.end())
+ {
+ printf("duplicate save key!\n");
+ assert(false);
+ }
+ keyset.insert(sf->desc);
+ #endif
+
+
+ #ifdef LOCAL_LE
+ // no need to ever loop one at a time if not flipping byte order
+ os->fwrite((char *)sf->v,size*count);
+ #else
+ if(size == 1) {
+ //special case: write a huge byte array
+ os->fwrite((char *)sf->v,count);
+ } else {
+ for(int i=0;i<count;i++) {
+ FlipByteOrder((uint8_t*)sf->v + i*size, size);
+ os->fwrite((char*)sf->v + i*size,size);
+ //Now restore the original byte order.
+ FlipByteOrder((uint8_t*)sf->v + i*size, size);
+ }
+ }
+ #endif
+ }
+ sf++;
+ }
+
+ return acc;
+}*/
+
+/*static int savestate_WriteChunk(EMUFILE* os, int type, const SFORMAT *sf)
+{
+ write32le(type,os);
+ if(!sf) return 4;
+ int bsize = SubWrite((EMUFILE*)0,sf);
+ write32le(bsize,os);
+
+ if(!SubWrite(os,sf))
+ {
+ return 8;
+ }
+ return bsize+8;
+}*/
+
+/*static void savestate_WriteChunk(EMUFILE* os, int type, void (*saveproc)(EMUFILE* os))
+{
+ uint32_t pos1 = os->ftell();
+
+ //write the type, size(placeholder), and data
+ write32le(type,os);
+ os->fseek(4, SEEK_CUR); // skip the size, we write that later
+ saveproc(os);
+
+ //get the size
+ uint32_t pos2 = os->ftell();
+ assert(pos2 != (uint32_t)-1); // if this assert fails, saveproc did something bad
+ uint32_t size = (pos2 - pos1) - (2 * sizeof(uint32_t));
+
+ //fill in the actual size
+ os->fseek(pos1 + sizeof(uint32_t),SEEK_SET);
+ write32le(size,os);
+ os->fseek(pos2,SEEK_SET);*/
+
+/*
+// old version of this function,
+// for reference in case the new one above starts misbehaving somehow:
+
+ // - this is retarded. why not write placeholders for size and then write directly to the stream
+ //and then go back and fill them in
+
+ //get the size
+ memorystream mstemp;
+ saveproc(&mstemp);
+ mstemp.flush();
+ uint32_t size = mstemp.size();
+
+ //write the type, size, and data
+ write32le(type,os);
+ write32le(size,os);
+ os->write(mstemp.buf(),size);
+*/
+//}
+
+//static void writechunks(EMUFILE* os);
+
+/*bool savestate_save(EMUFILE* outstream, int compressionLevel)
+{
+ #ifndef HAVE_LIBZ
+ compressionLevel = Z_NO_COMPRESSION;
+ #endif
+
+ EMUFILE_MEMORY ms;
+ EMUFILE* os;
+
+ if(compressionLevel != Z_NO_COMPRESSION)
+ {
+ //generate the savestate in memory first
+ os = (EMUFILE*)&ms;
+ writechunks(os);
+ }
+ else
+ {
+ os = outstream;
+ os->fseek(32,SEEK_SET); //skip the header
+ writechunks(os);
+ }
+
+ //save the length of the file
+ uint32_t len = os->ftell();
+
+ uint32_t comprlen = 0xFFFFFFFF;
+ uint8_t* cbuf;
+
+ //compress the data
+ int error = Z_OK;
+ if(compressionLevel != Z_NO_COMPRESSION)
+ {
+ cbuf = ms.buf();
+ uLongf comprlen2;
+ //worst case compression.
+ //zlib says "0.1% larger than sourceLen plus 12 bytes"
+ comprlen = (len>>9)+12 + len;
+ cbuf = new uint8_t[comprlen];
+ // Workaround to make it compile under linux 64bit
+ comprlen2 = comprlen;
+ //error = compress2(cbuf,&comprlen2,ms.buf(),len,compressionLevel);
+ comprlen = (uint32_t)comprlen2;
+ }
+
+ //dump the header
+ outstream->fseek(0,SEEK_SET);
+ outstream->fwrite(magic,16);
+ write32le(SAVESTATE_VERSION,outstream);
+ write32le(EMU_DESMUME_VERSION_NUMERIC(),outstream); //desmume version
+ write32le(len,outstream); //uncompressed length
+ write32le(comprlen,outstream); //compressed length (-1 if it is not compressed)
+
+ if(compressionLevel != Z_NO_COMPRESSION)
+ {
+ outstream->fwrite((char*)cbuf,comprlen==(uint32_t)-1?len:comprlen);
+ delete[] cbuf;
+ }
+
+ return error == Z_OK;
+}*/
+
+/*bool savestate_save (const char *file_name)
+{
+ EMUFILE_MEMORY ms;
+ size_t elems_written;
+#ifdef HAVE_LIBZ
+ if(!savestate_save(&ms, Z_DEFAULT_COMPRESSION))
+#else
+ if(!savestate_save(&ms, 0))
+#endif
+ return false;
+ FILE* file = fopen(file_name,"wb");
+ if(file)
+ {
+ elems_written = fwrite(ms.buf(),1,ms.size(),file);
+ fclose(file);
+ return elems_written == ms.size();
+ } else return false;
+}*/
+
+//extern SFORMAT SF_RTC[];
+
+/*static void writechunks(EMUFILE* os) {
+ savestate_WriteChunk(os,1,SF_ARM9);
+ savestate_WriteChunk(os,2,SF_ARM7);
+ savestate_WriteChunk(os,3,cp15_savestate);
+ savestate_WriteChunk(os,4,SF_MEM);
+ savestate_WriteChunk(os,5,SF_NDS);
+ savestate_WriteChunk(os,51,nds_savestate);
+ savestate_WriteChunk(os,60,SF_MMU);
+ savestate_WriteChunk(os,61,mmu_savestate);
+ //savestate_WriteChunk(os,7,gpu_savestate);
+ savestate_WriteChunk(os,8,spu_savestate);
+ //savestate_WriteChunk(os,81,mic_savestate);
+ //savestate_WriteChunk(os,90,SF_GFX3D);
+ //savestate_WriteChunk(os,91,gfx3d_savestate);
+ //savestate_WriteChunk(os,100,SF_MOVIE);
+ //savestate_WriteChunk(os,101,mov_savestate);
+ //savestate_WriteChunk(os,110,SF_WIFI);
+ //savestate_WriteChunk(os,120,SF_RTC);
+ savestate_WriteChunk(os,0xFFFFFFFF,(SFORMAT*)0);
+}*/
+
+/*static bool fake_gpu_loadstate(EMUFILE* is, int size)
+{
+ //read version
+ uint32_t version;
+
+ //sigh.. shouldve used a new version number
+ if(size == 256*192*2*2)
+ version = 0;
+ else if(size== 0x30024)
+ {
+ read32le(&version,is);
+ version = 1;
+ }
+ else
+ if(read32le(&version,is) != 1) return false;
+
+
+ if(version<0||version>1) return false;
+
+ uint8_t tmpu8_array[4*256*192];
+ is->fread((char*)tmpu8_array,sizeof(tmpu8_array));
+
+ if(version==1)
+ {
+ uint32_t tmpu32;
+ for (int i = 0; i < 8; ++i)
+ read32le(&tmpu32, is);*/
+ /*read32le(&MainScreen.gpu->affineInfo[0].x,is);
+ read32le(&MainScreen.gpu->affineInfo[0].y,is);
+ read32le(&MainScreen.gpu->affineInfo[1].x,is);
+ read32le(&MainScreen.gpu->affineInfo[1].y,is);
+ read32le(&SubScreen.gpu->affineInfo[0].x,is);
+ read32le(&SubScreen.gpu->affineInfo[0].y,is);
+ read32le(&SubScreen.gpu->affineInfo[1].x,is);
+ read32le(&SubScreen.gpu->affineInfo[1].y,is);*/
+ //removed per nitsuja feedback. anyway, this same thing will happen almost immediately in gpu line=0
+ //MainScreen.gpu->refreshAffineStartRegs(-1,-1);
+ //SubScreen.gpu->refreshAffineStartRegs(-1,-1);
+ /*}
+
+ //MainScreen.gpu->updateBLDALPHA();
+ //SubScreen.gpu->updateBLDALPHA();
+ return !is->fail();
+}*/
+
+/*static bool fake_mic_loadstate(EMUFILE* is, int size)
+{
+ uint32_t version;
+ if(read32le(&version,is) != 1) return false;
+ if(version > 1 || version == 0) { is->fseek(size-4, SEEK_CUR); return true; }
+
+ uint8_t tmpu8_Array[2][4096];
+ is->fread((char*)tmpu8_Array[0], 4096);
+ is->fread((char*)tmpu8_Array[1], 4096);
+ uint16_t tmpu16;
+ read16le(&tmpu16,is);
+ uint8_t tmpu8;
+ read8le(&tmpu8,is);
+ read8le(&tmpu8,is);
+ uint32_t tmpu32;
+ read32le(&tmpu32,is);
+ return true;
+}*/
+
+/*static uint32_t tmpu32_array16[16];
+static uint32_t tmpu32_array64[64];
+static uint32_t tmpu32_array4[4];
+static uint16_t tmpu16_array6[6];
+static uint8_t tmpu8_array4[4];
+static uint16_t tmpu16_array32[32];
+static uint8_t tmpu8_array128[128];
+static uint8_t tmpu8_arrayAlot[4*256*192];
+SFORMAT SF_GFX3D[]={
+ { "GCTL", 4, 1, &tmpu32}, // no longer regenerated indirectly, see comment in loadstate()
+ { "GPAT", 4, 1, &tmpu32},
+ { "GPAP", 4, 1, &tmpu32},
+ { "GINB", 4, 1, &tmpu32},
+ { "GTFM", 4, 1, &tmpu32},
+ { "GTPA", 4, 1, &tmpu32},
+ { "GMOD", 4, 1, &tmpu32},
+ { "GMTM", 4,16, tmpu32_array16},
+ { "GMCU", 4,64, tmpu32_array64},
+ { "ML4I", 1, 1, &tmpu8},
+ { "ML3I", 1, 1, &tmpu8},
+ { "MM4I", 1, 1, &tmpu8},
+ { "MM3I", 1, 1, &tmpu8},
+ { "MMxI", 1, 1, &tmpu8},
+ { "GSCO", 4, 1, tmpu32_array4},
+ { "GCOI", 1, 1, &tmpu8},
+ { "GVFM", 4, 1, &tmpu32},
+ { "GTRN", 4, 4, tmpu32_array4},
+ { "GTRI", 1, 1, &tmpu8},
+ { "GSCA", 4, 4, tmpu32_array4},
+ { "GSCI", 1, 1, &tmpu8},
+ { "G_T_", 4, 1, &tmpu32},
+ { "G_S_", 4, 1, &tmpu32},
+ { "GL_T", 4, 1, &tmpu32},
+ { "GL_S", 4, 1, &tmpu32},
+ { "GLCM", 4, 1, &tmpu32},
+ { "GLIN", 4, 1, &tmpu32},
+ { "GLI2", 4, 1, &tmpu32},
+ { "GLSB", 4, 1, &tmpu32},
+ { "GLBT", 4, 1, &tmpu32},
+ { "GLPT", 4, 1, &tmpu32},
+ { "GLPC", 4, 4, tmpu32_array4},
+ { "GBTC", 2, 6, tmpu16_array6},
+ { "GFHE", 4, 1, &gxFIFO.head},
+ { "GFTA", 4, 1, &gxFIFO.tail},
+ { "GFSZ", 4, 1, &gxFIFO.size},
+ { "GFCM", 1, HACK_GXIFO_SIZE, &gxFIFO.cmd[0]},
+ { "GFPM", 4, HACK_GXIFO_SIZE, &gxFIFO.param[0]},
+ { "GPHE", 1, 1, &gxPIPE.head},
+ { "GPTA", 1, 1, &gxPIPE.tail},
+ { "GPSZ", 1, 1, &gxPIPE.size},
+ { "GPCM", 1, 4, &gxPIPE.cmd[0]},
+ { "GPPM", 4, 4, &gxPIPE.param[0]},
+ { "GCOL", 1, 4, &tmpu8_array4},
+ { "GLCO", 4, 4, tmpu32_array4},
+ { "GLDI", 4, 4, tmpu32_array4},
+ { "GMDI", 2, 1, &tmpu16},
+ { "GMAM", 2, 1, &tmpu16},
+ { "GMSP", 2, 1, &tmpu16},
+ { "GMEM", 2, 1, &tmpu16},
+ { "GFLP", 4, 1, &tmpu32},
+ { "GDRP", 4, 1, &tmpu32},
+ { "GSET", 4, 1, &tmpu32},
+ { "GSEA", 4, 1, &tmpu32},
+ { "GSEB", 4, 1, &tmpu32},
+ { "GSEX", 4, 1, &tmpu32},
+ { "GSEE", 4, 1, &tmpu32},
+ { "GSEC", 4, 1, &tmpu32},
+ { "GSEF", 4, 1, &tmpu32},
+ { "GSEO", 4, 1, &tmpu32},
+ { "GFSH", 4, 1, &tmpu32},
+ { "GSSH", 4, 1, &tmpu32},
+ { "GSWB", 4, 1, &tmpu32},
+ { "GSSM", 4, 1, &tmpu32},
+ { "GSAR", 1, 1, &tmpu8},
+ { "GSVP", 4, 1, &tmpu32},
+ { "GSCC", 4, 1, &tmpu32},
+ { "GSCD", 4, 1, &tmpu32},
+ { "GSFC", 4, 4, tmpu32_array4},
+ { "GSFO", 4, 1, &tmpu32},
+ { "GST4", 2, 32, tmpu16_array32},
+ { "GSSU", 1, 128, tmpu8_array128},
+ { "GSSI", 4, 1, &tmpu32},
+ { "GSAF", 4, 1, &tmpu32},
+ { "GSPF", 4, 1, &tmpu32},
+ //------------------------
+ { "GTST", 4, 1, &tmpu32},
+ { "GTVC", 4, 1, &tmpu32},
+ { "GTVM", 4, 4, tmpu32_array4},
+ { "GTVF", 4, 1, &tmpu32},
+ { "G3CX", 1, 4*256*192, tmpu8_arrayAlot},
+ { 0 }
+};*/
+
+/*static uint8_t tmpu8_array8[8];
+static SFORMAT SF_RTC[]={
+ { "R000", 1, 1, &tmpu8},
+ { "R010", 1, 1, &tmpu8},
+ { "R020", 1, 1, &tmpu8},
+ { "R030", 1, 1, &tmpu8},
+
+ { "R040", 1, 1, &tmpu8},
+ { "R050", 1, 1, &tmpu8},
+ { "R060", 1, 1, &tmpu8},
+ { "R070", 1, 1, &tmpu8},
+ { "R080", 1, 1, &tmpu8},
+ { "R090", 1, 1, &tmpu8},
+ { "R100", 1, 1, &tmpu8},
+ { "R110", 2, 1, &tmpu16},
+
+ { "R120", 1, 1, &tmpu8},
+ { "R130", 1, 1, &tmpu8},
+ { "R140", 1, 1, &tmpu8},
+ { "R150", 1, 8, tmpu8_array8},
+
+ { "R160", 1, 8, tmpu8_array8},
+
+ { NULL, 0, 0, NULL }
+};*/
+
+/*static bool fake_gfx_hardware_loadstate(EMUFILE *f)
+{
+ uint32_t version;
+ if(read32le(&version,f) != 1) return false;
+ if(version != 0) return false;
+
+ uint32_t tempsize;
+ read32le(&tempsize,f);
+ uint32_t commandCursor = 4-tempsize;
+ //for(uint32_t i=0;i<commandCursor;i++) commandsPending[i].command = 0;
+ uint8_t tmpu8;
+ for(uint32_t i=commandCursor;i<4;i++) read8le(&commandsPending[i].command&tmpu8,f);
+ read32le(&tempsize,f);
+ //for(uint32_t i=0;i<commandCursor;i++) commandsPending[i].countdown = 0;
+ for(uint32_t i=commandCursor;i<4;i++) read8le(&commandsPending[i].countdown&tmpu8,f);
+
+ read8le(&countdown&tmpu8,f);
+
+ return true;
+}*/
+
+/*static bool fake_gfx3d_loadstate(EMUFILE* is, int size)
+{
+ int version;
+ if(read32le(&version,is) != 1) return false;
+ if(size==8) version = 0;
+
+
+ //gfx3d_glPolygonAttrib_cache();
+ //gfx3d_glTexImage_cache();
+ //gfx3d_glLightDirection_cache(0);
+ //gfx3d_glLightDirection_cache(1);
+ //gfx3d_glLightDirection_cache(2);
+ //gfx3d_glLightDirection_cache(3);
+
+ //jiggle the lists. and also wipe them. this is clearly not the best thing to be doing.
+ //listTwiddle = 0;
+ //polylist = &polylists[listTwiddle];
+ //vertlist = &vertlists[listTwiddle];
+
+#define OSREAD(x) is->fread((char*)&(x),sizeof((x)));
+ if(version>=1)
+ {
+ int tmpint;
+ //OSREAD(vertlist->count);
+ //OSREAD(tmpint);
+ is->fread(&tmpint, sizeof(int));
+ //for(int i=0;i<vertlist->count;i++)
+ for (int i = 0; i < tmpint; ++i)
+ {
+ //vertlist->list[i].load(is);
+ float tmpfloat;
+ uint8_t tmpu8;
+ for (int j = 0; j < 6; ++j)
+ //OSREAD(tmpfloat);
+ is->fread(&tmpfloat, sizeof(float));
+ for (int j = 0; j < 3; ++j)
+ //OSREAD(tmpu8);
+ is->fread(&tmpu8, sizeof(uint8_t));
+ for (int j = 0; j < 3; ++j)
+ //OSREAD(tmpfloat);
+ is->fread(&tmpfloat, sizeof(float));
+ }
+ //OSREAD(polylist->count);
+ //OSREAD(tmpint);
+ is->fread(&tmpint, sizeof(int));
+ //for(int i=0;i<polylist->count;i++)
+ for (int i = 0; i < tmpint; ++i)
+ {
+ //polylist->list[i].load(is);
+ int tmpint2;
+ uint16_t tmpu16;
+ uint32_t tmpu32;
+ float tmpfloat;
+ //OSREAD(tmpint2);
+ is->fread(&tmpint2, sizeof(int));
+ for (int j = 0; j < 4; ++j)
+ //OSREAD(tmpu16);
+ is->fread(&tmpu16, sizeof(uint16_t));
+ for (int j = 0; j < 4; ++j)
+ //OSREAD(tmpu32);
+ is->fread(&tmpu32, sizeof(uint32_t));
+ for (int j = 0; j < 2; ++j)
+ //OSREAD(tmpfloat);
+ is->fread(&tmpfloat, sizeof(float));
+ }
+ }
+
+ if(version>=2)
+ {
+ for(int i=0;i<4;i++)
+ {
+ uint32_t tmpu32;
+ //OSREAD(mtxStack[i].position);
+ //OSREAD(tmpu32);
+ is->fread(&tmpu32, sizeof(uint32_t));*/
+ /*for(int j=0;j<mtxStack[i].size*16;j++)
+ OSREAD(mtxStack[i].matrix[j]);*/
+ //if (!i || i == 3)
+ /*for (int j = 0; j < (!i || i == 3 ? 1 : 31) * 16; ++j)
+ //OSREAD(tmpu32)
+ is->fread(&tmpu32, sizeof(uint32_t));
+ //else
+ //for (int j = 0; j < 31 * 16; ++j)
+ //OSREAD(tmpu32);
+ }
+ }
+
+ if(version>=3) {
+ fake_gfx_hardware_loadstate(is);
+ }*/
+
+ /*gfx3d.polylist = &polylists[listTwiddle^1];
+ gfx3d.vertlist = &vertlists[listTwiddle^1];
+ gfx3d.polylist->count=0;
+ gfx3d.vertlist->count=0;*/
+
+ /*if(version >= 4)
+ {
+ uint32_t tmpu32_array16[16];
+ //OSREAD(cacheLightDirection);
+ //OSREAD(tmpu32_array16);
+ is->fread(tmpu32_array16, sizeof(tmpu32_array16));
+ //OSREAD(cacheHalfVector);
+ //OSREAD(tmpu32_array16);
+ is->fread(tmpu32_array16, sizeof(tmpu32_array16));
+ }
+
+ return true;
+}*/
+
+//static void fake_MovieRecord_parsePad(EMUFILE* fp/*, uint16_t& pad*/)
+/*{
+
+ char buf[13];
+ fp->fread(buf,13);*/
+ /*pad = 0;
+ for(int i=0;i<13;i++)
+ {
+ pad <<= 1;
+ pad |= ((buf[i]=='.'||buf[i]==' ')?0:1);
+ }*/
+//}
+
+/*static void fake_MovieRecord_parse(MovieData* md, EMUFILE* fp)
+{
+ //by the time we get in here, the initial pipe has already been extracted
+
+ //extract the commands
+ uint8_t tmpu8 = u32DecFromIstream(fp);
+
+ fp->fgetc(); //eat the pipe
+
+ fake_MovieRecord_parsePad(fp*//*, pad*///);
+ /*touch.x*///tmpu8 = u32DecFromIstream(fp);
+ /*touch.y*///tmpu8 = u32DecFromIstream(fp);
+ /*touch.touch*///tmpu8 = u32DecFromIstream(fp);
+
+ /*fp->fgetc(); //eat the pipe
+
+ //should be left at a newline
+}*/
+
+/*static bool fake_LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader)
+{
+ //TODO - start with something different. like 'desmume movie version 1"
+ int curr = fp->ftell();
+
+ //movie must start with "version 1"
+ char buf[9];
+ curr = fp->ftell();
+ fp->fread(buf,9);
+ fp->fseek(curr, SEEK_SET);
+// if(fp->fail()) return false;
+ if(memcmp(buf,"version 1",9))
+ return false;
+
+ std::string key,value;
+ enum {
+ NEWLINE, KEY, SEPARATOR, VALUE, RECORD, COMMENT
+ } state = NEWLINE;
+ bool bail = false;
+ for(;;)
+ {
+ bool iswhitespace, isrecchar, isnewline;
+ int c;
+ if(size--<=0) goto bail;
+ c = fp->fgetc();
+ if(c == -1)
+ goto bail;
+ iswhitespace = (c==' '||c=='\t');
+ isrecchar = (c=='|');
+ isnewline = (c==10||c==13);
+ if(isrecchar && movieData.binaryFlag && !stopAfterHeader)
+ {
+ LoadFM2_binarychunk(movieData, fp, size);
+ return true;
+ }
+ switch(state)
+ {
+ case NEWLINE:
+ if(isnewline) goto done;
+ if(iswhitespace) goto done;
+ if(isrecchar)
+ goto dorecord;
+ //must be a key
+ key = "";
+ value = "";
+ goto dokey;
+ break;
+ case RECORD:
+ {
+ dorecord:
+ if (stopAfterHeader) return true;
+ //int currcount = movieData.records.size();
+ //movieData.records.resize(currcount+1);
+ int preparse = fp->ftell();
+ //movieData.records[currcount].parse(&movieData, fp);
+ fake_MovieRecord_parse(fp);
+ int postparse = fp->ftell();
+ size -= (postparse-preparse);
+ state = NEWLINE;
+ break;
+ }
+
+ case KEY:
+ dokey: //dookie
+ state = KEY;
+ if(iswhitespace) goto doseparator;
+ if(isnewline) goto commit;
+ key += c;
+ break;
+ case SEPARATOR:
+ doseparator:
+ state = SEPARATOR;
+ if(isnewline) goto commit;
+ if(!iswhitespace) goto dovalue;
+ break;
+ case VALUE:
+ dovalue:
+ state = VALUE;
+ if(isnewline) goto commit;
+ value += c;
+ break;
+ case COMMENT:
+ default:
+ break;
+ }
+ goto done;
+
+ bail:
+ bail = true;
+ if(state == VALUE) goto commit;
+ goto done;
+ commit:
+ //movieData.installValue(key,value);
+ state = NEWLINE;
+ done: ;
+ if(bail) break;
+ }
+
+ return true;
+}*/
+
+/*static bool fake_mov_loadstate(EMUFILE* fp, int size)
+{
+ //load_successful = false;
+ static const int kMOVI = 0x49564F4D;
+ static const int kNOMO = 0x4F4D4F4E;
+
+ uint32_t cookie;
+ if(read32le(&cookie,fp) != 1) return false;
+ if(cookie == kNOMO)
+ {*/
+ /*if(movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY)
+ FinishPlayback();*/
+ /*return true;
+ }
+ else if(cookie != kMOVI)
+ return false;
+
+ size -= 4;*/
+
+ /*if (!movie_readonly && autoMovieBackup && freshMovie) //If auto-backup is on, movie has not been altered this session and the movie is in read+write mode
+ {
+ FCEUI_MakeBackupMovie(false); //Backup the movie before the contents get altered, but do not display messages
+ }*/
+
+ //a little rule: cant load states in read+write mode with a movie from an archive.
+ //so we are going to switch it to readonly mode in that case
+// if(!movie_readonly
+// //*&& FCEU_isFileInArchive(curMovieFilename)*/
+// ) {
+// FCEU_PrintError("Cannot loadstate in Read+Write with movie from archive. Movie is now Read-Only.");
+// movie_readonly = true;
+// }
+
+ //MovieData tempMovieData = MovieData();
+ //int curr = fp->ftell();
+ //if(!LoadFM2(tempMovieData, fp, size, false)) {
+ /*if (!fake_LoadFM2(fp, size, false)) {*/
+
+ // is->seekg((uint32_t)curr+size);
+ /* extern bool FCEU_state_loading_old_format;
+ if(FCEU_state_loading_old_format) {
+ if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_RECORD) {
+ FCEUI_StopMovie();
+ FCEU_PrintError("You have tried to use an old savestate while playing a movie. This is unsupported (since the old savestate has old-format movie data in it which can't be converted on the fly)");
+ }
+ }*/
+ /*return false;
+ }*/
+
+ //complex TAS logic for when a savestate is loaded:
+ //----------------
+ //if we are playing or recording and toggled read-only:
+ // then, the movie we are playing must match the guid of the one stored in the savestate or else error.
+ // the savestate is assumed to be in the same timeline as the current movie.
+ // if the current movie is not long enough to get to the savestate's frame#, then it is an error.
+ // the movie contained in the savestate will be discarded.
+ // the emulator will be put into play mode.
+ //if we are playing or recording and toggled read+write
+ // then, the movie we are playing must match the guid of the one stored in the savestate or else error.
+ // the movie contained in the savestate will be loaded into memory
+ // the frames in the movie after the savestate frame will be discarded
+ // the in-memory movie will have its rerecord count incremented
+ // the in-memory movie will be dumped to disk as fcm.
+ // the emulator will be put into record mode.
+ //if we are doing neither:
+ // then, we must discard this movie and just load the savestate
+
+
+ /*if(movieMode != MOVIEMODE_INACTIVE)
+ {
+ //handle moviefile mismatch
+ if(tempMovieData.guid != currMovieData.guid)
+ {
+ //mbg 8/18/08 - this code can be used to turn the error message into an OK/CANCEL
+ #ifdef WIN32
+ //std::string msg = "There is a mismatch between savestate's movie and current movie.\ncurrent: " + currMovieData.guid.toString() + "\nsavestate: " + tempMovieData.guid.toString() + "\n\nThis means that you have loaded a savestate belonging to a different movie than the one you are playing now.\n\nContinue loading this savestate anyway?";
+ //extern HWND pwindow;
+ //int result = MessageBox(pwindow,msg.c_str(),"Error loading savestate",MB_OKCANCEL);
+ //if(result == IDCANCEL)
+ // return false;
+ #else
+ FCEU_PrintError("Mismatch between savestate's movie and current movie.\ncurrent: %s\nsavestate: %s\n",currMovieData.guid.toString().c_str(),tempMovieData.guid.toString().c_str());
+ return false;
+ #endif
+ }
+
+ closeRecordingMovie();
+
+ if(!movie_readonly)
+ {
+ currMovieData = tempMovieData;
+ currMovieData.rerecordCount = currRerecordCount;
+ }
+
+ if(currFrameCounter > (int)currMovieData.records.size())
+ {
+ // if the frame counter is longer than our current movie,
+ // switch to "finished" mode.
+ // this is a mode that behaves like "inactive"
+ // except it permits switching to play/record by loading an earlier savestate.
+ // (and we continue to store the finished movie in savestates made while finished)
+ osd->setLineColor(255,0,0); // let's make the text red too to hopefully catch the user's attention a bit.
+ FinishPlayback();
+ osd->setLineColor(255,255,255);
+
+ //FCEU_PrintError("Savestate is from a frame (%d) after the final frame in the movie (%d). This is not permitted.", currFrameCounter, currMovieData.records.size()-1);
+ //return false;
+ }
+ else if(movie_readonly)
+ {
+ //-------------------------------------------------------------
+ //this code would reload the movie from disk. allegedly it is helpful to hexers, but
+ //it is way too slow with dsm format. so it is only here as a reminder, and in case someone
+ //wants to play with it
+ //-------------------------------------------------------------
+ //{
+ // fstream fs (curMovieFilename);
+ // if(!LoadFM2(tempMovieData, &fs, INT_MAX, false))
+ // {
+ // FCEU_PrintError("Failed to reload DSM after loading savestate");
+ // }
+ // fs.close();
+ // currMovieData = tempMovieData;
+ //}
+ //-------------------------------------------------------------
+
+ movieMode = MOVIEMODE_PLAY;
+ }
+ else
+ {
+ // #ifdef _S9XLUA_H
+ // if(!FCEU_LuaRerecordCountSkip())
+ currRerecordCount++;
+ // #endif
+
+ currMovieData.rerecordCount = currRerecordCount;
+ currMovieData.truncateAt(currFrameCounter);
+
+ openRecordingMovie(curMovieFilename);
+ if(!osRecordingMovie)
+ {
+ osd->setLineColor(255, 0, 0);
+ osd->addLine("Can't save movie file!");
+ }
+
+ //printf("DUMPING MOVIE: %d FRAMES\n",currMovieData.records.size());
+ currMovieData.dump(osRecordingMovie, false);
+ movieMode = MOVIEMODE_RECORD;
+ }
+ }
+
+ load_successful = true;
+ freshMovie = false;*/
+
+ //// Maximus: Show the last input combination entered from the
+ //// movie within the state
+ //if(current!=0) // <- mz: only if playing or recording a movie
+ // memcpy(&cur_input_display, joop, 4);
+
+ /*return true;
+}*/
+
+static bool ReadStateChunks(EMUFILE* is, int32_t totalsize)
+{
+ bool ret = true;
+ while(totalsize > 0)
+ {
+ uint32_t size;
+ uint32_t t;
+ if(!read32le(&t,is)) { ret=false; break; }
+ if(t == 0xFFFFFFFF) goto done;
+ if(!read32le(&size,is)) { ret=false; break; }
+ switch(t)
+ {
+ case 1: if(!ReadStateChunk(is,SF_ARM9,size)) ret=false; break;
+ case 2: if(!ReadStateChunk(is,SF_ARM7,size)) ret=false; break;
+ case 3: if(!cp15_loadstate(is,size)) ret=false; break;
+ case 4: if(!ReadStateChunk(is,SF_MEM,size)) ret=false; break;
+ case 5: if(!ReadStateChunk(is,SF_NDS,size)) ret=false; break;
+ case 51: if(!nds_loadstate(is,size)) ret=false; break;
+ case 60: if(!ReadStateChunk(is,SF_MMU,size)) ret=false; break;
+ case 61: if(!mmu_loadstate(is,size)) ret=false; break;
+ case 7: /*if(!fake_gpu_loadstate(is,size)) ret=false;*/ break;
+ case 8: if(!spu_loadstate(is,size)) ret=false; break;
+ case 81:/* if(!fake_mic_loadstate(is,size)) ret=false; break;*/
+ case 90:/* if(!ReadStateChunk(is,SF_GFX3D,size)) ret=false; break;*/
+ case 91:/* if(!fake_gfx3d_loadstate(is,size)) ret=false; break;*/
+ case 100:/* if(!ReadStateChunk(is,SF_MOVIE, size)) ret=false; break;*/
+ case 101:/* if(!fake_mov_loadstate(is, size)) ret=false; break;*/
+ case 110:/* if(!ReadStateChunk(is,SF_WIFI,size)) ret=false; break;*/
+ case 120:/* if(!ReadStateChunk(is,SF_RTC,size)) ret=false;*/ break;
+ default:
+ ret=false;
+ break;
+ }
+ if(!ret)
+ return false;
+ }
+done:
+
+ return ret;
+}
+
+void loadstate()
+{
+ // This should regenerate the vram banks
+ for (int i = 0; i < 0xA; i++)
+ _MMU_write08<ARMCPU_ARM9>(0x04000240+i, _MMU_read08<ARMCPU_ARM9>(0x04000240+i));
+
+ // This should regenerate the graphics power control register
+ _MMU_write16<ARMCPU_ARM9>(0x04000304, _MMU_read16<ARMCPU_ARM9>(0x04000304));
+
+ // This should regenerate the graphics configuration
+ //zero 27-jul-09 : was formerly up to 7F but that wrote to dispfifo which is dumb (one of nitsuja's desynch bugs [that he found, not caused])
+ //so then i brought it down to 66 but this resulted in a conceptual bug with affine start registers, which shouldnt get regenerated
+ //so then i just made this exhaustive list
+ // for (int i = REG_BASE_DISPA; i<=REG_BASE_DISPA + 0x66; i+=2)
+ //_MMU_write16<ARMCPU_ARM9>(i, _MMU_read16<ARMCPU_ARM9>(i));
+ // for (int i = REG_BASE_DISPB; i<=REG_BASE_DISPB + 0x7F; i+=2)
+ //_MMU_write16<ARMCPU_ARM9>(i, _MMU_read16<ARMCPU_ARM9>(i));
+ static const uint8_t mainRegenAddr[] = {0x00,0x02,0x08,0x0a,0x0c,0x0e,0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x50,0x52,0x54,0x64,0x66,0x6c};
+ static const uint8_t subRegenAddr[] = {0x00,0x02,0x08,0x0a,0x0c,0x0e,0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x50,0x52,0x54,0x6c};
+ for(uint32_t i=0;i<ARRAY_SIZE(mainRegenAddr);i++)
+ _MMU_write16<ARMCPU_ARM9>(REG_BASE_DISPA+mainRegenAddr[i], _MMU_read16<ARMCPU_ARM9>(REG_BASE_DISPA+mainRegenAddr[i]));
+ for(uint32_t i=0;i<ARRAY_SIZE(subRegenAddr);i++)
+ _MMU_write16<ARMCPU_ARM9>(REG_BASE_DISPB+subRegenAddr[i], _MMU_read16<ARMCPU_ARM9>(REG_BASE_DISPB+subRegenAddr[i]));
+ // no need to restore 0x60 since control and MMU.ARM9_REG are both in the savestates, and restoring it could mess up the ack bits anyway
+
+ SetupMMU(/*nds.Is_DebugConsole()*/false,nds.Is_DSI());
+
+ //execute = !driver->EMU_IsEmulationPaused();
+ execute = true;
+}
+
+bool savestate_load(EMUFILE* is)
+{
+ SAV_silent_fail_flag = false;
+ char header[16];
+ is->fread(header,16);
+ if(is->fail() || memcmp(header,magic,16))
+ return false;
+
+ uint32_t ssversion,dversion,len,comprlen;
+ if(!read32le(&ssversion,is)) return false;
+ if(!read32le(&dversion,is)) return false;
+ if(!read32le(&len,is)) return false;
+ if(!read32le(&comprlen,is)) return false;
+
+ if(ssversion != SAVESTATE_VERSION) return false;
+
+ std::vector<uint8_t> buf(len);
+
+ if(comprlen != 0xFFFFFFFF) {
+#ifndef HAVE_LIBZ
+ //without libz, we can't decompress this savestate
+ return false;
+#endif
+ std::vector<char> cbuf(comprlen);
+ is->fread(&cbuf[0],comprlen);
+ if(is->fail()) return false;
+
+#ifdef HAVE_LIBZ
+ uLongf uncomprlen = len;
+ int error = uncompress((uint8_t*)&buf[0],&uncomprlen,(uint8_t*)&cbuf[0],comprlen);
+ if(error != Z_OK || uncomprlen != len)
+ return false;
+#endif
+ } else {
+ is->fread((char*)&buf[0],len-32);
+ }
+
+ //GO!! READ THE SAVESTATE
+ //THERE IS NO GOING BACK NOW
+ //reset the emulator first to clean out the host's state
+
+ //while the series of resets below should work,
+ //we are testing the robustness of the savestate system with this full reset.
+ //the full reset wipes more things, so we can make sure that they are being restored correctly
+ //extern bool _HACK_DONT_STOPMOVIE;
+ //_HACK_DONT_STOPMOVIE = true;
+ NDS_Reset();
+ //_HACK_DONT_STOPMOVIE = false;
+
+ //reset some options to their old defaults which werent saved
+ //nds.debugConsole = false;
+
+ //GPU_Reset(MainScreen.gpu, 0);
+ //GPU_Reset(SubScreen.gpu, 1);
+ //gfx3d_reset();
+ //gpu3D->NDS_3D_Reset();
+ //SPU_Reset();
+
+ EMUFILE_MEMORY mstemp(&buf);
+ bool x = ReadStateChunks(&mstemp,(int32_t)len);
+
+ if(!x && !SAV_silent_fail_flag)
+ {
+ printf("Error loading savestate. It failed halfway through;\nSince there is no savestate backup system, your current game session is wrecked");
+#ifdef _WINDOWS
+ //HACK! we really need a better way to handle this kind of feedback
+ MessageBoxA(0,"Error loading savestate. It failed halfway through;\nSince there is no savestate backup system, your current game session is wrecked",0,0);
+#endif
+ return false;
+ }
+
+ loadstate();
+
+ /*if((nds.debugConsole!=0) != CommonSettings.DebugConsole) {
+ printf("WARNING: forcing console debug mode to: debugmode=%s\n",nds.debugConsole?"true":"false");
+ }*/
+
+ return true;
+}
+
+/*bool savestate_load(const char *file_name)
+{
+ EMUFILE_FILE f(file_name,"rb");
+ if(f.fail()) return false;
+
+ return savestate_load(&f);
+}*/
+
+//static std::stack<EMUFILE_MEMORY*> rewindFreeList;
+//static std::vector<EMUFILE_MEMORY*> rewindbuffer;
+
+//int rewindstates = 16;
+//int rewindinterval = 4;
+
+/*void rewindsave () {*/
+
+ /*if(currFrameCounter % rewindinterval)
+ return;*/
+
+ //printf("rewindsave"); printf("%d%s", currFrameCounter, "\n");
+
+
+ /*EMUFILE_MEMORY *ms;
+ if(!rewindFreeList.empty()) {
+ ms = rewindFreeList.top();
+ rewindFreeList.pop();
+ } else {
+ ms = new EMUFILE_MEMORY(1024*1024*12);
+ }
+
+ if(!savestate_save(ms, Z_NO_COMPRESSION))
+ return;
+
+ rewindbuffer.push_back(ms);
+
+ if((int)rewindbuffer.size() > rewindstates) {
+ delete *rewindbuffer.begin();
+ rewindbuffer.erase(rewindbuffer.begin());
+ }
+}*/
+
+/*void dorewind()
+{*/
+
+ /*if(currFrameCounter % rewindinterval)
+ return;*/
+
+ //printf("rewind\n");
+
+ /*nds.debugConsole = false;
+
+ int size = rewindbuffer.size();
+
+ if(size < 1) {
+ printf("rewind buffer empty\n");
+ return;
+ }
+
+ printf("%d", size);
+
+ EMUFILE_MEMORY* loadms = rewindbuffer[size-1];
+ loadms->fseek(32, SEEK_SET);
+
+ ReadStateChunks(loadms,loadms->size()-32);
+ loadstate();
+
+ if(rewindbuffer.size()>1)
+ {
+ rewindFreeList.push(loadms);
+ rewindbuffer.pop_back();
+ }
+
+}*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/saves.h
@@ -1,1 +1,76 @@
+/*
+ Copyright (C) 2006 Normmatt
+ Copyright (C) 2007 Pascal Giard
+ Copyright (C) 2007-2012 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SRAM_H
+#define _SRAM_H
+
+#include "types.h"
+
+#define SRAM_ADDRESS 0x0A000000
+#define SRAM_SIZE 0x10000
+#define NB_STATES 10
+
+//extern int lastSaveState;
+
+/*typedef struct
+{
+ bool exists;
+ char date[40];
+} savestates_t;*/
+
+
+struct SFORMAT
+{
+ //a string description of the element
+ const char *desc;
+
+ //the size of each element
+ uint32_t size;
+
+ //the number of each element
+ uint32_t count;
+
+ //a void* to the data or a void** to the data
+ void *v;
+};
+
+//extern savestates_t savestates[NB_STATES];
+
+//void clear_savestates();
+//void scan_savestates();
+uint8_t sram_read (uint32_t address);
+void sram_write (uint32_t address, uint8_t value);
+int sram_load (const char *file_name);
+int sram_save (const char *file_name);
+
+//bool savestate_load (const char *file_name);
+//bool savestate_save (const char *file_name);
+
+//void savestate_slot(int num);
+//void loadstate_slot(int num);
+
+void loadstate();
+bool savestate_load(class EMUFILE* is);
+//bool savestate_save(class EMUFILE* outstream, int compressionLevel);
+
+//void dorewind();
+//void rewindsave();
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/slot1.cpp
@@ -1,1 +1,59 @@
+/*
+ Copyright (C) 2010-2011 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+//#include <string>
+
+#include "slot1.h"
+
+//extern SLOT1INTERFACE slot1None;
+extern SLOT1INTERFACE slot1Retail;
+//extern SLOT1INTERFACE slot1R4;
+
+SLOT1INTERFACE slot1List[NDS_SLOT1_COUNT] = {
+ //slot1None,
+ slot1Retail,
+ //slot1R4
+};
+
+SLOT1INTERFACE slot1_device = slot1Retail; //default for frontends that dont even configure this
+//uint8_t slot1_device_type = NDS_SLOT1_RETAIL;
+
+/*bool slot1Init()
+{
+ return slot1_device.init();
+}*/
+
+/*void slot1Close()
+{
+ slot1_device.close();
+}*/
+
+/*void slot1Reset()
+{
+ slot1_device.reset();
+}*/
+
+/*bool slot1Change(NDS_SLOT1_TYPE changeToType)
+{
+ printf("slot1Change to: %d\n", changeToType);
+ if (changeToType > NDS_SLOT1_COUNT || changeToType < 0) return false;
+ slot1_device.close();
+ slot1_device_type = changeToType;
+ slot1_device = slot1List[slot1_device_type];
+ return slot1_device.init();
+}*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/slot1.h
@@ -1,1 +1,72 @@
+/*
+ Copyright (C) 2010-2011 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __SLOT1_H__
+#define __SLOT1_H__
+
+#include "common.h"
+#include "types.h"
+//#include "debug.h"
+
+struct SLOT1INTERFACE
+{
+ // The name of the plugin, this name will appear in the plugins list
+ const char * name;
+
+ //called once when the plugin starts up
+ bool (*init)();
+
+ //called when the emulator resets
+ void (*reset)();
+
+ //called when the plugin shuts down
+ void (*close)();
+
+ //called when the user configurating plugin
+ void (*config)();
+
+ //called when the emulator write to addon
+ void (*write08)(uint8_t PROCNUM, uint32_t adr, uint8_t val);
+ void (*write16)(uint8_t PROCNUM, uint32_t adr, uint16_t val);
+ void (*write32)(uint8_t PROCNUM, uint32_t adr, uint32_t val);
+
+ //called when the emulator read from addon
+ uint8_t (*read08)(uint8_t PROCNUM, uint32_t adr);
+ uint16_t (*read16)(uint8_t PROCNUM, uint32_t adr);
+ uint32_t (*read32)(uint8_t PROCNUM, uint32_t adr);
+
+ //called when the user get info about addon pak (description)
+ void (*info)(char *info);
+};
+
+extern SLOT1INTERFACE slot1_device; // current slot1 device
+
+enum NDS_SLOT1_TYPE
+{
+ //NDS_SLOT1_NONE,
+ NDS_SLOT1_RETAIL,
+ //NDS_SLOT1_R4,
+ NDS_SLOT1_COUNT // use for counter addons - MUST TO BE LAST!!!
+};
+
+//extern bool slot1Init();
+//extern void slot1Close();
+//extern void slot1Reset();
+//extern bool slot1Change(NDS_SLOT1_TYPE type); // change current adddon
+
+#endif //__ADDONS_H__
+
--- /dev/null
+++ b/src/in_2sf/desmume/thumb_instructions.cpp
@@ -1,1 +1,1166 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2008 shash
+ Copyright (C) 2008-2012 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <cassert>
+
+#include "bios.h"
+//#include "debug.h"
+#include "MMU.h"
+#include "NDSSystem.h"
+#include "thumb_instructions.h"
+#include "MMU_timing.h"
+
+#define cpu (&ARMPROC)
+#define TEMPLATE template<int PROCNUM>
+
+//#define REG_NUM(i, n) (((i)>>n)&0x7)
+static inline uint32_t REG_NUM(uint32_t i, uint32_t n) { return (i >> n) & 0x7; }
+
+//-----------------------------------------------------------------------------
+// Undefined instruction
+//-----------------------------------------------------------------------------
+TEMPLATE static uint32_t FASTCALL OP_UND_THUMB(const uint32_t)
+{
+ //INFO("THUMB%c: Undefined instruction: 0x%08X (%s) PC=0x%08X\n", cpu->proc_ID?'7':'9', cpu->instruction, decodeIntruction(true, cpu->instruction), cpu->instruct_adr);
+ TRAPUNDEF(cpu);
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// LSL
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_LSL_0(const uint32_t i)
+{
+ cpu->R[REG_NUM(i, 0)] = cpu->R[REG_NUM(i, 3)];
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LSL(const uint32_t i)
+{
+ uint32_t v = (i>>6) & 0x1F;
+ cpu->CPSR.bits.C = BIT_N(cpu->R[REG_NUM(i, 3)], 32-v);
+ cpu->R[REG_NUM(i, 0)] = (cpu->R[REG_NUM(i, 3)] << v);
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LSL_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_NUM(i, 3)] & 0xFF;
+
+ if(v == 0)
+ {
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ return 2;
+ }
+ if(v<32)
+ {
+ cpu->CPSR.bits.C = BIT_N(cpu->R[REG_NUM(i, 0)], 32-v);
+ cpu->R[REG_NUM(i, 0)] <<= v;
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ return 2;
+ }
+ if(v==32)
+ cpu->CPSR.bits.C = BIT0(cpu->R[REG_NUM(i, 0)]);
+ else
+ cpu->CPSR.bits.C = 0;
+
+ cpu->R[REG_NUM(i, 0)] = 0;
+ cpu->CPSR.bits.N = 0;
+ cpu->CPSR.bits.Z = 1;
+
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// LSR
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_LSR_0(const uint32_t i)
+{
+ cpu->CPSR.bits.C = BIT31(cpu->R[REG_NUM(i, 3)]);
+ cpu->R[REG_NUM(i, 0)] = 0;
+ cpu->CPSR.bits.N = 0;
+ cpu->CPSR.bits.Z = 1;
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LSR(const uint32_t i)
+{
+ uint32_t v = (i>>6) & 0x1F;
+ cpu->CPSR.bits.C = BIT_N(cpu->R[REG_NUM(i, 3)], v-1);
+ cpu->R[REG_NUM(i, 0)] = (cpu->R[REG_NUM(i, 3)] >> v);
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LSR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_NUM(i, 3)] & 0xFF;
+
+ if(v == 0)
+ {
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ return 2;
+ }
+ if(v<32)
+ {
+ cpu->CPSR.bits.C = BIT_N(cpu->R[REG_NUM(i, 0)], v-1);
+ cpu->R[REG_NUM(i, 0)] >>= v;
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ return 2;
+ }
+ if(v==32)
+ cpu->CPSR.bits.C = BIT31(cpu->R[REG_NUM(i, 0)]);
+ else
+ cpu->CPSR.bits.C = 0;
+ cpu->R[REG_NUM(i, 0)] = 0;
+ cpu->CPSR.bits.N = 0;
+ cpu->CPSR.bits.Z = 1;
+
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// ASR
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_ASR_0(const uint32_t i)
+{
+ cpu->CPSR.bits.C = BIT31(cpu->R[REG_NUM(i, 3)]);
+ cpu->R[REG_NUM(i, 0)] = BIT31(cpu->R[REG_NUM(i, 3)])*0xFFFFFFFF;
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ASR(const uint32_t i)
+{
+ uint32_t v = (i>>6) & 0x1F;
+ cpu->CPSR.bits.C = BIT_N(cpu->R[REG_NUM(i, 3)], v-1);
+ cpu->R[REG_NUM(i, 0)] = (uint32_t)(((int32_t)cpu->R[REG_NUM(i, 3)]) >> v);
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ASR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_NUM(i, 3)] & 0xFF;
+
+ if(v == 0)
+ {
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ return 2;
+ }
+ if(v<32)
+ {
+ cpu->CPSR.bits.C = BIT_N(cpu->R[REG_NUM(i, 0)], v-1);
+ cpu->R[REG_NUM(i, 0)] = (uint32_t)(((int32_t)cpu->R[REG_NUM(i, 0)]) >> v);
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ return 2;
+ }
+
+ cpu->CPSR.bits.C = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->R[REG_NUM(i, 0)] = BIT31(cpu->R[REG_NUM(i, 0)])*0xFFFFFFFF;
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// ADD
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_IMM3(const uint32_t i)
+{
+ uint32_t imm3 = (i >> 6) & 0x07;
+ uint32_t Rn = cpu->R[REG_NUM(i, 3)];
+
+ if (imm3 == 0) // mov 2
+ {
+ cpu->R[REG_NUM(i, 0)] = Rn;
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ cpu->CPSR.bits.C = 0;
+ cpu->CPSR.bits.V = 0;
+ return 1;
+ }
+
+ cpu->R[REG_NUM(i, 0)] = Rn + imm3;
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ cpu->CPSR.bits.C = CarryFrom(Rn, imm3);
+ cpu->CPSR.bits.V = OverflowFromADD(cpu->R[REG_NUM(i, 0)], Rn, imm3);
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_IMM8(const uint32_t i)
+{
+ uint32_t imm8 = (i & 0xFF);
+ uint32_t Rd = cpu->R[REG_NUM(i, 8)];
+
+ cpu->R[REG_NUM(i, 8)] = Rd + imm8;
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 8)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 8)] == 0);
+ cpu->CPSR.bits.C = CarryFrom(Rd, imm8);
+ cpu->CPSR.bits.V = OverflowFromADD(cpu->R[REG_NUM(i, 8)], Rd, imm8);
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_REG(const uint32_t i)
+{
+ uint32_t Rn = cpu->R[REG_NUM(i, 3)];
+ uint32_t Rm = cpu->R[REG_NUM(i, 6)];
+
+ cpu->R[REG_NUM(i, 0)] = Rn + Rm;
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ cpu->CPSR.bits.C = CarryFrom(Rn, Rm);
+ cpu->CPSR.bits.V = OverflowFromADD(cpu->R[REG_NUM(i, 0)], Rn, Rm);
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_SPE(const uint32_t i)
+{
+ uint32_t Rd = REG_NUM(i, 0) | ((i>>4)&8);
+
+ cpu->R[Rd] += cpu->R[REG_POS(i, 3)];
+
+ if(Rd==15)
+ {
+ cpu->next_instruction = cpu->R[15];
+ return 3;
+ }
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_2PC(const uint32_t i)
+{
+ cpu->R[REG_NUM(i, 8)] = (cpu->R[15]&0xFFFFFFFC) + ((i&0xFF)<<2);
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADD_2SP(const uint32_t i)
+{
+ cpu->R[REG_NUM(i, 8)] = cpu->R[13] + ((i&0xFF)<<2);
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// SUB
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_IMM3(const uint32_t i)
+{
+ uint32_t imm3 = (i>>6) & 0x07;
+ uint32_t Rn = cpu->R[REG_NUM(i, 3)];
+ uint32_t tmp = Rn - imm3;
+
+ cpu->R[REG_NUM(i, 0)] = tmp;
+ cpu->CPSR.bits.N = BIT31(tmp);
+ cpu->CPSR.bits.Z = (tmp == 0);
+ cpu->CPSR.bits.C = !BorrowFrom(Rn, imm3);
+ cpu->CPSR.bits.V = OverflowFromSUB(tmp, Rn, imm3);
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_IMM8(const uint32_t i)
+{
+ uint32_t imm8 = (i & 0xFF);
+ uint32_t Rd = cpu->R[REG_NUM(i, 8)];
+ uint32_t tmp = Rd - imm8;
+
+ cpu->R[REG_NUM(i, 8)] = tmp;
+ cpu->CPSR.bits.N = BIT31(tmp);
+ cpu->CPSR.bits.Z = (tmp == 0);
+ cpu->CPSR.bits.C = !BorrowFrom(Rd, imm8);
+ cpu->CPSR.bits.V = OverflowFromSUB(tmp, Rd, imm8);
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_SUB_REG(const uint32_t i)
+{
+ uint32_t Rn = cpu->R[REG_NUM(i, 3)];
+ uint32_t Rm = cpu->R[REG_NUM(i, 6)];
+ uint32_t tmp = Rn - Rm;
+
+ cpu->R[REG_NUM(i, 0)] = tmp;
+ cpu->CPSR.bits.N = BIT31(tmp);
+ cpu->CPSR.bits.Z = (tmp == 0);
+ cpu->CPSR.bits.C = !BorrowFrom(Rn, Rm);
+ cpu->CPSR.bits.V = OverflowFromSUB(tmp, Rn, Rm);
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// MOV
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_IMM8(const uint32_t i)
+{
+ cpu->R[REG_NUM(i, 8)] = (i & 0xFF);
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 8)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 8)] == 0;
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_MOV_SPE(const uint32_t i)
+{
+ uint32_t Rd = REG_NUM(i, 0) | ((i>>4)&8);
+
+ cpu->R[Rd] = cpu->R[REG_POS(i, 3)];
+
+ if(Rd==15)
+ {
+ cpu->next_instruction = cpu->R[15];
+ return 3;
+ }
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// CMP
+//-----------------------------------------------------------------------------
+TEMPLATE static uint32_t FASTCALL OP_CMP_IMM8(const uint32_t i)
+{
+ uint32_t tmp = cpu->R[REG_NUM(i, 8)] - (i & 0xFF);
+
+ cpu->CPSR.bits.N = BIT31(tmp);
+ cpu->CPSR.bits.Z = tmp == 0;
+ cpu->CPSR.bits.C = !BorrowFrom(cpu->R[REG_NUM(i, 8)], (i & 0xFF));
+ cpu->CPSR.bits.V = OverflowFromSUB(tmp, cpu->R[REG_NUM(i, 8)], (i & 0xFF));
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMP(const uint32_t i)
+{
+ uint32_t tmp = cpu->R[REG_NUM(i, 0)] - cpu->R[REG_NUM(i, 3)];
+
+ cpu->CPSR.bits.N = BIT31(tmp);
+ cpu->CPSR.bits.Z = tmp == 0;
+ cpu->CPSR.bits.C = !BorrowFrom(cpu->R[REG_NUM(i, 0)], cpu->R[REG_NUM(i, 3)]);
+ cpu->CPSR.bits.V = OverflowFromSUB(tmp, cpu->R[REG_NUM(i, 0)], cpu->R[REG_NUM(i, 3)]);
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_CMP_SPE(const uint32_t i)
+{
+ uint32_t Rn = (i&7) | ((i>>4)&8);
+
+ uint32_t tmp = cpu->R[Rn] - cpu->R[REG_POS(i, 3)];
+
+ cpu->CPSR.bits.N = BIT31(tmp);
+ cpu->CPSR.bits.Z = tmp == 0;
+ cpu->CPSR.bits.C = !BorrowFrom(cpu->R[Rn], cpu->R[REG_POS(i, 3)]);
+ cpu->CPSR.bits.V = OverflowFromSUB(tmp, cpu->R[Rn], cpu->R[REG_POS(i, 3)]);
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// AND
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_AND(const uint32_t i)
+{
+ cpu->R[REG_NUM(i, 0)] &= cpu->R[REG_NUM(i, 3)];
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// EOR
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_EOR(const uint32_t i)
+{
+ cpu->R[REG_NUM(i, 0)] ^= cpu->R[REG_NUM(i, 3)];
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// ADC
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_ADC_REG(const uint32_t i)
+{
+ uint32_t Rd = cpu->R[REG_NUM(i, 0)];
+ uint32_t Rm = cpu->R[REG_NUM(i, 3)];
+
+ if (!cpu->CPSR.bits.C)
+ {
+ cpu->R[REG_NUM(i, 0)] = Rd + Rm;
+ cpu->CPSR.bits.C = cpu->R[REG_NUM(i, 0)] < Rm;
+ }
+ else
+ {
+ cpu->R[REG_NUM(i, 0)] = Rd + Rm + 1;
+ cpu->CPSR.bits.C = cpu->R[REG_NUM(i, 0)] <= Rm;
+ }
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
+ cpu->CPSR.bits.V = BIT31((Rd ^ Rm ^ -1) & (Rd ^ cpu->R[REG_NUM(i, 0)]));
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// SBC
+//-----------------------------------------------------------------------------
+TEMPLATE static uint32_t FASTCALL OP_SBC_REG(const uint32_t i)
+{
+ uint32_t Rd = cpu->R[REG_NUM(i, 0)];
+ uint32_t Rm = cpu->R[REG_NUM(i, 3)];
+
+ if (!cpu->CPSR.bits.C)
+ {
+ cpu->R[REG_NUM(i, 0)] = Rd - Rm - 1;
+ cpu->CPSR.bits.C = Rd > Rm;
+ }
+ else
+ {
+ cpu->R[REG_NUM(i, 0)] = Rd - Rm;
+ cpu->CPSR.bits.C = Rd >= Rm;
+ }
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
+ cpu->CPSR.bits.V = BIT31((Rd ^ Rm) & (Rd ^ cpu->R[REG_NUM(i, 0)]));
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// ROR
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_ROR_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_NUM(i, 3)] & 0xFF;
+
+ if(v == 0)
+ {
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ return 2;
+ }
+
+ v &= 0x1F;
+ if(v == 0)
+ {
+ cpu->CPSR.bits.C = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ return 2;
+ }
+ cpu->CPSR.bits.C = BIT_N(cpu->R[REG_NUM(i, 0)], v-1);
+ cpu->R[REG_NUM(i, 0)] = ROR(cpu->R[REG_NUM(i, 0)], v);
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+
+ return 2;
+}
+
+//-----------------------------------------------------------------------------
+// TST
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_TST(const uint32_t i)
+{
+ uint32_t tmp = cpu->R[REG_NUM(i, 0)] & cpu->R[REG_NUM(i, 3)];
+ cpu->CPSR.bits.N = BIT31(tmp);
+ cpu->CPSR.bits.Z = (tmp == 0);
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// NEG
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_NEG(const uint32_t i)
+{
+ uint32_t Rm = cpu->R[REG_NUM(i, 3)];
+
+ cpu->R[REG_NUM(i, 0)] = (uint32_t)((int32_t)0 - (int32_t)Rm);
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
+ cpu->CPSR.bits.C = !BorrowFrom(0, Rm);
+ cpu->CPSR.bits.V = OverflowFromSUB(cpu->R[REG_NUM(i, 0)], 0, Rm);
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// CMN
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_CMN(const uint32_t i)
+{
+ uint32_t tmp = cpu->R[REG_NUM(i, 0)] + cpu->R[REG_NUM(i, 3)];
+
+ cpu->CPSR.bits.N = BIT31(tmp);
+ cpu->CPSR.bits.Z = tmp == 0;
+ cpu->CPSR.bits.C = CarryFrom(cpu->R[REG_NUM(i, 0)], cpu->R[REG_NUM(i, 3)]);
+ cpu->CPSR.bits.V = OverflowFromADD(tmp, cpu->R[REG_NUM(i, 0)], cpu->R[REG_NUM(i, 3)]);
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// ORR
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_ORR(const uint32_t i)
+{
+ cpu->R[REG_NUM(i, 0)] |= cpu->R[REG_NUM(i, 3)];
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// BIC
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_BIC(const uint32_t i)
+{
+ cpu->R[REG_NUM(i, 0)] &= (~cpu->R[REG_NUM(i, 3)]);
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = (cpu->R[REG_NUM(i, 0)] == 0);
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// MVN
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_MVN(const uint32_t i)
+{
+ cpu->R[REG_NUM(i, 0)] = (~cpu->R[REG_NUM(i, 3)]);
+
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// MUL
+//-----------------------------------------------------------------------------
+
+#define MUL_Mxx_END_THUMB(c) \
+ v >>= 8; \
+ if((v==0)||(v==0xFFFFFF)) \
+ return c+1; \
+ v >>= 8; \
+ if((v==0)||(v==0xFFFF)) \
+ return c+2; \
+ v >>= 8; \
+ if((v==0)||(v==0xFF)) \
+ return c+3; \
+ return c+4; \
+
+TEMPLATE static uint32_t FASTCALL OP_MUL_REG(const uint32_t i)
+{
+ uint32_t v = cpu->R[REG_NUM(i, 3)];
+
+ // FIXME:
+ //------ Rd = (Rm * Rd)[31:0]
+ //------ u64 res = ((u64)cpu->R[REG_NUM(i, 0)] * (u64)v));
+ //------ cpu->R[REG_NUM(i, 0)] = (uint32_t)(res & 0xFFFFFFFF);
+ //------
+
+ cpu->R[REG_NUM(i, 0)] *= v;
+ cpu->CPSR.bits.N = BIT31(cpu->R[REG_NUM(i, 0)]);
+ cpu->CPSR.bits.Z = cpu->R[REG_NUM(i, 0)] == 0;
+ //The MUL instruction is defined to leave the C flag unchanged in ARMv5 and above.
+ //In earlier versions of the architecture, the value of the C flag was UNPREDICTABLE
+ //after a MUL instruction.
+
+ if (!cpu->LDTBit) // ARM4T 1S + mI, m = 3
+ return 4;
+
+ MUL_Mxx_END_THUMB(1);
+}
+
+//-----------------------------------------------------------------------------
+// STRB / LDRB
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + ((i>>6)&0x1F);
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_NUM(i, 0)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2, adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + ((i>>6)&0x1F);
+ cpu->R[REG_NUM(i, 0)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3, adr);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_STRB_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)];
+ WRITE8(cpu->mem_if->data, adr, (uint8_t)cpu->R[REG_NUM(i, 0)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_WRITE>(2, adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRB_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)];
+ cpu->R[REG_NUM(i, 0)] = (uint32_t)READ8(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3, adr);
+}
+
+//-----------------------------------------------------------------------------
+// LDRSB
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSB_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)];
+ cpu->R[REG_NUM(i, 0)] = (uint32_t)((int8_t)READ8(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,8,MMU_AD_READ>(3, adr);
+}
+
+//-----------------------------------------------------------------------------
+// STRH / LDRH
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + ((i>>5)&0x3E);
+ WRITE16(cpu->mem_if->data, adr, (uint16_t)cpu->R[REG_NUM(i, 0)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2, adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + ((i>>5)&0x3E);
+ cpu->R[REG_NUM(i, 0)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3, adr);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_STRH_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)];
+ WRITE16(cpu->mem_if->data, adr, ((uint16_t)cpu->R[REG_NUM(i, 0)]));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2, adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDRH_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)];
+ cpu->R[REG_NUM(i, 0)] = (uint32_t)READ16(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3, adr);
+}
+
+//-----------------------------------------------------------------------------
+// LDRSH
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_LDRSH_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)];
+ cpu->R[REG_NUM(i, 0)] = (uint32_t)((int16_t)READ16(cpu->mem_if->data, adr));
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_READ>(3, adr);
+}
+
+//-----------------------------------------------------------------------------
+// STR / LDR
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_STR_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + ((i>>4)&0x7C);
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_NUM(i, 0)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2, adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_IMM_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 3)] + ((i>>4)&0x7C);
+ uint32_t tempValue = READ32(cpu->mem_if->data, adr);
+ adr = (adr&3)*8;
+ tempValue = (tempValue>>adr) | (tempValue<<(32-adr));
+ cpu->R[REG_NUM(i, 0)] = tempValue;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(3, adr);
+}
+
+
+TEMPLATE static uint32_t FASTCALL OP_STR_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 6)] + cpu->R[REG_NUM(i, 3)];
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_NUM(i, 0)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_WRITE>(2, adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_REG_OFF(const uint32_t i)
+{
+ uint32_t adr = (cpu->R[REG_NUM(i, 3)] + cpu->R[REG_NUM(i, 6)]);
+ uint32_t tempValue = READ32(cpu->mem_if->data, adr);
+ adr = (adr&3)*8;
+ tempValue = (tempValue>>adr) | (tempValue<<(32-adr));
+ cpu->R[REG_NUM(i, 0)] = tempValue;
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(3, adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_STR_SPREL(const uint32_t i)
+{
+ uint32_t adr = cpu->R[13] + ((i&0xFF)<<2);
+ WRITE32(cpu->mem_if->data, adr, cpu->R[REG_NUM(i, 8)]);
+
+ return MMU_aluMemAccessCycles<PROCNUM,16,MMU_AD_WRITE>(2, adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_SPREL(const uint32_t i)
+{
+ uint32_t adr = cpu->R[13] + ((i&0xFF)<<2);
+ cpu->R[REG_NUM(i, 8)] = READ32(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(3, adr);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDR_PCREL(const uint32_t i)
+{
+ uint32_t adr = (cpu->R[15]&0xFFFFFFFC) + ((i&0xFF)<<2);
+
+ cpu->R[REG_NUM(i, 8)] = READ32(cpu->mem_if->data, adr);
+
+ return MMU_aluMemAccessCycles<PROCNUM,32,MMU_AD_READ>(3, adr);
+}
+
+//-----------------------------------------------------------------------------
+// Adjust SP
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_ADJUST_P_SP(const uint32_t i)
+{
+ cpu->R[13] += ((i&0x7F)<<2);
+
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_ADJUST_M_SP(const uint32_t i)
+{
+ cpu->R[13] -= ((i&0x7F)<<2);
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// PUSH / POP
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_PUSH(const uint32_t i)
+{
+ uint32_t adr = cpu->R[13] - 4;
+ uint32_t c = 0, j;
+
+ for(j = 0; j<8; j++)
+ if(BIT_N(i, 7-j))
+ {
+ WRITE32(cpu->mem_if->data, adr, cpu->R[7-j]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(adr);
+ adr -= 4;
+ }
+ cpu->R[13] = adr + 4;
+
+ return MMU_aluMemCycles<PROCNUM>(3, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_PUSH_LR(const uint32_t i)
+{
+ uint32_t adr = cpu->R[13] - 4;
+ uint32_t c = 0, j;
+
+ WRITE32(cpu->mem_if->data, adr, cpu->R[14]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(adr);
+ adr -= 4;
+
+ for(j = 0; j<8; j++)
+ if(BIT_N(i, 7-j))
+ {
+ WRITE32(cpu->mem_if->data, adr, cpu->R[7-j]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(adr);
+ adr -= 4;
+ }
+ cpu->R[13] = adr + 4;
+
+ return MMU_aluMemCycles<PROCNUM>(4, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_POP(const uint32_t i)
+{
+ uint32_t adr = cpu->R[13];
+ uint32_t c = 0, j;
+
+ for(j = 0; j<8; j++)
+ if(BIT_N(i, j))
+ {
+ cpu->R[j] = READ32(cpu->mem_if->data, adr);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(adr);
+ adr += 4;
+ }
+ cpu->R[13] = adr;
+
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+// In ARMv5 and above, bit[0] of the loaded value
+// determines whether execution continues after this branch in ARM state or in Thumb state, as though the
+// following instruction had been executed:
+// BX (loaded_value)
+// In T variants of ARMv4, bit[0] of the loaded value is ignored and execution continues in Thumb state, as
+// though the following instruction had been executed:
+// MOV PC,(loaded_value)
+TEMPLATE static uint32_t FASTCALL OP_POP_PC(const uint32_t i)
+{
+ uint32_t adr = cpu->R[13];
+ uint32_t c = 0, j;
+ uint32_t v = 0;
+
+ for(j = 0; j<8; j++)
+ if(BIT_N(i, j))
+ {
+ cpu->R[j] = READ32(cpu->mem_if->data, adr);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(adr);
+ adr += 4;
+ }
+
+ v = READ32(cpu->mem_if->data, adr);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(adr);
+ if(cpu->LDTBit)
+ cpu->CPSR.bits.T = BIT0(v);
+
+ cpu->R[15] = v & 0xFFFFFFFE;
+ cpu->next_instruction = cpu->R[15];
+
+ cpu->R[13] = adr + 4;
+ return MMU_aluMemCycles<PROCNUM>(5, c);
+}
+
+//-----------------------------------------------------------------------------
+// STMIA / LDMIA
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_STMIA_THUMB(const uint32_t i)
+{
+ uint32_t adr = cpu->R[REG_NUM(i, 8)];
+ uint32_t c = 0, j;
+ uint32_t erList = 1; //Empty Register List
+
+ // ------ ARM_REF:
+ // ------ If <Rn> is specified in <registers>:
+ // ------ * If <Rn> is the lowest-numbered register specified in <registers>, the original value of <Rn> is stored.
+ // ------ * Otherwise, the stored value of <Rn> is UNPREDICTABLE.
+ if (BIT_N(i, REG_NUM(i, 8)))
+ printf("STMIA with Rb in Rlist\n");
+
+ for(j = 0; j<8; j++)
+ {
+ if(BIT_N(i, j))
+ {
+ WRITE32(cpu->mem_if->data, adr, cpu->R[j]);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_WRITE>(adr);
+ adr += 4;
+ erList = 0; //Register List isnt empty
+ }
+ }
+
+ if (erList)
+ printf("STMIA with Empty Rlist\n");
+
+ cpu->R[REG_NUM(i, 8)] = adr;
+ return MMU_aluMemCycles<PROCNUM>(2, c);
+}
+
+TEMPLATE static uint32_t FASTCALL OP_LDMIA_THUMB(const uint32_t i)
+{
+ uint32_t regIndex = REG_NUM(i, 8);
+ uint32_t adr = cpu->R[regIndex];
+ uint32_t c = 0, j;
+ uint32_t erList = 1; //Empty Register List
+
+ //if (BIT_N(i, regIndex))
+ // printf("LDMIA with Rb in Rlist at %08X\n",cpu->instruct_adr);
+
+ for(j = 0; j<8; j++)
+ {
+ if(BIT_N(i, j))
+ {
+ cpu->R[j] = READ32(cpu->mem_if->data, adr);
+ c += MMU_memAccessCycles<PROCNUM,32,MMU_AD_READ>(adr);
+ adr += 4;
+ erList = 0; //Register List isnt empty
+ }
+ }
+
+ if (erList)
+ printf("LDMIA with Empty Rlist\n");
+
+ // ARM_REF: THUMB: Causes base register write-back, and is not optional
+ // ARM_REF: If the base register <Rn> is specified in <registers>, the final value of <Rn> is the loaded value
+ // (not the written-back value).
+ if (!BIT_N(i, regIndex))
+ cpu->R[regIndex] = adr;
+
+ return MMU_aluMemCycles<PROCNUM>(3, c);
+}
+
+//-----------------------------------------------------------------------------
+// BKPT
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_BKPT_THUMB(const uint32_t)
+{
+ // TODO
+ printf("THUMB%c: Unimplemented opcode BKPT\n", PROCNUM?'7':'9');
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// SWI
+//-----------------------------------------------------------------------------
+
+TEMPLATE static uint32_t FASTCALL OP_SWI_THUMB(const uint32_t i)
+{
+ uint32_t swinum = i & 0xFF;
+
+ //ideas-style debug prints (execute this SWI with the null terminated string address in R0)
+ if(swinum==0xFC) {
+ //IdeasLog(cpu);
+ return 0;
+ }
+
+ //if the user has changed the intVector to point away from the nds bioses,
+ //then it doesn't really make any sense to use the builtin SWI's since
+ //the bios ones aren't getting called anyway
+ bool bypassBuiltinSWI =
+ (cpu->intVector == 0x00000000 && PROCNUM==0)
+ || (cpu->intVector == 0xFFFF0000 && PROCNUM==1);
+
+ if(cpu->swi_tab && !bypassBuiltinSWI) {
+ //zero 25-dec-2008 - in arm, we were masking to 0x1F.
+ //this is probably safer since an invalid opcode could crash the emu
+ //zero 30-jun-2009 - but they say that the ideas 0xFF should crash the device...
+ //uint32_t swinum = cpu->instruction & 0xFF;
+ swinum &= 0x1F;
+ //printf("%d ARM SWI %d\n",PROCNUM,swinum);
+ return cpu->swi_tab[swinum]() + 3;
+ }
+ else {
+ /* we use an irq thats not in the irq tab, as
+ it was replaced due to a changed intVector */
+ Status_Reg tmp = cpu->CPSR;
+ armcpu_switchMode(cpu, SVC); /* enter svc mode */
+ cpu->R[14] = cpu->next_instruction; /* jump to swi Vector */
+ cpu->SPSR = tmp; /* save old CPSR as new SPSR */
+ cpu->CPSR.bits.T = 0; /* handle as ARM32 code */
+ cpu->CPSR.bits.I = 1;
+ cpu->changeCPSR();
+ cpu->R[15] = cpu->intVector + 0x08;
+ cpu->next_instruction = cpu->R[15];
+ return 3;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Branch
+//-----------------------------------------------------------------------------
+
+#define SIGNEEXT_IMM11(i) (((i)&0x7FF) | (BIT10(i) * 0xFFFFF800))
+
+TEMPLATE static uint32_t FASTCALL OP_B_COND(const uint32_t i)
+{
+ if(!TEST_COND((i>>8)&0xF, 0, cpu->CPSR))
+ return 1;
+
+ cpu->R[15] += (uint32_t)((int8_t)(i&0xFF))<<1;
+ cpu->next_instruction = cpu->R[15];
+ return 3;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_B_UNCOND(const uint32_t i)
+{
+ cpu->R[15] += (SIGNEEXT_IMM11(i)<<1);
+ cpu->next_instruction = cpu->R[15];
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BLX(const uint32_t i)
+{
+ cpu->R[15] = (cpu->R[14] + ((i&0x7FF)<<1))&0xFFFFFFFC;
+ cpu->R[14] = cpu->next_instruction | 1;
+ cpu->next_instruction = cpu->R[15];
+ cpu->CPSR.bits.T = 0;
+ return 3;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BL_10(const uint32_t i)
+{
+ cpu->R[14] = cpu->R[15] + (SIGNEEXT_IMM11(i)<<12);
+ return 1;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BL_11(const uint32_t i)
+{
+ cpu->R[15] = (cpu->R[14] + ((i&0x7FF)<<1));
+ cpu->R[14] = cpu->next_instruction | 1;
+ cpu->next_instruction = cpu->R[15];
+ return 4;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BX_THUMB(const uint32_t i)
+{
+ // When using PC as operand with BX opcode, switch to ARM state and jump to (instruct_adr+4)
+ // Reference: http://nocash.emubase.de/gbatek.htm#thumb5hiregisteroperationsbranchexchange
+
+#if 0
+ if (REG_POS(i, 3) == 15)
+ {
+ cpu->CPSR.bits.T = 0;
+ cpu->R[15] &= 0xFFFFFFFC;
+ cpu->next_instruction = cpu->R[15];
+ }
+ else
+ {
+ uint32_t Rm = cpu->R[REG_POS(i, 3)];
+
+ cpu->CPSR.bits.T = BIT0(Rm);
+ cpu->R[15] = (Rm & 0xFFFFFFFE);
+ cpu->next_instruction = cpu->R[15];
+ }
+#else
+ uint32_t Rm = cpu->R[REG_POS(i, 3)];
+ //----- ARM_REF:
+ //----- Register 15 can be specified for <Rm>. If this is done, R15 is read as normal for Thumb code,
+ //----- that is, it is the address of the BX instruction itself plus 4. If the BX instruction is at a
+ //----- word-aligned address, this results in a branch to the next word, executing in ARM state.
+ //----- However, if the BX instruction is not at a word-aligned address, this means that the results of
+ //----- the instruction are UNPREDICTABLE (because the value read for R15 has bits[1:0]==0b10).
+ if (Rm == 15)
+ {
+ printf("THUMB%c: BX using PC as operand\n", PROCNUM?'7':'9');
+ //emu_halt();
+ }
+ cpu->CPSR.bits.T = BIT0(Rm);
+ cpu->R[15] = (Rm & (0xFFFFFFFC|(1<<cpu->CPSR.bits.T)));
+ cpu->next_instruction = cpu->R[15];
+#endif
+ return 3;
+}
+
+TEMPLATE static uint32_t FASTCALL OP_BLX_THUMB(const uint32_t i)
+{
+ uint32_t Rm = cpu->R[REG_POS(i, 3)];
+
+ cpu->CPSR.bits.T = BIT0(Rm);
+ //cpu->R[15] = (Rm & (0xFFFFFFFC|(1<<cpu->CPSR.bits.T)));
+ cpu->R[15] = Rm & 0xFFFFFFFE;
+ cpu->R[14] = cpu->next_instruction | 1;
+ cpu->next_instruction = cpu->R[15];
+
+ return 4;
+}
+
+//-----------------------------------------------------------------------------
+// The End
+//-----------------------------------------------------------------------------
+
+#define TABDECL(x) x<0>
+const ThumbOpFunc thumb_instructions_set_0[1024] = {
+#include "thumb_tabdef.inc"
+};
+#undef TABDECL
+
+#define TABDECL(x) x<1>
+const ThumbOpFunc thumb_instructions_set_1[1024] = {
+#include "thumb_tabdef.inc"
+};
+#undef TABDECL
+
+/*#define TABDECL(x) #x
+const char* thumb_instruction_names[1024] = {
+#include "thumb_tabdef.inc"
+};
+#undef TABDECL*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/thumb_instructions.h
@@ -1,1 +1,32 @@
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2006-2009 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef THUMB_INSTRUCTIONS_H
+#define THUMB_INSTRUCTIONS_H
+
+#include "armcpu.h"
+
+typedef uint32_t (FASTCALL* ThumbOpFunc)(const uint32_t i);
+
+extern const ThumbOpFunc thumb_instructions_set_0[1024];
+extern const ThumbOpFunc thumb_instructions_set_1[1024];
+
+//extern const char* thumb_instruction_names[1024];
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/thumb_tabdef.inc
@@ -1,1 +1,1106 @@
-
+/*
+ Copyright (C) 2006 yopyop
+ Copyright (C) 2006-2010 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+TABDECL( OP_LSL_0), //00 0000 0000
+TABDECL( OP_LSL), //00 0000 0001
+TABDECL( OP_LSL), //00 0000 0010
+TABDECL( OP_LSL), //00 0000 0011
+TABDECL( OP_LSL), //00 0000 0100
+TABDECL( OP_LSL), //00 0000 0101
+TABDECL( OP_LSL), //00 0000 0110
+TABDECL( OP_LSL), //00 0000 0111
+TABDECL( OP_LSL), //00 0000 1000
+TABDECL( OP_LSL), //00 0000 1001
+TABDECL( OP_LSL), //00 0000 1010
+TABDECL( OP_LSL), //00 0000 1011
+TABDECL( OP_LSL), //00 0000 1100
+TABDECL( OP_LSL), //00 0000 1101
+TABDECL( OP_LSL), //00 0000 1110
+TABDECL( OP_LSL), //00 0000 1111
+
+TABDECL( OP_LSL), //00 0001 0000
+TABDECL( OP_LSL), //00 0001 0001
+TABDECL( OP_LSL), //00 0001 0010
+TABDECL( OP_LSL), //00 0001 0011
+TABDECL( OP_LSL), //00 0001 0100
+TABDECL( OP_LSL), //00 0001 0101
+TABDECL( OP_LSL), //00 0001 0110
+TABDECL( OP_LSL), //00 0001 0111
+TABDECL( OP_LSL), //00 0001 1000
+TABDECL( OP_LSL), //00 0001 1001
+TABDECL( OP_LSL), //00 0001 1010
+TABDECL( OP_LSL), //00 0001 1011
+TABDECL( OP_LSL), //00 0001 1100
+TABDECL( OP_LSL), //00 0001 1101
+TABDECL( OP_LSL), //00 0001 1110
+TABDECL( OP_LSL), //00 0001 1111
+
+TABDECL( OP_LSR_0), //00 0010 0000
+TABDECL( OP_LSR), //00 0010 0001
+TABDECL( OP_LSR), //00 0010 0010
+TABDECL( OP_LSR), //00 0010 0011
+TABDECL( OP_LSR), //00 0010 0100
+TABDECL( OP_LSR), //00 0010 0101
+TABDECL( OP_LSR), //00 0010 0110
+TABDECL( OP_LSR), //00 0010 0111
+TABDECL( OP_LSR), //00 0010 1000
+TABDECL( OP_LSR), //00 0010 1001
+TABDECL( OP_LSR), //00 0010 1010
+TABDECL( OP_LSR), //00 0010 1011
+TABDECL( OP_LSR), //00 0010 1100
+TABDECL( OP_LSR), //00 0010 1101
+TABDECL( OP_LSR), //00 0010 1110
+TABDECL( OP_LSR), //00 0010 1111
+
+TABDECL( OP_LSR), //00 0011 0000
+TABDECL( OP_LSR), //00 0011 0001
+TABDECL( OP_LSR), //00 0011 0010
+TABDECL( OP_LSR), //00 0011 0011
+TABDECL( OP_LSR), //00 0011 0100
+TABDECL( OP_LSR), //00 0011 0101
+TABDECL( OP_LSR), //00 0011 0110
+TABDECL( OP_LSR), //00 0011 0111
+TABDECL( OP_LSR), //00 0011 1000
+TABDECL( OP_LSR), //00 0011 1001
+TABDECL( OP_LSR), //00 0011 1010
+TABDECL( OP_LSR), //00 0011 1011
+TABDECL( OP_LSR), //00 0011 1100
+TABDECL( OP_LSR), //00 0011 1101
+TABDECL( OP_LSR), //00 0011 1110
+TABDECL( OP_LSR), //00 0011 1111
+
+TABDECL( OP_ASR_0), //00 0100 0000
+TABDECL( OP_ASR), //00 0100 0001
+TABDECL( OP_ASR), //00 0100 0010
+TABDECL( OP_ASR), //00 0100 0011
+TABDECL( OP_ASR), //00 0100 0100
+TABDECL( OP_ASR), //00 0100 0101
+TABDECL( OP_ASR), //00 0100 0110
+TABDECL( OP_ASR), //00 0100 0111
+TABDECL( OP_ASR), //00 0100 1000
+TABDECL( OP_ASR), //00 0100 1001
+TABDECL( OP_ASR), //00 0100 1010
+TABDECL( OP_ASR), //00 0100 1011
+TABDECL( OP_ASR), //00 0100 1100
+TABDECL( OP_ASR), //00 0100 1101
+TABDECL( OP_ASR), //00 0100 1110
+TABDECL( OP_ASR), //00 0100 1111
+
+TABDECL( OP_ASR), //00 0101 0000
+TABDECL( OP_ASR), //00 0101 0001
+TABDECL( OP_ASR), //00 0101 0010
+TABDECL( OP_ASR), //00 0101 0011
+TABDECL( OP_ASR), //00 0101 0100
+TABDECL( OP_ASR), //00 0101 0101
+TABDECL( OP_ASR), //00 0101 0110
+TABDECL( OP_ASR), //00 0101 0111
+TABDECL( OP_ASR), //00 0101 1000
+TABDECL( OP_ASR), //00 0101 1001
+TABDECL( OP_ASR), //00 0101 1010
+TABDECL( OP_ASR), //00 0101 1011
+TABDECL( OP_ASR), //00 0101 1100
+TABDECL( OP_ASR), //00 0101 1101
+TABDECL( OP_ASR), //00 0101 1110
+TABDECL( OP_ASR), //00 0101 1111
+
+TABDECL( OP_ADD_REG), //00 0110 0000
+TABDECL( OP_ADD_REG), //00 0110 0001
+TABDECL( OP_ADD_REG), //00 0110 0010
+TABDECL( OP_ADD_REG), //00 0110 0011
+TABDECL( OP_ADD_REG), //00 0110 0100
+TABDECL( OP_ADD_REG), //00 0110 0101
+TABDECL( OP_ADD_REG), //00 0110 0110
+TABDECL( OP_ADD_REG), //00 0110 0111
+TABDECL( OP_SUB_REG), //00 0110 1000
+TABDECL( OP_SUB_REG), //00 0110 1001
+TABDECL( OP_SUB_REG), //00 0110 1010
+TABDECL( OP_SUB_REG), //00 0110 1011
+TABDECL( OP_SUB_REG), //00 0110 1100
+TABDECL( OP_SUB_REG), //00 0110 1101
+TABDECL( OP_SUB_REG), //00 0110 1110
+TABDECL( OP_SUB_REG), //00 0110 1111
+
+TABDECL( OP_ADD_IMM3), //00 0111 0000
+TABDECL( OP_ADD_IMM3), //00 0111 0001
+TABDECL( OP_ADD_IMM3), //00 0111 0010
+TABDECL( OP_ADD_IMM3), //00 0111 0011
+TABDECL( OP_ADD_IMM3), //00 0111 0100
+TABDECL( OP_ADD_IMM3), //00 0111 0101
+TABDECL( OP_ADD_IMM3), //00 0111 0110
+TABDECL( OP_ADD_IMM3), //00 0111 0111
+TABDECL( OP_SUB_IMM3), //00 0111 1000
+TABDECL( OP_SUB_IMM3), //00 0111 1001
+TABDECL( OP_SUB_IMM3), //00 0111 1010
+TABDECL( OP_SUB_IMM3), //00 0111 1011
+TABDECL( OP_SUB_IMM3), //00 0111 1100
+TABDECL( OP_SUB_IMM3), //00 0111 1101
+TABDECL( OP_SUB_IMM3), //00 0111 1110
+TABDECL( OP_SUB_IMM3), //00 0111 1111
+
+TABDECL( OP_MOV_IMM8), //00 1000 0000
+TABDECL( OP_MOV_IMM8), //00 1000 0001
+TABDECL( OP_MOV_IMM8), //00 1000 0010
+TABDECL( OP_MOV_IMM8), //00 1000 0011
+TABDECL( OP_MOV_IMM8), //00 1000 0100
+TABDECL( OP_MOV_IMM8), //00 1000 0101
+TABDECL( OP_MOV_IMM8), //00 1000 0110
+TABDECL( OP_MOV_IMM8), //00 1000 0111
+TABDECL( OP_MOV_IMM8), //00 1000 1000
+TABDECL( OP_MOV_IMM8), //00 1000 1001
+TABDECL( OP_MOV_IMM8), //00 1000 1010
+TABDECL( OP_MOV_IMM8), //00 1000 1011
+TABDECL( OP_MOV_IMM8), //00 1000 1100
+TABDECL( OP_MOV_IMM8), //00 1000 1101
+TABDECL( OP_MOV_IMM8), //00 1000 1110
+TABDECL( OP_MOV_IMM8), //00 1000 1111
+
+TABDECL( OP_MOV_IMM8), //00 1001 0000
+TABDECL( OP_MOV_IMM8), //00 1001 0001
+TABDECL( OP_MOV_IMM8), //00 1001 0010
+TABDECL( OP_MOV_IMM8), //00 1001 0011
+TABDECL( OP_MOV_IMM8), //00 1001 0100
+TABDECL( OP_MOV_IMM8), //00 1001 0101
+TABDECL( OP_MOV_IMM8), //00 1001 0110
+TABDECL( OP_MOV_IMM8), //00 1001 0111
+TABDECL( OP_MOV_IMM8), //00 1001 1000
+TABDECL( OP_MOV_IMM8), //00 1001 1001
+TABDECL( OP_MOV_IMM8), //00 1001 1010
+TABDECL( OP_MOV_IMM8), //00 1001 1011
+TABDECL( OP_MOV_IMM8), //00 1001 1100
+TABDECL( OP_MOV_IMM8), //00 1001 1101
+TABDECL( OP_MOV_IMM8), //00 1001 1110
+TABDECL( OP_MOV_IMM8), //00 1001 1111
+
+TABDECL( OP_CMP_IMM8), //00 1010 0000
+TABDECL( OP_CMP_IMM8), //00 1010 0001
+TABDECL( OP_CMP_IMM8), //00 1010 0010
+TABDECL( OP_CMP_IMM8), //00 1010 0011
+TABDECL( OP_CMP_IMM8), //00 1010 0100
+TABDECL( OP_CMP_IMM8), //00 1010 0101
+TABDECL( OP_CMP_IMM8), //00 1010 0110
+TABDECL( OP_CMP_IMM8), //00 1010 0111
+TABDECL( OP_CMP_IMM8), //00 1010 1000
+TABDECL( OP_CMP_IMM8), //00 1010 1001
+TABDECL( OP_CMP_IMM8), //00 1010 1010
+TABDECL( OP_CMP_IMM8), //00 1010 1011
+TABDECL( OP_CMP_IMM8), //00 1010 1100
+TABDECL( OP_CMP_IMM8), //00 1010 1101
+TABDECL( OP_CMP_IMM8), //00 1010 1110
+TABDECL( OP_CMP_IMM8), //00 1010 1111
+
+TABDECL( OP_CMP_IMM8), //00 1011 0000
+TABDECL( OP_CMP_IMM8), //00 1011 0001
+TABDECL( OP_CMP_IMM8), //00 1011 0010
+TABDECL( OP_CMP_IMM8), //00 1011 0011
+TABDECL( OP_CMP_IMM8), //00 1011 0100
+TABDECL( OP_CMP_IMM8), //00 1011 0101
+TABDECL( OP_CMP_IMM8), //00 1011 0110
+TABDECL( OP_CMP_IMM8), //00 1011 0111
+TABDECL( OP_CMP_IMM8), //00 1011 1000
+TABDECL( OP_CMP_IMM8), //00 1011 1001
+TABDECL( OP_CMP_IMM8), //00 1011 1010
+TABDECL( OP_CMP_IMM8), //00 1011 1011
+TABDECL( OP_CMP_IMM8), //00 1011 1100
+TABDECL( OP_CMP_IMM8), //00 1011 1101
+TABDECL( OP_CMP_IMM8), //00 1011 1110
+TABDECL( OP_CMP_IMM8), //00 1011 1111
+
+TABDECL( OP_ADD_IMM8), //00 1100 0000
+TABDECL( OP_ADD_IMM8), //00 1100 0001
+TABDECL( OP_ADD_IMM8), //00 1100 0010
+TABDECL( OP_ADD_IMM8), //00 1100 0011
+TABDECL( OP_ADD_IMM8), //00 1100 0100
+TABDECL( OP_ADD_IMM8), //00 1100 0101
+TABDECL( OP_ADD_IMM8), //00 1100 0110
+TABDECL( OP_ADD_IMM8), //00 1100 0111
+TABDECL( OP_ADD_IMM8), //00 1100 1000
+TABDECL( OP_ADD_IMM8), //00 1100 1001
+TABDECL( OP_ADD_IMM8), //00 1100 1010
+TABDECL( OP_ADD_IMM8), //00 1100 1011
+TABDECL( OP_ADD_IMM8), //00 1100 1100
+TABDECL( OP_ADD_IMM8), //00 1100 1101
+TABDECL( OP_ADD_IMM8), //00 1100 1110
+TABDECL( OP_ADD_IMM8), //00 1100 1111
+
+TABDECL( OP_ADD_IMM8), //00 1101 0000
+TABDECL( OP_ADD_IMM8), //00 1101 0001
+TABDECL( OP_ADD_IMM8), //00 1101 0010
+TABDECL( OP_ADD_IMM8), //00 1101 0011
+TABDECL( OP_ADD_IMM8), //00 1101 0100
+TABDECL( OP_ADD_IMM8), //00 1101 0101
+TABDECL( OP_ADD_IMM8), //00 1101 0110
+TABDECL( OP_ADD_IMM8), //00 1101 0111
+TABDECL( OP_ADD_IMM8), //00 1101 1000
+TABDECL( OP_ADD_IMM8), //00 1101 1001
+TABDECL( OP_ADD_IMM8), //00 1101 1010
+TABDECL( OP_ADD_IMM8), //00 1101 1011
+TABDECL( OP_ADD_IMM8), //00 1101 1100
+TABDECL( OP_ADD_IMM8), //00 1101 1101
+TABDECL( OP_ADD_IMM8), //00 1101 1110
+TABDECL( OP_ADD_IMM8), //00 1101 1111
+
+TABDECL( OP_SUB_IMM8), //00 1110 0000
+TABDECL( OP_SUB_IMM8), //00 1110 0001
+TABDECL( OP_SUB_IMM8), //00 1110 0010
+TABDECL( OP_SUB_IMM8), //00 1110 0011
+TABDECL( OP_SUB_IMM8), //00 1110 0100
+TABDECL( OP_SUB_IMM8), //00 1110 0101
+TABDECL( OP_SUB_IMM8), //00 1110 0110
+TABDECL( OP_SUB_IMM8), //00 1110 0111
+TABDECL( OP_SUB_IMM8), //00 1110 1000
+TABDECL( OP_SUB_IMM8), //00 1110 1001
+TABDECL( OP_SUB_IMM8), //00 1110 1010
+TABDECL( OP_SUB_IMM8), //00 1110 1011
+TABDECL( OP_SUB_IMM8), //00 1110 1100
+TABDECL( OP_SUB_IMM8), //00 1110 1101
+TABDECL( OP_SUB_IMM8), //00 1110 1110
+TABDECL( OP_SUB_IMM8), //00 1110 1111
+
+TABDECL( OP_SUB_IMM8), //00 1111 0000
+TABDECL( OP_SUB_IMM8), //00 1111 0001
+TABDECL( OP_SUB_IMM8), //00 1111 0010
+TABDECL( OP_SUB_IMM8), //00 1111 0011
+TABDECL( OP_SUB_IMM8), //00 1111 0100
+TABDECL( OP_SUB_IMM8), //00 1111 0101
+TABDECL( OP_SUB_IMM8), //00 1111 0110
+TABDECL( OP_SUB_IMM8), //00 1111 0111
+TABDECL( OP_SUB_IMM8), //00 1111 1000
+TABDECL( OP_SUB_IMM8), //00 1111 1001
+TABDECL( OP_SUB_IMM8), //00 1111 1010
+TABDECL( OP_SUB_IMM8), //00 1111 1011
+TABDECL( OP_SUB_IMM8), //00 1111 1100
+TABDECL( OP_SUB_IMM8), //00 1111 1101
+TABDECL( OP_SUB_IMM8), //00 1111 1110
+TABDECL( OP_SUB_IMM8), //00 1111 1111
+
+TABDECL( OP_AND), //01 0000 0000
+TABDECL( OP_EOR), //01 0000 0001
+TABDECL( OP_LSL_REG), //01 0000 0010
+TABDECL( OP_LSR_REG), //01 0000 0011
+TABDECL( OP_ASR_REG), //01 0000 0100
+TABDECL( OP_ADC_REG), //01 0000 0101
+TABDECL( OP_SBC_REG), //01 0000 0110
+TABDECL( OP_ROR_REG), //01 0000 0111
+TABDECL( OP_TST), //01 0000 1000
+TABDECL( OP_NEG), //01 0000 1001
+TABDECL( OP_CMP), //01 0000 1010
+TABDECL( OP_CMN), //01 0000 1011
+TABDECL( OP_ORR), //01 0000 1100
+TABDECL( OP_MUL_REG), //01 0000 1101
+TABDECL( OP_BIC), //01 0000 1110
+TABDECL( OP_MVN), //01 0000 1111
+
+TABDECL( OP_ADD_SPE), //01 0001 0000
+TABDECL( OP_ADD_SPE), //01 0001 0001
+TABDECL( OP_ADD_SPE), //01 0001 0010
+TABDECL( OP_ADD_SPE), //01 0001 0011
+TABDECL( OP_CMP_SPE), //01 0001 0100
+TABDECL( OP_CMP_SPE), //01 0001 0101
+TABDECL( OP_CMP_SPE), //01 0001 0110
+TABDECL( OP_CMP_SPE), //01 0001 0111
+TABDECL( OP_MOV_SPE), //01 0001 1000
+TABDECL( OP_MOV_SPE), //01 0001 1001
+TABDECL( OP_MOV_SPE), //01 0001 1010
+TABDECL( OP_MOV_SPE), //01 0001 1011
+TABDECL( OP_BX_THUMB), //01 0001 1100
+TABDECL( OP_BX_THUMB), //01 0001 1101
+TABDECL( OP_BLX_THUMB), //01 0001 1110
+TABDECL( OP_BLX_THUMB), //01 0001 1111
+
+TABDECL( OP_LDR_PCREL), //01 0010 0000
+TABDECL( OP_LDR_PCREL), //01 0010 0001
+TABDECL( OP_LDR_PCREL), //01 0010 0010
+TABDECL( OP_LDR_PCREL), //01 0010 0011
+TABDECL( OP_LDR_PCREL), //01 0010 0100
+TABDECL( OP_LDR_PCREL), //01 0010 0101
+TABDECL( OP_LDR_PCREL), //01 0010 0110
+TABDECL( OP_LDR_PCREL), //01 0010 0111
+TABDECL( OP_LDR_PCREL), //01 0010 1000
+TABDECL( OP_LDR_PCREL), //01 0010 1001
+TABDECL( OP_LDR_PCREL), //01 0010 1010
+TABDECL( OP_LDR_PCREL), //01 0010 1011
+TABDECL( OP_LDR_PCREL), //01 0010 1100
+TABDECL( OP_LDR_PCREL), //01 0010 1101
+TABDECL( OP_LDR_PCREL), //01 0010 1110
+TABDECL( OP_LDR_PCREL), //01 0010 1111
+
+TABDECL( OP_LDR_PCREL), //01 0011 0000
+TABDECL( OP_LDR_PCREL), //01 0011 0001
+TABDECL( OP_LDR_PCREL), //01 0011 0010
+TABDECL( OP_LDR_PCREL), //01 0011 0011
+TABDECL( OP_LDR_PCREL), //01 0011 0100
+TABDECL( OP_LDR_PCREL), //01 0011 0101
+TABDECL( OP_LDR_PCREL), //01 0011 0110
+TABDECL( OP_LDR_PCREL), //01 0011 0111
+TABDECL( OP_LDR_PCREL), //01 0011 1000
+TABDECL( OP_LDR_PCREL), //01 0011 1001
+TABDECL( OP_LDR_PCREL), //01 0011 1010
+TABDECL( OP_LDR_PCREL), //01 0011 1011
+TABDECL( OP_LDR_PCREL), //01 0011 1100
+TABDECL( OP_LDR_PCREL), //01 0011 1101
+TABDECL( OP_LDR_PCREL), //01 0011 1110
+TABDECL( OP_LDR_PCREL), //01 0011 1111
+
+TABDECL( OP_STR_REG_OFF), //01 0100 0000
+TABDECL( OP_STR_REG_OFF), //01 0100 0001
+TABDECL( OP_STR_REG_OFF), //01 0100 0010
+TABDECL( OP_STR_REG_OFF), //01 0100 0011
+TABDECL( OP_STR_REG_OFF), //01 0100 0100
+TABDECL( OP_STR_REG_OFF), //01 0100 0101
+TABDECL( OP_STR_REG_OFF), //01 0100 0110
+TABDECL( OP_STR_REG_OFF), //01 0100 0111
+TABDECL( OP_STRH_REG_OFF), //01 0100 1000
+TABDECL( OP_STRH_REG_OFF), //01 0100 1001
+TABDECL( OP_STRH_REG_OFF), //01 0100 1010
+TABDECL( OP_STRH_REG_OFF), //01 0100 1011
+TABDECL( OP_STRH_REG_OFF), //01 0100 1100
+TABDECL( OP_STRH_REG_OFF), //01 0100 1101
+TABDECL( OP_STRH_REG_OFF), //01 0100 1110
+TABDECL( OP_STRH_REG_OFF), //01 0100 1111
+
+TABDECL( OP_STRB_REG_OFF), //01 0101 0000
+TABDECL( OP_STRB_REG_OFF), //01 0101 0001
+TABDECL( OP_STRB_REG_OFF), //01 0101 0010
+TABDECL( OP_STRB_REG_OFF), //01 0101 0011
+TABDECL( OP_STRB_REG_OFF), //01 0101 0100
+TABDECL( OP_STRB_REG_OFF), //01 0101 0101
+TABDECL( OP_STRB_REG_OFF), //01 0101 0110
+TABDECL( OP_STRB_REG_OFF), //01 0101 0111
+TABDECL( OP_LDRSB_REG_OFF), //01 0101 1000
+TABDECL( OP_LDRSB_REG_OFF), //01 0101 1001
+TABDECL( OP_LDRSB_REG_OFF), //01 0101 1010
+TABDECL( OP_LDRSB_REG_OFF), //01 0101 1011
+TABDECL( OP_LDRSB_REG_OFF), //01 0101 1100
+TABDECL( OP_LDRSB_REG_OFF), //01 0101 1101
+TABDECL( OP_LDRSB_REG_OFF), //01 0101 1110
+TABDECL( OP_LDRSB_REG_OFF), //01 0101 1111
+
+TABDECL( OP_LDR_REG_OFF), //01 0110 0000
+TABDECL( OP_LDR_REG_OFF), //01 0110 0001
+TABDECL( OP_LDR_REG_OFF), //01 0110 0010
+TABDECL( OP_LDR_REG_OFF), //01 0110 0011
+TABDECL( OP_LDR_REG_OFF), //01 0110 0100
+TABDECL( OP_LDR_REG_OFF), //01 0110 0101
+TABDECL( OP_LDR_REG_OFF), //01 0110 0110
+TABDECL( OP_LDR_REG_OFF), //01 0110 0111
+TABDECL( OP_LDRH_REG_OFF), //01 0110 1000
+TABDECL( OP_LDRH_REG_OFF), //01 0110 1001
+TABDECL( OP_LDRH_REG_OFF), //01 0110 1010
+TABDECL( OP_LDRH_REG_OFF), //01 0110 1011
+TABDECL( OP_LDRH_REG_OFF), //01 0110 1100
+TABDECL( OP_LDRH_REG_OFF), //01 0110 1101
+TABDECL( OP_LDRH_REG_OFF), //01 0110 1110
+TABDECL( OP_LDRH_REG_OFF), //01 0110 1111
+
+TABDECL( OP_LDRB_REG_OFF), //01 0111 0000
+TABDECL( OP_LDRB_REG_OFF), //01 0111 0001
+TABDECL( OP_LDRB_REG_OFF), //01 0111 0010
+TABDECL( OP_LDRB_REG_OFF), //01 0111 0011
+TABDECL( OP_LDRB_REG_OFF), //01 0111 0100
+TABDECL( OP_LDRB_REG_OFF), //01 0111 0101
+TABDECL( OP_LDRB_REG_OFF), //01 0111 0110
+TABDECL( OP_LDRB_REG_OFF), //01 0111 0111
+TABDECL( OP_LDRSH_REG_OFF), //01 0111 1000
+TABDECL( OP_LDRSH_REG_OFF), //01 0111 1001
+TABDECL( OP_LDRSH_REG_OFF), //01 0111 1010
+TABDECL( OP_LDRSH_REG_OFF), //01 0111 1011
+TABDECL( OP_LDRSH_REG_OFF), //01 0111 1100
+TABDECL( OP_LDRSH_REG_OFF), //01 0111 1101
+TABDECL( OP_LDRSH_REG_OFF), //01 0111 1110
+TABDECL( OP_LDRSH_REG_OFF), //01 0111 1111
+
+TABDECL( OP_STR_IMM_OFF), //01 1000 0000
+TABDECL( OP_STR_IMM_OFF), //01 1000 0001
+TABDECL( OP_STR_IMM_OFF), //01 1000 0010
+TABDECL( OP_STR_IMM_OFF), //01 1000 0011
+TABDECL( OP_STR_IMM_OFF), //01 1000 0100
+TABDECL( OP_STR_IMM_OFF), //01 1000 0101
+TABDECL( OP_STR_IMM_OFF), //01 1000 0110
+TABDECL( OP_STR_IMM_OFF), //01 1000 0111
+TABDECL( OP_STR_IMM_OFF), //01 1000 1000
+TABDECL( OP_STR_IMM_OFF), //01 1000 1001
+TABDECL( OP_STR_IMM_OFF), //01 1000 1010
+TABDECL( OP_STR_IMM_OFF), //01 1000 1011
+TABDECL( OP_STR_IMM_OFF), //01 1000 1100
+TABDECL( OP_STR_IMM_OFF), //01 1000 1101
+TABDECL( OP_STR_IMM_OFF), //01 1000 1110
+TABDECL( OP_STR_IMM_OFF), //01 1000 1111
+
+TABDECL( OP_STR_IMM_OFF), //01 1001 0000
+TABDECL( OP_STR_IMM_OFF), //01 1001 0001
+TABDECL( OP_STR_IMM_OFF), //01 1001 0010
+TABDECL( OP_STR_IMM_OFF), //01 1001 0011
+TABDECL( OP_STR_IMM_OFF), //01 1001 0100
+TABDECL( OP_STR_IMM_OFF), //01 1001 0101
+TABDECL( OP_STR_IMM_OFF), //01 1001 0110
+TABDECL( OP_STR_IMM_OFF), //01 1001 0111
+TABDECL( OP_STR_IMM_OFF), //01 1001 1000
+TABDECL( OP_STR_IMM_OFF), //01 1001 1001
+TABDECL( OP_STR_IMM_OFF), //01 1001 1010
+TABDECL( OP_STR_IMM_OFF), //01 1001 1011
+TABDECL( OP_STR_IMM_OFF), //01 1001 1100
+TABDECL( OP_STR_IMM_OFF), //01 1001 1101
+TABDECL( OP_STR_IMM_OFF), //01 1001 1110
+TABDECL( OP_STR_IMM_OFF), //01 1001 1111
+
+TABDECL( OP_LDR_IMM_OFF), //01 1010 0000
+TABDECL( OP_LDR_IMM_OFF), //01 1010 0001
+TABDECL( OP_LDR_IMM_OFF), //01 1010 0010
+TABDECL( OP_LDR_IMM_OFF), //01 1010 0011
+TABDECL( OP_LDR_IMM_OFF), //01 1010 0100
+TABDECL( OP_LDR_IMM_OFF), //01 1010 0101
+TABDECL( OP_LDR_IMM_OFF), //01 1010 0110
+TABDECL( OP_LDR_IMM_OFF), //01 1010 0111
+TABDECL( OP_LDR_IMM_OFF), //01 1010 1000
+TABDECL( OP_LDR_IMM_OFF), //01 1010 1001
+TABDECL( OP_LDR_IMM_OFF), //01 1010 1010
+TABDECL( OP_LDR_IMM_OFF), //01 1010 1011
+TABDECL( OP_LDR_IMM_OFF), //01 1010 1100
+TABDECL( OP_LDR_IMM_OFF), //01 1010 1101
+TABDECL( OP_LDR_IMM_OFF), //01 1010 1110
+TABDECL( OP_LDR_IMM_OFF), //01 1010 1111
+
+TABDECL( OP_LDR_IMM_OFF), //01 1011 0000
+TABDECL( OP_LDR_IMM_OFF), //01 1011 0001
+TABDECL( OP_LDR_IMM_OFF), //01 1011 0010
+TABDECL( OP_LDR_IMM_OFF), //01 1011 0011
+TABDECL( OP_LDR_IMM_OFF), //01 1011 0100
+TABDECL( OP_LDR_IMM_OFF), //01 1011 0101
+TABDECL( OP_LDR_IMM_OFF), //01 1011 0110
+TABDECL( OP_LDR_IMM_OFF), //01 1011 0111
+TABDECL( OP_LDR_IMM_OFF), //01 1011 1000
+TABDECL( OP_LDR_IMM_OFF), //01 1011 1001
+TABDECL( OP_LDR_IMM_OFF), //01 1011 1010
+TABDECL( OP_LDR_IMM_OFF), //01 1011 1011
+TABDECL( OP_LDR_IMM_OFF), //01 1011 1100
+TABDECL( OP_LDR_IMM_OFF), //01 1011 1101
+TABDECL( OP_LDR_IMM_OFF), //01 1011 1110
+TABDECL( OP_LDR_IMM_OFF), //01 1011 1111
+
+TABDECL( OP_STRB_IMM_OFF), //01 1100 0000
+TABDECL( OP_STRB_IMM_OFF), //01 1100 0001
+TABDECL( OP_STRB_IMM_OFF), //01 1100 0010
+TABDECL( OP_STRB_IMM_OFF), //01 1100 0011
+TABDECL( OP_STRB_IMM_OFF), //01 1100 0100
+TABDECL( OP_STRB_IMM_OFF), //01 1100 0101
+TABDECL( OP_STRB_IMM_OFF), //01 1100 0110
+TABDECL( OP_STRB_IMM_OFF), //01 1100 0111
+TABDECL( OP_STRB_IMM_OFF), //01 1100 1000
+TABDECL( OP_STRB_IMM_OFF), //01 1100 1001
+TABDECL( OP_STRB_IMM_OFF), //01 1100 1010
+TABDECL( OP_STRB_IMM_OFF), //01 1100 1011
+TABDECL( OP_STRB_IMM_OFF), //01 1100 1100
+TABDECL( OP_STRB_IMM_OFF), //01 1100 1101
+TABDECL( OP_STRB_IMM_OFF), //01 1100 1110
+TABDECL( OP_STRB_IMM_OFF), //01 1100 1111
+
+TABDECL( OP_STRB_IMM_OFF), //01 1101 0000
+TABDECL( OP_STRB_IMM_OFF), //01 1101 0001
+TABDECL( OP_STRB_IMM_OFF), //01 1101 0010
+TABDECL( OP_STRB_IMM_OFF), //01 1101 0011
+TABDECL( OP_STRB_IMM_OFF), //01 1101 0100
+TABDECL( OP_STRB_IMM_OFF), //01 1101 0101
+TABDECL( OP_STRB_IMM_OFF), //01 1101 0110
+TABDECL( OP_STRB_IMM_OFF), //01 1101 0111
+TABDECL( OP_STRB_IMM_OFF), //01 1101 1000
+TABDECL( OP_STRB_IMM_OFF), //01 1101 1001
+TABDECL( OP_STRB_IMM_OFF), //01 1101 1010
+TABDECL( OP_STRB_IMM_OFF), //01 1101 1011
+TABDECL( OP_STRB_IMM_OFF), //01 1101 1100
+TABDECL( OP_STRB_IMM_OFF), //01 1101 1101
+TABDECL( OP_STRB_IMM_OFF), //01 1101 1110
+TABDECL( OP_STRB_IMM_OFF), //01 1101 1111
+
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 0000
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 0001
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 0010
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 0011
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 0100
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 0101
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 0110
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 0111
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 1000
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 1001
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 1010
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 1011
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 1100
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 1101
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 1110
+TABDECL( OP_LDRB_IMM_OFF), //01 1110 1111
+
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 0000
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 0001
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 0010
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 0011
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 0100
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 0101
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 0110
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 0111
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 1000
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 1001
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 1010
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 1011
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 1100
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 1101
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 1110
+TABDECL( OP_LDRB_IMM_OFF), //01 1111 1111
+
+TABDECL( OP_STRH_IMM_OFF), //10 0000 0000
+TABDECL( OP_STRH_IMM_OFF), //10 0000 0001
+TABDECL( OP_STRH_IMM_OFF), //10 0000 0010
+TABDECL( OP_STRH_IMM_OFF), //10 0000 0011
+TABDECL( OP_STRH_IMM_OFF), //10 0000 0100
+TABDECL( OP_STRH_IMM_OFF), //10 0000 0101
+TABDECL( OP_STRH_IMM_OFF), //10 0000 0110
+TABDECL( OP_STRH_IMM_OFF), //10 0000 0111
+TABDECL( OP_STRH_IMM_OFF), //10 0000 1000
+TABDECL( OP_STRH_IMM_OFF), //10 0000 1001
+TABDECL( OP_STRH_IMM_OFF), //10 0000 1010
+TABDECL( OP_STRH_IMM_OFF), //10 0000 1011
+TABDECL( OP_STRH_IMM_OFF), //10 0000 1100
+TABDECL( OP_STRH_IMM_OFF), //10 0000 1101
+TABDECL( OP_STRH_IMM_OFF), //10 0000 1110
+TABDECL( OP_STRH_IMM_OFF), //10 0000 1111
+
+TABDECL( OP_STRH_IMM_OFF), //10 0001 0000
+TABDECL( OP_STRH_IMM_OFF), //10 0001 0001
+TABDECL( OP_STRH_IMM_OFF), //10 0001 0010
+TABDECL( OP_STRH_IMM_OFF), //10 0001 0011
+TABDECL( OP_STRH_IMM_OFF), //10 0001 0100
+TABDECL( OP_STRH_IMM_OFF), //10 0001 0101
+TABDECL( OP_STRH_IMM_OFF), //10 0001 0110
+TABDECL( OP_STRH_IMM_OFF), //10 0001 0111
+TABDECL( OP_STRH_IMM_OFF), //10 0001 1000
+TABDECL( OP_STRH_IMM_OFF), //10 0001 1001
+TABDECL( OP_STRH_IMM_OFF), //10 0001 1010
+TABDECL( OP_STRH_IMM_OFF), //10 0001 1011
+TABDECL( OP_STRH_IMM_OFF), //10 0001 1100
+TABDECL( OP_STRH_IMM_OFF), //10 0001 1101
+TABDECL( OP_STRH_IMM_OFF), //10 0001 1110
+TABDECL( OP_STRH_IMM_OFF), //10 0001 1111
+
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 0000
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 0001
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 0010
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 0011
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 0100
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 0101
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 0110
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 0111
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 1000
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 1001
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 1010
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 1011
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 1100
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 1101
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 1110
+TABDECL( OP_LDRH_IMM_OFF), //10 0010 1111
+
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 0000
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 0001
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 0010
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 0011
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 0100
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 0101
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 0110
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 0111
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 1000
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 1001
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 1010
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 1011
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 1100
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 1101
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 1110
+TABDECL( OP_LDRH_IMM_OFF), //10 0011 1111
+
+TABDECL( OP_STR_SPREL), //10 0100 0000
+TABDECL( OP_STR_SPREL), //10 0100 0001
+TABDECL( OP_STR_SPREL), //10 0100 0010
+TABDECL( OP_STR_SPREL), //10 0100 0011
+TABDECL( OP_STR_SPREL), //10 0100 0100
+TABDECL( OP_STR_SPREL), //10 0100 0101
+TABDECL( OP_STR_SPREL), //10 0100 0110
+TABDECL( OP_STR_SPREL), //10 0100 0111
+TABDECL( OP_STR_SPREL), //10 0100 1000
+TABDECL( OP_STR_SPREL), //10 0100 1001
+TABDECL( OP_STR_SPREL), //10 0100 1010
+TABDECL( OP_STR_SPREL), //10 0100 1011
+TABDECL( OP_STR_SPREL), //10 0100 1100
+TABDECL( OP_STR_SPREL), //10 0100 1101
+TABDECL( OP_STR_SPREL), //10 0100 1110
+TABDECL( OP_STR_SPREL), //10 0100 1111
+
+TABDECL( OP_STR_SPREL), //10 0101 0000
+TABDECL( OP_STR_SPREL), //10 0101 0001
+TABDECL( OP_STR_SPREL), //10 0101 0010
+TABDECL( OP_STR_SPREL), //10 0101 0011
+TABDECL( OP_STR_SPREL), //10 0101 0100
+TABDECL( OP_STR_SPREL), //10 0101 0101
+TABDECL( OP_STR_SPREL), //10 0101 0110
+TABDECL( OP_STR_SPREL), //10 0101 0111
+TABDECL( OP_STR_SPREL), //10 0101 1000
+TABDECL( OP_STR_SPREL), //10 0101 1001
+TABDECL( OP_STR_SPREL), //10 0101 1010
+TABDECL( OP_STR_SPREL), //10 0101 1011
+TABDECL( OP_STR_SPREL), //10 0101 1100
+TABDECL( OP_STR_SPREL), //10 0101 1101
+TABDECL( OP_STR_SPREL), //10 0101 1110
+TABDECL( OP_STR_SPREL), //10 0101 1111
+
+TABDECL( OP_LDR_SPREL), //10 0110 0000
+TABDECL( OP_LDR_SPREL), //10 0110 0001
+TABDECL( OP_LDR_SPREL), //10 0110 0010
+TABDECL( OP_LDR_SPREL), //10 0110 0011
+TABDECL( OP_LDR_SPREL), //10 0110 0100
+TABDECL( OP_LDR_SPREL), //10 0110 0101
+TABDECL( OP_LDR_SPREL), //10 0110 0110
+TABDECL( OP_LDR_SPREL), //10 0110 0111
+TABDECL( OP_LDR_SPREL), //10 0110 1000
+TABDECL( OP_LDR_SPREL), //10 0110 1001
+TABDECL( OP_LDR_SPREL), //10 0110 1010
+TABDECL( OP_LDR_SPREL), //10 0110 1011
+TABDECL( OP_LDR_SPREL), //10 0110 1100
+TABDECL( OP_LDR_SPREL), //10 0110 1101
+TABDECL( OP_LDR_SPREL), //10 0110 1110
+TABDECL( OP_LDR_SPREL), //10 0110 1111
+
+TABDECL( OP_LDR_SPREL), //10 0111 0000
+TABDECL( OP_LDR_SPREL), //10 0111 0001
+TABDECL( OP_LDR_SPREL), //10 0111 0010
+TABDECL( OP_LDR_SPREL), //10 0111 0011
+TABDECL( OP_LDR_SPREL), //10 0111 0100
+TABDECL( OP_LDR_SPREL), //10 0111 0101
+TABDECL( OP_LDR_SPREL), //10 0111 0110
+TABDECL( OP_LDR_SPREL), //10 0111 0111
+TABDECL( OP_LDR_SPREL), //10 0111 1000
+TABDECL( OP_LDR_SPREL), //10 0111 1001
+TABDECL( OP_LDR_SPREL), //10 0111 1010
+TABDECL( OP_LDR_SPREL), //10 0111 1011
+TABDECL( OP_LDR_SPREL), //10 0111 1100
+TABDECL( OP_LDR_SPREL), //10 0111 1101
+TABDECL( OP_LDR_SPREL), //10 0111 1110
+TABDECL( OP_LDR_SPREL), //10 0111 1111
+
+TABDECL( OP_ADD_2PC), //10 1000 0000
+TABDECL( OP_ADD_2PC), //10 1000 0001
+TABDECL( OP_ADD_2PC), //10 1000 0010
+TABDECL( OP_ADD_2PC), //10 1000 0011
+TABDECL( OP_ADD_2PC), //10 1000 0100
+TABDECL( OP_ADD_2PC), //10 1000 0101
+TABDECL( OP_ADD_2PC), //10 1000 0110
+TABDECL( OP_ADD_2PC), //10 1000 0111
+TABDECL( OP_ADD_2PC), //10 1000 1000
+TABDECL( OP_ADD_2PC), //10 1000 1001
+TABDECL( OP_ADD_2PC), //10 1000 1010
+TABDECL( OP_ADD_2PC), //10 1000 1011
+TABDECL( OP_ADD_2PC), //10 1000 1100
+TABDECL( OP_ADD_2PC), //10 1000 1101
+TABDECL( OP_ADD_2PC), //10 1000 1110
+TABDECL( OP_ADD_2PC), //10 1000 1111
+
+TABDECL( OP_ADD_2PC), //10 1001 0000
+TABDECL( OP_ADD_2PC), //10 1001 0001
+TABDECL( OP_ADD_2PC), //10 1001 0010
+TABDECL( OP_ADD_2PC), //10 1001 0011
+TABDECL( OP_ADD_2PC), //10 1001 0100
+TABDECL( OP_ADD_2PC), //10 1001 0101
+TABDECL( OP_ADD_2PC), //10 1001 0110
+TABDECL( OP_ADD_2PC), //10 1001 0111
+TABDECL( OP_ADD_2PC), //10 1001 1000
+TABDECL( OP_ADD_2PC), //10 1001 1001
+TABDECL( OP_ADD_2PC), //10 1001 1010
+TABDECL( OP_ADD_2PC), //10 1001 1011
+TABDECL( OP_ADD_2PC), //10 1001 1100
+TABDECL( OP_ADD_2PC), //10 1001 1101
+TABDECL( OP_ADD_2PC), //10 1001 1110
+TABDECL( OP_ADD_2PC), //10 1001 1111
+
+TABDECL( OP_ADD_2SP), //10 1010 0000
+TABDECL( OP_ADD_2SP), //10 1010 0001
+TABDECL( OP_ADD_2SP), //10 1010 0010
+TABDECL( OP_ADD_2SP), //10 1010 0011
+TABDECL( OP_ADD_2SP), //10 1010 0100
+TABDECL( OP_ADD_2SP), //10 1010 0101
+TABDECL( OP_ADD_2SP), //10 1010 0110
+TABDECL( OP_ADD_2SP), //10 1010 0111
+TABDECL( OP_ADD_2SP), //10 1010 1000
+TABDECL( OP_ADD_2SP), //10 1010 1001
+TABDECL( OP_ADD_2SP), //10 1010 1010
+TABDECL( OP_ADD_2SP), //10 1010 1011
+TABDECL( OP_ADD_2SP), //10 1010 1100
+TABDECL( OP_ADD_2SP), //10 1010 1101
+TABDECL( OP_ADD_2SP), //10 1010 1110
+TABDECL( OP_ADD_2SP), //10 1010 1111
+
+TABDECL( OP_ADD_2SP), //10 1011 0000
+TABDECL( OP_ADD_2SP), //10 1011 0001
+TABDECL( OP_ADD_2SP), //10 1011 0010
+TABDECL( OP_ADD_2SP), //10 1011 0011
+TABDECL( OP_ADD_2SP), //10 1011 0100
+TABDECL( OP_ADD_2SP), //10 1011 0101
+TABDECL( OP_ADD_2SP), //10 1011 0110
+TABDECL( OP_ADD_2SP), //10 1011 0111
+TABDECL( OP_ADD_2SP), //10 1011 1000
+TABDECL( OP_ADD_2SP), //10 1011 1001
+TABDECL( OP_ADD_2SP), //10 1011 1010
+TABDECL( OP_ADD_2SP), //10 1011 1011
+TABDECL( OP_ADD_2SP), //10 1011 1100
+TABDECL( OP_ADD_2SP), //10 1011 1101
+TABDECL( OP_ADD_2SP), //10 1011 1110
+TABDECL( OP_ADD_2SP), //10 1011 1111
+
+TABDECL( OP_ADJUST_P_SP), //10 1100 0000
+TABDECL( OP_ADJUST_P_SP), //10 1100 0001
+TABDECL( OP_ADJUST_M_SP), //10 1100 0010
+TABDECL( OP_ADJUST_M_SP), //10 1100 0011
+TABDECL( OP_UND_THUMB), //10 1100 0100
+TABDECL( OP_UND_THUMB), //10 1100 0101
+TABDECL( OP_UND_THUMB), //10 1100 0110
+TABDECL( OP_UND_THUMB), //10 1100 0111
+TABDECL( OP_UND_THUMB), //10 1100 1000
+TABDECL( OP_UND_THUMB), //10 1100 1001
+TABDECL( OP_UND_THUMB), //10 1100 1010
+TABDECL( OP_UND_THUMB), //10 1100 1011
+TABDECL( OP_UND_THUMB), //10 1100 1100
+TABDECL( OP_UND_THUMB), //10 1100 1101
+TABDECL( OP_UND_THUMB), //10 1100 1110
+TABDECL( OP_UND_THUMB), //10 1100 1111
+
+TABDECL( OP_PUSH), //10 1101 0000
+TABDECL( OP_PUSH), //10 1101 0001
+TABDECL( OP_PUSH), //10 1101 0010
+TABDECL( OP_PUSH), //10 1101 0011
+TABDECL( OP_PUSH_LR), //10 1101 0100
+TABDECL( OP_PUSH_LR), //10 1101 0101
+TABDECL( OP_PUSH_LR), //10 1101 0110
+TABDECL( OP_PUSH_LR), //10 1101 0111
+TABDECL( OP_UND_THUMB), //10 1101 1000
+TABDECL( OP_UND_THUMB), //10 1101 1001
+TABDECL( OP_UND_THUMB), //10 1101 1010
+TABDECL( OP_UND_THUMB), //10 1101 1011
+TABDECL( OP_UND_THUMB), //10 1101 1100
+TABDECL( OP_UND_THUMB), //10 1101 1101
+TABDECL( OP_UND_THUMB), //10 1101 1110
+TABDECL( OP_UND_THUMB), //10 1101 1111
+
+TABDECL( OP_UND_THUMB), //10 1110 0000
+TABDECL( OP_UND_THUMB), //10 1110 0001
+TABDECL( OP_UND_THUMB), //10 1110 0010
+TABDECL( OP_UND_THUMB), //10 1110 0011
+TABDECL( OP_UND_THUMB), //10 1110 0100
+TABDECL( OP_UND_THUMB), //10 1110 0101
+TABDECL( OP_UND_THUMB), //10 1110 0110
+TABDECL( OP_UND_THUMB), //10 1110 0111
+TABDECL( OP_UND_THUMB), //10 1110 1000
+TABDECL( OP_UND_THUMB), //10 1110 1001
+TABDECL( OP_UND_THUMB), //10 1110 1010
+TABDECL( OP_UND_THUMB), //10 1110 1011
+TABDECL( OP_UND_THUMB), //10 1110 1100
+TABDECL( OP_UND_THUMB), //10 1110 1101
+TABDECL( OP_UND_THUMB), //10 1110 1110
+TABDECL( OP_UND_THUMB), //10 1110 1111
+
+TABDECL( OP_POP), //10 1111 0000
+TABDECL( OP_POP), //10 1111 0001
+TABDECL( OP_POP), //10 1111 0010
+TABDECL( OP_POP), //10 1111 0011
+TABDECL( OP_POP_PC), //10 1111 0100
+TABDECL( OP_POP_PC), //10 1111 0101
+TABDECL( OP_POP_PC), //10 1111 0110
+TABDECL( OP_POP_PC), //10 1111 0111
+TABDECL( OP_BKPT_THUMB), //10 1111 1000
+TABDECL( OP_BKPT_THUMB), //10 1111 1001
+TABDECL( OP_BKPT_THUMB), //10 1111 1010
+TABDECL( OP_BKPT_THUMB), //10 1111 1011
+TABDECL( OP_UND_THUMB), //10 1111 1100
+TABDECL( OP_UND_THUMB), //10 1111 1101
+TABDECL( OP_UND_THUMB), //10 1111 1110
+TABDECL( OP_UND_THUMB), //10 1111 1111
+
+TABDECL( OP_STMIA_THUMB), //11 0000 0000
+TABDECL( OP_STMIA_THUMB), //11 0000 0001
+TABDECL( OP_STMIA_THUMB), //11 0000 0010
+TABDECL( OP_STMIA_THUMB), //11 0000 0011
+TABDECL( OP_STMIA_THUMB), //11 0000 0100
+TABDECL( OP_STMIA_THUMB), //11 0000 0101
+TABDECL( OP_STMIA_THUMB), //11 0000 0110
+TABDECL( OP_STMIA_THUMB), //11 0000 0111
+TABDECL( OP_STMIA_THUMB), //11 0000 1000
+TABDECL( OP_STMIA_THUMB), //11 0000 1001
+TABDECL( OP_STMIA_THUMB), //11 0000 1010
+TABDECL( OP_STMIA_THUMB), //11 0000 1011
+TABDECL( OP_STMIA_THUMB), //11 0000 1100
+TABDECL( OP_STMIA_THUMB), //11 0000 1101
+TABDECL( OP_STMIA_THUMB), //11 0000 1110
+TABDECL( OP_STMIA_THUMB), //11 0000 1111
+
+TABDECL( OP_STMIA_THUMB), //11 0001 0000
+TABDECL( OP_STMIA_THUMB), //11 0001 0001
+TABDECL( OP_STMIA_THUMB), //11 0001 0010
+TABDECL( OP_STMIA_THUMB), //11 0001 0011
+TABDECL( OP_STMIA_THUMB), //11 0001 0100
+TABDECL( OP_STMIA_THUMB), //11 0001 0101
+TABDECL( OP_STMIA_THUMB), //11 0001 0110
+TABDECL( OP_STMIA_THUMB), //11 0001 0111
+TABDECL( OP_STMIA_THUMB), //11 0001 1000
+TABDECL( OP_STMIA_THUMB), //11 0001 1001
+TABDECL( OP_STMIA_THUMB), //11 0001 1010
+TABDECL( OP_STMIA_THUMB), //11 0001 1011
+TABDECL( OP_STMIA_THUMB), //11 0001 1100
+TABDECL( OP_STMIA_THUMB), //11 0001 1101
+TABDECL( OP_STMIA_THUMB), //11 0001 1110
+TABDECL( OP_STMIA_THUMB), //11 0001 1111
+
+TABDECL( OP_LDMIA_THUMB), //11 0010 0000
+TABDECL( OP_LDMIA_THUMB), //11 0010 0001
+TABDECL( OP_LDMIA_THUMB), //11 0010 0010
+TABDECL( OP_LDMIA_THUMB), //11 0010 0011
+TABDECL( OP_LDMIA_THUMB), //11 0010 0100
+TABDECL( OP_LDMIA_THUMB), //11 0010 0101
+TABDECL( OP_LDMIA_THUMB), //11 0010 0110
+TABDECL( OP_LDMIA_THUMB), //11 0010 0111
+TABDECL( OP_LDMIA_THUMB), //11 0010 1000
+TABDECL( OP_LDMIA_THUMB), //11 0010 1001
+TABDECL( OP_LDMIA_THUMB), //11 0010 1010
+TABDECL( OP_LDMIA_THUMB), //11 0010 1011
+TABDECL( OP_LDMIA_THUMB), //11 0010 1100
+TABDECL( OP_LDMIA_THUMB), //11 0010 1101
+TABDECL( OP_LDMIA_THUMB), //11 0010 1110
+TABDECL( OP_LDMIA_THUMB), //11 0010 1111
+
+TABDECL( OP_LDMIA_THUMB), //11 0011 0000
+TABDECL( OP_LDMIA_THUMB), //11 0011 0001
+TABDECL( OP_LDMIA_THUMB), //11 0011 0010
+TABDECL( OP_LDMIA_THUMB), //11 0011 0011
+TABDECL( OP_LDMIA_THUMB), //11 0011 0100
+TABDECL( OP_LDMIA_THUMB), //11 0011 0101
+TABDECL( OP_LDMIA_THUMB), //11 0011 0110
+TABDECL( OP_LDMIA_THUMB), //11 0011 0111
+TABDECL( OP_LDMIA_THUMB), //11 0011 1000
+TABDECL( OP_LDMIA_THUMB), //11 0011 1001
+TABDECL( OP_LDMIA_THUMB), //11 0011 1010
+TABDECL( OP_LDMIA_THUMB), //11 0011 1011
+TABDECL( OP_LDMIA_THUMB), //11 0011 1100
+TABDECL( OP_LDMIA_THUMB), //11 0011 1101
+TABDECL( OP_LDMIA_THUMB), //11 0011 1110
+TABDECL( OP_LDMIA_THUMB), //11 0011 1111
+
+TABDECL( OP_B_COND), //11 0100 0000
+TABDECL( OP_B_COND), //11 0100 0001
+TABDECL( OP_B_COND), //11 0100 0010
+TABDECL( OP_B_COND), //11 0100 0011
+TABDECL( OP_B_COND), //11 0100 0100
+TABDECL( OP_B_COND), //11 0100 0101
+TABDECL( OP_B_COND), //11 0100 0110
+TABDECL( OP_B_COND), //11 0100 0111
+TABDECL( OP_B_COND), //11 0100 1000
+TABDECL( OP_B_COND), //11 0100 1001
+TABDECL( OP_B_COND), //11 0100 1010
+TABDECL( OP_B_COND), //11 0100 1011
+TABDECL( OP_B_COND), //11 0100 1100
+TABDECL( OP_B_COND), //11 0100 1101
+TABDECL( OP_B_COND), //11 0100 1110
+TABDECL( OP_B_COND), //11 0100 1111
+
+TABDECL( OP_B_COND), //11 0101 0000
+TABDECL( OP_B_COND), //11 0101 0001
+TABDECL( OP_B_COND), //11 0101 0010
+TABDECL( OP_B_COND), //11 0101 0011
+TABDECL( OP_B_COND), //11 0101 0100
+TABDECL( OP_B_COND), //11 0101 0101
+TABDECL( OP_B_COND), //11 0101 0110
+TABDECL( OP_B_COND), //11 0101 0111
+TABDECL( OP_B_COND), //11 0101 1000
+TABDECL( OP_B_COND), //11 0101 1001
+TABDECL( OP_B_COND), //11 0101 1010
+TABDECL( OP_B_COND), //11 0101 1011
+TABDECL( OP_B_COND), //11 0101 1100
+TABDECL( OP_B_COND), //11 0101 1101
+TABDECL( OP_B_COND), //11 0101 1110
+TABDECL( OP_B_COND), //11 0101 1111
+
+TABDECL( OP_B_COND), //11 0110 0000
+TABDECL( OP_B_COND), //11 0110 0001
+TABDECL( OP_B_COND), //11 0110 0010
+TABDECL( OP_B_COND), //11 0110 0011
+TABDECL( OP_B_COND), //11 0110 0100
+TABDECL( OP_B_COND), //11 0110 0101
+TABDECL( OP_B_COND), //11 0110 0110
+TABDECL( OP_B_COND), //11 0110 0111
+TABDECL( OP_B_COND), //11 0110 1000
+TABDECL( OP_B_COND), //11 0110 1001
+TABDECL( OP_B_COND), //11 0110 1010
+TABDECL( OP_B_COND), //11 0110 1011
+TABDECL( OP_B_COND), //11 0110 1100
+TABDECL( OP_B_COND), //11 0110 1101
+TABDECL( OP_B_COND), //11 0110 1110
+TABDECL( OP_B_COND), //11 0110 1111
+
+TABDECL( OP_B_COND), //11 0111 0000
+TABDECL( OP_B_COND), //11 0111 0001
+TABDECL( OP_B_COND), //11 0111 0010
+TABDECL( OP_B_COND), //11 0111 0011
+TABDECL( OP_B_COND), //11 0111 0100
+TABDECL( OP_B_COND), //11 0111 0101
+TABDECL( OP_B_COND), //11 0111 0110
+TABDECL( OP_B_COND), //11 0111 0111
+TABDECL( OP_B_COND), //11 0111 1000
+TABDECL( OP_B_COND), //11 0111 1001
+TABDECL( OP_B_COND), //11 0111 1010
+TABDECL( OP_B_COND), //11 0111 1011
+TABDECL( OP_SWI_THUMB), //11 0111 1100
+TABDECL( OP_SWI_THUMB), //11 0111 1101
+TABDECL( OP_SWI_THUMB), //11 0111 1110
+TABDECL( OP_SWI_THUMB), //11 0111 1111
+
+TABDECL( OP_B_UNCOND), //11 1000 0000
+TABDECL( OP_B_UNCOND), //11 1000 0001
+TABDECL( OP_B_UNCOND), //11 1000 0010
+TABDECL( OP_B_UNCOND), //11 1000 0011
+TABDECL( OP_B_UNCOND), //11 1000 0100
+TABDECL( OP_B_UNCOND), //11 1000 0101
+TABDECL( OP_B_UNCOND), //11 1000 0110
+TABDECL( OP_B_UNCOND), //11 1000 0111
+TABDECL( OP_B_UNCOND), //11 1000 1000
+TABDECL( OP_B_UNCOND), //11 1000 1001
+TABDECL( OP_B_UNCOND), //11 1000 1010
+TABDECL( OP_B_UNCOND), //11 1000 1011
+TABDECL( OP_B_UNCOND), //11 1000 1100
+TABDECL( OP_B_UNCOND), //11 1000 1101
+TABDECL( OP_B_UNCOND), //11 1000 1110
+TABDECL( OP_B_UNCOND), //11 1000 1111
+
+TABDECL( OP_B_UNCOND), //11 1001 0000
+TABDECL( OP_B_UNCOND), //11 1001 0001
+TABDECL( OP_B_UNCOND), //11 1001 0010
+TABDECL( OP_B_UNCOND), //11 1001 0011
+TABDECL( OP_B_UNCOND), //11 1001 0100
+TABDECL( OP_B_UNCOND), //11 1001 0101
+TABDECL( OP_B_UNCOND), //11 1001 0110
+TABDECL( OP_B_UNCOND), //11 1001 0111
+TABDECL( OP_B_UNCOND), //11 1001 1000
+TABDECL( OP_B_UNCOND), //11 1001 1001
+TABDECL( OP_B_UNCOND), //11 1001 1010
+TABDECL( OP_B_UNCOND), //11 1001 1011
+TABDECL( OP_B_UNCOND), //11 1001 1100
+TABDECL( OP_B_UNCOND), //11 1001 1101
+TABDECL( OP_B_UNCOND), //11 1001 1110
+TABDECL( OP_B_UNCOND), //11 1001 1111
+
+TABDECL( OP_BLX), //11 1010 0000
+TABDECL( OP_BLX), //11 1010 0001
+TABDECL( OP_BLX), //11 1010 0010
+TABDECL( OP_BLX), //11 1010 0011
+TABDECL( OP_BLX), //11 1010 0100
+TABDECL( OP_BLX), //11 1010 0101
+TABDECL( OP_BLX), //11 1010 0110
+TABDECL( OP_BLX), //11 1010 0111
+TABDECL( OP_BLX), //11 1010 1000
+TABDECL( OP_BLX), //11 1010 1001
+TABDECL( OP_BLX), //11 1010 1010
+TABDECL( OP_BLX), //11 1010 1011
+TABDECL( OP_BLX), //11 1010 1100
+TABDECL( OP_BLX), //11 1010 1101
+TABDECL( OP_BLX), //11 1010 1110
+TABDECL( OP_BLX), //11 1010 1111
+
+TABDECL( OP_BLX), //11 1011 0000
+TABDECL( OP_BLX), //11 1011 0001
+TABDECL( OP_BLX), //11 1011 0010
+TABDECL( OP_BLX), //11 1011 0011
+TABDECL( OP_BLX), //11 1011 0100
+TABDECL( OP_BLX), //11 1011 0101
+TABDECL( OP_BLX), //11 1011 0110
+TABDECL( OP_BLX), //11 1011 0111
+TABDECL( OP_BLX), //11 1011 1000
+TABDECL( OP_BLX), //11 1011 1001
+TABDECL( OP_BLX), //11 1011 1010
+TABDECL( OP_BLX), //11 1011 1011
+TABDECL( OP_BLX), //11 1011 1100
+TABDECL( OP_BLX), //11 1011 1101
+TABDECL( OP_BLX), //11 1011 1110
+TABDECL( OP_BLX), //11 1011 1111
+
+TABDECL( OP_BL_10), //11 1100 0000
+TABDECL( OP_BL_10), //11 1100 0001
+TABDECL( OP_BL_10), //11 1100 0010
+TABDECL( OP_BL_10), //11 1100 0011
+TABDECL( OP_BL_10), //11 1100 0100
+TABDECL( OP_BL_10), //11 1100 0101
+TABDECL( OP_BL_10), //11 1100 0110
+TABDECL( OP_BL_10), //11 1100 0111
+TABDECL( OP_BL_10), //11 1100 1000
+TABDECL( OP_BL_10), //11 1100 1001
+TABDECL( OP_BL_10), //11 1100 1010
+TABDECL( OP_BL_10), //11 1100 1011
+TABDECL( OP_BL_10), //11 1100 1100
+TABDECL( OP_BL_10), //11 1100 1101
+TABDECL( OP_BL_10), //11 1100 1110
+TABDECL( OP_BL_10), //11 1100 1111
+
+TABDECL( OP_BL_10), //11 1101 0000
+TABDECL( OP_BL_10), //11 1101 0001
+TABDECL( OP_BL_10), //11 1101 0010
+TABDECL( OP_BL_10), //11 1101 0011
+TABDECL( OP_BL_10), //11 1101 0100
+TABDECL( OP_BL_10), //11 1101 0101
+TABDECL( OP_BL_10), //11 1101 0110
+TABDECL( OP_BL_10), //11 1101 0111
+TABDECL( OP_BL_10), //11 1101 1000
+TABDECL( OP_BL_10), //11 1101 1001
+TABDECL( OP_BL_10), //11 1101 1010
+TABDECL( OP_BL_10), //11 1101 1011
+TABDECL( OP_BL_10), //11 1101 1100
+TABDECL( OP_BL_10), //11 1101 1101
+TABDECL( OP_BL_10), //11 1101 1110
+TABDECL( OP_BL_10), //11 1101 1111
+
+TABDECL( OP_BL_11), //11 1110 0000
+TABDECL( OP_BL_11), //11 1110 0001
+TABDECL( OP_BL_11), //11 1110 0010
+TABDECL( OP_BL_11), //11 1110 0011
+TABDECL( OP_BL_11), //11 1110 0100
+TABDECL( OP_BL_11), //11 1110 0101
+TABDECL( OP_BL_11), //11 1110 0110
+TABDECL( OP_BL_11), //11 1110 0111
+TABDECL( OP_BL_11), //11 1110 1000
+TABDECL( OP_BL_11), //11 1110 1001
+TABDECL( OP_BL_11), //11 1110 1010
+TABDECL( OP_BL_11), //11 1110 1011
+TABDECL( OP_BL_11), //11 1110 1100
+TABDECL( OP_BL_11), //11 1110 1101
+TABDECL( OP_BL_11), //11 1110 1110
+TABDECL( OP_BL_11), //11 1110 1111
+
+TABDECL( OP_BL_11), //11 1111 0000
+TABDECL( OP_BL_11), //11 1111 0001
+TABDECL( OP_BL_11), //11 1111 0010
+TABDECL( OP_BL_11), //11 1111 0011
+TABDECL( OP_BL_11), //11 1111 0100
+TABDECL( OP_BL_11), //11 1111 0101
+TABDECL( OP_BL_11), //11 1111 0110
+TABDECL( OP_BL_11), //11 1111 0111
+TABDECL( OP_BL_11), //11 1111 1000
+TABDECL( OP_BL_11), //11 1111 1001
+TABDECL( OP_BL_11), //11 1111 1010
+TABDECL( OP_BL_11), //11 1111 1011
+TABDECL( OP_BL_11), //11 1111 1100
+TABDECL( OP_BL_11), //11 1111 1101
+TABDECL( OP_BL_11), //11 1111 1110
+TABDECL( OP_BL_11), //11 1111 1111
+
--- /dev/null
+++ b/src/in_2sf/desmume/types.h
@@ -1,1 +1,404 @@
-
+/*
+ Copyright (C) 2005 Guillaume Duhamel
+ Copyright (C) 2008-2011 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef TYPES_HPP
+#define TYPES_HPP
+
+#include "pstdint.h"
+
+//analyze microsoft compilers
+#ifdef _MSC_VER
+ //#define _WINDOWS
+ #ifdef _M_X64
+ //#define _WIN64 //already defined in x64 compiler
+ #else
+ //#define _WIN32 //already defined
+ #endif
+#endif
+
+//todo - everyone will want to support this eventually, i suppose
+#ifdef _WINDOWS
+//#include "config.h"
+#endif
+
+//enforce a constraint: gdb stub requires developer
+#if defined(GDB_STUB) && !defined(DEVELOPER)
+#define DEVELOPER
+#endif
+
+#ifdef DEVELOPER
+#define IF_DEVELOPER(X) X
+#else
+#define IF_DEVELOPER(X)
+#endif
+
+#ifdef _WINDOWS
+ //#define HAVE_WX //not useful yet....
+ #define HAVE_LIBAGG
+ #define ENABLE_SSE
+ #define ENABLE_SSE2
+ #ifdef DEVELOPER
+ #define HAVE_LUA
+ #endif
+#endif
+
+#ifdef __GNUC__
+#ifdef __SSE__
+#define ENABLE_SSE
+#endif
+#ifdef __SSE2__
+#define ENABLE_SSE2
+#endif
+#endif
+
+#ifdef NOSSE
+#undef ENABLE_SSE
+#endif
+
+#ifdef NOSSE2
+#undef ENABLE_SSE2
+#endif
+
+#ifdef _MSC_VER
+#define strcasecmp(x,y) _stricmp(x,y)
+#define strncasecmp(x, y, l) strnicmp(x, y, l)
+#define snprintf _snprintf
+#else
+//#define WINAPI
+#endif
+
+#ifndef MAX_PATH
+#ifdef __GNUC__
+#include <climits>
+#ifndef PATH_MAX
+#define MAX_PATH 1024
+#else
+#define MAX_PATH PATH_MAX
+#endif
+#endif
+#endif
+
+#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
+#define DS_ALIGN(X) __declspec(align(X))
+#elif defined(__GNUC__)
+#define DS_ALIGN(X) __attribute__ ((aligned (X)))
+#else
+#define DS_ALIGN(X)
+#endif
+
+#define CACHE_ALIGN DS_ALIGN(32)
+
+//use this for example when you want a byte value to be better-aligned
+#define FAST_ALIGN DS_ALIGN(4)
+
+#ifndef FASTCALL
+#ifdef __MINGW32__
+#define FASTCALL __attribute__((fastcall))
+#elif defined (__i386__) && !defined(__clang__)
+#define FASTCALL __attribute__((regparm(3)))
+#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
+#define FASTCALL
+#else
+#define FASTCALL
+#endif
+#endif
+
+/*---------- GPU3D fixed-points types -----------*/
+
+typedef int32_t f32;
+#define inttof32(n) ((n) << 12)
+#define f32toint(n) ((n) >> 12)
+#define floattof32(n) ((int32_t)((n) * (1 << 12)))
+#define f32tofloat(n) (((float)(n)) / (float)(1<<12))
+
+typedef int16_t t16;
+#define f32tot16(n) ((t16)(n >> 8))
+#define inttot16(n) ((n) << 4)
+#define t16toint(n) ((n) >> 4)
+#define floattot16(n) ((t16)((n) * (1 << 4)))
+#define t16ofloat(n) (((float)(n)) / (float)(1<<4))
+
+typedef int16_t v16;
+#define inttov16(n) ((n) << 12)
+#define f32tov16(n) (n)
+#define floattov16(n) ((v16)((n) * (1 << 12)))
+#define v16toint(n) ((n) >> 12)
+#define v16tofloat(n) (((float)(n)) / (float)(1<<12))
+
+typedef int16_t v10;
+#define inttov10(n) ((n) << 9)
+#define f32tov10(n) ((v10)(n >> 3))
+#define v10toint(n) ((n) >> 9)
+#define floattov10(n) ((v10)((n) * (1 << 9)))
+#define v10tofloat(n) (((float)(n)) / (float)(1<<9))
+
+/*----------------------*/
+
+#ifdef __BIG_ENDIAN__
+#ifndef WORDS_BIGENDIAN
+#define WORDS_BIGENDIAN
+#endif
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define LOCAL_BE
+#else
+# define LOCAL_LE
+#endif
+
+/* little endian (ds' endianess) to local endianess convert macros */
+#ifdef LOCAL_BE /* local arch is big endian */
+# define LE_TO_LOCAL_16(x) ((((x)&0xff)<<8)|(((x)>>8)&0xff))
+# define LE_TO_LOCAL_32(x) ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)>>8)&0xff00)|(((x)>>24)&0xff))
+# define LE_TO_LOCAL_64(x) ((((x)&0xff)<<56)|(((x)&0xff00)<<40)|(((x)&0xff0000)<<24)|(((x)&0xff000000)<<8)|(((x)>>8)&0xff000000)|(((x)>>24)&0xff00)|(((x)>>40)&0xff00)|(((x)>>56)&0xff))
+# define LOCAL_TO_LE_16(x) ((((x)&0xff)<<8)|(((x)>>8)&0xff))
+# define LOCAL_TO_LE_32(x) ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)>>8)&0xff00)|(((x)>>24)&0xff))
+# define LOCAL_TO_LE_64(x) ((((x)&0xff)<<56)|(((x)&0xff00)<<40)|(((x)&0xff0000)<<24)|(((x)&0xff000000)<<8)|(((x)>>8)&0xff000000)|(((x)>>24)&0xff00)|(((x)>>40)&0xff00)|(((x)>>56)&0xff))
+#else /* local arch is little endian */
+# define LE_TO_LOCAL_16(x) (x)
+# define LE_TO_LOCAL_32(x) (x)
+# define LE_TO_LOCAL_64(x) (x)
+# define LOCAL_TO_LE_16(x) (x)
+# define LOCAL_TO_LE_32(x) (x)
+# define LOCAL_TO_LE_64(x) (x)
+#endif
+
+// kilobytes and megabytes macro
+#define MB(x) ((x)*1024*1024)
+#define KB(x) ((x)*1024)
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define CPU_STR(c) ((c==ARM9)?"ARM9":"ARM7")
+typedef enum
+{
+ ARM9 = 0,
+ ARM7 = 1
+} cpu_id_t;
+
+///endian-flips count bytes. count should be even and nonzero.
+inline void FlipByteOrder(uint8_t *src, uint32_t count)
+{
+ uint8_t *start=src;
+ uint8_t *end=src+count-1;
+
+ if((count&1) || !count) return; /* This shouldn't happen. */
+
+ while(count--)
+ {
+ uint8_t tmp;
+
+ tmp=*end;
+ *end=*start;
+ *start=tmp;
+ end--;
+ start++;
+ }
+}
+
+
+
+inline uint64_t double_to_u64(double d) {
+ union {
+ uint64_t a;
+ double b;
+ } fuxor;
+ fuxor.b = d;
+ return fuxor.a;
+}
+
+inline double u64_to_double(uint64_t u) {
+ union {
+ uint64_t a;
+ double b;
+ } fuxor;
+ fuxor.a = u;
+ return fuxor.b;
+}
+
+/*inline uint32_t float_to_u32(float f) {
+ union {
+ uint32_t a;
+ float b;
+ } fuxor;
+ fuxor.b = f;
+ return fuxor.a;
+}*/
+
+/*inline float u32_to_float(uint32_t u) {
+ union {
+ uint32_t a;
+ float b;
+ } fuxor;
+ fuxor.a = u;
+ return fuxor.b;
+}*/
+
+
+///stores a 32bit value into the provided byte array in guaranteed little endian form
+/*inline void en32lsb(uint8_t *buf, uint32_t morp)
+{
+ buf[0]=(uint8_t)(morp);
+ buf[1]=(uint8_t)(morp>>8);
+ buf[2]=(uint8_t)(morp>>16);
+ buf[3]=(uint8_t)(morp>>24);
+}*/
+
+/*inline void en16lsb(uint8_t* buf, uint16_t morp)
+{
+ buf[0]=(uint8_t)morp;
+ buf[1]=(uint8_t)(morp>>8);
+}*/
+
+///unpacks a 64bit little endian value from the provided byte array into host byte order
+/*inline uint64_t de64lsb(uint8_t *morp)
+{
+ return morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24)|((uint64_t)morp[4]<<32)|((uint64_t)morp[5]<<40)|((uint64_t)morp[6]<<48)|((uint64_t)morp[7]<<56);
+}*/
+
+///unpacks a 32bit little endian value from the provided byte array into host byte order
+/*inline uint32_t de32lsb(uint8_t *morp)
+{
+ return morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24);
+}*/
+
+///unpacks a 16bit little endian value from the provided byte array into host byte order
+/*inline uint16_t de16lsb(uint8_t *morp)
+{
+ return morp[0]|(morp[1]<<8);
+}*/
+
+#ifndef ARRAY_SIZE
+//taken from winnt.h
+extern "C++" // templates cannot be declared to have 'C' linkage
+template <typename T, size_t N>
+char (*BLAHBLAHBLAH( UNALIGNED T (&)[N] ))[N];
+
+#define ARRAY_SIZE(A) (sizeof(*BLAHBLAHBLAH(A)))
+#endif
+
+
+//fairly standard for loop macros
+#define MACRODO1(TRICK,TODO) { const int X = TRICK; TODO; }
+#define MACRODO2(X,TODO) { MACRODO1((X),TODO) MACRODO1(((X)+1),TODO) }
+#define MACRODO4(X,TODO) { MACRODO2((X),TODO) MACRODO2(((X)+2),TODO) }
+#define MACRODO8(X,TODO) { MACRODO4((X),TODO) MACRODO4(((X)+4),TODO) }
+#define MACRODO16(X,TODO) { MACRODO8((X),TODO) MACRODO8(((X)+8),TODO) }
+#define MACRODO32(X,TODO) { MACRODO16((X),TODO) MACRODO16(((X)+16),TODO) }
+#define MACRODO64(X,TODO) { MACRODO32((X),TODO) MACRODO32(((X)+32),TODO) }
+#define MACRODO128(X,TODO) { MACRODO64((X),TODO) MACRODO64(((X)+64),TODO) }
+#define MACRODO256(X,TODO) { MACRODO128((X),TODO) MACRODO128(((X)+128),TODO) }
+
+//this one lets you loop any number of times (as long as N<256)
+#define MACRODO_N(N,TODO) {\
+ if((N)&0x100) MACRODO256(0,TODO); \
+ if((N)&0x080) MACRODO128((N)&(0x100),TODO); \
+ if((N)&0x040) MACRODO64((N)&(0x100|0x080),TODO); \
+ if((N)&0x020) MACRODO32((N)&(0x100|0x080|0x040),TODO); \
+ if((N)&0x010) MACRODO16((N)&(0x100|0x080|0x040|0x020),TODO); \
+ if((N)&0x008) MACRODO8((N)&(0x100|0x080|0x040|0x020|0x010),TODO); \
+ if((N)&0x004) MACRODO4((N)&(0x100|0x080|0x040|0x020|0x010|0x008),TODO); \
+ if((N)&0x002) MACRODO2((N)&(0x100|0x080|0x040|0x020|0x010|0x008|0x004),TODO); \
+ if((N)&0x001) MACRODO1((N)&(0x100|0x080|0x040|0x020|0x010|0x008|0x004|0x002),TODO); \
+}
+
+//---------------------------
+//Binary constant generator macro By Tom Torfs - donated to the public domain
+
+//turn a numeric literal into a hex constant
+//(avoids problems with leading zeroes)
+//8-bit constants max value 0x11111111, always fits in unsigned long
+#define HEX__(n) 0x##n##LU
+
+//8-bit conversion function
+#define B8__(x) ((x&0x0000000FLU)?1:0) \
++((x&0x000000F0LU)?2:0) \
++((x&0x00000F00LU)?4:0) \
++((x&0x0000F000LU)?8:0) \
++((x&0x000F0000LU)?16:0) \
++((x&0x00F00000LU)?32:0) \
++((x&0x0F000000LU)?64:0) \
++((x&0xF0000000LU)?128:0)
+
+//for upto 8-bit binary constants
+#define B8(d) ((unsigned char)B8__(HEX__(d)))
+
+// for upto 16-bit binary constants, MSB first
+#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) \
++ B8(dlsb))
+
+// for upto 32-bit binary constants, MSB first */
+#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \
++ ((unsigned long)B8(db2)<<16) \
++ ((unsigned long)B8(db3)<<8) \
++ B8(dlsb))
+
+//Sample usage:
+//B8(01010101) = 85
+//B16(10101010,01010101) = 43605
+//B32(10000000,11111111,10101010,01010101) = 2164238933
+//---------------------------
+
+#ifndef CTASSERT
+#define CTASSERT(x) typedef char __assert ## y[(x) ? 1 : -1]
+#endif
+
+//static const char hexValid[23] = {"0123456789ABCDEFabcdef"};
+
+
+template<typename T> inline void reconstruct(T* t) {
+ t->~T();
+ new(t) T();
+}
+
+//-------------fixed point speedup macros
+
+/*#if defined(_WIN32) && !defined(__MINGW32__)
+#define WIN32_LEAN_AND_MEAN
+#include <intrin.h>
+#endif*/
+
+/*inline int64_t fx32_mul(const int32_t a, const int32_t b)
+{
+#if defined(_WIN32) && !defined(__MINGW32__)
+ return __emul(a,b);
+#else
+ return ((int64_t)a)*((int64_t)b);
+#endif
+}*/
+
+/*inline int32_t fx32_shiftdown(const int64_t a)
+{
+#if defined(_WIN32) && !defined(__MINGW32__)
+ return (int32_t)__ll_rshift(a,12);
+#else
+ return (int32_t)(a>>12);
+#endif
+}*/
+
+/*inline int64_t fx32_shiftup(const int32_t a)
+{
+#if defined(_WIN32) && !defined(__MINGW32__)
+ return __ll_lshift(a,12);
+#else
+ return ((int64_t)a)<<12;
+#endif
+}*/
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/utils/dlditool.cpp
@@ -1,1 +1,750 @@
-
+/*
+ dlditool - Dynamically Linked Disk Interface patch tool
+ Copyright (C) 2006 Michael Chisholm (Chishm)
+
+ Send all queries to chishm@hotmail.com
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ * v1.24d - 2010-06-14 - zeromus
+ * Modified for inclusion in desmume
+
+ * v1.24 - 2007-08-02 - SmileyDude
+ * Now using EXIT_SUCCESS and EXIT_FAILURE at the suggestion of MachinShin.
+ * Defined EXIT_NO_DLDI_SECTION for when there is no DLDI section in a file.
+ * Added cast to strcmp() call to appease the compiler.
+
+ * v1.23 - 2007-01-23 - Chishm
+ * Fixed bug when DLDI section doesn't exist
+ * addr_t is now a signed int
+
+ * v1.22 - 2007-01-12 - WinterMute
+ * add search paths for dldi files
+
+ * v1.21 - 2007-01-12 - Chishm
+ * Improved error messages
+
+ * v1.20 - 2007-01-11 - Chishm
+ * Changed offset calculation method
+
+ * v1.10 - 2007-01-07 - Chishm
+ * Removed assumptions about endianess of computer
+ * Word size shouldn't matter now either, except that an int type must be at least 32 bits long
+ * Added *.sc.nds and *.gba.nds file extensions
+ * Improved command line argument parsing
+
+ * v1.01 - 2006-12-30 - Chishm
+ * Minor bugfix parsing 3 arguments
+
+ * v1.00 - 2006-12-25 - Chishm
+ * Original release
+*/
+//#define VERSION "v1.24"
+
+#include <cstdio>
+#include <cstring>
+#include <cctype>
+#include <cerrno>
+#include <cstdlib>
+#include <cstdarg>
+
+#include "pstdint.h"
+#ifndef _MSC_VER
+//#include <stdint.h>
+#include <unistd.h>
+#include <sys/param.h>
+#else
+//typedef int int32_t;
+#define MAXPATHLEN 1024
+#endif
+
+#include <sys/stat.h>
+
+namespace DLDI
+{
+
+//#ifndef bool
+// typedef enum {false = 0, true = !0} bool;
+//#endif
+
+typedef int32_t addr_t;
+typedef unsigned char data_t;
+
+#define FEATURE_MEDIUM_CANREAD 0x00000001
+#define FEATURE_MEDIUM_CANWRITE 0x00000002
+#define FEATURE_SLOT_GBA 0x00000010
+#define FEATURE_SLOT_NDS 0x00000020
+
+#define MAGIC_TOKEN 0xBF8DA5ED
+
+#define FIX_ALL 0x01
+#define FIX_GLUE 0x02
+#define FIX_GOT 0x04
+#define FIX_BSS 0x08
+
+#define DLDI_VERSION 1
+
+#define EXIT_NO_DLDI_SECTION 2
+
+enum DldiOffsets {
+ DO_magicString = 0x00, // "\xED\xA5\x8D\xBF Chishm"
+ DO_magicToken = 0x00, // 0xBF8DA5ED
+ DO_magicShortString = 0x04, // " Chishm"
+ DO_version = 0x0C,
+ DO_driverSize = 0x0D,
+ DO_fixSections = 0x0E,
+ DO_allocatedSpace = 0x0F,
+
+ DO_friendlyName = 0x10,
+
+ DO_text_start = 0x40, // Data start
+ DO_data_end = 0x44, // Data end
+ DO_glue_start = 0x48, // Interworking glue start -- Needs address fixing
+ DO_glue_end = 0x4C, // Interworking glue end
+ DO_got_start = 0x50, // GOT start -- Needs address fixing
+ DO_got_end = 0x54, // GOT end
+ DO_bss_start = 0x58, // bss start -- Needs setting to zero
+ DO_bss_end = 0x5C, // bss end
+
+ // IO_INTERFACE data
+ DO_ioType = 0x60,
+ DO_features = 0x64,
+ DO_startup = 0x68,
+ DO_isInserted = 0x6C,
+ DO_readSectors = 0x70,
+ DO_writeSectors = 0x74,
+ DO_clearStatus = 0x78,
+ DO_shutdown = 0x7C,
+ DO_code = 0x80
+};
+
+const data_t dldiMagicString[] = "\xED\xA5\x8D\xBF Chishm";
+const char dldiFileExtension[] = ".dldi";
+
+
+void printUsage (char* programName) {
+ printf ("Usage:\n");
+ printf ("%s <dldi> <app>\n", programName);
+ printf (" <dldi> the dldi patch file to apply\n");
+ printf (" <app> the application binary to apply the patch to\n");
+ return;
+}
+
+addr_t readAddr (data_t *mem, addr_t offset) {
+ return (addr_t)(
+ (mem[offset + 0] << 0) |
+ (mem[offset + 1] << 8) |
+ (mem[offset + 2] << 16) |
+ (mem[offset + 3] << 24)
+ );
+}
+
+void writeAddr (data_t *mem, addr_t offset, addr_t value) {
+ mem[offset + 0] = (data_t)(value >> 0);
+ mem[offset + 1] = (data_t)(value >> 8);
+ mem[offset + 2] = (data_t)(value >> 16);
+ mem[offset + 3] = (data_t)(value >> 24);
+}
+
+int stringCaseInsensitiveCompare (const char *str1, const char *str2) {
+ while (tolower(*str1) == tolower(*str2)) {
+ if (*str1 == '\0') {
+ return 0;
+ }
+ str1++;
+ str2++;
+ }
+ return tolower(*str1) - tolower(*str2);
+}
+
+bool stringEndsWith (const char *str, const char *end) {
+ const char* strEnd;
+ if (strlen (str) < strlen(end)) {
+ return false;
+ }
+ strEnd = &str[strlen (str) - strlen(end)];
+ return stringCaseInsensitiveCompare (strEnd, end) == 0;
+}
+
+bool stringStartsWith (const char *str, const char *start) {
+ return strstr (str, start) == str;
+}
+
+addr_t quickFind (const data_t* data, const data_t* search, size_t dataLen, size_t searchLen) {
+ const int32_t* dataChunk = (const int32_t*) data;
+ int searchChunk = ((const int32_t*)search)[0];
+ addr_t i;
+ addr_t dataChunkEnd = (addr_t)(dataLen / sizeof(int32_t));
+
+ for ( i = 0; i < dataChunkEnd; i++) {
+ if (dataChunk[i] == searchChunk) {
+ if ((i*sizeof(int32_t) + searchLen) > dataLen) {
+ return -1;
+ }
+ if (memcmp (&data[i*sizeof(int32_t)], search, searchLen) == 0) {
+ return i*sizeof(int32_t);
+ }
+ }
+ }
+
+ return -1;
+}
+
+FILE *openDLDIFile(const char *argv0, char *dldiFileName ) {
+
+
+ FILE *dldiFile;
+ char *dldiPATH;
+ char appPath[MAXPATHLEN];
+ char appName[MAXPATHLEN];
+ char appPathName[MAXPATHLEN];
+
+ char *ptr, *lastSlash;
+ struct stat buf;
+
+ // add .dldi extension to filename
+ if (!stringEndsWith (dldiFileName, dldiFileExtension)) {
+ strcat (dldiFileName, dldiFileExtension);
+ }
+
+ printf ("Trying \"%s\"\n", dldiFileName);
+ // try opening from current directory
+ dldiFile = fopen(dldiFileName,"rb");
+
+ if ( NULL != dldiFile ) return dldiFile;
+
+ // check if the filename has a path component
+ // check both slash varieties, win32 understands both
+ // if we have a directory separator don't bother with search paths
+ if ( NULL != strstr(dldiFileName,"\\") ) return NULL;
+ if ( NULL != strstr(dldiFileName,"/") ) return NULL;
+
+ // check for DLDIPATH in environment
+ dldiPATH = getenv("DLDIPATH");
+
+
+ if ( NULL != dldiPATH ) {
+ strcpy(appPath,dldiPATH);
+ if ( appPath[strlen(appPath)] != '\\' && appPath[strlen(appPath)] != '/' )
+ strcat(appPath,"/");
+ strcat ( appPath, dldiFileName );
+
+ printf ("Trying \"%s\"\n", appPath);
+ dldiFile = fopen(appPath,"rb");
+
+ if ( NULL != dldiFile ) return dldiFile;
+
+ }
+
+
+ lastSlash = NULL;
+ ptr = const_cast<char *>(argv0);
+
+ while ( *(ptr++) != 0 ) {
+ if ( *ptr == '\\' || * ptr == '/' )
+ lastSlash = ptr;
+ }
+
+ if ( NULL != lastSlash ) {
+ *(lastSlash++) = '\0';
+ strcpy(appPath, argv0);
+ strcpy(appName, lastSlash);
+ strcat(appPath, "/");
+ } else {
+ strcpy(appPath, "");
+ strcpy(appName, argv0);
+ }
+
+
+ // finally try in the application path
+ // if argv0 contains a directory separator we have a path component
+
+ if ( NULL == strstr(appPath,"\\") && NULL == strstr(appPath,"/") ) {
+
+ // no path in argv0 so search system path
+ char *sysPATH = getenv("PATH");
+ char *nextPATH;
+ char *thisPATH = sysPATH;
+ printf("Searching system path\n%s\n",sysPATH);
+
+ while(1) {
+ nextPATH = strstr(thisPATH, ":" ); // find next PATH separator
+
+ if ( NULL != nextPATH )
+ *(nextPATH++) = '\0'; // terminate string, point to next component
+
+ strcpy(appPath,thisPATH);
+ strcat(appPath,"/");
+ strcpy(appPathName,appPath);
+ strcat(appPathName,appName); // add application name
+
+ if ( stat(appPathName,&buf) == 0 ) // if it exists we found the path
+ break;
+
+ thisPATH = nextPATH;
+ strcpy(appPath,""); // empty path
+ if ( thisPATH == NULL) break;
+ }
+ }
+
+ strcat(appPath,"dldi/"); // add dldi folder
+ strcat(appPath,dldiFileName); // add dldi filename to path
+ printf ("Trying \"%s\"\n", appPath);
+
+ return fopen(appPath,"rb"); // no more places to check, just return this handle
+}
+
+//int main(int argc, char* argv[])
+//{
+//
+// char *dldiFileName = NULL;
+// char *appFileName = NULL;
+//
+// addr_t memOffset; // Offset of DLDI after the file is loaded into memory
+// addr_t patchOffset; // Position of patch destination in the file
+// addr_t relocationOffset; // Value added to all offsets within the patch to fix it properly
+// addr_t ddmemOffset; // Original offset used in the DLDI file
+// addr_t ddmemStart; // Start of range that offsets can be in the DLDI file
+// addr_t ddmemEnd; // End of range that offsets can be in the DLDI file
+// addr_t ddmemSize; // Size of range that offsets can be in the DLDI file
+//
+// addr_t addrIter;
+//
+// FILE* dldiFile;
+// FILE* appFile;
+//
+// data_t *pDH;
+// data_t *pAH;
+//
+// data_t *appFileData = NULL;
+// size_t appFileSize = 0;
+// data_t *dldiFileData = NULL;
+// size_t dldiFileSize = 0;
+//
+// int i;
+//
+// printf ("Dynamically Linked Disk Interface patch tool " VERSION " by Michael Chisholm (Chishm)\n\n");
+//
+// for (i = 1; i < argc; i++) {
+// if (dldiFileName == NULL) {
+// dldiFileName = (char*) malloc (strlen (argv[i]) + 1 + sizeof(dldiFileExtension));
+// if (!dldiFileName) {
+// return EXIT_FAILURE;
+// }
+// strcpy (dldiFileName, argv[i]);
+// } else if (appFileName == NULL) {
+// appFileName = (char*) malloc (strlen (argv[i]) + 1);
+// if (!appFileName) {
+// return EXIT_FAILURE;
+// }
+// strcpy (appFileName, argv[i]);
+// } else {
+// printUsage (argv[0]);
+// return EXIT_FAILURE;
+// }
+// }
+//
+// if ((dldiFileName == NULL) || (appFileName == NULL)) {
+// printUsage (argv[0]);
+// return EXIT_FAILURE;
+// }
+//
+// if (!(dldiFile = openDLDIFile(argv[0],dldiFileName))) {
+// printf ("Cannot open \"%s\" - %s\n", dldiFileName, strerror(errno));
+// return EXIT_FAILURE;
+// }
+//
+// if (!(appFile = fopen (appFileName, "rb+"))) {
+// printf ("Cannot open \"%s\" - %s\n", appFileName, strerror(errno));
+// return EXIT_FAILURE;
+// }
+//
+// // Load the app file and the DLDI patch file
+// fseek (appFile, 0, SEEK_END);
+// appFileSize = ftell(appFile);
+// appFileData = (data_t*) malloc (appFileSize);
+// fseek (appFile, 0, SEEK_SET);
+//
+// fseek (dldiFile, 0, SEEK_END);
+// dldiFileSize = ftell(dldiFile);
+// dldiFileData = (data_t*) malloc (dldiFileSize);
+// fseek (dldiFile, 0, SEEK_SET);
+//
+// if (!appFileData || !dldiFileData) {
+// fclose (appFile);
+// fclose (dldiFile);
+// if (appFileData) free (appFileData);
+// if (dldiFileData) free (dldiFileData);
+// printf ("Out of memory\n");
+// return EXIT_FAILURE;
+// }
+//
+// fread (appFileData, 1, appFileSize, appFile);
+// fread (dldiFileData, 1, dldiFileSize, dldiFile);
+// fclose (dldiFile);
+//
+// // Find the DSDI reserved space in the file
+// patchOffset = quickFind (appFileData, dldiMagicString, appFileSize, sizeof(dldiMagicString)/sizeof(char));
+//
+// if (patchOffset < 0) {
+// printf ("%s does not have a DLDI section\n", appFileName);
+// return EXIT_NO_DLDI_SECTION;
+// }
+//
+// pDH = dldiFileData;
+// pAH = &appFileData[patchOffset];
+//
+// // Make sure the DLDI file is valid and usable
+// if (strcmp ((char*)dldiMagicString, (char*)&pDH[DO_magicString]) != 0) {
+// printf ("Invalid DLDI file\n");
+// return EXIT_FAILURE;
+// }
+// if (pDH[DO_version] != DLDI_VERSION) {
+// printf ("Incorrect DLDI file version. Expected %d, found %d.\n", DLDI_VERSION, pDH[DO_version]);
+// return EXIT_FAILURE;
+// }
+// if (pDH[DO_driverSize] > pAH[DO_allocatedSpace]) {
+// printf ("Not enough space for patch. Available %d bytes, need %d bytes\n", ( 1 << pAH[DO_allocatedSpace]), ( 1 << pDH[DO_driverSize]) );
+// return EXIT_FAILURE;
+// }
+//
+// memOffset = readAddr (pAH, DO_text_start);
+// if (memOffset == 0) {
+// memOffset = readAddr (pAH, DO_startup) - DO_code;
+// }
+// ddmemOffset = readAddr (pDH, DO_text_start);
+// relocationOffset = memOffset - ddmemOffset;
+//
+// printf ("Old driver: %s\n", &pAH[DO_friendlyName]);
+// printf ("New driver: %s\n", &pDH[DO_friendlyName]);
+// printf ("\n");
+// printf ("Position in file: 0x%08X\n", patchOffset);
+// printf ("Position in memory: 0x%08X\n", memOffset);
+// printf ("Patch base address: 0x%08X\n", ddmemOffset);
+// printf ("Relocation offset: 0x%08X\n", relocationOffset);
+// printf ("\n");
+//
+// ddmemStart = readAddr (pDH, DO_text_start);
+// ddmemSize = (1 << pDH[DO_driverSize]);
+// ddmemEnd = ddmemStart + ddmemSize;
+//
+// // Remember how much space is actually reserved
+// pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace];
+// // Copy the DLDI patch into the application
+// memcpy (pAH, pDH, dldiFileSize);
+//
+// // Fix the section pointers in the header
+// writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset);
+// writeAddr (pAH, DO_data_end, readAddr (pAH, DO_data_end) + relocationOffset);
+// writeAddr (pAH, DO_glue_start, readAddr (pAH, DO_glue_start) + relocationOffset);
+// writeAddr (pAH, DO_glue_end, readAddr (pAH, DO_glue_end) + relocationOffset);
+// writeAddr (pAH, DO_got_start, readAddr (pAH, DO_got_start) + relocationOffset);
+// writeAddr (pAH, DO_got_end, readAddr (pAH, DO_got_end) + relocationOffset);
+// writeAddr (pAH, DO_bss_start, readAddr (pAH, DO_bss_start) + relocationOffset);
+// writeAddr (pAH, DO_bss_end, readAddr (pAH, DO_bss_end) + relocationOffset);
+// // Fix the function pointers in the header
+// writeAddr (pAH, DO_startup, readAddr (pAH, DO_startup) + relocationOffset);
+// writeAddr (pAH, DO_isInserted, readAddr (pAH, DO_isInserted) + relocationOffset);
+// writeAddr (pAH, DO_readSectors, readAddr (pAH, DO_readSectors) + relocationOffset);
+// writeAddr (pAH, DO_writeSectors, readAddr (pAH, DO_writeSectors) + relocationOffset);
+// writeAddr (pAH, DO_clearStatus, readAddr (pAH, DO_clearStatus) + relocationOffset);
+// writeAddr (pAH, DO_shutdown, readAddr (pAH, DO_shutdown) + relocationOffset);
+//
+// if (pDH[DO_fixSections] & FIX_ALL) {
+// // Search through and fix pointers within the data section of the file
+// for (addrIter = (readAddr(pDH, DO_text_start) - ddmemStart); addrIter < (readAddr(pDH, DO_data_end) - ddmemStart); addrIter++) {
+// if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
+// writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
+// }
+// }
+// }
+//
+// if (pDH[DO_fixSections] & FIX_GLUE) {
+// // Search through and fix pointers within the glue section of the file
+// for (addrIter = (readAddr(pDH, DO_glue_start) - ddmemStart); addrIter < (readAddr(pDH, DO_glue_end) - ddmemStart); addrIter++) {
+// if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
+// writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
+// }
+// }
+// }
+//
+// if (pDH[DO_fixSections] & FIX_GOT) {
+// // Search through and fix pointers within the Global Offset Table section of the file
+// for (addrIter = (readAddr(pDH, DO_got_start) - ddmemStart); addrIter < (readAddr(pDH, DO_got_end) - ddmemStart); addrIter++) {
+// if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
+// writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
+// }
+// }
+// }
+//
+// if (pDH[DO_fixSections] & FIX_BSS) {
+// // Initialise the BSS to 0
+// memset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start));
+// }
+//
+// // Write the patch back to the file
+// fseek (appFile, patchOffset, SEEK_SET);
+// fwrite (pAH, 1, ddmemSize, appFile);
+// fclose (appFile);
+//
+// free (appFileData);
+// free (dldiFileData);
+//
+// printf ("Patched successfully\n");
+//
+// return EXIT_SUCCESS;
+//}
+
+// Source File: mpcf.dldi
+// Time: 6/14/2010 9:38 PM
+// Orig. Offset: 0 / 0x00000000
+// Length: 1876 / 0x00000754 (bytes)
+data_t mpcf_dldi[1876] =
+{
+ 0xED, 0xA5, 0x8D, 0xBF, 0x20, 0x43, 0x68, 0x69, 0x73, 0x68, 0x6D, 0x00, 0x01, 0x0B, 0x0C, 0x00,
+ 0x47, 0x42, 0x41, 0x20, 0x4D, 0x6F, 0x76, 0x69, 0x65, 0x20, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72,
+ 0x20, 0x28, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x20, 0x46, 0x6C, 0x61, 0x73, 0x68, 0x29,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xBF, 0x54, 0x07, 0x80, 0xBF, 0x98, 0x00, 0x80, 0xBF, 0x98, 0x00, 0x80, 0xBF,
+ 0x50, 0x07, 0x80, 0xBF, 0x50, 0x07, 0x80, 0xBF, 0x54, 0x07, 0x80, 0xBF, 0x70, 0x07, 0x80, 0xBF,
+ 0x4D, 0x50, 0x43, 0x46, 0x13, 0x00, 0x00, 0x00, 0x3C, 0x01, 0x80, 0xBF, 0x98, 0x01, 0x80, 0xBF,
+ 0x78, 0x02, 0x80, 0xBF, 0xC8, 0x04, 0x80, 0xBF, 0xC8, 0x01, 0x80, 0xBF, 0x10, 0x07, 0x80, 0xBF,
+ 0x0D, 0xC0, 0xA0, 0xE1, 0xF8, 0xDF, 0x2D, 0xE9, 0x04, 0xB0, 0x4C, 0xE2, 0x28, 0xD0, 0x4B, 0xE2,
+ 0xF0, 0x6F, 0x9D, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 0x10, 0x40, 0x2D, 0xE9, 0x2C, 0x40, 0x9F, 0xE5,
+ 0x00, 0x30, 0xD4, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0x24, 0x20, 0x9F, 0xE5, 0x05, 0x00, 0x00, 0x1A,
+ 0x00, 0x00, 0x52, 0xE3, 0x1C, 0x00, 0x9F, 0xE5, 0x0F, 0xE0, 0xA0, 0x11, 0x12, 0xFF, 0x2F, 0x11,
+ 0x01, 0x30, 0xA0, 0xE3, 0x00, 0x30, 0xC4, 0xE5, 0x10, 0x40, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1,
+ 0x54, 0x07, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x48, 0x07, 0x80, 0xBF, 0x04, 0xE0, 0x2D, 0xE5,
+ 0x40, 0x30, 0x9F, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0x04, 0xD0, 0x4D, 0xE2, 0x38, 0x00, 0x9F, 0xE5,
+ 0x38, 0x10, 0x9F, 0xE5, 0x0F, 0xE0, 0xA0, 0x11, 0x13, 0xFF, 0x2F, 0x11, 0x30, 0x00, 0x9F, 0xE5,
+ 0x00, 0x30, 0x90, 0xE5, 0x00, 0x00, 0x53, 0xE3, 0x28, 0x30, 0x9F, 0xE5, 0x02, 0x00, 0x00, 0x0A,
+ 0x00, 0x00, 0x53, 0xE3, 0x0F, 0xE0, 0xA0, 0x11, 0x13, 0xFF, 0x2F, 0x11, 0x04, 0xD0, 0x8D, 0xE2,
+ 0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x48, 0x07, 0x80, 0xBF,
+ 0x58, 0x07, 0x80, 0xBF, 0x4C, 0x07, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x09, 0x14, 0xA0, 0xE3,
+ 0x06, 0x18, 0x81, 0xE2, 0xB0, 0x30, 0xD1, 0xE1, 0x03, 0x30, 0xE0, 0xE1, 0x03, 0x38, 0xA0, 0xE1,
+ 0x23, 0x38, 0xA0, 0xE1, 0xFF, 0x30, 0x03, 0xE2, 0xB0, 0x30, 0xC1, 0xE1, 0xB0, 0x20, 0xD1, 0xE1,
+ 0x04, 0xE0, 0x2D, 0xE5, 0xAA, 0xCC, 0xA0, 0xE3, 0x55, 0xEC, 0xE0, 0xE3, 0x03, 0x00, 0x52, 0xE1,
+ 0xAA, 0xE0, 0x4E, 0xE2, 0x55, 0xC0, 0x8C, 0xE2, 0x00, 0x00, 0xA0, 0xE3, 0x03, 0x00, 0x00, 0x1A,
+ 0xB0, 0xE0, 0xC1, 0xE1, 0xB0, 0x30, 0xD1, 0xE1, 0x0C, 0x00, 0x53, 0xE0, 0x01, 0x00, 0xA0, 0x13,
+ 0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x26, 0x35, 0xA0, 0xE3, 0x03, 0x37, 0x83, 0xE2,
+ 0x50, 0x20, 0xA0, 0xE3, 0xB0, 0x20, 0xC3, 0xE1, 0xB0, 0x00, 0xD3, 0xE1, 0x00, 0x08, 0xA0, 0xE1,
+ 0x20, 0x08, 0xA0, 0xE1, 0xFF, 0x00, 0x00, 0xE2, 0x50, 0x00, 0x50, 0xE3, 0x00, 0x00, 0xA0, 0x13,
+ 0x01, 0x00, 0xA0, 0x03, 0x1E, 0xFF, 0x2F, 0xE1, 0x09, 0x34, 0xA0, 0xE3, 0x0E, 0x38, 0x83, 0xE2,
+ 0xB0, 0x20, 0xD3, 0xE1, 0x80, 0x00, 0x12, 0xE3, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0xA0, 0xE3,
+ 0x01, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x50, 0xE1, 0x08, 0x00, 0x00, 0x0A, 0x09, 0x34, 0xA0, 0xE3,
+ 0x0E, 0x38, 0x83, 0xE2, 0xB0, 0x20, 0xD3, 0xE1, 0x26, 0x17, 0xA0, 0xE3, 0x96, 0x1C, 0x81, 0xE2,
+ 0x80, 0x00, 0x12, 0xE3, 0x01, 0x00, 0x80, 0xE2, 0x80, 0x10, 0x81, 0xE2, 0xF4, 0xFF, 0xFF, 0x1A,
+ 0x26, 0x15, 0xA0, 0xE3, 0x03, 0x17, 0x81, 0xE2, 0xB0, 0x30, 0xD1, 0xE1, 0x50, 0x30, 0x13, 0xE2,
+ 0x01, 0x00, 0xA0, 0x13, 0x1E, 0xFF, 0x2F, 0x11, 0x26, 0x27, 0xA0, 0xE3, 0x96, 0x2C, 0x82, 0xE2,
+ 0x03, 0x00, 0xA0, 0xE1, 0x80, 0x20, 0x82, 0xE2, 0x01, 0x00, 0x00, 0xEA, 0x02, 0x00, 0x50, 0xE1,
+ 0x0A, 0x00, 0x00, 0x0A, 0xB0, 0x30, 0xD1, 0xE1, 0x50, 0x30, 0x13, 0xE2, 0x01, 0x00, 0x80, 0xE2,
+ 0xF9, 0xFF, 0xFF, 0x0A, 0x26, 0x37, 0xA0, 0xE3, 0x96, 0x3C, 0x83, 0xE2, 0x7F, 0x30, 0x83, 0xE2,
+ 0x03, 0x00, 0x50, 0xE1, 0x00, 0x00, 0xA0, 0xC3, 0x01, 0x00, 0xA0, 0xD3, 0x1E, 0xFF, 0x2F, 0xE1,
+ 0x03, 0x00, 0xA0, 0xE1, 0x1E, 0xFF, 0x2F, 0xE1, 0xF0, 0x4B, 0x2D, 0xE9, 0x09, 0x34, 0xA0, 0xE3,
+ 0x0E, 0x38, 0x83, 0xE2, 0xB0, 0xC0, 0xD3, 0xE1, 0x80, 0x00, 0x1C, 0xE3, 0x10, 0xD0, 0x4D, 0xE2,
+ 0x01, 0x90, 0xA0, 0xE1, 0x02, 0xE0, 0xA0, 0xE1, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0xC0, 0xA0, 0xE3,
+ 0x01, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x5C, 0xE1, 0x08, 0x00, 0x00, 0x0A, 0x09, 0x34, 0xA0, 0xE3,
+ 0x0E, 0x38, 0x83, 0xE2, 0xB0, 0x20, 0xD3, 0xE1, 0x26, 0x17, 0xA0, 0xE3, 0x96, 0x1C, 0x81, 0xE2,
+ 0x80, 0x00, 0x12, 0xE3, 0x01, 0xC0, 0x8C, 0xE2, 0x80, 0x10, 0x81, 0xE2, 0xF4, 0xFF, 0xFF, 0x1A,
+ 0x26, 0xC5, 0xA0, 0xE3, 0x03, 0xC7, 0x8C, 0xE2, 0xB0, 0x30, 0xDC, 0xE1, 0x50, 0x30, 0x13, 0xE2,
+ 0x26, 0x17, 0xA0, 0x03, 0x96, 0x1C, 0x81, 0x02, 0x03, 0x20, 0xA0, 0x01, 0x80, 0x10, 0x81, 0x02,
+ 0x02, 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x52, 0xE1, 0x67, 0x00, 0x00, 0x0A,
+ 0xB0, 0x30, 0xDC, 0xE1, 0x50, 0x00, 0x13, 0xE3, 0x01, 0x20, 0x82, 0xE2, 0xF9, 0xFF, 0xFF, 0x0A,
+ 0x26, 0x37, 0xA0, 0xE3, 0x96, 0x3C, 0x83, 0xE2, 0x7F, 0x30, 0x83, 0xE2, 0x03, 0x00, 0x52, 0xE1,
+ 0x5E, 0x00, 0x00, 0xCA, 0xFF, 0x00, 0x59, 0xE3, 0x00, 0x30, 0xA0, 0x83, 0x0C, 0x30, 0x8D, 0x85,
+ 0x5E, 0x00, 0x00, 0x9A, 0x00, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 0xFF, 0x30, 0x03, 0xE2,
+ 0x09, 0x54, 0xA0, 0xE3, 0x04, 0x30, 0x8D, 0xE5, 0x0C, 0x30, 0x9D, 0xE5, 0x20, 0x4C, 0xA0, 0xE1,
+ 0x0E, 0xB0, 0xA0, 0xE1, 0x05, 0x60, 0xA0, 0xE1, 0x20, 0x74, 0xA0, 0xE1, 0x05, 0x20, 0xA0, 0xE1,
+ 0x20, 0x18, 0xA0, 0xE1, 0x05, 0xC0, 0xA0, 0xE1, 0x05, 0x00, 0xA0, 0xE1, 0x05, 0xE0, 0xA0, 0xE1,
+ 0x01, 0x57, 0x85, 0xE2, 0xB0, 0x30, 0xC5, 0xE1, 0x04, 0x30, 0x9D, 0xE5, 0x0F, 0x40, 0x04, 0xE2,
+ 0x06, 0x68, 0x86, 0xE2, 0xB0, 0x30, 0xC6, 0xE1, 0xFF, 0x70, 0x07, 0xE2, 0x02, 0x27, 0x82, 0xE2,
+ 0xFF, 0x10, 0x01, 0xE2, 0x0A, 0x08, 0x80, 0xE2, 0xE0, 0x40, 0x84, 0xE3, 0x03, 0xC7, 0x8C, 0xE2,
+ 0x0E, 0xE8, 0x8E, 0xE2, 0x20, 0x30, 0xA0, 0xE3, 0xB0, 0x70, 0xC2, 0xE1, 0xB0, 0x10, 0xC0, 0xE1,
+ 0xB0, 0x40, 0xCC, 0xE1, 0xB0, 0x30, 0xCE, 0xE1, 0x0B, 0x80, 0xA0, 0xE1, 0x01, 0x90, 0x59, 0xE2,
+ 0x3E, 0x00, 0x00, 0x3A, 0x26, 0x25, 0xA0, 0xE3, 0x03, 0x27, 0x82, 0xE2, 0xB0, 0x30, 0xD2, 0xE1,
+ 0x03, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 0xFF, 0x30, 0x03, 0xE2, 0x58, 0x00, 0x53, 0xE3,
+ 0x26, 0x17, 0xA0, 0x13, 0x96, 0x1C, 0x81, 0x12, 0x02, 0x00, 0xA0, 0x11, 0x80, 0x10, 0x81, 0x12,
+ 0x00, 0x20, 0xA0, 0x13, 0x02, 0x00, 0x00, 0x1A, 0x0D, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x52, 0xE1,
+ 0x26, 0x00, 0x00, 0x0A, 0xB0, 0x30, 0xD0, 0xE1, 0x03, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1,
+ 0xFF, 0x30, 0x03, 0xE2, 0x58, 0x00, 0x53, 0xE3, 0x01, 0x20, 0x82, 0xE2, 0xF6, 0xFF, 0xFF, 0x1A,
+ 0x26, 0x37, 0xA0, 0xE3, 0x96, 0x3C, 0x83, 0xE2, 0x7F, 0x30, 0x83, 0xE2, 0x03, 0x00, 0x52, 0xE1,
+ 0x1A, 0x00, 0x00, 0xCA, 0x01, 0x00, 0x18, 0xE3, 0x0B, 0x10, 0xA0, 0x01, 0xFF, 0x20, 0xA0, 0x03,
+ 0x09, 0x04, 0xA0, 0x03, 0x0E, 0x00, 0x00, 0x0A, 0x08, 0x10, 0xA0, 0xE1, 0xFF, 0x00, 0xA0, 0xE3,
+ 0x09, 0xC4, 0xA0, 0xE3, 0xB0, 0x30, 0xDC, 0xE1, 0x03, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1,
+ 0x01, 0x00, 0x40, 0xE2, 0x43, 0x24, 0xA0, 0xE1, 0x01, 0x00, 0x70, 0xE3, 0x01, 0x20, 0xC1, 0xE5,
+ 0x00, 0x30, 0xC1, 0xE5, 0x02, 0x10, 0x81, 0xE2, 0xF5, 0xFF, 0xFF, 0x1A, 0x02, 0x8C, 0x88, 0xE2,
+ 0xCD, 0xFF, 0xFF, 0xEA, 0x01, 0x20, 0x42, 0xE2, 0xB0, 0x30, 0xD0, 0xE1, 0x01, 0x00, 0x72, 0xE3,
+ 0xB2, 0x30, 0xC1, 0xE0, 0xFA, 0xFF, 0xFF, 0x1A, 0x02, 0xBC, 0x8B, 0xE2, 0xC6, 0xFF, 0xFF, 0xEA,
+ 0x00, 0x00, 0xA0, 0xE3, 0x10, 0xD0, 0x8D, 0xE2, 0xF0, 0x4B, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1,
+ 0x09, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 0x0C, 0x30, 0x8D, 0xE5, 0x9C, 0xFF, 0xFF, 0xEA,
+ 0x01, 0x00, 0xA0, 0xE3, 0xF6, 0xFF, 0xFF, 0xEA, 0xF0, 0x4B, 0x2D, 0xE9, 0x09, 0x34, 0xA0, 0xE3,
+ 0x0E, 0x38, 0x83, 0xE2, 0xB0, 0xC0, 0xD3, 0xE1, 0x80, 0x00, 0x1C, 0xE3, 0x10, 0xD0, 0x4D, 0xE2,
+ 0x01, 0x90, 0xA0, 0xE1, 0x02, 0xE0, 0xA0, 0xE1, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0xC0, 0xA0, 0xE3,
+ 0x01, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x5C, 0xE1, 0x08, 0x00, 0x00, 0x0A, 0x09, 0x34, 0xA0, 0xE3,
+ 0x0E, 0x38, 0x83, 0xE2, 0xB0, 0x20, 0xD3, 0xE1, 0x26, 0x17, 0xA0, 0xE3, 0x96, 0x1C, 0x81, 0xE2,
+ 0x80, 0x00, 0x12, 0xE3, 0x01, 0xC0, 0x8C, 0xE2, 0x80, 0x10, 0x81, 0xE2, 0xF4, 0xFF, 0xFF, 0x1A,
+ 0x26, 0xC5, 0xA0, 0xE3, 0x03, 0xC7, 0x8C, 0xE2, 0xB0, 0x30, 0xDC, 0xE1, 0x50, 0x30, 0x13, 0xE2,
+ 0x26, 0x17, 0xA0, 0x03, 0x96, 0x1C, 0x81, 0x02, 0x03, 0x20, 0xA0, 0x01, 0x80, 0x10, 0x81, 0x02,
+ 0x02, 0x00, 0x00, 0x0A, 0x0A, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x52, 0xE1, 0x65, 0x00, 0x00, 0x0A,
+ 0xB0, 0x30, 0xDC, 0xE1, 0x50, 0x00, 0x13, 0xE3, 0x01, 0x20, 0x82, 0xE2, 0xF9, 0xFF, 0xFF, 0x0A,
+ 0x26, 0x37, 0xA0, 0xE3, 0x96, 0x3C, 0x83, 0xE2, 0x7F, 0x30, 0x83, 0xE2, 0x03, 0x00, 0x52, 0xE1,
+ 0x5C, 0x00, 0x00, 0xCA, 0xFF, 0x00, 0x59, 0xE3, 0x00, 0x30, 0xA0, 0x83, 0x0C, 0x30, 0x8D, 0x85,
+ 0x5C, 0x00, 0x00, 0x9A, 0x00, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 0xFF, 0x30, 0x03, 0xE2,
+ 0x09, 0x54, 0xA0, 0xE3, 0x04, 0x30, 0x8D, 0xE5, 0x0C, 0x30, 0x9D, 0xE5, 0x20, 0x4C, 0xA0, 0xE1,
+ 0x0E, 0xB0, 0xA0, 0xE1, 0x05, 0x60, 0xA0, 0xE1, 0x20, 0x74, 0xA0, 0xE1, 0x05, 0x20, 0xA0, 0xE1,
+ 0x20, 0x18, 0xA0, 0xE1, 0x05, 0xC0, 0xA0, 0xE1, 0x05, 0x00, 0xA0, 0xE1, 0x05, 0xE0, 0xA0, 0xE1,
+ 0x01, 0x57, 0x85, 0xE2, 0xB0, 0x30, 0xC5, 0xE1, 0x04, 0x30, 0x9D, 0xE5, 0x0F, 0x40, 0x04, 0xE2,
+ 0x06, 0x68, 0x86, 0xE2, 0xB0, 0x30, 0xC6, 0xE1, 0xFF, 0x70, 0x07, 0xE2, 0x02, 0x27, 0x82, 0xE2,
+ 0xFF, 0x10, 0x01, 0xE2, 0x0A, 0x08, 0x80, 0xE2, 0xE0, 0x40, 0x84, 0xE3, 0x03, 0xC7, 0x8C, 0xE2,
+ 0x0E, 0xE8, 0x8E, 0xE2, 0x30, 0x30, 0xA0, 0xE3, 0xB0, 0x70, 0xC2, 0xE1, 0xB0, 0x10, 0xC0, 0xE1,
+ 0xB0, 0x40, 0xCC, 0xE1, 0xB0, 0x30, 0xCE, 0xE1, 0x0B, 0x80, 0xA0, 0xE1, 0x01, 0x90, 0x59, 0xE2,
+ 0x3C, 0x00, 0x00, 0x3A, 0x26, 0x25, 0xA0, 0xE3, 0x03, 0x27, 0x82, 0xE2, 0xB0, 0x30, 0xD2, 0xE1,
+ 0x03, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1, 0xFF, 0x30, 0x03, 0xE2, 0x58, 0x00, 0x53, 0xE3,
+ 0x26, 0x17, 0xA0, 0x13, 0x96, 0x1C, 0x81, 0x12, 0x02, 0x00, 0xA0, 0x11, 0x80, 0x10, 0x81, 0x12,
+ 0x00, 0x20, 0xA0, 0x13, 0x02, 0x00, 0x00, 0x1A, 0x0D, 0x00, 0x00, 0xEA, 0x01, 0x00, 0x52, 0xE1,
+ 0x24, 0x00, 0x00, 0x0A, 0xB0, 0x30, 0xD0, 0xE1, 0x03, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1,
+ 0xFF, 0x30, 0x03, 0xE2, 0x58, 0x00, 0x53, 0xE3, 0x01, 0x20, 0x82, 0xE2, 0xF6, 0xFF, 0xFF, 0x1A,
+ 0x26, 0x37, 0xA0, 0xE3, 0x96, 0x3C, 0x83, 0xE2, 0x7F, 0x30, 0x83, 0xE2, 0x03, 0x00, 0x52, 0xE1,
+ 0x18, 0x00, 0x00, 0xCA, 0x01, 0x00, 0x18, 0xE3, 0x0B, 0x10, 0xA0, 0x01, 0xFF, 0x20, 0xA0, 0x03,
+ 0x09, 0x04, 0xA0, 0x03, 0x0C, 0x00, 0x00, 0x0A, 0x08, 0x10, 0xA0, 0xE1, 0xFF, 0x00, 0xA0, 0xE3,
+ 0x09, 0xC4, 0xA0, 0xE3, 0x00, 0x30, 0xD1, 0xE5, 0x01, 0x20, 0xD1, 0xE5, 0x01, 0x00, 0x40, 0xE2,
+ 0x02, 0x34, 0x83, 0xE1, 0x01, 0x00, 0x70, 0xE3, 0xB0, 0x30, 0xCC, 0xE1, 0x02, 0x10, 0x81, 0xE2,
+ 0xF7, 0xFF, 0xFF, 0x1A, 0x02, 0x8C, 0x88, 0xE2, 0xCF, 0xFF, 0xFF, 0xEA, 0x01, 0x20, 0x42, 0xE2,
+ 0xB2, 0x30, 0xD1, 0xE0, 0x01, 0x00, 0x72, 0xE3, 0xB0, 0x30, 0xC0, 0xE1, 0xFA, 0xFF, 0xFF, 0x1A,
+ 0x02, 0xBC, 0x8B, 0xE2, 0xC8, 0xFF, 0xFF, 0xEA, 0x00, 0x00, 0xA0, 0xE3, 0x10, 0xD0, 0x8D, 0xE2,
+ 0xF0, 0x4B, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1, 0x09, 0x38, 0xA0, 0xE1, 0x23, 0x38, 0xA0, 0xE1,
+ 0x0C, 0x30, 0x8D, 0xE5, 0x9E, 0xFF, 0xFF, 0xEA, 0x01, 0x00, 0xA0, 0xE3, 0xF6, 0xFF, 0xFF, 0xEA,
+ 0x04, 0xE0, 0x2D, 0xE5, 0x04, 0xD0, 0x4D, 0xE2, 0xAA, 0xFE, 0xFF, 0xEB, 0x04, 0xD0, 0x8D, 0xE2,
+ 0x04, 0xE0, 0x9D, 0xE4, 0x1E, 0xFF, 0x2F, 0xE1, 0x0D, 0xC0, 0xA0, 0xE1, 0xF8, 0xDF, 0x2D, 0xE9,
+ 0x04, 0xB0, 0x4C, 0xE2, 0x28, 0xD0, 0x4B, 0xE2, 0xF0, 0x6F, 0x9D, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1,
+ 0xDC, 0x00, 0x80, 0xBF, 0x98, 0x00, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+}; //unsigned char mpcf_dldi[1876]
+
+bool tryPatch(void* data, size_t size)
+{
+ // Find the DSDI reserved space in the file
+ addr_t patchOffset = quickFind ((data_t*)data, dldiMagicString, size, sizeof(dldiMagicString)/sizeof(char));
+
+ //no DLDI section
+ if (patchOffset < 0)
+ return false;
+
+ data_t *pDH = mpcf_dldi;
+ data_t *pAH = (data_t*)data + patchOffset;
+
+ if (pDH[DO_driverSize] > pAH[DO_allocatedSpace]) {
+ printf ("Not enough space for patch. Available %d bytes, need %d bytes\n", ( 1 << pAH[DO_allocatedSpace]), ( 1 << pDH[DO_driverSize]) );
+ return false;
+ }
+
+ if(memcmp(&pAH[DO_friendlyName],"Default (No interface)",22))
+ {
+ printf("Would have been a candidate for auto-patch DLDI, but there was already a patch installed.");
+ return false;
+ }
+
+ //----should be able to patch OK-----
+
+ addr_t memOffset; // Offset of DLDI after the file is loaded into memory
+ addr_t relocationOffset; // Value added to all offsets within the patch to fix it properly
+ addr_t ddmemOffset; // Original offset used in the DLDI file
+ addr_t ddmemStart; // Start of range that offsets can be in the DLDI file
+ addr_t ddmemEnd; // End of range that offsets can be in the DLDI file
+ addr_t ddmemSize; // Size of range that offsets can be in the DLDI file
+
+ addr_t addrIter;
+
+
+ memOffset = readAddr (pAH, DO_text_start);
+ if (memOffset == 0) {
+ memOffset = readAddr (pAH, DO_startup) - DO_code;
+ }
+ ddmemOffset = readAddr (pDH, DO_text_start);
+ relocationOffset = memOffset - ddmemOffset;
+
+ printf ("AUTO-PATCHING DLDI to MPCF! Lucky you!\n\n");
+ printf ("Old driver: %s\n", &pAH[DO_friendlyName]);
+ printf ("New driver: %s\n", &pDH[DO_friendlyName]);
+ printf ("\n");
+ printf ("Position in file: 0x%08X\n", patchOffset);
+ printf ("Position in memory: 0x%08X\n", memOffset);
+ printf ("Patch base address: 0x%08X\n", ddmemOffset);
+ printf ("Relocation offset: 0x%08X\n", relocationOffset);
+ printf ("\n");
+
+ ddmemStart = readAddr (pDH, DO_text_start);
+ ddmemSize = (1 << pDH[DO_driverSize]);
+ ddmemEnd = ddmemStart + ddmemSize;
+
+ // Remember how much space is actually reserved
+ pDH[DO_allocatedSpace] = pAH[DO_allocatedSpace];
+ // Copy the DLDI patch into the application
+ memcpy (pAH, pDH, sizeof(mpcf_dldi));
+
+ // Fix the section pointers in the header
+ writeAddr (pAH, DO_text_start, readAddr (pAH, DO_text_start) + relocationOffset);
+ writeAddr (pAH, DO_data_end, readAddr (pAH, DO_data_end) + relocationOffset);
+ writeAddr (pAH, DO_glue_start, readAddr (pAH, DO_glue_start) + relocationOffset);
+ writeAddr (pAH, DO_glue_end, readAddr (pAH, DO_glue_end) + relocationOffset);
+ writeAddr (pAH, DO_got_start, readAddr (pAH, DO_got_start) + relocationOffset);
+ writeAddr (pAH, DO_got_end, readAddr (pAH, DO_got_end) + relocationOffset);
+ writeAddr (pAH, DO_bss_start, readAddr (pAH, DO_bss_start) + relocationOffset);
+ writeAddr (pAH, DO_bss_end, readAddr (pAH, DO_bss_end) + relocationOffset);
+ // Fix the function pointers in the header
+ writeAddr (pAH, DO_startup, readAddr (pAH, DO_startup) + relocationOffset);
+ writeAddr (pAH, DO_isInserted, readAddr (pAH, DO_isInserted) + relocationOffset);
+ writeAddr (pAH, DO_readSectors, readAddr (pAH, DO_readSectors) + relocationOffset);
+ writeAddr (pAH, DO_writeSectors, readAddr (pAH, DO_writeSectors) + relocationOffset);
+ writeAddr (pAH, DO_clearStatus, readAddr (pAH, DO_clearStatus) + relocationOffset);
+ writeAddr (pAH, DO_shutdown, readAddr (pAH, DO_shutdown) + relocationOffset);
+
+ if (pDH[DO_fixSections] & FIX_ALL) {
+ // Search through and fix pointers within the data section of the file
+ for (addrIter = (readAddr(pDH, DO_text_start) - ddmemStart); addrIter < (readAddr(pDH, DO_data_end) - ddmemStart); addrIter++) {
+ if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
+ writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
+ }
+ }
+ }
+
+ if (pDH[DO_fixSections] & FIX_GLUE) {
+ // Search through and fix pointers within the glue section of the file
+ for (addrIter = (readAddr(pDH, DO_glue_start) - ddmemStart); addrIter < (readAddr(pDH, DO_glue_end) - ddmemStart); addrIter++) {
+ if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
+ writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
+ }
+ }
+ }
+
+ if (pDH[DO_fixSections] & FIX_GOT) {
+ // Search through and fix pointers within the Global Offset Table section of the file
+ for (addrIter = (readAddr(pDH, DO_got_start) - ddmemStart); addrIter < (readAddr(pDH, DO_got_end) - ddmemStart); addrIter++) {
+ if ((ddmemStart <= readAddr(pAH, addrIter)) && (readAddr(pAH, addrIter) < ddmemEnd)) {
+ writeAddr (pAH, addrIter, readAddr(pAH, addrIter) + relocationOffset);
+ }
+ }
+ }
+
+ if (pDH[DO_fixSections] & FIX_BSS) {
+ // Initialise the BSS to 0
+ memset (&pAH[readAddr(pDH, DO_bss_start) - ddmemStart] , 0, readAddr(pDH, DO_bss_end) - readAddr(pDH, DO_bss_start));
+ }
+
+ return true;
+}
+
+} //namespace DLDI
+
--- /dev/null
+++ b/src/in_2sf/desmume/utils/xstring.cpp
@@ -1,1 +1,747 @@
-
+//taken from fceux on 10/27/08
+//subsequently modified for desmume
+
+/*
+ Copyright (C) 2008-2009 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string>
+#include <vector>
+
+#include "xstring.h"
+
+//a vc-style substring operation (very kind and lenient)
+/*std::string strsub(const std::string& str, int pos, int len) {
+ int strlen = str.size();
+
+ if(strlen==0) return str; //empty strings always return empty strings
+ if(pos>=strlen) return str; //if you start past the end of the string, return the entire string. this is unusual, but there you have it
+
+ //clipping
+ if(pos<0) {
+ len += pos;
+ pos = 0;
+ }
+
+ if (pos+len>=strlen)
+ len=strlen-pos+1;
+
+ //return str.str().substr(pos,len);
+ return str.substr(pos,len);
+}*/
+
+//std::string strmid(const std::string& str, int pos, int len) { return strsub(str,pos,len); }
+//std::string strleft(const std::string& str, int len) { return strsub(str,0,len); }
+//std::string strright(const std::string& str, int len) { return len ? strsub(str,str.size()-len,len) : ""; }
+/*std::string toupper(const std::string& str)
+{
+ std::string ret = str;
+ for(uint32_t i=0;i<str.size();i++)
+ ret[i] = toupper(ret[i]);
+ return ret;
+}*/
+
+///Upper case routine. Returns number of characters modified
+/*int str_ucase(char *str) {
+ uint32_t i=0,j=0;
+
+ while (i < strlen(str)) {
+ if ((str[i] >= 'a') && (str[i] <= 'z')) {
+ str[i] &= ~0x20;
+ j++;
+ }
+ i++;
+ }
+ return j;
+}*/
+
+
+///Lower case routine. Returns number of characters modified
+/*int str_lcase(char *str) {
+ uint32_t i=0,j=0;
+
+ while (i < strlen(str)) {
+ if ((str[i] >= 'A') && (str[i] <= 'Z')) {
+ str[i] |= 0x20;
+ j++;
+ }
+ i++;
+ }
+ return j;
+}*/
+
+
+///White space-trimming routine
+
+///Removes whitespace from left side of string, depending on the flags set (See STRIP_x definitions in xstring.h)
+///Returns number of characters removed
+/*int str_ltrim(char *str, int flags) {
+ uint32_t i=0;
+
+ while (str[0]) {
+ if ((str[0] != ' ') || (str[0] != '\t') || (str[0] != '\r') || (str[0] != '\n')) break;
+
+ if ((flags & STRIP_SP) && (str[0] == ' ')) {
+ i++;
+ strcpy(str,str+1);
+ }
+ if ((flags & STRIP_TAB) && (str[0] == '\t')) {
+ i++;
+ strcpy(str,str+1);
+ }
+ if ((flags & STRIP_CR) && (str[0] == '\r')) {
+ i++;
+ strcpy(str,str+1);
+ }
+ if ((flags & STRIP_LF) && (str[0] == '\n')) {
+ i++;
+ strcpy(str,str+1);
+ }
+ }
+ return i;
+}*/
+
+
+///White space-trimming routine
+
+///Removes whitespace from right side of string, depending on the flags set (See STRIP_x definitions in xstring.h)
+///Returns number of characters removed
+/*int str_rtrim(char *str, int flags) {
+ uint32_t i=0;
+
+ while (strlen(str)) {
+ if ((str[strlen(str)-1] != ' ') ||
+ (str[strlen(str)-1] != '\t') ||
+ (str[strlen(str)-1] != '\r') ||
+ (str[strlen(str)-1] != '\n')) break;
+
+ if ((flags & STRIP_SP) && (str[0] == ' ')) {
+ i++;
+ str[strlen(str)-1] = 0;
+ }
+ if ((flags & STRIP_TAB) && (str[0] == '\t')) {
+ i++;
+ str[strlen(str)-1] = 0;
+ }
+ if ((flags & STRIP_CR) && (str[0] == '\r')) {
+ i++;
+ str[strlen(str)-1] = 0;
+ }
+ if ((flags & STRIP_LF) && (str[0] == '\n')) {
+ i++;
+ str[strlen(str)-1] = 0;
+ }
+ }
+ return i;
+}*/
+
+
+///White space-stripping routine
+
+///Removes whitespace depending on the flags set (See STRIP_x definitions in xstring.h)
+///Returns number of characters removed, or -1 on error
+/*int str_strip(char *str, int flags) {
+ uint32_t i=0,j=0;
+ char *astr,chr;
+
+ if (!strlen(str)) return -1;
+ if (!(flags & (STRIP_SP|STRIP_TAB|STRIP_CR|STRIP_LF))) return -1;
+ if (!(astr = (char*)malloc(strlen(str)+1))) return -1;
+ while (i < strlen(str)) {
+ chr = str[i++];
+ if ((flags & STRIP_SP) && (chr == ' ')) chr = 0;
+ if ((flags & STRIP_TAB) && (chr == '\t')) chr = 0;
+ if ((flags & STRIP_CR) && (chr == '\r')) chr = 0;
+ if ((flags & STRIP_LF) && (chr == '\n')) chr = 0;
+
+ if (chr) astr[j++] = chr;
+ }
+ astr[j] = 0;
+ strcpy(str,astr);
+ free(astr);
+ return j;
+}*/
+
+
+///Character replacement routine
+
+///Replaces all instances of 'search' with 'replace'
+///Returns number of characters modified
+/*int chr_replace(char *str, char search, char replace) {
+ uint32_t i=0,j=0;
+
+ while (i < strlen(str)) {
+ if (str[i] == search) {
+ str[i] = replace;
+ j++;
+ }
+ i++;
+ }
+ return j;
+}*/
+
+
+///Sub-String replacement routine
+
+///Replaces all instances of 'search' with 'replace'
+///Returns number of sub-strings modified, or -1 on error
+/*int str_replace(char *str, char *search, char *replace) {
+ uint32_t i=0,j=0;
+ int searchlen,replacelen;
+ char *astr;
+
+ searchlen = strlen(search);
+ replacelen = strlen(replace);
+ if ((!strlen(str)) || (!searchlen)) return -1; //note: allow *replace to have a length of zero!
+ if (!(astr = (char*)malloc(strlen(str)+1))) return -1;
+ while (i < strlen(str)) {
+ if (!strncmp(str+i,search,searchlen)) {
+ if (replacelen) memcpy(astr+j,replace,replacelen);
+ i += searchlen;
+ j += replacelen;
+ }
+ else astr[j++] = str[i++];
+ }
+ astr[j] = 0;
+ strcpy(str,astr);
+ free(astr);
+ return j;
+}*/
+
+/*static const struct Base64Table
+{
+ Base64Table()
+ {
+ size_t a=0;
+ for(a=0; a<256; ++a) data[a] = 0xFF; // mark everything as invalid by default
+ // create value->ascii mapping
+ a=0;
+ for(unsigned char c='A'; c<='Z'; ++c) data[a++] = c; // 0..25
+ for(unsigned char c='a'; c<='z'; ++c) data[a++] = c; // 26..51
+ for(unsigned char c='0'; c<='9'; ++c) data[a++] = c; // 52..61
+ data[62] = '+'; // 62
+ data[63] = '/'; // 63
+ // create ascii->value mapping (but due to overlap, write it to highbit region)
+ for(a=0; a<64; ++a) data[data[a]^0x80] = a; //
+ data[((unsigned char)'=') ^ 0x80] = 0;
+ }
+ unsigned char operator[] (size_t pos) const { return data[pos]; }
+private:
+ unsigned char data[256];
+} Base64Table;*/
+
+/*std::string u32ToHexString(uint32_t val)
+{
+ char temp[16];
+ sprintf(temp,"%08X",val);
+ return temp;
+}*/
+
+///Converts the provided data to a string in a standard, user-friendly, round-trippable format
+/*std::string BytesToString(const void* data, int len)
+{
+ char temp[16];
+ if(len==1) {
+ sprintf(temp,"%d",*(const unsigned char*)data);
+ return temp;
+ } else if(len==2) {
+ sprintf(temp,"%d",*(const unsigned short*)data);
+ return temp;
+ } else if(len==4) {
+ sprintf(temp,"%d",*(const unsigned int*)data);
+ return temp;
+ }
+
+ std::string ret;
+ if(1) // use base64
+ {
+ const unsigned char* src = (const unsigned char*)data;
+ ret = "base64:";
+ for(int n; len > 0; len -= n)
+ {
+ unsigned char input[3] = {0,0,0};
+ for(n=0; n<3 && n<len; ++n)
+ input[n] = *src++;
+ unsigned char output[4] =
+ {
+ Base64Table[ input[0] >> 2 ],
+ Base64Table[ ((input[0] & 0x03) << 4) | (input[1] >> 4) ],
+ n<2 ? '=' : Base64Table[ ((input[1] & 0x0F) << 2) | (input[2] >> 6) ],
+ n<3 ? '=' : Base64Table[ input[2] & 0x3F ]
+ };
+ ret.append(output, output+4);
+ }
+ }
+ else // use hex
+ {
+ ret.resize(len*2+2);
+ ret[0] = '0';
+ ret[1] = 'x';
+ for(int i=0;i<len;i++)
+ {
+ int a = (((const unsigned char*)data)[i]>>4);
+ int b = (((const unsigned char*)data)[i])&15;
+ if(a>9) a += 'A'-10;
+ else a += '0';
+ if(b>9) b += 'A'-10;
+ else b += '0';
+ ret[2+i*2] = a;
+ ret[2+i*2+1] = b;
+ }
+ }
+ return ret;
+}*/
+
+///returns -1 if this is not a hex string
+/*int HexStringToBytesLength(const std::string& str)
+{
+ if(str.size()>2 && str[0] == '0' && toupper(str[1]) == 'X')
+ return str.size()/2-1;
+ else return -1;
+}*/
+
+/*int Base64StringToBytesLength(const std::string& str)
+{
+ if(str.size() < 7 || (str.size()-7) % 4 || str.substr(0,7) != "base64:") return -1;
+
+ size_t c = ((str.size() - 7) / 4) * 3;
+ if(str[str.size()-1] == '=') { --c;
+ if(str[str.size()-2] == '=') --c; }
+ return c;
+}*/
+
+///parses a string in the same format as BytesToString
+///returns true if success.
+/*bool StringToBytes(const std::string& str, void* data, int len)
+{
+ if(str.substr(0,7) == "base64:")
+ {
+ // base64
+ unsigned char* tgt = (unsigned char*)data;
+ for(size_t pos = 7; pos < str.size() && len > 0; )
+ {
+ unsigned char input[4], converted[4];
+ for(int i=0; i<4; ++i)
+ {
+ if(pos >= str.size() && i > 0) return false; // invalid data
+ input[i] = str[pos++];
+ if(input[i] & 0x80) return false; // illegal character
+ converted[i] = Base64Table[input[i]^0x80];
+ if(converted[i] & 0x80) return false; // illegal character
+ }
+ unsigned char outpacket[3] =
+ {
+ (converted[0] << 2) | (converted[1] >> 4),
+ (converted[1] << 4) | (converted[2] >> 2),
+ (converted[2] << 6) | (converted[3])
+ };
+ int outlen = (input[2] == '=') ? 1 : (input[3] == '=' ? 2 : 3);
+ if(outlen > len) outlen = len;
+ memcpy(tgt, outpacket, outlen);
+ tgt += outlen;
+ len -= outlen;
+ }
+ return true;
+ }
+ if(str.size()>2 && str[0] == '0' && toupper(str[1]) == 'X')
+ {
+ // hex
+ int amt = len;
+ int bytesAvailable = str.size()/2;
+ if(bytesAvailable < amt)
+ amt = bytesAvailable;
+ const char* cstr = str.c_str()+2;
+ for(int i=0;i<amt;i++) {
+ char a = toupper(cstr[i*2]);
+ char b = toupper(cstr[i*2+1]);
+ if(a>='A') a=a-'A'+10;
+ else a-='0';
+ if(b>='A') b=b-'A'+10;
+ else b-='0';
+ unsigned char val = ((unsigned char)a<<4)|(unsigned char)b;
+ ((unsigned char*)data)[i] = val;
+ }
+ return true;
+ }
+
+ if(len==1) {
+ int x = atoi(str.c_str());
+ *(unsigned char*)data = x;
+ return true;
+ } else if(len==2) {
+ int x = atoi(str.c_str());
+ *(unsigned short*)data = x;
+ return true;
+ } else if(len==4) {
+ int x = atoi(str.c_str());
+ *(unsigned int*)data = x;
+ return true;
+ }
+ //we can't handle it
+ return false;
+}*/
+
+/// \brief convert input string into vector of string tokens
+///
+/// \note consecutive delimiters will be treated as single delimiter
+/// \note delimiters are _not_ included in return data
+///
+/// \param input string to be parsed
+/// \param delims list of delimiters.
+
+std::vector<std::string> tokenize_str(const std::string & str,
+ const std::string & delims=", \t")
+{
+ using namespace std;
+ // Skip delims at beginning, find start of first token
+ string::size_type lastPos = str.find_first_not_of(delims, 0);
+ // Find next delimiter @ end of token
+ string::size_type pos = str.find_first_of(delims, lastPos);
+
+ // output vector
+ vector<string> tokens;
+
+ while (string::npos != pos || string::npos != lastPos)
+ {
+ // Found a token, add it to the vector.
+ tokens.push_back(str.substr(lastPos, pos - lastPos));
+ // Skip delims. Note the "not_of". this is beginning of token
+ lastPos = str.find_first_not_of(delims, pos);
+ // Find next delimiter at end of token.
+ pos = str.find_first_of(delims, lastPos);
+ }
+
+ return tokens;
+}
+
+//this code was taken from WINE (LGPL)
+//http://google.com/codesearch?hl=en&q=+lang:c+splitpath+show:CPvw9Z-euls:_RSotQzmLeU:KGzljMEYFbY&sa=N&cd=9&ct=rc&cs_p=http://gentoo.osuosl.org/distfiles/Wine-20050524.tar.gz&cs_f=wine-20050524/programs/winefile/splitpath.c
+/*void splitpath(const char* path, char* drv, char* dir, char* name, char* ext)
+{
+ const char* end;*/ /* end of processed string */
+ //const char* p; /* search pointer */
+ //const char* s; /* copy pointer */
+
+ /* extract drive name */
+ /*if (path[0] && path[1]==':') {
+ if (drv) {
+ *drv++ = *path++;
+ *drv++ = *path++;
+ *drv = '\0';
+ } else path+=2;
+ } else if (drv)
+ *drv = '\0';*/
+
+ /* search for end of string or stream separator */
+ /*for(end=path; *end && *end!=':'; )
+ end++;*/
+
+ /* search for begin of file extension */
+ /*for(p=end; p>path && *--p!='\\' && *p!='/'; )
+ if (*p == '.') {
+ end = p;
+ break;
+ }
+
+ if (ext)
+ for(s=end; (*ext=*s++); )
+ ext++;
+ else
+ for(s=end; *s++; ) {}*/
+
+ /* search for end of directory name */
+ /*for(p=end; p>path; )
+ if (*--p=='\\' || *p=='/') {
+ p++;
+ break;
+ }
+
+ if (name) {
+ for(s=p; s<end; )
+ *name++ = *s++;
+
+ *name = '\0';
+ } else
+ for(s=p; s<end; )
+ s++;
+
+ if (dir) {
+ for(s=path; s<p; )
+ *dir++ = *s++;
+
+ *dir = '\0';
+ }
+}*/
+
+//mbg 5/12/08
+//for the curious, I tested U16ToHexStr and it was 10x faster than printf.
+//so the author of these dedicated functions is not insane, and I will leave them.
+
+//static char TempArray[11];
+
+/*uint16_t FastStrToU16(char* s, bool& valid)
+{
+ int i;
+ uint16_t v=0;
+ for(i=0; i < 4; i++)
+ {
+ if(s[i] == 0) return v;
+ v<<=4;
+ if(s[i] >= '0' && s[i] <= '9')
+ {
+ v+=s[i]-'0';
+ }
+ else if(s[i] >= 'a' && s[i] <= 'f')
+ {
+ v+=s[i]-'a'+10;
+ }
+ else if(s[i] >= 'A' && s[i] <= 'F')
+ {
+ v+=s[i]-'A'+10;
+ }
+ else
+ {
+ valid = false;
+ return 0xFFFF;
+ }
+ }
+ valid = true;
+ return v;
+}*/
+
+/*char *U8ToDecStr(uint8_t a)
+{
+ TempArray[0] = '0' + a/100;
+ TempArray[1] = '0' + (a%100)/10;
+ TempArray[2] = '0' + (a%10);
+ TempArray[3] = 0;
+ return TempArray;
+}*/
+
+/*char *U16ToDecStr(uint16_t a)
+{
+ TempArray[0] = '0' + a/10000;
+ TempArray[1] = '0' + (a%10000)/1000;
+ TempArray[2] = '0' + (a%1000)/100;
+ TempArray[3] = '0' + (a%100)/10;
+ TempArray[4] = '0' + (a%10);
+ TempArray[5] = 0;
+ return TempArray;
+}*/
+
+/*char *U32ToDecStr(char* buf, uint32_t a)
+{
+ buf[0] = '0' + a/1000000000;
+ buf[1] = '0' + (a%1000000000)/100000000;
+ buf[2] = '0' + (a%100000000)/10000000;
+ buf[3] = '0' + (a%10000000)/1000000;
+ buf[4] = '0' + (a%1000000)/100000;
+ buf[5] = '0' + (a%100000)/10000;
+ buf[6] = '0' + (a%10000)/1000;
+ buf[7] = '0' + (a%1000)/100;
+ buf[8] = '0' + (a%100)/10;
+ buf[9] = '0' + (a%10);
+ buf[10] = 0;
+ return buf;
+}*/
+/*char *U32ToDecStr(uint32_t a)
+{
+ return U32ToDecStr(TempArray,a);
+}*/
+
+/*char *U16ToHexStr(uint16_t a)
+{
+ TempArray[0] = a/4096 > 9?'A'+a/4096-10:'0' + a/4096;
+ TempArray[1] = (a%4096)/256 > 9?'A'+(a%4096)/256 - 10:'0' + (a%4096)/256;
+ TempArray[2] = (a%256)/16 > 9?'A'+(a%256)/16 - 10:'0' + (a%256)/16;
+ TempArray[3] = a%16 > 9?'A'+(a%16) - 10:'0' + (a%16);
+ TempArray[4] = 0;
+ return TempArray;
+}*/
+
+/*char *U8ToHexStr(uint8_t a)
+{
+ TempArray[0] = a/16 > 9?'A'+a/16 - 10:'0' + a/16;
+ TempArray[1] = a%16 > 9?'A'+(a%16) - 10:'0' + (a%16);
+ TempArray[2] = 0;
+ return TempArray;
+}*/
+
+/*std::string stditoa(int n)
+{
+ char tempbuf[16];
+ sprintf(tempbuf, "%d", n);
+ return tempbuf;
+}*/
+
+
+/*std::string readNullTerminatedAscii(std::istream* is)
+{
+ std::string ret;
+ ret.reserve(50);
+ for(;;)
+ {
+ int c = is->get();
+ if(c == 0) break;
+ else ret += (char)c;
+ }
+ return ret;
+}*/
+
+// replace all instances of victim with replacement
+/*std::string mass_replace(const std::string &source, const std::string &victim, const std::string &replacement)
+{
+ std::string answer = source;
+ std::string::size_type j = 0;
+ while ((j = answer.find(victim, j)) != std::string::npos )
+ {
+ answer.replace(j, victim.length(), replacement);
+ j+= replacement.length();
+ }
+ return answer;
+}*/
+
+//http://www.codeproject.com/KB/string/UtfConverter.aspx
+/*#include "ConvertUTF.h"
+namespace UtfConverter
+{
+ static std::wstring FromUtf8(const std::string& utf8string)
+ {
+ size_t widesize = utf8string.length();
+ if (sizeof(wchar_t) == 2)
+ {
+ wchar_t* widestringnative = new wchar_t[widesize+1];
+ const UTF8* sourcestart = reinterpret_cast<const UTF8*>(utf8string.c_str());
+ const UTF8* sourceend = sourcestart + widesize;
+ UTF16* targetstart = reinterpret_cast<UTF16*>(widestringnative);
+ UTF16* targetend = targetstart + widesize+1;
+ ConversionResult res = ConvertUTF8toUTF16(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
+ if (res != conversionOK)
+ {
+ delete [] widestringnative;
+ throw std::exception();
+ }
+ *targetstart = 0;
+ std::wstring resultstring(widestringnative);
+ delete [] widestringnative;
+ return resultstring;
+ }
+ else if (sizeof(wchar_t) == 4)
+ {
+ wchar_t* widestringnative = new wchar_t[widesize+1];
+ const UTF8* sourcestart = reinterpret_cast<const UTF8*>(utf8string.c_str());
+ const UTF8* sourceend = sourcestart + widesize;
+ UTF32* targetstart = reinterpret_cast<UTF32*>(widestringnative);
+ UTF32* targetend = targetstart + widesize;
+ ConversionResult res = ConvertUTF8toUTF32(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
+ if (res != conversionOK)
+ {
+ delete [] widestringnative;
+ throw std::exception();
+ }
+ *targetstart = 0;
+ std::wstring resultstring(widestringnative);
+ delete [] widestringnative;
+ return resultstring;
+ }
+ else
+ {
+ throw std::exception();
+ }
+ return L"";
+ }
+
+ static std::string ToUtf8(const std::wstring& widestring)
+ {
+ size_t widesize = widestring.length();
+
+ if (sizeof(wchar_t) == 2)
+ {
+ size_t utf8size = 3 * widesize + 1;
+ char* utf8stringnative = new char[utf8size];
+ const UTF16* sourcestart = reinterpret_cast<const UTF16*>(widestring.c_str());
+ const UTF16* sourceend = sourcestart + widesize;
+ UTF8* targetstart = reinterpret_cast<UTF8*>(utf8stringnative);
+ UTF8* targetend = targetstart + utf8size;
+ ConversionResult res = ConvertUTF16toUTF8(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
+ if (res != conversionOK)
+ {
+ delete [] utf8stringnative;
+ throw std::exception();
+ }
+ *targetstart = 0;
+ std::string resultstring(utf8stringnative);
+ delete [] utf8stringnative;
+ return resultstring;
+ }
+ else if (sizeof(wchar_t) == 4)
+ {
+ size_t utf8size = 4 * widesize + 1;
+ char* utf8stringnative = new char[utf8size];
+ const UTF32* sourcestart = reinterpret_cast<const UTF32*>(widestring.c_str());
+ const UTF32* sourceend = sourcestart + widesize;
+ UTF8* targetstart = reinterpret_cast<UTF8*>(utf8stringnative);
+ UTF8* targetend = targetstart + utf8size;
+ ConversionResult res = ConvertUTF32toUTF8(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
+ if (res != conversionOK)
+ {
+ delete [] utf8stringnative;
+ throw std::exception();
+ }
+ *targetstart = 0;
+ std::string resultstring(utf8stringnative);
+ delete [] utf8stringnative;
+ return resultstring;
+ }
+ else
+ {
+ throw std::exception();
+ }
+ return "";
+ }
+}*/
+
+//convert a std::string to std::wstring
+/*std::wstring mbstowcs(std::string str)
+{
+ try {
+ return UtfConverter::FromUtf8(str);
+ } catch(std::exception) {
+ return L"(failed UTF-8 conversion)";
+ }
+}*/
+
+/*std::string wcstombs(std::wstring str)
+{
+ return UtfConverter::ToUtf8(str);
+}*/
+
+
+//TODO - dont we already have another function that can do this
+/*std::string getExtension(const char* input) {
+ char buf[1024];
+ strcpy(buf,input);
+ char* dot=strrchr(buf,'.');
+ if(!dot)
+ return "";
+ char ext [512];
+ strcpy(ext, dot+1);
+ int k, extlen=strlen(ext);
+ for(k=0;k<extlen;k++)
+ ext[k]=tolower(ext[k]);
+ return ext;
+}*/
+
--- /dev/null
+++ b/src/in_2sf/desmume/utils/xstring.h
@@ -1,1 +1,135 @@
+//taken from fceux on 27-oct-2008
+//subsequently modified for desmume
+/*
+ Copyright (C) 2008-2009 DeSmuME team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _STRINGUTIL_H_
+#define _STRINGUTIL_H_
+
+#include <string>
+#include <vector>
+//#include <iostream>
+//#include <cstdio>
+//#include <cstring>
+//#include <cstdlib>
+
+//#include "../types.h"
+//#include "emufile.h"
+
+//definitions for str_strip() flags
+//static const int STRIP_SP = 0x01; // space
+//static const int STRIP_TAB = 0x02; // tab
+//static const int STRIP_CR = 0x04; // carriage return
+//static const int STRIP_LF = 0x08; // line feed
+
+//int str_ucase(char *str);
+//int str_lcase(char *str);
+//int str_ltrim(char *str, int flags);
+//int str_rtrim(char *str, int flags);
+//int str_strip(char *str, int flags);
+//int chr_replace(char *str, char search, char replace);
+//int str_replace(char *str, char *search, char *replace);
+
+//std::string strsub(const std::string &str, int pos, int len);
+//std::string strmid(const std::string &str, int pos, int len);
+//std::string strleft(const std::string &str, int len);
+//std::string strright(const std::string &str, int len);
+//std::string toupper(const std::string &str);
+
+//int HexStringToBytesLength(const std::string &str);
+//int Base64StringToBytesLength(const std::string &str);
+//std::string u32ToHexString(uint32_t val);
+//std::string BytesToString(const void *data, int len);
+//bool StringToBytes(const std::string &str, void *data, int len);
+
+std::vector<std::string> tokenize_str(const std::string &str,const std::string &delims);
+//void splitpath(const char *path, char *drv, char *dir, char *name, char *ext);
+
+//uint16_t FastStrToU16(char *s, bool &valid);
+//char *U16ToDecStr(uint16_t a);
+//char *U32ToDecStr(uint32_t a);
+//char *U32ToDecStr(char *buf, uint32_t a);
+//char *U8ToDecStr(uint8_t a);
+//char *U8ToHexStr(uint8_t a);
+//char *U16ToHexStr(uint16_t a);
+
+//std::string stditoa(int n);
+
+//std::string readNullTerminatedAscii(std::istream *is);
+
+// extracts a decimal uint from an istream
+/*template<typename T> T templateIntegerDecFromIstream(EMUFILE *is)
+{
+ unsigned int ret = 0;
+ bool pre = true;
+
+ for (;;)
+ {
+ int c = is->fgetc();
+ if (c == -1)
+ return ret;
+ int d = c - '0';
+ if (d < 0 || d > 9)
+ {
+ if (!pre)
+ break;
+ }
+ else
+ {
+ pre = false;
+ ret *= 10;
+ ret += d;
+ }
+ }
+ is->unget();
+ return ret;
+}*/
+
+//inline uint32_t u32DecFromIstream(EMUFILE *is) { return templateIntegerDecFromIstream<uint32_t>(is); }
+//inline uint64_t u64DecFromIstream(EMUFILE *is) { return templateIntegerDecFromIstream<uint64_t>(is); }
+
+//puts an optionally 0-padded decimal integer of type T into the ostream (0-padding is quicker)
+/*template<typename T, int DIGITS, bool PAD> void putdec(EMUFILE *os, T dec)
+{
+ char temp[DIGITS];
+ int ctr = 0;
+ for(int i = 0; i < DIGITS; ++i)
+ {
+ int quot = dec / 10;
+ int rem = dec % 10;
+ temp[DIGITS - 1 - i] = '0' + rem;
+ if (!PAD && rem)
+ ctr = i;
+ dec = quot;
+ }
+ if (!PAD)
+ os->fwrite(temp + DIGITS - ctr - 1, ctr + 1);
+ else
+ os->fwrite(temp, DIGITS);
+}*/
+
+//std::string mass_replace(const std::string &source, const std::string &victim, const std::string &replacement);
+
+//std::wstring mbstowcs(std::string str);
+//std::string wcstombs(std::wstring str);
+
+// TODO - dont we already have another function that can do this
+//std::string getExtension(const char *input);
+
+#endif
+
--- /dev/null
+++ b/src/in_2sf/desmume/version.cpp
@@ -1,1 +1,90 @@
+/*
+ Copyright (C) 2009-2011 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "types.h"
+#include "version.h"
+
+//todo - everyone will want to support this eventually, i suppose
+/*#if defined(_WINDOWS) && !defined(WXPORT)
+#include "svnrev.h"
+#else*/
+/*#ifdef SVN_REV
+#define SVN_REV_STR SVN_REV
+#else
+#define SVN_REV_STR ""
+#endif*/
+//#endif
+
+#define DESMUME_NAME "DeSmuME"
+
+#if defined(_WIN64)
+#define DESMUME_PLATFORM_STRING " x64"
+#elif defined(_WIN32)
+#define DESMUME_PLATFORM_STRING " x86"
+#else
+#define DESMUME_PLATFORM_STRING ""
+#endif
+
+#ifndef ENABLE_SSE2
+ #ifndef ENABLE_SSE
+ #define DESMUME_CPUEXT_STRING " NOSSE"
+ #else
+ #define DESMUME_CPUEXT_STRING " NOSSE2"
+ #endif
+#else
+#define DESMUME_CPUEXT_STRING ""
+#endif
+
+/*#ifdef DEVELOPER
+#define DESMUME_FEATURE_STRING " dev+"
+#else
+#define DESMUME_FEATURE_STRING ""
+#endif*/
+
+/*#if defined(DEBUG)
+#define DESMUME_SUBVERSION_STRING " debug"
+#elif defined(PUBLIC_RELEASE)
+#define DESMUME_SUBVERSION_STRING ""
+#else
+#define DESMUME_SUBVERSION_STRING " svn" SVN_REV_STR
+#endif*/
+
+#if defined(__INTEL_COMPILER)
+#define DESMUME_COMPILER " (Intel) "
+//#define DESMUME_COMPILER_DETAIL " (Intel) "
+#elif defined(_MSC_VER)
+#define DESMUME_COMPILER ""
+//#define DESMUME_COMPILER_DETAIL " msvc " _Py_STRINGIZE(_MSC_VER)
+//#define _Py_STRINGIZE(X) _Py_STRINGIZE1((X))
+//#define _Py_STRINGIZE1(X) _Py_STRINGIZE2 ## X
+//#define _Py_STRINGIZE2(X) #X
+//re: http://72.14.203.104/search?q=cache:HG-okth5NGkJ:mail.python.org/pipermail/python-checkins/2002-November/030704.html+_msc_ver+compiler+version+string&hl=en&gl=us&ct=clnk&cd=5
+#else
+// TODO: make for others compilers
+#define DESMUME_COMPILER ""
+//#define DESMUME_COMPILER_DETAIL ""
+#endif
+
+//#define DESMUME_VERSION_NUMERIC 90800
+#define DESMUME_VERSION_STRING " 0.9.8" /*DESMUME_SUBVERSION_STRING*/ /*DESMUME_FEATURE_STRING*/ DESMUME_PLATFORM_STRING DESMUME_CPUEXT_STRING DESMUME_COMPILER
+#define DESMUME_NAME_AND_VERSION DESMUME_NAME DESMUME_VERSION_STRING
+
+//uint32_t EMU_DESMUME_VERSION_NUMERIC() { return DESMUME_VERSION_NUMERIC; }
+const char* EMU_DESMUME_VERSION_STRING() { return DESMUME_VERSION_STRING; }
+const char* EMU_DESMUME_NAME_AND_VERSION() { return DESMUME_NAME_AND_VERSION; }
+//const char* EMU_DESMUME_COMPILER_DETAIL() { return DESMUME_COMPILER_DETAIL; }
+
--- /dev/null
+++ b/src/in_2sf/desmume/version.h
@@ -1,1 +1,26 @@
+/*
+ Copyright (C) 2009-2011 DeSmuME team
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string>
+
+#include "types.h"
+
+//uint32_t EMU_DESMUME_VERSION_NUMERIC();
+const char *EMU_DESMUME_VERSION_STRING();
+const char *EMU_DESMUME_NAME_AND_VERSION();
+//const char *EMU_DESMUME_COMPILER_DETAIL();
+
--- /dev/null
+++ b/src/in_gsf/XSFConfig_GSF.cpp
@@ -1,1 +1,147 @@
+/*
+ * xSF - GSF configuration
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Partially based on the vio*sf framework
+ */
+#include <bitset>
+#include "XSFPlayer.h"
+#include "XSFConfig.h"
+#include "convert.h"
+#include "BigSString.h"
+#include "vbam/gba/Sound.h"
+
+enum
+{
+ idLowPassFiltering = 1000,
+ idMutes
+};
+
+class XSFConfig_GSF : public XSFConfig
+{
+protected:
+ static bool initLowPassFiltering;
+ static std::wstring initMutes;
+
+ friend class XSFConfig;
+ bool lowPassFiltering;
+ std::bitset<6> mutes;
+
+ XSFConfig_GSF();
+ void LoadSpecificConfig();
+ void SaveSpecificConfig();
+ void GenerateSpecificDialogs();
+ INT_PTR CALLBACK ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void ResetSpecificConfigDefaults(HWND hwndDlg);
+ void SaveSpecificConfigDialog(HWND hwndDlg);
+ void CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
+public:
+ void About(HWND parent);
+};
+
+unsigned XSFConfig::initSampleRate = 44100;
+std::wstring XSFConfig::commonName = L"GSF Decoder";
+std::wstring XSFConfig::versionNumber = L"0.9b";
+bool XSFConfig_GSF::initLowPassFiltering = true;
+std::wstring XSFConfig_GSF::initMutes = L"000000";
+
+XSFConfig *XSFConfig::Create()
+{
+ return new XSFConfig_GSF();
+}
+
+XSFConfig_GSF::XSFConfig_GSF() : XSFConfig(), lowPassFiltering(false), mutes()
+{
+ this->supportedSampleRates.push_back(8000);
+ this->supportedSampleRates.push_back(11025);
+ this->supportedSampleRates.push_back(16000);
+ this->supportedSampleRates.push_back(22050);
+ this->supportedSampleRates.push_back(32000);
+ this->supportedSampleRates.push_back(44100);
+ this->supportedSampleRates.push_back(48000);
+ this->supportedSampleRates.push_back(88200);
+ this->supportedSampleRates.push_back(96000);
+ this->supportedSampleRates.push_back(176400);
+ this->supportedSampleRates.push_back(192000);
+}
+
+void XSFConfig_GSF::LoadSpecificConfig()
+{
+ this->lowPassFiltering = this->configIO->GetValue(L"LowPassFiltering", XSFConfig_GSF::initLowPassFiltering);
+ std::wstringstream mutesSS(this->configIO->GetValue(L"Mutes", XSFConfig_GSF::initMutes));
+ mutesSS >> this->mutes;
+}
+
+void XSFConfig_GSF::SaveSpecificConfig()
+{
+ this->configIO->SetValue(L"LowPassFiltering", this->lowPassFiltering);
+ this->configIO->SetValue(L"Mutes", this->mutes.to_string<wchar_t>());
+}
+
+void XSFConfig_GSF::GenerateSpecificDialogs()
+{
+ this->configDialog.AddCheckBoxControl(DialogCheckBoxBuilder(L"Low-Pass Filtering").WithSize(80, 10).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 7), 2).WithTabStop().
+ WithID(idLowPassFiltering));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Mute").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10)).IsLeftJustified());
+ this->configDialog.AddListBoxControl(DialogListBoxBuilder().WithSize(78, 45).WithExactHeight().InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idMutes).WithBorder().
+ WithVerticalScrollbar().WithMultipleSelect().WithTabStop());
+}
+
+INT_PTR CALLBACK XSFConfig_GSF::ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // Low-Pass Filtering
+ if (this->lowPassFiltering)
+ SendMessageW(GetDlgItem(hwndDlg, idLowPassFiltering), BM_SETCHECK, BST_CHECKED, 0);
+ // Mutes
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Square 1"));
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Square 2"));
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Wave Pattern"));
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Noise"));
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"PCM A"));
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"PCM B"));
+ for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, this->mutes[x], x);
+ break;
+ case WM_COMMAND:
+ break;
+ }
+
+ return XSFConfig::ConfigDialogProc(hwndDlg, uMsg, wParam, lParam);
+}
+
+void XSFConfig_GSF::ResetSpecificConfigDefaults(HWND hwndDlg)
+{
+ SendMessageW(GetDlgItem(hwndDlg, idLowPassFiltering), BM_SETCHECK, XSFConfig_GSF::initLowPassFiltering ? BST_CHECKED : BST_UNCHECKED, 0);
+ auto tmpMutes = std::bitset<6>(XSFConfig_GSF::initMutes);
+ for (int x = 0, numMutes = tmpMutes.size(); x < numMutes; ++x)
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, tmpMutes[x], x);
+}
+
+void XSFConfig_GSF::SaveSpecificConfigDialog(HWND hwndDlg)
+{
+ this->lowPassFiltering = SendMessageW(GetDlgItem(hwndDlg, idLowPassFiltering), BM_GETCHECK, 0, 0) == BST_CHECKED;
+ for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
+ this->mutes[x] = !!SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_GETSEL, x, 0);
+}
+
+void XSFConfig_GSF::CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad)
+{
+ if (!preLoad)
+ {
+ soundInterpolation = this->lowPassFiltering;
+ unsigned long tmpMutes = this->mutes.to_ulong();
+ soundSetEnable((((tmpMutes & 0x30) << 4) | (tmpMutes & 0xF)) ^ 0x30F);
+ }
+}
+
+void XSFConfig_GSF::About(HWND parent)
+{
+ MessageBox(parent, (XSFConfig::commonName + L" v" + XSFConfig::versionNumber + L", using xSF Winamp plugin framework (based on the vio*sf plugins) by Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]\n\n"
+ L"Utilizes modified VBA-M, SVN revision 1102, for audio playback.").c_str(), (XSFConfig::commonName + L" v" + XSFConfig::versionNumber).c_str(), MB_OK);
+}
+
--- /dev/null
+++ b/src/in_gsf/XSFPlayer_GSF.cpp
@@ -1,1 +1,254 @@
-
+/*
+ * xSF - GSF Player
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Based on a modified viogsf v0.08
+ *
+ * Partially based on the vio*sf framework
+ *
+ * Utilizes a modified VBA-M, SVN revision 1102, for playback
+ * http://vba-m.com/
+ */
+
+#include <memory>
+#include <zlib.h>
+#include "convert.h"
+#include "XSFPlayer.h"
+#include "XSFCommon.h"
+#include "vbam/gba/Globals.h"
+#include "vbam/gba/Sound.h"
+#include "vbam/common/SoundDriver.h"
+
+class XSFPlayer_GSF : public XSFPlayer
+{
+public:
+ XSFPlayer_GSF(const std::string &filename);
+ XSFPlayer_GSF(const std::wstring &filename);
+ ~XSFPlayer_GSF() { this->Terminate(); }
+ bool Load();
+ void GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples);
+ void Terminate();
+};
+
+const char *XSFPlayer::WinampDescription = "GSF Decoder";
+const char *XSFPlayer::WinampExts = "gsf;minigsf\0Game Boy Advance Sound Format files (*.gsf;*.minigsf)\0";
+
+XSFPlayer *XSFPlayer::Create(const std::string &fn)
+{
+ return new XSFPlayer_GSF(fn);
+}
+
+XSFPlayer *XSFPlayer::Create(const std::wstring &fn)
+{
+ return new XSFPlayer_GSF(fn);
+}
+
+static struct
+{
+ std::vector<uint8_t> rom;
+ unsigned entry;
+} loaderwork;
+
+int mapgsf(uint8_t *d, int l, int &s)
+{
+ if (static_cast<size_t>(l) > loaderwork.rom.size())
+ l = loaderwork.rom.size();
+ if (l)
+ memcpy(d, &loaderwork.rom[0], l);
+ s = l;
+ return l;
+}
+
+static struct
+{
+ std::vector<uint8_t> buf;
+ uint32_t len, fil, cur;
+} buffer = { std::vector<uint8_t>(), 0, 0, 0 };
+
+class GSFSoundDriver : public SoundDriver
+{
+ void freebuffer()
+ {
+ buffer.buf.clear();
+ buffer.len = buffer.fil = buffer.cur = 0;
+ }
+public:
+ bool init(long sampleRate)
+ {
+ freebuffer();
+ uint32_t len = (sampleRate / 10) << 2;
+ buffer.buf.resize(len);
+ buffer.len = len;
+ return true;
+ }
+
+ void pause()
+ {
+ }
+
+ void reset()
+ {
+ }
+
+ void resume()
+ {
+ }
+
+ void write(uint16_t *finalWave, int length)
+ {
+ if (static_cast<uint32_t>(length) > buffer.len - buffer.fil)
+ length = buffer.len - buffer.fil;
+ if (length > 0)
+ {
+ memcpy(&buffer.buf[buffer.fil], finalWave, length);
+ buffer.fil += length;
+ }
+ }
+
+ void setThrottle(unsigned short throttle)
+ {
+ }
+};
+
+SoundDriver *systemSoundInit()
+{
+ return new GSFSoundDriver();
+}
+
+static void Map2SFSection(const std::vector<uint8_t> §ion, int level)
+{
+ auto &data = loaderwork.rom;
+
+ uint32_t entry = Get32BitsLE(§ion[0]), offset = Get32BitsLE(§ion[4]) & 0x1FFFFFF, size = Get32BitsLE(§ion[8]), finalSize = size + offset;
+ if (level == 1)
+ loaderwork.entry = entry;
+ finalSize = NextHighestPowerOf2(finalSize);
+ if (data.empty())
+ data.resize(finalSize + 10, 0);
+ else if (data.size() < size + offset)
+ data.resize(offset + finalSize + 10);
+ memcpy(&data[offset], §ion[12], size);
+}
+
+static bool Map2SF(XSFFile *xSF, int level)
+{
+ if (!xSF->IsValidType(0x22))
+ return false;
+
+ auto &programSection = xSF->GetProgramSection();
+
+ if (!programSection.empty())
+ Map2SFSection(programSection, level);
+
+ return true;
+}
+
+static bool RecursiveLoad2SF(XSFFile *xSF, int level)
+{
+ if (level <= 10 && xSF->GetTagExists("_lib"))
+ {
+#ifdef _WIN32
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetWStr()) + xSF->GetTagValue("_lib").GetWStr(), 8, 12));
+#else
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetAnsi()) + xSF->GetTagValue("_lib").GetAnsi(), 8, 12));
+#endif
+ if (!RecursiveLoad2SF(libxSF.get(), level + 1))
+ return false;
+ }
+
+ if (!Map2SF(xSF, level))
+ return false;
+
+ unsigned n = 2;
+ bool found;
+ do
+ {
+ found = false;
+ std::string libTag = "_lib" + stringify(n++);
+ if (xSF->GetTagExists(libTag))
+ {
+ found = true;
+#ifdef _WIN32
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetWStr()) + xSF->GetTagValue(libTag).GetWStr(), 8, 12));
+#else
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetAnsi()) + xSF->GetTagValue(libTag).GetAnsi(), 8, 12));
+#endif
+ if (!RecursiveLoad2SF(libxSF.get(), level + 1))
+ return false;
+ }
+ } while (found);
+
+ return true;
+}
+
+static bool Load2SF(XSFFile *xSF)
+{
+ loaderwork.rom.clear();
+ loaderwork.entry = 0;
+
+ return RecursiveLoad2SF(xSF, 1);
+}
+
+XSFPlayer_GSF::XSFPlayer_GSF(const std::string &filename) : XSFPlayer()
+{
+ this->xSF = new XSFFile(filename, 8, 12);
+}
+
+XSFPlayer_GSF::XSFPlayer_GSF(const std::wstring &filename) : XSFPlayer()
+{
+ this->xSF = new XSFFile(filename, 8, 12);
+}
+
+bool XSFPlayer_GSF::Load()
+{
+ if (!Load2SF(this->xSF))
+ return false;
+
+ cpuIsMultiBoot = (loaderwork.entry >> 24) == 2;
+
+ CPULoadRom(NULL);
+
+ soundSetSampleRate(this->sampleRate);
+ soundInit();
+ soundReset();
+ soundSetEnable(0x3FF);
+
+ CPUInit(NULL, false);
+ CPUReset();
+
+ return XSFPlayer::Load();
+}
+
+void XSFPlayer_GSF::GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples)
+{
+ unsigned bytes = samples << 2;
+ while (bytes)
+ {
+ unsigned remainbytes = buffer.fil - buffer.cur;
+ while (!remainbytes)
+ {
+ buffer.cur = buffer.fil = 0;
+ CPULoop(250000);
+
+ remainbytes = buffer.fil - buffer.cur;
+ }
+ unsigned len = remainbytes;
+ if (len > bytes)
+ len = bytes;
+ memcpy(&buf[offset], &buffer.buf[buffer.cur], len);
+ bytes -= len;
+ offset += len;
+ buffer.cur += len;
+ }
+}
+
+void XSFPlayer_GSF::Terminate()
+{
+ CPUCleanUp();
+ soundShutdown();
+
+ loaderwork.rom.clear();
+ loaderwork.entry = 0;
+}
+
--- /dev/null
+++ b/src/in_gsf/vbam/License.txt
@@ -1,1 +1,29 @@
+Copyright for all files in trunk/src excluding gb_apu
+or when stated otherwise in the source file:
+ VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator
+ Copyright (C) 1999-2003 Forgotten
+ Copyright (C) 2004-2006 Forgotten and the VBA development team
+Copyright for the modifications to the files mentioned above:
+ VisualBoyAdvance-M GB/GBA emulator
+ Copyright (C) 2007-2008 VBA-M development team
+
+
+All files excluding gb_apu, modified files from zlib
+or when stated otherwise in the source file
+are distributed under the GNU GPL v2:
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or(at your option)
+any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Blip_Buffer.cpp
@@ -1,1 +1,466 @@
-
+// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
+
+#include "Blip_Buffer.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+/* Copyright (C) 2003-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 */
+
+// TODO: use scoped for variables in treble_eq()
+
+#ifdef BLARGG_ENABLE_OPTIMIZER
+ #include BLARGG_ENABLE_OPTIMIZER
+#endif
+
+int const silent_buf_size = 1; // size used for Silent_Blip_Buffer
+
+Blip_Buffer::Blip_Buffer()
+{
+ factor_ = (blip_ulong)LONG_MAX;
+ buffer_ = 0;
+ buffer_size_ = 0;
+ sample_rate_ = 0;
+ bass_shift_ = 0;
+ clock_rate_ = 0;
+ bass_freq_ = 16;
+ length_ = 0;
+
+ // assumptions code makes about implementation-defined features
+ #ifndef NDEBUG
+ // right shift of negative value preserves sign
+ buf_t_ i = -0x7FFFFFFE;
+ assert( (i >> 1) == -0x3FFFFFFF );
+
+ // casting to short truncates to 16 bits and sign-extends
+ i = 0x18000;
+ assert( (short) i == -0x8000 );
+ #endif
+
+ clear();
+}
+
+Blip_Buffer::~Blip_Buffer()
+{
+ if ( buffer_size_ != silent_buf_size )
+ free( buffer_ );
+}
+
+Silent_Blip_Buffer::Silent_Blip_Buffer()
+{
+ factor_ = 0;
+ buffer_ = buf;
+ buffer_size_ = silent_buf_size;
+ clear();
+}
+
+void Blip_Buffer::clear( int entire_buffer )
+{
+ offset_ = 0;
+ reader_accum_ = 0;
+ modified_ = 0;
+ if ( buffer_ )
+ {
+ long count = (entire_buffer ? buffer_size_ : samples_avail());
+ memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) );
+ }
+}
+
+Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
+{
+ if ( buffer_size_ == silent_buf_size )
+ {
+ assert( 0 );
+ return "Internal (tried to resize Silent_Blip_Buffer)";
+ }
+
+ // start with maximum length that resampled time can represent
+ long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64;
+ if ( msec != blip_max_length )
+ {
+ long s = (new_rate * (msec + 1) + 999) / 1000;
+ if ( s < new_size )
+ new_size = s;
+ else
+ assert( 0 ); // fails if requested buffer length exceeds limit
+ }
+
+ if ( buffer_size_ != new_size )
+ {
+ void* p = realloc( buffer_, (new_size + blip_buffer_extra_) * sizeof *buffer_ );
+ if ( !p )
+ return "Out of memory";
+ buffer_ = (buf_t_*) p;
+ }
+
+ buffer_size_ = new_size;
+ assert( buffer_size_ != silent_buf_size ); // size should never happen to match this
+
+ // update things based on the sample rate
+ sample_rate_ = new_rate;
+ length_ = new_size * 1000 / new_rate - 1;
+ if ( msec )
+ assert( length_ == msec ); // ensure length is same as that passed in
+
+ // update these since they depend on sample rate
+ if ( clock_rate_ )
+ clock_rate( clock_rate_ );
+ bass_freq( bass_freq_ );
+
+ clear();
+
+ return 0; // success
+}
+
+blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const
+{
+ double ratio = (double) sample_rate_ / rate;
+ blip_long factor = (blip_long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
+ assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
+ return (blip_resampled_time_t) factor;
+}
+
+void Blip_Buffer::bass_freq( int freq )
+{
+ bass_freq_ = freq;
+ int shift = 31;
+ if ( freq > 0 )
+ {
+ shift = 13;
+ long f = (freq << 16) / sample_rate_;
+ while ( (f >>= 1) && --shift ) { }
+ }
+ bass_shift_ = shift;
+}
+
+void Blip_Buffer::end_frame( blip_time_t t )
+{
+ offset_ += t * factor_;
+ assert( samples_avail() <= (long) buffer_size_ ); // fails if time is past end of buffer
+}
+
+long Blip_Buffer::count_samples( blip_time_t t ) const
+{
+ blip_resampled_time_t last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY;
+ blip_resampled_time_t first_sample = offset_ >> BLIP_BUFFER_ACCURACY;
+ return long (last_sample - first_sample);
+}
+
+blip_time_t Blip_Buffer::count_clocks( long count ) const
+{
+ if ( !factor_ )
+ {
+ assert( 0 ); // sample rate and clock rates must be set first
+ return 0;
+ }
+
+ if ( count > buffer_size_ )
+ count = buffer_size_;
+ blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
+ return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_);
+}
+
+void Blip_Buffer::remove_samples( long count )
+{
+ if ( count )
+ {
+ remove_silence( count );
+
+ // copy remaining samples to beginning and clear old samples
+ long remain = samples_avail() + blip_buffer_extra_;
+ memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ );
+ memset( buffer_ + remain, 0, count * sizeof *buffer_ );
+ }
+}
+
+// Blip_Synth_
+
+Blip_Synth_Fast_::Blip_Synth_Fast_()
+{
+ buf = 0;
+ last_amp = 0;
+ delta_factor = 0;
+}
+
+void Blip_Synth_Fast_::volume_unit( double new_unit )
+{
+ delta_factor = int (new_unit * (1L << blip_sample_bits) + 0.5);
+}
+
+#if !BLIP_BUFFER_FAST
+
+Blip_Synth_::Blip_Synth_( short* p, int w ) :
+ impulses( p ),
+ width( w )
+{
+ volume_unit_ = 0.0;
+ kernel_unit = 0;
+ buf = 0;
+ last_amp = 0;
+ delta_factor = 0;
+}
+
+#undef PI
+#define PI 3.1415926535897932384626433832795029
+
+static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff )
+{
+ if ( cutoff >= 0.999 )
+ cutoff = 0.999;
+
+ if ( treble < -300.0 )
+ treble = -300.0;
+ if ( treble > 5.0 )
+ treble = 5.0;
+
+ double const maxh = 4096.0;
+ double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
+ double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
+ double const to_angle = PI / 2 / maxh / oversample;
+ for ( int i = 0; i < count; i++ )
+ {
+ double angle = ((i - count) * 2 + 1) * to_angle;
+ double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
+ double cos_nc_angle = cos( maxh * cutoff * angle );
+ double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
+ double cos_angle = cos( angle );
+
+ c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
+ double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle);
+ double b = 2.0 - cos_angle - cos_angle;
+ double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
+
+ out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d
+ }
+}
+
+void blip_eq_t::generate( float* out, int count ) const
+{
+ // lower cutoff freq for narrow kernels with their wider transition band
+ // (8 points->1.49, 16 points->1.15)
+ double oversample = blip_res * 2.25 / count + 0.85;
+ double half_rate = sample_rate * 0.5;
+ if ( cutoff_freq )
+ oversample = half_rate / cutoff_freq;
+ double cutoff = rolloff_freq * oversample / half_rate;
+
+ gen_sinc( out, count, blip_res * oversample, treble, cutoff );
+
+ // apply (half of) hamming window
+ double to_fraction = PI / (count - 1);
+ for ( int i = count; i--; )
+ out [i] *= 0.54f - 0.46f * (float) cos( i * to_fraction );
+}
+
+void Blip_Synth_::adjust_impulse()
+{
+ // sum pairs for each phase and add error correction to end of first half
+ int const size = impulses_size();
+ for ( int p = blip_res; p-- >= blip_res / 2; )
+ {
+ int p2 = blip_res - 2 - p;
+ long error = kernel_unit;
+ for ( int i = 1; i < size; i += blip_res )
+ {
+ error -= impulses [i + p ];
+ error -= impulses [i + p2];
+ }
+ if ( p == p2 )
+ error /= 2; // phase = 0.5 impulse uses same half for both sides
+ impulses [size - blip_res + p] += (short) error;
+ //printf( "error: %ld\n", error );
+ }
+
+ //for ( int i = blip_res; i--; printf( "\n" ) )
+ // for ( int j = 0; j < width / 2; j++ )
+ // printf( "%5ld,", impulses [j * blip_res + i + 1] );
+}
+
+void Blip_Synth_::treble_eq( blip_eq_t const& eq )
+{
+ float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2];
+
+ int const half_size = blip_res / 2 * (width - 1);
+ eq.generate( &fimpulse [blip_res], half_size );
+
+ int i;
+
+ // need mirror slightly past center for calculation
+ for ( i = blip_res; i--; )
+ fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
+
+ // starts at 0
+ for ( i = 0; i < blip_res; i++ )
+ fimpulse [i] = 0.0f;
+
+ // find rescale factor
+ double total = 0.0;
+ for ( i = 0; i < half_size; i++ )
+ total += fimpulse [blip_res + i];
+
+ //double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
+ //double const base_unit = 37888.0; // allows treble to +5 dB
+ double const base_unit = 32768.0; // necessary for blip_unscaled to work
+ double rescale = base_unit / 2 / total;
+ kernel_unit = (long) base_unit;
+
+ // integrate, first difference, rescale, convert to int
+ double sum = 0.0;
+ double next = 0.0;
+ int const size = this->impulses_size();
+ for ( i = 0; i < size; i++ )
+ {
+ impulses [i] = (short) (int) floor( (next - sum) * rescale + 0.5 );
+ sum += fimpulse [i];
+ next += fimpulse [i + blip_res];
+ }
+ adjust_impulse();
+
+ // volume might require rescaling
+ double vol = volume_unit_;
+ if ( vol )
+ {
+ volume_unit_ = 0.0;
+ volume_unit( vol );
+ }
+}
+
+void Blip_Synth_::volume_unit( double new_unit )
+{
+ if ( new_unit != volume_unit_ )
+ {
+ // use default eq if it hasn't been set yet
+ if ( !kernel_unit )
+ treble_eq( -8.0 );
+
+ volume_unit_ = new_unit;
+ double factor = new_unit * (1L << blip_sample_bits) / kernel_unit;
+
+ if ( factor > 0.0 )
+ {
+ int shift = 0;
+
+ // if unit is really small, might need to attenuate kernel
+ while ( factor < 2.0 )
+ {
+ shift++;
+ factor *= 2.0;
+ }
+
+ if ( shift )
+ {
+ kernel_unit >>= shift;
+ assert( kernel_unit > 0 ); // fails if volume unit is too low
+
+ // keep values positive to avoid round-towards-zero of sign-preserving
+ // right shift for negative values
+ long offset = 0x8000 + (1 << (shift - 1));
+ long offset2 = 0x8000 >> shift;
+ for ( int i = impulses_size(); i--; )
+ impulses [i] = (short) (int) (((impulses [i] + offset) >> shift) - offset2);
+ adjust_impulse();
+ }
+ }
+ delta_factor = (int) floor( factor + 0.5 );
+ //printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit );
+ }
+}
+#endif
+
+long Blip_Buffer::read_samples( blip_sample_t* out_, long max_samples, int stereo )
+{
+ long count = samples_avail();
+ if ( count > max_samples )
+ count = max_samples;
+
+ if ( count )
+ {
+ int const bass = BLIP_READER_BASS( *this );
+ BLIP_READER_BEGIN( reader, *this );
+ BLIP_READER_ADJ_( reader, count );
+ blip_sample_t* BLIP_RESTRICT out = out_ + count;
+ blip_long offset = (blip_long) -count;
+
+ if ( !stereo )
+ {
+ do
+ {
+ blip_long s = BLIP_READER_READ( reader );
+ BLIP_READER_NEXT_IDX_( reader, bass, offset );
+ BLIP_CLAMP( s, s );
+ out [offset] = (blip_sample_t) s;
+ }
+ while ( ++offset );
+ }
+ else
+ {
+ do
+ {
+ blip_long s = BLIP_READER_READ( reader );
+ BLIP_READER_NEXT_IDX_( reader, bass, offset );
+ BLIP_CLAMP( s, s );
+ out [offset * 2] = (blip_sample_t) s;
+ }
+ while ( ++offset );
+ }
+
+ BLIP_READER_END( reader, *this );
+
+ remove_samples( count );
+ }
+ return count;
+}
+
+void Blip_Buffer::mix_samples( blip_sample_t const* in, long count )
+{
+ if ( buffer_size_ == silent_buf_size )
+ {
+ assert( 0 );
+ return;
+ }
+
+ buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2;
+
+ int const sample_shift = blip_sample_bits - 16;
+ int prev = 0;
+ while ( count-- )
+ {
+ blip_long s = (blip_long) *in++ << sample_shift;
+ *out += s - prev;
+ prev = s;
+ ++out;
+ }
+ *out -= prev;
+}
+
+blip_ulong const subsample_mask = (1L << BLIP_BUFFER_ACCURACY) - 1;
+
+void Blip_Buffer::save_state( blip_buffer_state_t* out )
+{
+ assert( samples_avail() == 0 );
+ out->offset_ = offset_;
+ out->reader_accum_ = reader_accum_;
+ memcpy( out->buf, &buffer_ [offset_ >> BLIP_BUFFER_ACCURACY], sizeof out->buf );
+}
+
+void Blip_Buffer::load_state( blip_buffer_state_t const& in )
+{
+ clear( false );
+
+ offset_ = in.offset_;
+ reader_accum_ = in.reader_accum_;
+ memcpy( buffer_, in.buf, sizeof in.buf );
+}
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Blip_Buffer.h
@@ -1,1 +1,557 @@
-
+// Band-limited sound synthesis buffer
+
+// Blip_Buffer 0.4.1
+#ifndef BLIP_BUFFER_H
+#define BLIP_BUFFER_H
+
+ // internal
+ #include <limits.h>
+ #if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF
+ typedef long blip_long;
+ typedef unsigned long blip_ulong;
+ #else
+ typedef int blip_long;
+ typedef unsigned blip_ulong;
+ #endif
+
+// Time unit at source clock rate
+typedef blip_long blip_time_t;
+
+// Output samples are 16-bit signed, with a range of -32768 to 32767
+typedef short blip_sample_t;
+enum { blip_sample_max = 32767 };
+
+struct blip_buffer_state_t;
+
+class Blip_Buffer {
+public:
+ typedef const char* blargg_err_t;
+
+ // Sets output sample rate and buffer length in milliseconds (1/1000 sec, defaults
+ // to 1/4 second) and clears buffer. If there isn't enough memory, leaves buffer
+ // untouched and returns "Out of memory", otherwise returns NULL.
+ blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
+
+ // Sets number of source time units per second
+ void clock_rate( long clocks_per_sec );
+
+ // Ends current time frame of specified duration and makes its samples available
+ // (along with any still-unread samples) for reading with read_samples(). Begins
+ // a new time frame at the end of the current frame.
+ void end_frame( blip_time_t time );
+
+ // Reads at most 'max_samples' out of buffer into 'dest', removing them from
+ // the buffer. Returns number of samples actually read and removed. If stereo is
+ // true, increments 'dest' one extra time after writing each sample, to allow
+ // easy interleving of two channels into a stereo output buffer.
+ long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
+
+// Additional features
+
+ // Removes all available samples and clear buffer to silence. If 'entire_buffer' is
+ // false, just clears out any samples waiting rather than the entire buffer.
+ void clear( int entire_buffer = 1 );
+
+ // Number of samples available for reading with read_samples()
+ long samples_avail() const;
+
+ // Removes 'count' samples from those waiting to be read
+ void remove_samples( long count );
+
+ // Sets frequency high-pass filter frequency, where higher values reduce bass more
+ void bass_freq( int frequency );
+
+ // Current output sample rate
+ long sample_rate() const;
+
+ // Length of buffer in milliseconds
+ int length() const;
+
+ // Number of source time units per second
+ long clock_rate() const;
+
+// Experimental features
+
+ // Saves state, including high-pass filter and tails of last deltas.
+ // All samples must have been read from buffer before calling this.
+ void save_state( blip_buffer_state_t* out );
+
+ // Loads state. State must have been saved from Blip_Buffer with same
+ // settings during same run of program. States can NOT be stored on disk.
+ // Clears buffer before loading state.
+ void load_state( blip_buffer_state_t const& in );
+
+ // Number of samples delay from synthesis to samples read out
+ int output_latency() const;
+
+ // Counts number of clocks needed until 'count' samples will be available.
+ // If buffer can't even hold 'count' samples, returns number of clocks until
+ // buffer becomes full.
+ blip_time_t count_clocks( long count ) const;
+
+ // Number of raw samples that can be mixed within frame of specified duration.
+ long count_samples( blip_time_t duration ) const;
+
+ // Mixes in 'count' samples from 'buf_in'
+ void mix_samples( blip_sample_t const* buf_in, long count );
+
+
+ // Signals that sound has been added to buffer. Could be done automatically in
+ // Blip_Synth, but that would affect performance more, as you can arrange that
+ // this is called only once per time frame rather than for every delta.
+ void set_modified() { modified_ = this; }
+
+ // not documented yet
+ blip_ulong unsettled() const;
+ Blip_Buffer* clear_modified() { Blip_Buffer* b = modified_; modified_ = 0; return b; }
+ void remove_silence( long count );
+ typedef blip_ulong blip_resampled_time_t;
+ blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }
+ blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
+ blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
+public:
+ Blip_Buffer();
+ ~Blip_Buffer();
+
+ // Deprecated
+ typedef blip_resampled_time_t resampled_time_t;
+ blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
+ blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
+private:
+ // noncopyable
+ Blip_Buffer( const Blip_Buffer& );
+ Blip_Buffer& operator = ( const Blip_Buffer& );
+public:
+ typedef blip_long buf_t_;
+ blip_ulong factor_;
+ blip_resampled_time_t offset_;
+ buf_t_* buffer_;
+ blip_long buffer_size_;
+ blip_long reader_accum_;
+ int bass_shift_;
+private:
+ long sample_rate_;
+ long clock_rate_;
+ int bass_freq_;
+ int length_;
+ Blip_Buffer* modified_; // non-zero = true (more optimal than using bool, heh)
+ friend class Blip_Reader;
+};
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
+// but reduce maximum buffer size.
+#ifndef BLIP_BUFFER_ACCURACY
+ #define BLIP_BUFFER_ACCURACY 16
+#endif
+
+// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
+// noticeable broadband noise when synthesizing high frequency square waves.
+// Affects size of Blip_Synth objects since they store the waveform directly.
+#ifndef BLIP_PHASE_BITS
+ #if BLIP_BUFFER_FAST
+ #define BLIP_PHASE_BITS 8
+ #else
+ #define BLIP_PHASE_BITS 6
+ #endif
+#endif
+
+ // Internal
+ typedef blip_ulong blip_resampled_time_t;
+ int const blip_widest_impulse_ = 16;
+ int const blip_buffer_extra_ = blip_widest_impulse_ + 2;
+ int const blip_res = 1 << BLIP_PHASE_BITS;
+ class blip_eq_t;
+
+ class Blip_Synth_Fast_ {
+ public:
+ Blip_Buffer* buf;
+ int last_amp;
+ int delta_factor;
+
+ void volume_unit( double );
+ Blip_Synth_Fast_();
+ void treble_eq( blip_eq_t const& ) { }
+ };
+
+ class Blip_Synth_ {
+ public:
+ Blip_Buffer* buf;
+ int last_amp;
+ int delta_factor;
+
+ void volume_unit( double );
+ Blip_Synth_( short* impulses, int width );
+ void treble_eq( blip_eq_t const& );
+ private:
+ double volume_unit_;
+ short* const impulses;
+ int const width;
+ blip_long kernel_unit;
+ int impulses_size() const { return blip_res / 2 * width + 1; }
+ void adjust_impulse();
+ };
+
+// Quality level, better = slower. In general, use blip_good_quality.
+const int blip_med_quality = 8;
+const int blip_good_quality = 12;
+const int blip_high_quality = 16;
+
+// Range specifies the greatest expected change in amplitude. Calculate it
+// by finding the difference between the maximum and minimum expected
+// amplitudes (max - min).
+template<int quality,int range>
+class Blip_Synth {
+public:
+ // Sets overall volume of waveform
+ void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
+
+ // Configures low-pass filter (see blip_buffer.txt)
+ void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }
+
+ // Gets/sets Blip_Buffer used for output
+ Blip_Buffer* output() const { return impl.buf; }
+ void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }
+
+ // Updates amplitude of waveform at given time. Using this requires a separate
+ // Blip_Synth for each waveform.
+ void update( blip_time_t time, int amplitude );
+
+// Low-level interface
+
+ // Adds an amplitude transition of specified delta, optionally into specified buffer
+ // rather than the one set with output(). Delta can be positive or negative.
+ // The actual change in amplitude is delta * (volume / range)
+ void offset( blip_time_t, int delta, Blip_Buffer* ) const;
+ void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
+
+ // Works directly in terms of fractional output samples. Contact author for more info.
+ void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
+
+ // Same as offset(), except code is inlined for higher performance
+ void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
+ offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
+ }
+ void offset_inline( blip_time_t t, int delta ) const {
+ offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
+ }
+
+private:
+#if BLIP_BUFFER_FAST
+ Blip_Synth_Fast_ impl;
+#else
+ Blip_Synth_ impl;
+ typedef short imp_t;
+ imp_t impulses [blip_res * (quality / 2) + 1];
+public:
+ Blip_Synth() : impl( impulses, quality ) { }
+#endif
+};
+
+// Low-pass equalization parameters
+class blip_eq_t {
+public:
+ // Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
+ // treble, small positive values (0 to 5.0) increase treble.
+ blip_eq_t( double treble_db = 0 );
+
+ // See blip_buffer.txt
+ blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
+
+private:
+ double treble;
+ long rolloff_freq;
+ long sample_rate;
+ long cutoff_freq;
+ void generate( float* out, int count ) const;
+ friend class Blip_Synth_;
+};
+
+int const blip_sample_bits = 30;
+
+// Dummy Blip_Buffer to direct sound output to, for easy muting without
+// having to stop sound code.
+class Silent_Blip_Buffer : public Blip_Buffer {
+ buf_t_ buf [blip_buffer_extra_ + 1];
+public:
+ // The following cannot be used (an assertion will fail if attempted):
+ blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );
+ blip_time_t count_clocks( long count ) const;
+ void mix_samples( blip_sample_t const* buf, long count );
+
+ Silent_Blip_Buffer();
+};
+
+ #if __GNUC__ >= 3 || _MSC_VER >= 1100
+ #define BLIP_RESTRICT __restrict
+ #else
+ #define BLIP_RESTRICT
+ #endif
+
+// Optimized reading from Blip_Buffer, for use in custom sample output
+
+// Begins reading from buffer. Name should be unique to the current block.
+#define BLIP_READER_BEGIN( name, blip_buffer ) \
+ const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\
+ blip_long name##_reader_accum = (blip_buffer).reader_accum_
+
+// Gets value to pass to BLIP_READER_NEXT()
+#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)
+
+// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal
+// code at the cost of having no bass control
+int const blip_reader_default_bass = 9;
+
+// Current sample
+#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16))
+
+// Current raw sample in full internal resolution
+#define BLIP_READER_READ_RAW( name ) (name##_reader_accum)
+
+// Advances to next sample
+#define BLIP_READER_NEXT( name, bass ) \
+ (void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))
+
+// Ends reading samples from buffer. The number of samples read must now be removed
+// using Blip_Buffer::remove_samples().
+#define BLIP_READER_END( name, blip_buffer ) \
+ (void) ((blip_buffer).reader_accum_ = name##_reader_accum)
+
+
+// experimental
+#define BLIP_READER_ADJ_( name, offset ) (name##_reader_buf += offset)
+
+blip_long const blip_reader_idx_factor = sizeof (Blip_Buffer::buf_t_);
+
+#define BLIP_READER_NEXT_IDX_( name, bass, idx ) {\
+ name##_reader_accum -= name##_reader_accum >> (bass);\
+ name##_reader_accum += name##_reader_buf [(idx)];\
+}
+
+#define BLIP_READER_NEXT_RAW_IDX_( name, bass, idx ) {\
+ name##_reader_accum -= name##_reader_accum >> (bass);\
+ name##_reader_accum +=\
+ *(Blip_Buffer::buf_t_ const*) ((char const*) name##_reader_buf + (idx));\
+}
+
+// Compatibility with older version
+const long blip_unscaled = 65535;
+const int blip_low_quality = blip_med_quality;
+const int blip_best_quality = blip_high_quality;
+
+// Deprecated; use BLIP_READER macros as follows:
+// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );
+// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );
+// r.read() -> BLIP_READER_READ( r )
+// r.read_raw() -> BLIP_READER_READ_RAW( r )
+// r.next( bass ) -> BLIP_READER_NEXT( r, bass )
+// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass )
+// r.end( buf ) -> BLIP_READER_END( r, buf )
+class Blip_Reader {
+public:
+ int begin( Blip_Buffer& );
+ blip_long read() const { return accum >> (blip_sample_bits - 16); }
+ blip_long read_raw() const { return accum; }
+ void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
+ void end( Blip_Buffer& b ) { b.reader_accum_ = accum; }
+private:
+ const Blip_Buffer::buf_t_* buf;
+ blip_long accum;
+};
+
+#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
+ defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
+ #define BLIP_CLAMP_( in ) in < -0x8000 || 0x7FFF < in
+#else
+ #define BLIP_CLAMP_( in ) (blip_sample_t) in != in
+#endif
+
+// Clamp sample to blip_sample_t range
+#define BLIP_CLAMP( sample, out )\
+ { if ( BLIP_CLAMP_( (sample) ) ) (out) = ((sample) >> 24) ^ 0x7FFF; }
+
+struct blip_buffer_state_t
+{
+ blip_resampled_time_t offset_;
+ blip_long reader_accum_;
+ blip_long buf [blip_buffer_extra_];
+};
+
+// End of public interface
+
+#ifndef assert
+ #include <assert.h>
+#endif
+
+template<int quality,int range>
+inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
+ int delta, Blip_Buffer* blip_buf ) const
+{
+ // If this assertion fails, it means that an attempt was made to add a delta
+ // at a negative time or past the end of the buffer.
+ assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
+
+ delta *= impl.delta_factor;
+ blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
+ int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
+
+#if BLIP_BUFFER_FAST
+ blip_long left = buf [0] + delta;
+
+ // Kind of crappy, but doing shift after multiply results in overflow.
+ // Alternate way of delaying multiply by delta_factor results in worse
+ // sub-sample resolution.
+ blip_long right = (delta >> BLIP_PHASE_BITS) * phase;
+ left -= right;
+ right += buf [1];
+
+ buf [0] = left;
+ buf [1] = right;
+#else
+
+ int const fwd = (blip_widest_impulse_ - quality) / 2;
+ int const rev = fwd + quality - 2;
+ int const mid = quality / 2 - 1;
+
+ imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;
+
+ #if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
+ defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
+
+ // this straight forward version gave in better code on GCC for x86
+
+ #define ADD_IMP( out, in ) \
+ buf [out] += (blip_long) imp [blip_res * (in)] * delta
+
+ #define BLIP_FWD( i ) {\
+ ADD_IMP( fwd + i, i );\
+ ADD_IMP( fwd + 1 + i, i + 1 );\
+ }
+ #define BLIP_REV( r ) {\
+ ADD_IMP( rev - r, r + 1 );\
+ ADD_IMP( rev + 1 - r, r );\
+ }
+
+ BLIP_FWD( 0 )
+ if ( quality > 8 ) BLIP_FWD( 2 )
+ if ( quality > 12 ) BLIP_FWD( 4 )
+ {
+ ADD_IMP( fwd + mid - 1, mid - 1 );
+ ADD_IMP( fwd + mid , mid );
+ imp = impulses + phase;
+ }
+ if ( quality > 12 ) BLIP_REV( 6 )
+ if ( quality > 8 ) BLIP_REV( 4 )
+ BLIP_REV( 2 )
+
+ ADD_IMP( rev , 1 );
+ ADD_IMP( rev + 1, 0 );
+
+ #undef ADD_IMP
+
+ #else
+
+ // for RISC processors, help compiler by reading ahead of writes
+
+ #define BLIP_FWD( i ) {\
+ blip_long t0 = i0 * delta + buf [fwd + i];\
+ blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\
+ i0 = imp [blip_res * (i + 2)];\
+ buf [fwd + i] = t0;\
+ buf [fwd + 1 + i] = t1;\
+ }
+ #define BLIP_REV( r ) {\
+ blip_long t0 = i0 * delta + buf [rev - r];\
+ blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\
+ i0 = imp [blip_res * (r - 1)];\
+ buf [rev - r] = t0;\
+ buf [rev + 1 - r] = t1;\
+ }
+
+ blip_long i0 = *imp;
+ BLIP_FWD( 0 )
+ if ( quality > 8 ) BLIP_FWD( 2 )
+ if ( quality > 12 ) BLIP_FWD( 4 )
+ {
+ blip_long t0 = i0 * delta + buf [fwd + mid - 1];
+ blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ];
+ imp = impulses + phase;
+ i0 = imp [blip_res * mid];
+ buf [fwd + mid - 1] = t0;
+ buf [fwd + mid ] = t1;
+ }
+ if ( quality > 12 ) BLIP_REV( 6 )
+ if ( quality > 8 ) BLIP_REV( 4 )
+ BLIP_REV( 2 )
+
+ blip_long t0 = i0 * delta + buf [rev ];
+ blip_long t1 = *imp * delta + buf [rev + 1];
+ buf [rev ] = t0;
+ buf [rev + 1] = t1;
+ #endif
+
+#endif
+}
+
+#undef BLIP_FWD
+#undef BLIP_REV
+
+template<int quality,int range>
+#if BLIP_BUFFER_FAST
+ inline
+#endif
+void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
+{
+ offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
+}
+
+template<int quality,int range>
+#if BLIP_BUFFER_FAST
+ inline
+#endif
+void Blip_Synth<quality,range>::update( blip_time_t t, int amp )
+{
+ int delta = amp - impl.last_amp;
+ impl.last_amp = amp;
+ offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
+}
+
+inline blip_eq_t::blip_eq_t( double t ) :
+ treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }
+inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :
+ treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }
+
+inline int Blip_Buffer::length() const { return length_; }
+inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }
+inline long Blip_Buffer::sample_rate() const { return sample_rate_; }
+inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }
+inline long Blip_Buffer::clock_rate() const { return clock_rate_; }
+inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }
+
+inline int Blip_Reader::begin( Blip_Buffer& blip_buf )
+{
+ buf = blip_buf.buffer_;
+ accum = blip_buf.reader_accum_;
+ return blip_buf.bass_shift_;
+}
+
+inline void Blip_Buffer::remove_silence( long count )
+{
+ // fails if you try to remove more samples than available
+ assert( count <= samples_avail() );
+ offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
+}
+
+inline blip_ulong Blip_Buffer::unsettled() const
+{
+ return reader_accum_ >> (blip_sample_bits - 16);
+}
+
+int const blip_max_length = 0;
+int const blip_default_length = 250; // 1/4 second
+
+#endif
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Effects_Buffer.cpp
@@ -1,1 +1,639 @@
-
+// Game_Music_Emu $vers. http://www.slack.net/~ant/
+
+#include "Effects_Buffer.h"
+
+#include <string.h>
+
+/* Copyright (C) 2006-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 */
+
+#include "blargg_source.h"
+
+int const fixed_shift = 12;
+#define TO_FIXED( f ) fixed_t ((f) * ((fixed_t) 1 << fixed_shift))
+#define FROM_FIXED( f ) ((f) >> fixed_shift)
+
+int const max_read = 2560; // determines minimum delay
+
+Effects_Buffer::Effects_Buffer( int max_bufs, long echo_size_ ) : Multi_Buffer( stereo )
+{
+ echo_size = max( max_read * (long) stereo, echo_size_ & ~1 );
+ clock_rate_ = 0;
+ bass_freq_ = 90;
+ bufs = 0;
+ bufs_size = 0;
+ bufs_max = max( max_bufs, (int) extra_chans );
+ no_echo = true;
+ no_effects = true;
+
+ // defaults
+ config_.enabled = false;
+ config_.delay [0] = 120;
+ config_.delay [1] = 122;
+ config_.feedback = 0.2f;
+ config_.treble = 0.4f;
+
+ static float const sep = 0.8f;
+ config_.side_chans [0].pan = -sep;
+ config_.side_chans [1].pan = +sep;
+ config_.side_chans [0].vol = 1.0f;
+ config_.side_chans [1].vol = 1.0f;
+
+ memset( &s, 0, sizeof s );
+ clear();
+}
+
+Effects_Buffer::~Effects_Buffer()
+{
+ delete_bufs();
+}
+
+// avoid using new []
+blargg_err_t Effects_Buffer::new_bufs( int size )
+{
+ bufs = (buf_t*) malloc( size * sizeof *bufs );
+ CHECK_ALLOC( bufs );
+ for ( int i = 0; i < size; i++ )
+ new (bufs + i) buf_t;
+ bufs_size = size;
+ return 0;
+}
+
+void Effects_Buffer::delete_bufs()
+{
+ if ( bufs )
+ {
+ for ( int i = bufs_size; --i >= 0; )
+ bufs [i].~buf_t();
+ free( bufs );
+ bufs = 0;
+ }
+ bufs_size = 0;
+}
+
+blargg_err_t Effects_Buffer::set_sample_rate( long rate, int msec )
+{
+ // extra to allow farther past-the-end pointers
+ mixer.samples_read = 0;
+ RETURN_ERR( echo.resize( echo_size + stereo ) );
+ return Multi_Buffer::set_sample_rate( rate, msec );
+}
+
+void Effects_Buffer::clock_rate( long rate )
+{
+ clock_rate_ = rate;
+ for ( int i = bufs_size; --i >= 0; )
+ bufs [i].clock_rate( clock_rate_ );
+}
+
+void Effects_Buffer::bass_freq( int freq )
+{
+ bass_freq_ = freq;
+ for ( int i = bufs_size; --i >= 0; )
+ bufs [i].bass_freq( bass_freq_ );
+}
+
+blargg_err_t Effects_Buffer::set_channel_count( int count, int const* types )
+{
+ RETURN_ERR( Multi_Buffer::set_channel_count( count, types ) );
+
+ delete_bufs();
+
+ mixer.samples_read = 0;
+
+ RETURN_ERR( chans.resize( count + extra_chans ) );
+
+ RETURN_ERR( new_bufs( min( bufs_max, count + extra_chans ) ) );
+
+ for ( int i = bufs_size; --i >= 0; )
+ RETURN_ERR( bufs [i].set_sample_rate( sample_rate(), length() ) );
+
+ for ( int i = chans.size(); --i >= 0; )
+ {
+ chan_t& ch = chans [i];
+ ch.cfg.vol = 1.0f;
+ ch.cfg.pan = 0.0f;
+ ch.cfg.surround = false;
+ ch.cfg.echo = false;
+ }
+ // side channels with echo
+ chans [2].cfg.echo = true;
+ chans [3].cfg.echo = true;
+
+ clock_rate( clock_rate_ );
+ bass_freq( bass_freq_ );
+ apply_config();
+ clear();
+
+ return 0;
+}
+
+void Effects_Buffer::clear_echo()
+{
+ if ( echo.size() )
+ memset( echo.begin(), 0, echo.size() * sizeof echo [0] );
+}
+
+void Effects_Buffer::clear()
+{
+ echo_pos = 0;
+ s.low_pass [0] = 0;
+ s.low_pass [1] = 0;
+ mixer.samples_read = 0;
+
+ for ( int i = bufs_size; --i >= 0; )
+ bufs [i].clear();
+ clear_echo();
+}
+
+Effects_Buffer::channel_t Effects_Buffer::channel( int i )
+{
+ i += extra_chans;
+ require( extra_chans <= i && i < (int) chans.size() );
+ return chans [i].channel;
+}
+
+
+// Configuration
+
+// 3 wave positions with/without surround, 2 multi (one with same config as wave)
+int const simple_bufs = 3 * 2 + 2 - 1;
+
+Simple_Effects_Buffer::Simple_Effects_Buffer() :
+ Effects_Buffer( extra_chans + simple_bufs, 18 * 1024L )
+{
+ config_.echo = 0.20f;
+ config_.stereo = 0.20f;
+ config_.surround = true;
+ config_.enabled = false;
+}
+
+void Simple_Effects_Buffer::apply_config()
+{
+ Effects_Buffer::config_t& c = Effects_Buffer::config();
+
+ c.enabled = config_.enabled;
+ if ( c.enabled )
+ {
+ c.delay [0] = 120;
+ c.delay [1] = 122;
+ c.feedback = config_.echo * 0.7f;
+ c.treble = 0.6f - 0.3f * config_.echo;
+
+ float sep = config_.stereo + 0.80f;
+ if ( sep > 1.0f )
+ sep = 1.0f;
+
+ c.side_chans [0].pan = -sep;
+ c.side_chans [1].pan = +sep;
+
+ for ( int i = channel_count(); --i >= 0; )
+ {
+ chan_config_t& ch = Effects_Buffer::chan_config( i );
+
+ ch.pan = 0.0f;
+ ch.surround = config_.surround;
+ ch.echo = false;
+
+ int const type = (channel_types() ? channel_types() [i] : 0);
+ if ( !(type & noise_type) )
+ {
+ int index = (type & type_index_mask) % 6 - 3;
+ if ( index < 0 )
+ {
+ index += 3;
+ ch.surround = false;
+ ch.echo = true;
+ }
+ if ( index >= 1 )
+ {
+ ch.pan = config_.stereo;
+ if ( index == 1 )
+ ch.pan = -ch.pan;
+ }
+ }
+ else if ( type & 1 )
+ {
+ ch.surround = false;
+ }
+ }
+ }
+
+ Effects_Buffer::apply_config();
+}
+
+int Effects_Buffer::min_delay() const
+{
+ require( sample_rate() );
+ return max_read * 1000L / sample_rate();
+}
+
+int Effects_Buffer::max_delay() const
+{
+ require( sample_rate() );
+ return (echo_size / stereo - max_read) * 1000L / sample_rate();
+}
+
+void Effects_Buffer::apply_config()
+{
+ int i;
+
+ if ( !bufs_size )
+ return;
+
+ s.treble = TO_FIXED( config_.treble );
+
+ bool echo_dirty = false;
+
+ fixed_t old_feedback = s.feedback;
+ s.feedback = TO_FIXED( config_.feedback );
+ if ( !old_feedback && s.feedback )
+ echo_dirty = true;
+
+ // delays
+ for ( i = stereo; --i >= 0; )
+ {
+ long delay = config_.delay [i] * sample_rate() / 1000 * stereo;
+ delay = max( delay, long (max_read * stereo) );
+ delay = min( delay, long (echo_size - max_read * stereo) );
+ if ( s.delay [i] != delay )
+ {
+ s.delay [i] = delay;
+ echo_dirty = true;
+ }
+ }
+
+ // side channels
+ for ( i = 2; --i >= 0; )
+ {
+ chans [i+2].cfg.vol = chans [i].cfg.vol = config_.side_chans [i].vol * 0.5f;
+ chans [i+2].cfg.pan = chans [i].cfg.pan = config_.side_chans [i].pan;
+ }
+
+ // convert volumes
+ for ( i = chans.size(); --i >= 0; )
+ {
+ chan_t& ch = chans [i];
+ ch.vol [0] = TO_FIXED( ch.cfg.vol - ch.cfg.vol * ch.cfg.pan );
+ ch.vol [1] = TO_FIXED( ch.cfg.vol + ch.cfg.vol * ch.cfg.pan );
+ if ( ch.cfg.surround )
+ ch.vol [0] = -ch.vol [0];
+ }
+
+ assign_buffers();
+
+ // set side channels
+ for ( i = chans.size(); --i >= 0; )
+ {
+ chan_t& ch = chans [i];
+ ch.channel.left = chans [ch.cfg.echo*2 ].channel.center;
+ ch.channel.right = chans [ch.cfg.echo*2+1].channel.center;
+ }
+
+ bool old_echo = !no_echo && !no_effects;
+
+ // determine whether effects and echo are needed at all
+ no_effects = true;
+ no_echo = true;
+ for ( i = chans.size(); --i >= extra_chans; )
+ {
+ chan_t& ch = chans [i];
+ if ( ch.cfg.echo && s.feedback )
+ no_echo = false;
+
+ if ( ch.vol [0] != TO_FIXED( 1 ) || ch.vol [1] != TO_FIXED( 1 ) )
+ no_effects = false;
+ }
+ if ( !no_echo )
+ no_effects = false;
+
+ if ( chans [0].vol [0] != TO_FIXED( 1 ) ||
+ chans [0].vol [1] != TO_FIXED( 0 ) ||
+ chans [1].vol [0] != TO_FIXED( 0 ) ||
+ chans [1].vol [1] != TO_FIXED( 1 ) )
+ no_effects = false;
+
+ if ( !config_.enabled )
+ no_effects = true;
+
+ if ( no_effects )
+ {
+ for ( i = chans.size(); --i >= 0; )
+ {
+ chan_t& ch = chans [i];
+ ch.channel.center = &bufs [2];
+ ch.channel.left = &bufs [0];
+ ch.channel.right = &bufs [1];
+ }
+ }
+
+ mixer.bufs [0] = &bufs [0];
+ mixer.bufs [1] = &bufs [1];
+ mixer.bufs [2] = &bufs [2];
+
+ if ( echo_dirty || (!old_echo && (!no_echo && !no_effects)) )
+ clear_echo();
+
+ channels_changed();
+}
+
+void Effects_Buffer::assign_buffers()
+{
+ // assign channels to buffers
+ int buf_count = 0;
+ for ( int i = 0; i < (int) chans.size(); i++ )
+ {
+ // put second two side channels at end to give priority to main channels
+ // in case closest matching is necessary
+ int x = i;
+ if ( i > 1 )
+ x += 2;
+ if ( x >= (int) chans.size() )
+ x -= (chans.size() - 2);
+ chan_t& ch = chans [x];
+
+ int b = 0;
+ for ( ; b < buf_count; b++ )
+ {
+ if ( ch.vol [0] == bufs [b].vol [0] &&
+ ch.vol [1] == bufs [b].vol [1] &&
+ (ch.cfg.echo == bufs [b].echo || !s.feedback) )
+ break;
+ }
+
+ if ( b >= buf_count )
+ {
+ if ( buf_count < bufs_max )
+ {
+ bufs [b].vol [0] = ch.vol [0];
+ bufs [b].vol [1] = ch.vol [1];
+ bufs [b].echo = ch.cfg.echo;
+ buf_count++;
+ }
+ else
+ {
+ // TODO: this is a mess, needs refinement
+ dprintf( "Effects_Buffer ran out of buffers; using closest match\n" );
+ b = 0;
+ fixed_t best_dist = TO_FIXED( 8 );
+ for ( int h = buf_count; --h >= 0; )
+ {
+ #define CALC_LEVELS( vols, sum, diff, surround ) \
+ fixed_t sum, diff;\
+ bool surround = false;\
+ {\
+ fixed_t vol_0 = vols [0];\
+ if ( vol_0 < 0 ) vol_0 = -vol_0, surround = true;\
+ fixed_t vol_1 = vols [1];\
+ if ( vol_1 < 0 ) vol_1 = -vol_1, surround = true;\
+ sum = vol_0 + vol_1;\
+ diff = vol_0 - vol_1;\
+ }
+ CALC_LEVELS( ch.vol, ch_sum, ch_diff, ch_surround );
+ CALC_LEVELS( bufs [h].vol, buf_sum, buf_diff, buf_surround );
+
+ fixed_t dist = abs( ch_sum - buf_sum ) + abs( ch_diff - buf_diff );
+
+ if ( ch_surround != buf_surround )
+ dist += TO_FIXED( 1 ) / 2;
+
+ if ( s.feedback && ch.cfg.echo != bufs [h].echo )
+ dist += TO_FIXED( 1 ) / 2;
+
+ if ( best_dist > dist )
+ {
+ best_dist = dist;
+ b = h;
+ }
+ }
+ }
+ }
+
+ //dprintf( "ch %d->buf %d\n", x, b );
+ ch.channel.center = &bufs [b];
+ }
+}
+
+
+// Mixing
+
+void Effects_Buffer::end_frame( blip_time_t time )
+{
+ for ( int i = bufs_size; --i >= 0; )
+ bufs [i].end_frame( time );
+}
+
+long Effects_Buffer::read_samples( blip_sample_t* out, long out_size )
+{
+ out_size = min( out_size, samples_avail() );
+
+ int pair_count = int (out_size >> 1);
+ require( pair_count * stereo == out_size ); // must read an even number of samples
+ if ( pair_count )
+ {
+ if ( no_effects )
+ {
+ mixer.read_pairs( out, pair_count );
+ }
+ else
+ {
+ int pairs_remain = pair_count;
+ do
+ {
+ // mix at most max_read pairs at a time
+ int count = max_read;
+ if ( count > pairs_remain )
+ count = pairs_remain;
+
+ if ( no_echo )
+ {
+ // optimization: clear echo here to keep mix_effects() a leaf function
+ echo_pos = 0;
+ memset( echo.begin(), 0, count * stereo * sizeof echo [0] );
+ }
+ mix_effects( out, count );
+
+ blargg_long new_echo_pos = echo_pos + count * stereo;
+ if ( new_echo_pos >= echo_size )
+ new_echo_pos -= echo_size;
+ echo_pos = new_echo_pos;
+ assert( echo_pos < echo_size );
+
+ out += count * stereo;
+ mixer.samples_read += count;
+ pairs_remain -= count;
+ }
+ while ( pairs_remain );
+ }
+
+ if ( samples_avail() <= 0 || immediate_removal() )
+ {
+ for ( int i = bufs_size; --i >= 0; )
+ {
+ buf_t& b = bufs [i];
+ // TODO: might miss non-silence settling since it checks END of last read
+ if ( b.non_silent() )
+ b.remove_samples( mixer.samples_read );
+ else
+ b.remove_silence( mixer.samples_read );
+ }
+ mixer.samples_read = 0;
+ }
+ }
+ return out_size;
+}
+
+void Effects_Buffer::mix_effects( blip_sample_t* out_, int pair_count )
+{
+ typedef fixed_t stereo_fixed_t [stereo];
+
+ // add channels with echo, do echo, add channels without echo, then convert to 16-bit and output
+ int echo_phase = 1;
+ do
+ {
+ // mix any modified buffers
+ {
+ buf_t* buf = bufs;
+ int bufs_remain = bufs_size;
+ do
+ {
+ if ( buf->non_silent() && ( buf->echo == !!echo_phase ) )
+ {
+ stereo_fixed_t* BLIP_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos];
+ int const bass = BLIP_READER_BASS( *buf );
+ BLIP_READER_BEGIN( in, *buf );
+ BLIP_READER_ADJ_( in, mixer.samples_read );
+ fixed_t const vol_0 = buf->vol [0];
+ fixed_t const vol_1 = buf->vol [1];
+
+ int count = unsigned (echo_size - echo_pos) / stereo;
+ int remain = pair_count;
+ if ( count > remain )
+ count = remain;
+ do
+ {
+ remain -= count;
+ BLIP_READER_ADJ_( in, count );
+
+ out += count;
+ int offset = -count;
+ do
+ {
+ fixed_t s = BLIP_READER_READ( in );
+ BLIP_READER_NEXT_IDX_( in, bass, offset );
+
+ out [offset] [0] += s * vol_0;
+ out [offset] [1] += s * vol_1;
+ }
+ while ( ++offset );
+
+ out = (stereo_fixed_t*) echo.begin();
+ count = remain;
+ }
+ while ( remain );
+
+ BLIP_READER_END( in, *buf );
+ }
+ buf++;
+ }
+ while ( --bufs_remain );
+ }
+
+ // add echo
+ if ( echo_phase && !no_echo )
+ {
+ fixed_t const feedback = s.feedback;
+ fixed_t const treble = s.treble;
+
+ int i = 1;
+ do
+ {
+ fixed_t low_pass = s.low_pass [i];
+
+ fixed_t* echo_end = &echo [echo_size + i];
+ fixed_t const* BLIP_RESTRICT in_pos = &echo [echo_pos + i];
+ blargg_long out_offset = echo_pos + i + s.delay [i];
+ if ( out_offset >= echo_size )
+ out_offset -= echo_size;
+ assert( out_offset < echo_size );
+ fixed_t* BLIP_RESTRICT out_pos = &echo [out_offset];
+
+ // break into up to three chunks to avoid having to handle wrap-around
+ // in middle of core loop
+ int remain = pair_count;
+ do
+ {
+ fixed_t const* pos = in_pos;
+ if ( pos < out_pos )
+ pos = out_pos;
+ int count = blargg_ulong ((char*) echo_end - (char const*) pos) /
+ unsigned (stereo * sizeof (fixed_t));
+ if ( count > remain )
+ count = remain;
+ remain -= count;
+
+ in_pos += count * stereo;
+ out_pos += count * stereo;
+ int offset = -count;
+ do
+ {
+ low_pass += FROM_FIXED( in_pos [offset * stereo] - low_pass ) * treble;
+ out_pos [offset * stereo] = FROM_FIXED( low_pass ) * feedback;
+ }
+ while ( ++offset );
+
+ if ( in_pos >= echo_end ) in_pos -= echo_size;
+ if ( out_pos >= echo_end ) out_pos -= echo_size;
+ }
+ while ( remain );
+
+ s.low_pass [i] = low_pass;
+ }
+ while ( --i >= 0 );
+ }
+ }
+ while ( --echo_phase >= 0 );
+
+ // clamp to 16 bits
+ {
+ stereo_fixed_t const* BLIP_RESTRICT in = (stereo_fixed_t*) &echo [echo_pos];
+ typedef blip_sample_t stereo_blip_sample_t [stereo];
+ stereo_blip_sample_t* BLIP_RESTRICT out = (stereo_blip_sample_t*) out_;
+ int count = unsigned (echo_size - echo_pos) / (unsigned) stereo;
+ int remain = pair_count;
+ if ( count > remain )
+ count = remain;
+ do
+ {
+ remain -= count;
+ in += count;
+ out += count;
+ int offset = -count;
+ do
+ {
+ fixed_t in_0 = FROM_FIXED( in [offset] [0] );
+ fixed_t in_1 = FROM_FIXED( in [offset] [1] );
+
+ BLIP_CLAMP( in_0, in_0 );
+ out [offset] [0] = (blip_sample_t) in_0;
+
+ BLIP_CLAMP( in_1, in_1 );
+ out [offset] [1] = (blip_sample_t) in_1;
+ }
+ while ( ++offset );
+
+ in = (stereo_fixed_t*) echo.begin();
+ count = remain;
+ }
+ while ( remain );
+ }
+}
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Effects_Buffer.h
@@ -1,1 +1,144 @@
+// Multi-channel effects buffer with echo and individual panning for each channel
+// Game_Music_Emu $vers
+#ifndef EFFECTS_BUFFER_H
+#define EFFECTS_BUFFER_H
+
+#include "Multi_Buffer.h"
+
+// See Simple_Effects_Buffer (below) for a simpler interface
+
+class Effects_Buffer : public Multi_Buffer {
+public:
+ // To reduce memory usage, fewer buffers can be used (with a best-fit
+ // approach if there are too few), and maximum echo delay can be reduced
+ Effects_Buffer( int max_bufs = 32, long echo_size = 24 * 1024L );
+
+ struct pan_vol_t
+ {
+ float vol; // 0.0 = silent, 0.5 = half volume, 1.0 = normal
+ float pan; // -1.0 = left, 0.0 = center, +1.0 = right
+ };
+
+ // Global configuration
+ struct config_t
+ {
+ bool enabled; // false = disable all effects
+
+ // Current sound is echoed at adjustable left/right delay,
+ // with reduced treble and volume (feedback).
+ float treble; // 1.0 = full treble, 0.1 = very little, 0.0 = silent
+ int delay [2]; // left, right delays (msec)
+ float feedback; // 0.0 = no echo, 0.5 = each echo half previous, 1.0 = cacophony
+ pan_vol_t side_chans [2]; // left and right side channel volume and pan
+ };
+ config_t& config() { return config_; }
+
+ // Limits of delay (msec)
+ int min_delay() const;
+ int max_delay() const;
+
+ // Per-channel configuration. Two or more channels with matching parameters are
+ // optimized to internally use the same buffer.
+ struct chan_config_t : pan_vol_t
+ {
+ // (inherited from pan_vol_t)
+ //float vol; // these only affect center channel
+ //float pan;
+ bool surround; // if true, negates left volume to put sound in back
+ bool echo; // false = channel doesn't have any echo
+ };
+ chan_config_t& chan_config( int i ) { return chans [i + extra_chans].cfg; }
+
+ // Apply any changes made to config() and chan_config()
+ virtual void apply_config();
+
+public:
+ ~Effects_Buffer();
+ blargg_err_t set_sample_rate( long samples_per_sec, int msec = blip_default_length );
+ blargg_err_t set_channel_count( int, int const* = 0 );
+ void clock_rate( long );
+ void bass_freq( int );
+ void clear();
+ channel_t channel( int );
+ void end_frame( blip_time_t );
+ long read_samples( blip_sample_t*, long );
+ long samples_avail() const { return (bufs [0].samples_avail() - mixer.samples_read) * 2; }
+ enum { stereo = 2 };
+ typedef blargg_long fixed_t;
+protected:
+ enum { extra_chans = stereo * stereo };
+private:
+ config_t config_;
+ long clock_rate_;
+ int bass_freq_;
+
+ blargg_long echo_size;
+
+ struct chan_t
+ {
+ fixed_t vol [stereo];
+ chan_config_t cfg;
+ channel_t channel;
+ };
+ blargg_vector<chan_t> chans;
+
+ struct buf_t : Tracked_Blip_Buffer
+ {
+ fixed_t vol [stereo];
+ bool echo;
+
+ void* operator new ( size_t, void* p ) { return p; }
+ void operator delete ( void* ) { }
+
+ ~buf_t() { }
+ };
+ buf_t* bufs;
+ int bufs_size;
+ int bufs_max; // bufs_size <= bufs_max, to limit memory usage
+ Stereo_Mixer mixer;
+
+ struct {
+ long delay [stereo];
+ fixed_t treble;
+ fixed_t feedback;
+ fixed_t low_pass [stereo];
+ } s;
+
+ blargg_vector<fixed_t> echo;
+ blargg_long echo_pos;
+
+ bool no_effects;
+ bool no_echo;
+
+ void assign_buffers();
+ void clear_echo();
+ void mix_effects( blip_sample_t* out, int pair_count );
+ blargg_err_t new_bufs( int size );
+ void delete_bufs();
+};
+
+// Simpler interface and lower memory usage
+class Simple_Effects_Buffer : public Effects_Buffer {
+public:
+ struct config_t
+ {
+ bool enabled; // false = disable all effects
+ float echo; // 0.0 = none, 1.0 = lots
+ float stereo; // 0.0 = channels in center, 1.0 = channels on left/right
+ bool surround; // true = put some channels in back
+ };
+ config_t& config() { return config_; }
+
+ // Apply any changes made to config()
+ void apply_config();
+
+public:
+ Simple_Effects_Buffer();
+private:
+ config_t config_;
+ void chan_config(); // hide
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Gb_Apu.cpp
@@ -1,1 +1,405 @@
-
+// Gb_Snd_Emu 0.2.0. http://www.slack.net/~ant/
+
+#include "Gb_Apu.h"
+
+/* Copyright (C) 2003-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 */
+
+#include "blargg_source.h"
+
+unsigned const vol_reg = 0xFF24;
+unsigned const stereo_reg = 0xFF25;
+unsigned const status_reg = 0xFF26;
+unsigned const wave_ram = 0xFF30;
+
+int const power_mask = 0x80;
+
+void Gb_Apu::treble_eq( blip_eq_t const& eq )
+{
+ good_synth.treble_eq( eq );
+ med_synth .treble_eq( eq );
+}
+
+inline int Gb_Apu::calc_output( int osc ) const
+{
+ int bits = regs [stereo_reg - start_addr] >> osc;
+ return (bits >> 3 & 2) | (bits & 1);
+}
+
+void Gb_Apu::set_output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right, int osc )
+{
+ // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL)
+ require( !center || (center && !left && !right) || (center && left && right) );
+ require( (unsigned) osc <= osc_count ); // fails if you pass invalid osc index
+
+ if ( !center || !left || !right )
+ {
+ left = center;
+ right = center;
+ }
+
+ int i = (unsigned) osc % osc_count;
+ do
+ {
+ Gb_Osc& o = *oscs [i];
+ o.outputs [1] = right;
+ o.outputs [2] = left;
+ o.outputs [3] = center;
+ o.output = o.outputs [calc_output( i )];
+ }
+ while ( ++i < osc );
+}
+
+void Gb_Apu::synth_volume( int iv )
+{
+ double v = volume_ * 0.60 / osc_count / 15 /*steps*/ / 8 /*master vol range*/ * iv;
+ good_synth.volume( v );
+ med_synth .volume( v );
+}
+
+void Gb_Apu::apply_volume()
+{
+ // TODO: Doesn't handle differing left and right volumes (panning).
+ // Not worth the complexity.
+ int data = regs [vol_reg - start_addr];
+ int left = data >> 4 & 7;
+ int right = data & 7;
+ //if ( data & 0x88 ) dprintf( "Vin: %02X\n", data & 0x88 );
+ //if ( left != right ) dprintf( "l: %d r: %d\n", left, right );
+ synth_volume( max( left, right ) + 1 );
+}
+
+void Gb_Apu::volume( double v )
+{
+ if ( volume_ != v )
+ {
+ volume_ = v;
+ apply_volume();
+ }
+}
+
+void Gb_Apu::reset_regs()
+{
+ for ( int i = 0; i < 0x20; i++ )
+ regs [i] = 0;
+
+ square1.reset();
+ square2.reset();
+ wave .reset();
+ noise .reset();
+
+ apply_volume();
+}
+
+void Gb_Apu::reset_lengths()
+{
+ square1.length_ctr = 64;
+ square2.length_ctr = 64;
+ wave .length_ctr = 256;
+ noise .length_ctr = 64;
+}
+
+void Gb_Apu::reduce_clicks( bool reduce )
+{
+ reduce_clicks_ = reduce;
+
+ // Click reduction makes DAC off generate same output as volume 0
+ int dac_off_amp = 0;
+ if ( reduce && wave.mode != mode_agb ) // AGB already eliminates clicks
+ dac_off_amp = -Gb_Osc::dac_bias;
+
+ for ( int i = 0; i < osc_count; i++ )
+ oscs [i]->dac_off_amp = dac_off_amp;
+
+ // AGB always eliminates clicks on wave channel using same method
+ if ( wave.mode == mode_agb )
+ wave.dac_off_amp = -Gb_Osc::dac_bias;
+}
+
+void Gb_Apu::reset( mode_t mode, bool agb_wave )
+{
+ // Hardware mode
+ if ( agb_wave )
+ mode = mode_agb; // using AGB wave features implies AGB hardware
+ wave.agb_mask = agb_wave ? 0xFF : 0;
+ for ( int i = 0; i < osc_count; i++ )
+ oscs [i]->mode = mode;
+ reduce_clicks( reduce_clicks_ );
+
+ // Reset state
+ frame_time = 0;
+ last_time = 0;
+ frame_phase = 0;
+
+ reset_regs();
+ reset_lengths();
+
+ // Load initial wave RAM
+ static byte const initial_wave [2] [16] = {
+ {0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C,0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA},
+ {0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF},
+ };
+ for ( int b = 2; --b >= 0; )
+ {
+ // Init both banks (does nothing if not in AGB mode)
+ // TODO: verify that this works
+ write_register( 0, 0xFF1A, b * 0x40 );
+ for ( unsigned i = 0; i < sizeof initial_wave [0]; i++ )
+ write_register( 0, i + wave_ram, initial_wave [(mode != mode_dmg)] [i] );
+ }
+}
+
+void Gb_Apu::set_tempo( double t )
+{
+ frame_period = 4194304 / 512; // 512 Hz
+ if ( t != 1.0 )
+ frame_period = blip_time_t (frame_period / t);
+}
+
+Gb_Apu::Gb_Apu()
+{
+ wave.wave_ram = ®s [wave_ram - start_addr];
+
+ oscs [0] = &square1;
+ oscs [1] = &square2;
+ oscs [2] = &wave;
+ oscs [3] = &noise;
+
+ for ( int i = osc_count; --i >= 0; )
+ {
+ Gb_Osc& o = *oscs [i];
+ o.regs = ®s [i * 5];
+ o.output = 0;
+ o.outputs [0] = 0;
+ o.outputs [1] = 0;
+ o.outputs [2] = 0;
+ o.outputs [3] = 0;
+ o.good_synth = &good_synth;
+ o.med_synth = &med_synth;
+ }
+
+ reduce_clicks_ = false;
+ set_tempo( 1.0 );
+ volume_ = 1.0;
+ reset();
+}
+
+void Gb_Apu::run_until_( blip_time_t end_time )
+{
+ while ( true )
+ {
+ // run oscillators
+ blip_time_t time = end_time;
+ if ( time > frame_time )
+ time = frame_time;
+
+ square1.run( last_time, time );
+ square2.run( last_time, time );
+ wave .run( last_time, time );
+ noise .run( last_time, time );
+ last_time = time;
+
+ if ( time == end_time )
+ break;
+
+ // run frame sequencer
+ frame_time += frame_period * Gb_Osc::clk_mul;
+ switch ( frame_phase++ )
+ {
+ case 2:
+ case 6:
+ // 128 Hz
+ square1.clock_sweep();
+ case 0:
+ case 4:
+ // 256 Hz
+ square1.clock_length();
+ square2.clock_length();
+ wave .clock_length();
+ noise .clock_length();
+ break;
+
+ case 7:
+ // 64 Hz
+ frame_phase = 0;
+ square1.clock_envelope();
+ square2.clock_envelope();
+ noise .clock_envelope();
+ }
+ }
+}
+
+inline void Gb_Apu::run_until( blip_time_t time )
+{
+ require( time >= last_time ); // end_time must not be before previous time
+ if ( time > last_time )
+ run_until_( time );
+}
+
+void Gb_Apu::end_frame( blip_time_t end_time )
+{
+ if ( end_time > last_time )
+ run_until( end_time );
+
+ frame_time -= end_time;
+ assert( frame_time >= 0 );
+
+ last_time -= end_time;
+ assert( last_time >= 0 );
+}
+
+void Gb_Apu::silence_osc( Gb_Osc& o )
+{
+ int delta = -o.last_amp;
+ if ( delta )
+ {
+ o.last_amp = 0;
+ if ( o.output )
+ {
+ o.output->set_modified();
+ med_synth.offset( last_time, delta, o.output );
+ }
+ }
+}
+
+void Gb_Apu::apply_stereo()
+{
+ for ( int i = osc_count; --i >= 0; )
+ {
+ Gb_Osc& o = *oscs [i];
+ Blip_Buffer* out = o.outputs [calc_output( i )];
+ if ( o.output != out )
+ {
+ silence_osc( o );
+ o.output = out;
+ }
+ }
+}
+
+void Gb_Apu::write_register( blip_time_t time, unsigned addr, int data )
+{
+ require( (unsigned) data < 0x100 );
+
+ int reg = addr - start_addr;
+ if ( (unsigned) reg >= register_count )
+ {
+ require( false );
+ return;
+ }
+
+ if ( addr < status_reg && !(regs [status_reg - start_addr] & power_mask) )
+ {
+ // Power is off
+
+ // length counters can only be written in DMG mode
+ if ( wave.mode != mode_dmg || (reg != 1 && reg != 5+1 && reg != 10+1 && reg != 15+1) )
+ return;
+
+ if ( reg < 10 )
+ data &= 0x3F; // clear square duty
+ }
+
+ run_until( time );
+
+ if ( addr >= wave_ram )
+ {
+ wave.write( addr, data );
+ }
+ else
+ {
+ int old_data = regs [reg];
+ regs [reg] = data;
+
+ if ( addr < vol_reg )
+ {
+ // Oscillator
+ write_osc( reg / 5, reg, old_data, data );
+ }
+ else if ( addr == vol_reg && data != old_data )
+ {
+ // Master volume
+ for ( int i = osc_count; --i >= 0; )
+ silence_osc( *oscs [i] );
+
+ apply_volume();
+ }
+ else if ( addr == stereo_reg )
+ {
+ // Stereo panning
+ apply_stereo();
+ }
+ else if ( addr == status_reg && (data ^ old_data) & power_mask )
+ {
+ // Power control
+ frame_phase = 0;
+ for ( int i = osc_count; --i >= 0; )
+ silence_osc( *oscs [i] );
+
+ reset_regs();
+ if ( wave.mode != mode_dmg )
+ reset_lengths();
+
+ regs [status_reg - start_addr] = data;
+ }
+ }
+}
+
+int Gb_Apu::read_register( blip_time_t time, unsigned addr )
+{
+ run_until( time );
+
+ int reg = addr - start_addr;
+ if ( (unsigned) reg >= register_count )
+ {
+ require( false );
+ return 0;
+ }
+
+ if ( addr >= wave_ram )
+ return wave.read( addr );
+
+ // Value read back has some bits always set
+ static byte const masks [] = {
+ 0x80,0x3F,0x00,0xFF,0xBF,
+ 0xFF,0x3F,0x00,0xFF,0xBF,
+ 0x7F,0xFF,0x9F,0xFF,0xBF,
+ 0xFF,0xFF,0x00,0x00,0xBF,
+ 0x00,0x00,0x70,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+ };
+ int mask = masks [reg];
+ if ( wave.agb_mask && (reg == 10 || reg == 12) )
+ mask = 0x1F; // extra implemented bits in wave regs on AGB
+ int data = regs [reg] | mask;
+
+ // Status register
+ if ( addr == status_reg )
+ {
+ data &= 0xF0;
+ data |= (int) square1.enabled << 0;
+ data |= (int) square2.enabled << 1;
+ data |= (int) wave .enabled << 2;
+ data |= (int) noise .enabled << 3;
+ }
+
+ return data;
+}
+
+int Gb_Apu::read_status()
+{
+ int data = 0;
+ data |= (int) square1.enabled << 0;
+ data |= (int) square2.enabled << 1;
+ data |= (int) wave .enabled << 2;
+ data |= (int) noise .enabled << 3;
+ return data;
+}
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Gb_Apu.h
@@ -1,1 +1,186 @@
+// Nintendo Game Boy sound hardware emulator with save state support
+// Gb_Snd_Emu 0.2.0
+#ifndef GB_APU_H
+#define GB_APU_H
+
+#include "Gb_Oscs.h"
+
+struct gb_apu_state_t;
+
+class Gb_Apu {
+public:
+// Basics
+
+ // Clock rate that sound hardware runs at.
+ enum { clock_rate = 4194304 * GB_APU_OVERCLOCK };
+
+ // Sets buffer(s) to generate sound into. If left and right are NULL, output is mono.
+ // If all are NULL, no output is generated but other emulation still runs.
+ // If chan is specified, only that channel's output is changed, otherwise all are.
+ enum { osc_count = 4 }; // 0: Square 1, 1: Square 2, 2: Wave, 3: Noise
+ void set_output( Blip_Buffer* center, Blip_Buffer* left = NULL, Blip_Buffer* right = NULL,
+ int chan = osc_count );
+
+ // Resets hardware to initial power on state BEFORE boot ROM runs. Mode selects
+ // sound hardware. Additional AGB wave features are enabled separately.
+ enum mode_t {
+ mode_dmg, // Game Boy monochrome
+ mode_cgb, // Game Boy Color
+ mode_agb // Game Boy Advance
+ };
+ void reset( mode_t mode = mode_cgb, bool agb_wave = false );
+
+ // Reads and writes must be within the start_addr to end_addr range, inclusive.
+ // Addresses outside this range are not mapped to the sound hardware.
+ enum { start_addr = 0xFF10 };
+ enum { end_addr = 0xFF3F };
+ enum { register_count = end_addr - start_addr + 1 };
+
+ // Times are specified as the number of clocks since the beginning of the
+ // current time frame.
+
+ // Emulates CPU write of data to addr at specified time.
+ void write_register( blip_time_t time, unsigned addr, int data );
+
+ // Emulates CPU read from addr at specified time.
+ int read_register( blip_time_t time, unsigned addr );
+
+ // Emulates sound hardware up to specified time, ends current time frame, then
+ // starts a new frame at time 0.
+ void end_frame( blip_time_t frame_length );
+
+// Sound adjustments
+
+ // Sets overall volume, where 1.0 is normal.
+ void volume( double );
+
+ // If true, reduces clicking by disabling DAC biasing. Note that this reduces
+ // emulation accuracy, since the clicks are authentic.
+ void reduce_clicks( bool reduce = true );
+
+ // Sets treble equalization.
+ void treble_eq( blip_eq_t const& );
+
+ // Treble and bass values for various hardware.
+ enum {
+ speaker_treble = -47, // speaker on system
+ speaker_bass = 2000,
+ dmg_treble = 0, // headphones on each system
+ dmg_bass = 30,
+ cgb_treble = 0,
+ cgb_bass = 300, // CGB has much less bass
+ agb_treble = 0,
+ agb_bass = 30
+ };
+
+ // Sets frame sequencer rate, where 1.0 is normal. Meant for adjusting the
+ // tempo in a game music player.
+ void set_tempo( double );
+
+// Save states
+
+ // Saves full emulation state to state_out. Data format is portable and
+ // includes some extra space to avoid expansion in case more state needs
+ // to be stored in the future.
+ void save_state( gb_apu_state_t* state_out );
+
+ // Loads state. You should call reset() BEFORE this.
+ blargg_err_t load_state( gb_apu_state_t const& in );
+
+public:
+ Gb_Apu();
+
+ // Use set_output() in place of these
+ BLARGG_DEPRECATED void output ( Blip_Buffer* c ) { set_output( c, c, c ); }
+ BLARGG_DEPRECATED void output ( Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( c, l, r ); }
+ BLARGG_DEPRECATED void osc_output( int i, Blip_Buffer* c ) { set_output( c, c, c, i ); }
+ BLARGG_DEPRECATED void osc_output( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) { set_output( c, l, r, i ); }
+
+private:
+ // noncopyable
+ Gb_Apu( const Gb_Apu& );
+ Gb_Apu& operator = ( const Gb_Apu& );
+
+ Gb_Osc* oscs [osc_count];
+ blip_time_t last_time; // time sound emulator has been run to
+ blip_time_t frame_period; // clocks between each frame sequencer step
+ double volume_;
+ bool reduce_clicks_;
+
+ Gb_Sweep_Square square1;
+ Gb_Square square2;
+ Gb_Wave wave;
+ Gb_Noise noise;
+ blip_time_t frame_time; // time of next frame sequencer action
+ int frame_phase; // phase of next frame sequencer step
+ enum { regs_size = register_count + 0x10 };
+ BOOST::uint8_t regs [regs_size];// last values written to registers
+
+ // large objects after everything else
+ Gb_Osc::Good_Synth good_synth;
+ Gb_Osc::Med_Synth med_synth;
+
+ void reset_lengths();
+ void reset_regs();
+ int calc_output( int osc ) const;
+ void apply_stereo();
+ void apply_volume();
+ void synth_volume( int );
+ void run_until_( blip_time_t );
+ void run_until( blip_time_t );
+ void silence_osc( Gb_Osc& );
+ void write_osc( int index, int reg, int old_data, int data );
+ const char* save_load( gb_apu_state_t*, bool save );
+ void save_load2( gb_apu_state_t*, bool save );
+ friend class Gb_Apu_Tester;
+
+public:
+ int read_status();
+};
+
+// Format of save state. Should be stable across versions of the library,
+// with earlier versions properly opening later save states. Includes some
+// room for expansion so the state size shouldn't increase.
+struct gb_apu_state_t
+{
+#if GB_APU_CUSTOM_STATE
+ // Values stored as plain int so your code can read/write them easily.
+ // Structure can NOT be written to disk, since format is not portable.
+ typedef int val_t;
+#else
+ // Values written in portable little-endian format, allowing structure
+ // to be written directly to disk.
+ typedef unsigned char val_t [4];
+#endif
+
+ enum { format0 = 0x50414247 };
+
+ val_t format; // format of all following data
+ val_t version; // later versions just add fields to end
+
+ unsigned char regs [0x40];
+ val_t frame_time;
+ val_t frame_phase;
+
+ val_t sweep_freq;
+ val_t sweep_delay;
+ val_t sweep_enabled;
+ val_t sweep_neg;
+ val_t noise_divider;
+ val_t wave_buf;
+
+ val_t delay [4];
+ val_t length_ctr [4];
+ val_t phase [4];
+ val_t enabled [4];
+
+ val_t env_delay [3];
+ val_t env_volume [3];
+ val_t env_enabled [3];
+
+ val_t unused [13]; // for future expansion
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Gb_Apu_State.cpp
@@ -1,1 +1,120 @@
+// Gb_Snd_Emu $vers. http://www.slack.net/~ant/
+#include "Gb_Apu.h"
+
+#include <string.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 */
+
+#include "blargg_source.h"
+
+#if GB_APU_CUSTOM_STATE
+ #define REFLECT( x, y ) (save ? (io->y) = (x) : (x) = (io->y) )
+#else
+ #define REFLECT( x, y ) (save ? set_val( io->y, x ) : (void) ((x) = get_val( io->y )))
+
+ static blargg_ulong get_val( byte const* p )
+ {
+ return p [3] * 0x1000000 + p [2] * 0x10000 + p [1] * 0x100 + p [0];
+ }
+
+ static void set_val( byte* p, blargg_ulong n )
+ {
+ p [0] = (byte) (n );
+ p [1] = (byte) (n >> 8);
+ p [2] = (byte) (n >> 16);
+ p [3] = (byte) (n >> 24);
+ }
+#endif
+
+inline const char* Gb_Apu::save_load( gb_apu_state_t* io, bool save )
+{
+ #if !GB_APU_CUSTOM_STATE
+ assert( sizeof (gb_apu_state_t) == 256 );
+ #endif
+
+ int format = io->format0;
+ REFLECT( format, format );
+ if ( format != io->format0 )
+ return "Unsupported sound save state format";
+
+ int version = 0;
+ REFLECT( version, version );
+
+ // Registers and wave RAM
+ assert( regs_size == sizeof io->regs );
+ if ( save )
+ memcpy( io->regs, regs, sizeof io->regs );
+ else
+ memcpy( regs, io->regs, sizeof regs );
+
+ // Frame sequencer
+ REFLECT( frame_time, frame_time );
+ REFLECT( frame_phase, frame_phase );
+
+ REFLECT( square1.sweep_freq, sweep_freq );
+ REFLECT( square1.sweep_delay, sweep_delay );
+ REFLECT( square1.sweep_enabled, sweep_enabled );
+ REFLECT( square1.sweep_neg, sweep_neg );
+
+ REFLECT( noise.divider, noise_divider );
+ REFLECT( wave.sample_buf, wave_buf );
+
+ return 0;
+}
+
+// second function to avoid inline limits of some compilers
+inline void Gb_Apu::save_load2( gb_apu_state_t* io, bool save )
+{
+ for ( int i = osc_count; --i >= 0; )
+ {
+ Gb_Osc& osc = *oscs [i];
+ REFLECT( osc.delay, delay [i] );
+ REFLECT( osc.length_ctr, length_ctr [i] );
+ REFLECT( osc.phase, phase [i] );
+ REFLECT( osc.enabled, enabled [i] );
+
+ if ( i != 2 )
+ {
+ int j = min( i, 2 );
+ Gb_Env& env = STATIC_CAST(Gb_Env&,osc);
+ REFLECT( env.env_delay, env_delay [j] );
+ REFLECT( env.volume, env_volume [j] );
+ REFLECT( env.env_enabled, env_enabled [j] );
+ }
+ }
+}
+
+void Gb_Apu::save_state( gb_apu_state_t* out )
+{
+ (void) save_load( out, true );
+ save_load2( out, true );
+
+ #if !GB_APU_CUSTOM_STATE
+ memset( out->unused, 0, sizeof out->unused );
+ #endif
+}
+
+blargg_err_t Gb_Apu::load_state( gb_apu_state_t const& in )
+{
+ RETURN_ERR( save_load( CONST_CAST(gb_apu_state_t*,&in), false ) );
+ save_load2( CONST_CAST(gb_apu_state_t*,&in), false );
+
+ apply_stereo();
+ synth_volume( 0 ); // suppress output for the moment
+ run_until_( last_time ); // get last_amp updated
+ apply_volume(); // now use correct volume
+
+ return 0;
+}
+
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Gb_Oscs.cpp
@@ -1,1 +1,666 @@
-
+// Gb_Snd_Emu 0.2.0. http://www.slack.net/~ant/
+
+#include "Gb_Apu.h"
+
+/* Copyright (C) 2003-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 */
+
+#include "blargg_source.h"
+
+bool const cgb_02 = false; // enables bug in early CGB units that causes problems in some games
+bool const cgb_05 = false; // enables CGB-05 zombie behavior
+
+int const trigger_mask = 0x80;
+int const length_enabled = 0x40;
+
+void Gb_Osc::reset()
+{
+ output = 0;
+ last_amp = 0;
+ delay = 0;
+ phase = 0;
+ enabled = false;
+}
+
+inline void Gb_Osc::update_amp( blip_time_t time, int new_amp )
+{
+ output->set_modified();
+ int delta = new_amp - last_amp;
+ if ( delta )
+ {
+ last_amp = new_amp;
+ med_synth->offset( time, delta, output );
+ }
+}
+
+// Units
+
+void Gb_Osc::clock_length()
+{
+ if ( (regs [4] & length_enabled) && length_ctr )
+ {
+ if ( --length_ctr <= 0 )
+ enabled = false;
+ }
+}
+
+inline int Gb_Env::reload_env_timer()
+{
+ int raw = regs [2] & 7;
+ env_delay = (raw ? raw : 8);
+ return raw;
+}
+
+void Gb_Env::clock_envelope()
+{
+ if ( env_enabled && --env_delay <= 0 && reload_env_timer() )
+ {
+ int v = volume + (regs [2] & 0x08 ? +1 : -1);
+ if ( 0 <= v && v <= 15 )
+ volume = v;
+ else
+ env_enabled = false;
+ }
+}
+
+inline void Gb_Sweep_Square::reload_sweep_timer()
+{
+ sweep_delay = (regs [0] & period_mask) >> 4;
+ if ( !sweep_delay )
+ sweep_delay = 8;
+}
+
+void Gb_Sweep_Square::calc_sweep( bool update )
+{
+ int const shift = regs [0] & shift_mask;
+ int const delta = sweep_freq >> shift;
+ sweep_neg = (regs [0] & 0x08) != 0;
+ int const freq = sweep_freq + (sweep_neg ? -delta : delta);
+
+ if ( freq > 0x7FF )
+ {
+ enabled = false;
+ }
+ else if ( shift && update )
+ {
+ sweep_freq = freq;
+
+ regs [3] = freq & 0xFF;
+ regs [4] = (regs [4] & ~0x07) | (freq >> 8 & 0x07);
+ }
+}
+
+void Gb_Sweep_Square::clock_sweep()
+{
+ if ( --sweep_delay <= 0 )
+ {
+ reload_sweep_timer();
+ if ( sweep_enabled && (regs [0] & period_mask) )
+ {
+ calc_sweep( true );
+ calc_sweep( false );
+ }
+ }
+}
+
+int Gb_Wave::access( unsigned addr ) const
+{
+ if ( enabled && mode != Gb_Apu::mode_agb )
+ {
+ addr = phase & (bank_size - 1);
+ if ( mode == Gb_Apu::mode_dmg )
+ {
+ addr++;
+ if ( delay > clk_mul )
+ return -1; // can only access within narrow time window while playing
+ }
+ addr >>= 1;
+ }
+ return addr & 0x0F;
+}
+
+// write_register
+
+int Gb_Osc::write_trig( int frame_phase, int max_len, int old_data )
+{
+ int data = regs [4];
+
+ if ( (frame_phase & 1) && !(old_data & length_enabled) && length_ctr )
+ {
+ if ( (data & length_enabled) || cgb_02 )
+ length_ctr--;
+ }
+
+ if ( data & trigger_mask )
+ {
+ enabled = true;
+ if ( !length_ctr )
+ {
+ length_ctr = max_len;
+ if ( (frame_phase & 1) && (data & length_enabled) )
+ length_ctr--;
+ }
+ }
+
+ if ( !length_ctr )
+ enabled = false;
+
+ return data & trigger_mask;
+}
+
+inline void Gb_Env::zombie_volume( int old, int data )
+{
+ int v = volume;
+ if ( mode == Gb_Apu::mode_agb || cgb_05 )
+ {
+ // CGB-05 behavior, very close to AGB behavior as well
+ if ( (old ^ data) & 8 )
+ {
+ if ( !(old & 8) )
+ {
+ v++;
+ if ( old & 7 )
+ v++;
+ }
+
+ v = 16 - v;
+ }
+ else if ( (old & 0x0F) == 8 )
+ {
+ v++;
+ }
+ }
+ else
+ {
+ // CGB-04&02 behavior, very close to MGB behavior as well
+ if ( !(old & 7) && env_enabled )
+ v++;
+ else if ( !(old & 8) )
+ v += 2;
+
+ if ( (old ^ data) & 8 )
+ v = 16 - v;
+ }
+ volume = v & 0x0F;
+}
+
+bool Gb_Env::write_register( int frame_phase, int reg, int old, int data )
+{
+ int const max_len = 64;
+
+ switch ( reg )
+ {
+ case 1:
+ length_ctr = max_len - (data & (max_len - 1));
+ break;
+
+ case 2:
+ if ( !dac_enabled() )
+ enabled = false;
+
+ zombie_volume( old, data );
+
+ if ( (data & 7) && env_delay == 8 )
+ {
+ env_delay = 1;
+ clock_envelope(); // TODO: really happens at next length clock
+ }
+ break;
+
+ case 4:
+ if ( write_trig( frame_phase, max_len, old ) )
+ {
+ volume = regs [2] >> 4;
+ reload_env_timer();
+ env_enabled = true;
+ if ( frame_phase == 7 )
+ env_delay++;
+ if ( !dac_enabled() )
+ enabled = false;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Gb_Square::write_register( int frame_phase, int reg, int old_data, int data )
+{
+ bool result = Gb_Env::write_register( frame_phase, reg, old_data, data );
+ if ( result )
+ delay = (delay & (4 * clk_mul - 1)) + period();
+ return result;
+}
+
+inline void Gb_Noise::write_register( int frame_phase, int reg, int old_data, int data )
+{
+ if ( Gb_Env::write_register( frame_phase, reg, old_data, data ) )
+ {
+ phase = 0x7FFF;
+ delay += 8 * clk_mul;
+ }
+}
+
+inline void Gb_Sweep_Square::write_register( int frame_phase, int reg, int old_data, int data )
+{
+ if ( reg == 0 && sweep_enabled && sweep_neg && !(data & 0x08) )
+ enabled = false; // sweep negate disabled after used
+
+ if ( Gb_Square::write_register( frame_phase, reg, old_data, data ) )
+ {
+ sweep_freq = frequency();
+ sweep_neg = false;
+ reload_sweep_timer();
+ sweep_enabled = (regs [0] & (period_mask | shift_mask)) != 0;
+ if ( regs [0] & shift_mask )
+ calc_sweep( false );
+ }
+}
+
+void Gb_Wave::corrupt_wave()
+{
+ int pos = ((phase + 1) & (bank_size - 1)) >> 1;
+ if ( pos < 4 )
+ wave_ram [0] = wave_ram [pos];
+ else
+ for ( int i = 4; --i >= 0; )
+ wave_ram [i] = wave_ram [(pos & ~3) + i];
+}
+
+inline void Gb_Wave::write_register( int frame_phase, int reg, int old_data, int data )
+{
+ int const max_len = 256;
+
+ switch ( reg )
+ {
+ case 0:
+ if ( !dac_enabled() )
+ enabled = false;
+ break;
+
+ case 1:
+ length_ctr = max_len - data;
+ break;
+
+ case 4:
+ bool was_enabled = enabled;
+ if ( write_trig( frame_phase, max_len, old_data ) )
+ {
+ if ( !dac_enabled() )
+ enabled = false;
+ else if ( mode == Gb_Apu::mode_dmg && was_enabled &&
+ (unsigned) (delay - 2 * clk_mul) < 2 * clk_mul )
+ corrupt_wave();
+
+ phase = 0;
+ delay = period() + 6 * clk_mul;
+ }
+ }
+}
+
+void Gb_Apu::write_osc( int index, int reg, int old_data, int data )
+{
+ reg -= index * 5;
+ switch ( index )
+ {
+ case 0: square1.write_register( frame_phase, reg, old_data, data ); break;
+ case 1: square2.write_register( frame_phase, reg, old_data, data ); break;
+ case 2: wave .write_register( frame_phase, reg, old_data, data ); break;
+ case 3: noise .write_register( frame_phase, reg, old_data, data ); break;
+ }
+}
+
+// Synthesis
+
+void Gb_Square::run( blip_time_t time, blip_time_t end_time )
+{
+ // Calc duty and phase
+ static byte const duty_offsets [4] = { 1, 1, 3, 7 };
+ static byte const duties [4] = { 1, 2, 4, 6 };
+ int const duty_code = regs [1] >> 6;
+ int duty_offset = duty_offsets [duty_code];
+ int duty = duties [duty_code];
+ if ( mode == Gb_Apu::mode_agb )
+ {
+ // AGB uses inverted duty
+ duty_offset -= duty;
+ duty = 8 - duty;
+ }
+ int ph = (this->phase + duty_offset) & 7;
+
+ // Determine what will be generated
+ int vol = 0;
+ Blip_Buffer* const out = this->output;
+ if ( out )
+ {
+ int amp = dac_off_amp;
+ if ( dac_enabled() )
+ {
+ if ( enabled )
+ vol = this->volume;
+
+ amp = -dac_bias;
+ if ( mode == Gb_Apu::mode_agb )
+ amp = -(vol >> 1);
+
+ // Play inaudible frequencies as constant amplitude
+ if ( frequency() >= 0x7FA && delay < 32 * clk_mul )
+ {
+ amp += (vol * duty) >> 3;
+ vol = 0;
+ }
+
+ if ( ph < duty )
+ {
+ amp += vol;
+ vol = -vol;
+ }
+ }
+ update_amp( time, amp );
+ }
+
+ // Generate wave
+ time += delay;
+ if ( time < end_time )
+ {
+ int const per = this->period();
+ if ( !vol )
+ {
+ // Maintain phase when not playing
+ int count = (end_time - time + per - 1) / per;
+ ph += count; // will be masked below
+ time += (blip_time_t) count * per;
+ }
+ else
+ {
+ // Output amplitude transitions
+ int delta = vol;
+ do
+ {
+ ph = (ph + 1) & 7;
+ if ( ph == 0 || ph == duty )
+ {
+ good_synth->offset_inline( time, delta, out );
+ delta = -delta;
+ }
+ time += per;
+ }
+ while ( time < end_time );
+
+ if ( delta != vol )
+ last_amp -= delta;
+ }
+ this->phase = (ph - duty_offset) & 7;
+ }
+ delay = time - end_time;
+}
+
+// Quickly runs LFSR for a large number of clocks. For use when noise is generating
+// no sound.
+static unsigned run_lfsr( unsigned s, unsigned mask, int count )
+{
+ bool const optimized = true; // set to false to use only unoptimized loop in middle
+
+ // optimization used in several places:
+ // ((s & (1 << b)) << n) ^ ((s & (1 << b)) << (n + 1)) = (s & (1 << b)) * (3 << n)
+
+ if ( mask == 0x4000 && optimized )
+ {
+ if ( count >= 32767 )
+ count %= 32767;
+
+ // Convert from Fibonacci to Galois configuration,
+ // shifted left 1 bit
+ s ^= (s & 1) * 0x8000;
+
+ // Each iteration is equivalent to clocking LFSR 255 times
+ while ( (count -= 255) > 0 )
+ s ^= ((s & 0xE) << 12) ^ ((s & 0xE) << 11) ^ (s >> 3);
+ count += 255;
+
+ // Each iteration is equivalent to clocking LFSR 15 times
+ // (interesting similarity to single clocking below)
+ while ( (count -= 15) > 0 )
+ s ^= ((s & 2) * (3 << 13)) ^ (s >> 1);
+ count += 15;
+
+ // Remaining singles
+ while ( --count >= 0 )
+ s = ((s & 2) * (3 << 13)) ^ (s >> 1);
+
+ // Convert back to Fibonacci configuration
+ s &= 0x7FFF;
+ }
+ else if ( count < 8 || !optimized )
+ {
+ // won't fully replace upper 8 bits, so have to do the unoptimized way
+ while ( --count >= 0 )
+ s = (s >> 1 | mask) ^ (mask & (0 - ((s - 1) & 2)));
+ }
+ else
+ {
+ if ( count > 127 )
+ {
+ count %= 127;
+ if ( !count )
+ count = 127; // must run at least once
+ }
+
+ // Need to keep one extra bit of history
+ s = s << 1 & 0xFF;
+
+ // Convert from Fibonacci to Galois configuration,
+ // shifted left 2 bits
+ s ^= (s & 2) * 0x80;
+
+ // Each iteration is equivalent to clocking LFSR 7 times
+ // (interesting similarity to single clocking below)
+ while ( (count -= 7) > 0 )
+ s ^= ((s & 4) * (3 << 5)) ^ (s >> 1);
+ count += 7;
+
+ // Remaining singles
+ while ( --count >= 0 )
+ s = ((s & 4) * (3 << 5)) ^ (s >> 1);
+
+ // Convert back to Fibonacci configuration and
+ // repeat last 8 bits above significant 7
+ s = (s << 7 & 0x7F80) | (s >> 1 & 0x7F);
+ }
+
+ return s;
+}
+
+void Gb_Noise::run( blip_time_t time, blip_time_t end_time )
+{
+ // Determine what will be generated
+ int vol = 0;
+ Blip_Buffer* const out = this->output;
+ if ( out )
+ {
+ int amp = dac_off_amp;
+ if ( dac_enabled() )
+ {
+ if ( enabled )
+ vol = this->volume;
+
+ amp = -dac_bias;
+ if ( mode == Gb_Apu::mode_agb )
+ amp = -(vol >> 1);
+
+ if ( !(phase & 1) )
+ {
+ amp += vol;
+ vol = -vol;
+ }
+ }
+
+ // AGB negates final output
+ if ( mode == Gb_Apu::mode_agb )
+ {
+ vol = -vol;
+ amp = -amp;
+ }
+
+ update_amp( time, amp );
+ }
+
+ // Run timer and calculate time of next LFSR clock
+ static byte const period1s [8] = { 1, 2, 4, 6, 8, 10, 12, 14 };
+ int const period1 = period1s [regs [3] & 7] * clk_mul;
+ {
+ int extra = (end_time - time) - delay;
+ int const per2 = this->period2();
+ time += delay + ((divider ^ (per2 >> 1)) & (per2 - 1)) * period1;
+
+ int count = (extra < 0 ? 0 : (extra + period1 - 1) / period1);
+ divider = (divider - count) & period2_mask;
+ delay = count * period1 - extra;
+ }
+
+ // Generate wave
+ if ( time < end_time )
+ {
+ unsigned const mask = this->lfsr_mask();
+ unsigned bits = this->phase;
+
+ int per = period2( period1 * 8 );
+ if ( period2_index() >= 0xE )
+ {
+ time = end_time;
+ }
+ else if ( !vol )
+ {
+ // Maintain phase when not playing
+ int count = (end_time - time + per - 1) / per;
+ time += (blip_time_t) count * per;
+ bits = run_lfsr( bits, ~mask, count );
+ }
+ else
+ {
+ // Output amplitude transitions
+ int delta = -vol;
+ do
+ {
+ unsigned changed = bits + 1;
+ bits = bits >> 1 & mask;
+ if ( changed & 2 )
+ {
+ bits |= ~mask;
+ delta = -delta;
+ med_synth->offset_inline( time, delta, out );
+ }
+ time += per;
+ }
+ while ( time < end_time );
+
+ if ( delta == vol )
+ last_amp += delta;
+ }
+ this->phase = bits;
+ }
+}
+
+void Gb_Wave::run( blip_time_t time, blip_time_t end_time )
+{
+ // Calc volume
+ static byte const volumes [8] = { 0, 4, 2, 1, 3, 3, 3, 3 };
+ int const volume_shift = 2;
+ int const volume_idx = regs [2] >> 5 & (agb_mask | 3); // 2 bits on DMG/CGB, 3 on AGB
+ int const volume_mul = volumes [volume_idx];
+
+ // Determine what will be generated
+ int playing = false;
+ Blip_Buffer* const out = this->output;
+ if ( out )
+ {
+ int amp = dac_off_amp;
+ if ( dac_enabled() )
+ {
+ // Play inaudible frequencies as constant amplitude
+ amp = 8 << 4; // really depends on average of all samples in wave
+
+ // if delay is larger, constant amplitude won't start yet
+ if ( frequency() <= 0x7FB || delay > 15 * clk_mul )
+ {
+ if ( volume_mul )
+ playing = (int) enabled;
+
+ amp = (sample_buf << (phase << 2 & 4) & 0xF0) * playing;
+ }
+
+ amp = ((amp * volume_mul) >> (volume_shift + 4)) - dac_bias;
+ }
+ update_amp( time, amp );
+ }
+
+ // Generate wave
+ time += delay;
+ if ( time < end_time )
+ {
+ byte const* wave = this->wave_ram;
+
+ // wave size and bank
+ int const size20_mask = 0x20;
+ int const flags = regs [0] & agb_mask;
+ int const wave_mask = (flags & size20_mask) | 0x1F;
+ int swap_banks = 0;
+ if ( flags & bank40_mask )
+ {
+ swap_banks = flags & size20_mask;
+ wave += bank_size/2 - (swap_banks >> 1);
+ }
+
+ int ph = this->phase ^ swap_banks;
+ ph = (ph + 1) & wave_mask; // pre-advance
+
+ int const per = this->period();
+ if ( !playing )
+ {
+ // Maintain phase when not playing
+ int count = (end_time - time + per - 1) / per;
+ ph += count; // will be masked below
+ time += (blip_time_t) count * per;
+ }
+ else
+ {
+ // Output amplitude transitions
+ int lamp = this->last_amp + dac_bias;
+ do
+ {
+ // Extract nybble
+ int nybble = wave [ph >> 1] << (ph << 2 & 4) & 0xF0;
+ ph = (ph + 1) & wave_mask;
+
+ // Scale by volume
+ int amp = (nybble * volume_mul) >> (volume_shift + 4);
+
+ int delta = amp - lamp;
+ if ( delta )
+ {
+ lamp = amp;
+ med_synth->offset_inline( time, delta, out );
+ }
+ time += per;
+ }
+ while ( time < end_time );
+ this->last_amp = lamp - dac_bias;
+ }
+ ph = (ph - 1) & wave_mask; // undo pre-advance and mask position
+
+ // Keep track of last byte read
+ if ( enabled )
+ sample_buf = wave [ph >> 1];
+
+ this->phase = ph ^ swap_banks; // undo swapped banks
+ }
+ delay = time - end_time;
+}
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Gb_Oscs.h
@@ -1,1 +1,192 @@
+// Private oscillators used by Gb_Apu
+// Gb_Snd_Emu 0.2.0
+#ifndef GB_OSCS_H
+#define GB_OSCS_H
+
+#include "blargg_common.h"
+#include "Blip_Buffer.h"
+
+#ifndef GB_APU_OVERCLOCK
+ #define GB_APU_OVERCLOCK 1
+#endif
+
+#if GB_APU_OVERCLOCK & (GB_APU_OVERCLOCK - 1)
+ #error "GB_APU_OVERCLOCK must be a power of 2"
+#endif
+
+class Gb_Osc {
+protected:
+
+ // 11-bit frequency in NRx3 and NRx4
+ int frequency() const { return (regs [4] & 7) * 0x100 + regs [3]; }
+
+ void update_amp( blip_time_t, int new_amp );
+ int write_trig( int frame_phase, int max_len, int old_data );
+public:
+
+ enum { clk_mul = GB_APU_OVERCLOCK };
+ enum { dac_bias = 7 };
+
+ Blip_Buffer* outputs [4];// NULL, right, left, center
+ Blip_Buffer* output; // where to output sound
+ BOOST::uint8_t* regs; // osc's 5 registers
+ int mode; // mode_dmg, mode_cgb, mode_agb
+ int dac_off_amp;// amplitude when DAC is off
+ int last_amp; // current amplitude in Blip_Buffer
+ typedef Blip_Synth<blip_good_quality,1> Good_Synth;
+ typedef Blip_Synth<blip_med_quality ,1> Med_Synth;
+ Good_Synth const* good_synth;
+ Med_Synth const* med_synth;
+
+ int delay; // clocks until frequency timer expires
+ int length_ctr; // length counter
+ unsigned phase; // waveform phase (or equivalent)
+ bool enabled; // internal enabled flag
+
+ void clock_length();
+ void reset();
+};
+
+class Gb_Env : public Gb_Osc {
+public:
+ Gb_Env() : env_enabled(false), env_delay(0) {}
+ int env_delay;
+ int volume;
+ bool env_enabled;
+
+ void clock_envelope();
+ bool write_register( int frame_phase, int reg, int old_data, int data );
+
+ void reset()
+ {
+ env_delay = 0;
+ volume = 0;
+ Gb_Osc::reset();
+ }
+protected:
+ // Non-zero if DAC is enabled
+ int dac_enabled() const { return regs [2] & 0xF8; }
+private:
+ void zombie_volume( int old, int data );
+ int reload_env_timer();
+};
+
+class Gb_Square : public Gb_Env {
+public:
+ bool write_register( int frame_phase, int reg, int old_data, int data );
+ void run( blip_time_t, blip_time_t );
+
+ void reset()
+ {
+ Gb_Env::reset();
+ delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger)
+ }
+private:
+ // Frequency timer period
+ int period() const { return (2048 - frequency()) * (4 * clk_mul); }
+};
+
+class Gb_Sweep_Square : public Gb_Square {
+public:
+ int sweep_freq;
+ int sweep_delay;
+ bool sweep_enabled;
+ bool sweep_neg;
+
+ void clock_sweep();
+ void write_register( int frame_phase, int reg, int old_data, int data );
+
+ void reset()
+ {
+ sweep_freq = 0;
+ sweep_delay = 0;
+ sweep_enabled = false;
+ sweep_neg = false;
+ Gb_Square::reset();
+ }
+private:
+ enum { period_mask = 0x70 };
+ enum { shift_mask = 0x07 };
+
+ void calc_sweep( bool update );
+ void reload_sweep_timer();
+};
+
+class Gb_Noise : public Gb_Env {
+public:
+
+ int divider; // noise has more complex frequency divider setup
+
+ void run( blip_time_t, blip_time_t );
+ void write_register( int frame_phase, int reg, int old_data, int data );
+
+ void reset()
+ {
+ divider = 0;
+ Gb_Env::reset();
+ delay = 4 * clk_mul; // TODO: remove?
+ }
+private:
+ enum { period2_mask = 0x1FFFF };
+
+ int period2_index() const { return regs [3] >> 4; }
+ int period2( int base = 8 ) const { return base << period2_index(); }
+ unsigned lfsr_mask() const { return (regs [3] & 0x08) ? ~0x4040 : ~0x4000; }
+};
+
+class Gb_Wave : public Gb_Osc {
+public:
+ int sample_buf; // last wave RAM byte read (hardware has this as well)
+
+ void write_register( int frame_phase, int reg, int old_data, int data );
+ void run( blip_time_t, blip_time_t );
+
+ // Reads/writes wave RAM
+ int read( unsigned addr ) const;
+ void write( unsigned addr, int data );
+
+ void reset()
+ {
+ sample_buf = 0;
+ Gb_Osc::reset();
+ }
+
+private:
+ enum { bank40_mask = 0x40 };
+ enum { bank_size = 32 };
+
+ int agb_mask; // 0xFF if AGB features enabled, 0 otherwise
+ BOOST::uint8_t* wave_ram; // 32 bytes (64 nybbles), stored in APU
+
+ friend class Gb_Apu;
+
+ // Frequency timer period
+ int period() const { return (2048 - frequency()) * (2 * clk_mul); }
+
+ // Non-zero if DAC is enabled
+ int dac_enabled() const { return regs [0] & 0x80; }
+
+ void corrupt_wave();
+
+ BOOST::uint8_t* wave_bank() const { return &wave_ram [(~regs [0] & bank40_mask) >> 2 & agb_mask]; }
+
+ // Wave index that would be accessed, or -1 if no access would occur
+ int access( unsigned addr ) const;
+};
+
+inline int Gb_Wave::read( unsigned addr ) const
+{
+ int index = access( addr );
+ return (index < 0 ? 0xFF : wave_bank() [index]);
+}
+
+inline void Gb_Wave::write( unsigned addr, int data )
+{
+ int index = access( addr );
+ if ( index >= 0 )
+ wave_bank() [index] = data;;
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Multi_Buffer.cpp
@@ -1,1 +1,282 @@
-
+// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
+
+#include "Multi_Buffer.h"
+
+/* Copyright (C) 2003-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 */
+
+#include "blargg_source.h"
+
+#ifdef BLARGG_ENABLE_OPTIMIZER
+ #include BLARGG_ENABLE_OPTIMIZER
+#endif
+
+Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf )
+{
+ length_ = 0;
+ sample_rate_ = 0;
+ channels_changed_count_ = 1;
+ channel_types_ = 0;
+ channel_count_ = 0;
+ immediate_removal_ = true;
+}
+
+Multi_Buffer::channel_t Multi_Buffer::channel( int /*index*/ )
+{
+ static channel_t const ch = { 0, 0, 0 };
+ return ch;
+}
+
+// Silent_Buffer
+
+Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse
+{
+ // TODO: better to use empty Blip_Buffer so caller never has to check for NULL?
+ chan.left = 0;
+ chan.center = 0;
+ chan.right = 0;
+}
+
+// Mono_Buffer
+
+Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 )
+{
+ chan.center = &buf;
+ chan.left = &buf;
+ chan.right = &buf;
+}
+
+Mono_Buffer::~Mono_Buffer() { }
+
+blargg_err_t Mono_Buffer::set_sample_rate( long rate, int msec )
+{
+ RETURN_ERR( buf.set_sample_rate( rate, msec ) );
+ return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() );
+}
+
+
+// Tracked_Blip_Buffer
+
+Tracked_Blip_Buffer::Tracked_Blip_Buffer()
+{
+ last_non_silence = 0;
+}
+
+void Tracked_Blip_Buffer::clear()
+{
+ last_non_silence = 0;
+ Blip_Buffer::clear();
+}
+
+void Tracked_Blip_Buffer::end_frame( blip_time_t t )
+{
+ Blip_Buffer::end_frame( t );
+ if ( clear_modified() )
+ last_non_silence = samples_avail() + blip_buffer_extra_;
+}
+
+blip_ulong Tracked_Blip_Buffer::non_silent() const
+{
+ return last_non_silence | unsettled();
+}
+
+inline void Tracked_Blip_Buffer::remove_( long n )
+{
+ if ( (last_non_silence -= n) < 0 )
+ last_non_silence = 0;
+}
+
+void Tracked_Blip_Buffer::remove_silence( long n )
+{
+ remove_( n );
+ Blip_Buffer::remove_silence( n );
+}
+
+void Tracked_Blip_Buffer::remove_samples( long n )
+{
+ remove_( n );
+ Blip_Buffer::remove_samples( n );
+}
+
+void Tracked_Blip_Buffer::remove_all_samples()
+{
+ long avail = samples_avail();
+ if ( !non_silent() )
+ remove_silence( avail );
+ else
+ remove_samples( avail );
+}
+
+long Tracked_Blip_Buffer::read_samples( blip_sample_t* out, long count )
+{
+ count = Blip_Buffer::read_samples( out, count );
+ remove_( count );
+ return count;
+}
+
+// Stereo_Buffer
+
+int const stereo = 2;
+
+Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 )
+{
+ chan.center = mixer.bufs [2] = &bufs [2];
+ chan.left = mixer.bufs [0] = &bufs [0];
+ chan.right = mixer.bufs [1] = &bufs [1];
+ mixer.samples_read = 0;
+}
+
+Stereo_Buffer::~Stereo_Buffer() { }
+
+blargg_err_t Stereo_Buffer::set_sample_rate( long rate, int msec )
+{
+ mixer.samples_read = 0;
+ for ( int i = bufs_size; --i >= 0; )
+ RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) );
+ return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() );
+}
+
+void Stereo_Buffer::clock_rate( long rate )
+{
+ for ( int i = bufs_size; --i >= 0; )
+ bufs [i].clock_rate( rate );
+}
+
+void Stereo_Buffer::bass_freq( int bass )
+{
+ for ( int i = bufs_size; --i >= 0; )
+ bufs [i].bass_freq( bass );
+}
+
+void Stereo_Buffer::clear()
+{
+ mixer.samples_read = 0;
+ for ( int i = bufs_size; --i >= 0; )
+ bufs [i].clear();
+}
+
+void Stereo_Buffer::end_frame( blip_time_t time )
+{
+ for ( int i = bufs_size; --i >= 0; )
+ bufs [i].end_frame( time );
+}
+
+long Stereo_Buffer::read_samples( blip_sample_t* out, long out_size )
+{
+ require( (out_size & 1) == 0 ); // must read an even number of samples
+ out_size = min( out_size, samples_avail() );
+
+ int pair_count = int (out_size >> 1);
+ if ( pair_count )
+ {
+ mixer.read_pairs( out, pair_count );
+
+ if ( samples_avail() <= 0 || immediate_removal() )
+ {
+ for ( int i = bufs_size; --i >= 0; )
+ {
+ buf_t& b = bufs [i];
+ // TODO: might miss non-silence settling since it checks END of last read
+ if ( !b.non_silent() )
+ b.remove_silence( mixer.samples_read );
+ else
+ b.remove_samples( mixer.samples_read );
+ }
+ mixer.samples_read = 0;
+ }
+ }
+ return out_size;
+}
+
+
+// Stereo_Mixer
+
+// mixers use a single index value to improve performance on register-challenged processors
+// offset goes from negative to zero
+
+void Stereo_Mixer::read_pairs( blip_sample_t* out, int count )
+{
+ // TODO: if caller never marks buffers as modified, uses mono
+ // except that buffer isn't cleared, so caller can encounter
+ // subtle problems and not realize the cause.
+ samples_read += count;
+ if ( bufs [0]->non_silent() | bufs [1]->non_silent() )
+ mix_stereo( out, count );
+ else
+ mix_mono( out, count );
+}
+
+void Stereo_Mixer::mix_mono( blip_sample_t* out_, int count )
+{
+ int const bass = BLIP_READER_BASS( *bufs [2] );
+ BLIP_READER_BEGIN( center, *bufs [2] );
+ BLIP_READER_ADJ_( center, samples_read );
+
+ typedef blip_sample_t stereo_blip_sample_t [stereo];
+ stereo_blip_sample_t* BLIP_RESTRICT out = (stereo_blip_sample_t*) out_ + count;
+ int offset = -count;
+ do
+ {
+ blargg_long s = BLIP_READER_READ( center );
+ BLIP_READER_NEXT_IDX_( center, bass, offset );
+ BLIP_CLAMP( s, s );
+
+ out [offset] [0] = (blip_sample_t) s;
+ out [offset] [1] = (blip_sample_t) s;
+ }
+ while ( ++offset );
+
+ BLIP_READER_END( center, *bufs [2] );
+}
+
+void Stereo_Mixer::mix_stereo( blip_sample_t* out_, int count )
+{
+ blip_sample_t* BLIP_RESTRICT out = out_ + count * stereo;
+
+ // do left + center and right + center separately to reduce register load
+ Tracked_Blip_Buffer* const* buf = &bufs [2];
+ while ( true ) // loop runs twice
+ {
+ --buf;
+ --out;
+
+ int const bass = BLIP_READER_BASS( *bufs [2] );
+ BLIP_READER_BEGIN( side, **buf );
+ BLIP_READER_BEGIN( center, *bufs [2] );
+
+ BLIP_READER_ADJ_( side, samples_read );
+ BLIP_READER_ADJ_( center, samples_read );
+
+ int offset = -count;
+ do
+ {
+ blargg_long s = BLIP_READER_READ_RAW( center ) + BLIP_READER_READ_RAW( side );
+ s >>= blip_sample_bits - 16;
+ BLIP_READER_NEXT_IDX_( side, bass, offset );
+ BLIP_READER_NEXT_IDX_( center, bass, offset );
+ BLIP_CLAMP( s, s );
+
+ ++offset; // before write since out is decremented to slightly before end
+ out [offset * stereo] = (blip_sample_t) s;
+ }
+ while ( offset );
+
+ BLIP_READER_END( side, **buf );
+
+ if ( buf != bufs )
+ continue;
+
+ // only end center once
+ BLIP_READER_END( center, *bufs [2] );
+ break;
+ }
+}
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/Multi_Buffer.h
@@ -1,1 +1,206 @@
-
+// Multi-channel sound buffer interface, and basic mono and stereo buffers
+
+// Blip_Buffer 0.4.1
+#ifndef MULTI_BUFFER_H
+#define MULTI_BUFFER_H
+
+#include "blargg_common.h"
+#include "Blip_Buffer.h"
+
+// Interface to one or more Blip_Buffers mapped to one or more channels
+// consisting of left, center, and right buffers.
+class Multi_Buffer {
+public:
+ Multi_Buffer( int samples_per_frame );
+ virtual ~Multi_Buffer() { }
+
+ // Sets the number of channels available and optionally their types
+ // (type information used by Effects_Buffer)
+ enum { type_index_mask = 0xFF };
+ enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type };
+ virtual blargg_err_t set_channel_count( int, int const* types = 0 );
+ int channel_count() const { return channel_count_; }
+
+ // Gets indexed channel, from 0 to channel count - 1
+ struct channel_t {
+ Blip_Buffer* center;
+ Blip_Buffer* left;
+ Blip_Buffer* right;
+ };
+ virtual channel_t channel( int index ) BLARGG_PURE( ; )
+
+ // See Blip_Buffer.h
+ virtual blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ) BLARGG_PURE( ; )
+ virtual void clock_rate( long ) BLARGG_PURE( { } )
+ virtual void bass_freq( int ) BLARGG_PURE( { } )
+ virtual void clear() BLARGG_PURE( { } )
+ long sample_rate() const;
+
+ // Length of buffer, in milliseconds
+ int length() const;
+
+ // See Blip_Buffer.h
+ virtual void end_frame( blip_time_t ) BLARGG_PURE( { } )
+
+ // Number of samples per output frame (1 = mono, 2 = stereo)
+ int samples_per_frame() const;
+
+ // Count of changes to channel configuration. Incremented whenever
+ // a change is made to any of the Blip_Buffers for any channel.
+ unsigned channels_changed_count() { return channels_changed_count_; }
+
+ // See Blip_Buffer.h
+ virtual long read_samples( blip_sample_t*, long ) BLARGG_PURE( { return 0; } )
+ virtual long samples_avail() const BLARGG_PURE( { return 0; } )
+
+public:
+ BLARGG_DISABLE_NOTHROW
+ void disable_immediate_removal() { immediate_removal_ = false; }
+protected:
+ bool immediate_removal() const { return immediate_removal_; }
+ int const* channel_types() const { return channel_types_; }
+ void channels_changed() { channels_changed_count_++; }
+private:
+ // noncopyable
+ Multi_Buffer( const Multi_Buffer& );
+ Multi_Buffer& operator = ( const Multi_Buffer& );
+
+ unsigned channels_changed_count_;
+ long sample_rate_;
+ int length_;
+ int channel_count_;
+ int const samples_per_frame_;
+ int const* channel_types_;
+ bool immediate_removal_;
+};
+
+// Uses a single buffer and outputs mono samples.
+class Mono_Buffer : public Multi_Buffer {
+ Blip_Buffer buf;
+ channel_t chan;
+public:
+ // Buffer used for all channels
+ Blip_Buffer* center() { return &buf; }
+
+public:
+ Mono_Buffer();
+ ~Mono_Buffer();
+ blargg_err_t set_sample_rate( long rate, int msec = blip_default_length );
+ void clock_rate( long rate ) { buf.clock_rate( rate ); }
+ void bass_freq( int freq ) { buf.bass_freq( freq ); }
+ void clear() { buf.clear(); }
+ long samples_avail() const { return buf.samples_avail(); }
+ long read_samples( blip_sample_t* p, long s ) { return buf.read_samples( p, s ); }
+ channel_t channel( int ) { return chan; }
+ void end_frame( blip_time_t t ) { buf.end_frame( t ); }
+};
+
+ class Tracked_Blip_Buffer : public Blip_Buffer {
+ public:
+ // Non-zero if buffer still has non-silent samples in it. Requires that you call
+ // set_modified() appropriately.
+ blip_ulong non_silent() const;
+
+ // remove_samples( samples_avail() )
+ void remove_all_samples();
+
+ public:
+ BLARGG_DISABLE_NOTHROW
+
+ long read_samples( blip_sample_t*, long );
+ void remove_silence( long );
+ void remove_samples( long );
+ Tracked_Blip_Buffer();
+ void clear();
+ void end_frame( blip_time_t );
+ private:
+ blip_long last_non_silence;
+ void remove_( long );
+ };
+
+ class Stereo_Mixer {
+ public:
+ Tracked_Blip_Buffer* bufs [3];
+ blargg_long samples_read;
+
+ Stereo_Mixer() : samples_read( 0 ) { }
+ void read_pairs( blip_sample_t* out, int count );
+ private:
+ void mix_mono ( blip_sample_t* out, int pair_count );
+ void mix_stereo( blip_sample_t* out, int pair_count );
+ };
+
+// Uses three buffers (one for center) and outputs stereo sample pairs.
+class Stereo_Buffer : public Multi_Buffer {
+public:
+
+ // Buffers used for all channels
+ Blip_Buffer* center() { return &bufs [2]; }
+ Blip_Buffer* left() { return &bufs [0]; }
+ Blip_Buffer* right() { return &bufs [1]; }
+
+public:
+ Stereo_Buffer();
+ ~Stereo_Buffer();
+ blargg_err_t set_sample_rate( long, int msec = blip_default_length );
+ void clock_rate( long );
+ void bass_freq( int );
+ void clear();
+ channel_t channel( int ) { return chan; }
+ void end_frame( blip_time_t );
+
+ long samples_avail() const { return (bufs [0].samples_avail() - mixer.samples_read) * 2; }
+ long read_samples( blip_sample_t*, long );
+
+private:
+ enum { bufs_size = 3 };
+ typedef Tracked_Blip_Buffer buf_t;
+ buf_t bufs [bufs_size];
+ Stereo_Mixer mixer;
+ channel_t chan;
+ long samples_avail_;
+};
+
+// Silent_Buffer generates no samples, useful where no sound is wanted
+class Silent_Buffer : public Multi_Buffer {
+ channel_t chan;
+public:
+ Silent_Buffer();
+ blargg_err_t set_sample_rate( long rate, int msec = blip_default_length );
+ void clock_rate( long ) { }
+ void bass_freq( int ) { }
+ void clear() { }
+ channel_t channel( int ) { return chan; }
+ void end_frame( blip_time_t ) { }
+ long samples_avail() const { return 0; }
+ long read_samples( blip_sample_t*, long ) { return 0; }
+};
+
+
+inline blargg_err_t Multi_Buffer::set_sample_rate( long rate, int msec )
+{
+ sample_rate_ = rate;
+ length_ = msec;
+ return 0;
+}
+
+inline blargg_err_t Silent_Buffer::set_sample_rate( long rate, int msec )
+{
+ return Multi_Buffer::set_sample_rate( rate, msec );
+}
+
+inline int Multi_Buffer::samples_per_frame() const { return samples_per_frame_; }
+
+inline long Multi_Buffer::sample_rate() const { return sample_rate_; }
+
+inline int Multi_Buffer::length() const { return length_; }
+
+inline blargg_err_t Multi_Buffer::set_channel_count( int n, int const* types )
+{
+ channel_count_ = n;
+ channel_types_ = types;
+ return 0;
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/blargg_common.h
@@ -1,1 +1,207 @@
-
+// Sets up common environment for Shay Green's libraries.
+// To change configuration options, modify blargg_config.h, not this file.
+
+// Gb_Snd_Emu 0.2.0
+#ifndef BLARGG_COMMON_H
+#define BLARGG_COMMON_H
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+
+#undef BLARGG_COMMON_H
+// allow blargg_config.h to #include blargg_common.h
+#include "blargg_config.h"
+#ifndef BLARGG_COMMON_H
+#define BLARGG_COMMON_H
+
+// BLARGG_RESTRICT: equivalent to restrict, where supported
+#if __GNUC__ >= 3 || _MSC_VER >= 1100
+ #define BLARGG_RESTRICT __restrict
+#else
+ #define BLARGG_RESTRICT
+#endif
+
+// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
+// CONST_CAST( T,expr): Used in place of const_cast<T> (expr)
+#ifndef STATIC_CAST
+ #if __GNUC__ >= 4
+ #define STATIC_CAST(T,expr) static_cast<T> (expr)
+ #define CONST_CAST( T,expr) const_cast<T> (expr)
+ #else
+ #define STATIC_CAST(T,expr) ((T) (expr))
+ #define CONST_CAST( T,expr) ((T) (expr))
+ #endif
+#endif
+
+// blargg_err_t (0 on success, otherwise error string)
+#ifndef blargg_err_t
+ typedef const char* blargg_err_t;
+#endif
+
+// blargg_vector - very lightweight vector of POD types (no constructor/destructor)
+template<class T>
+class blargg_vector {
+ T* begin_;
+ size_t size_;
+public:
+ blargg_vector() : begin_( 0 ), size_( 0 ) { }
+ ~blargg_vector() { free( begin_ ); }
+ size_t size() const { return size_; }
+ T* begin() const { return begin_; }
+ T* end() const { return begin_ + size_; }
+ blargg_err_t resize( size_t n )
+ {
+ // TODO: blargg_common.cpp to hold this as an outline function, ugh
+ void* p = realloc( begin_, n * sizeof (T) );
+ if ( p )
+ begin_ = (T*) p;
+ else if ( n > size_ ) // realloc failure only a problem if expanding
+ return "Out of memory";
+ size_ = n;
+ return 0;
+ }
+ void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); }
+ T& operator [] ( size_t n ) const
+ {
+ assert( n <= size_ ); // <= to allow past-the-end value
+ return begin_ [n];
+ }
+};
+
+#ifndef BLARGG_DISABLE_NOTHROW
+ // throw spec mandatory in ISO C++ if operator new can return NULL
+ #if __cplusplus >= 199711 || __GNUC__ >= 3
+ #define BLARGG_THROWS( spec ) throw spec
+ #else
+ #define BLARGG_THROWS( spec )
+ #endif
+ #define BLARGG_DISABLE_NOTHROW \
+ void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\
+ void operator delete ( void* p ) { free( p ); }
+ #define BLARGG_NEW new
+#else
+ #include <new>
+ #define BLARGG_NEW new (std::nothrow)
+#endif
+
+// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant)
+#define BLARGG_4CHAR( a, b, c, d ) \
+ ((a&0xFF)*0x1000000 + (b&0xFF)*0x10000 + (c&0xFF)*0x100 + (d&0xFF))
+
+// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
+#ifndef BOOST_STATIC_ASSERT
+ #ifdef _MSC_VER
+ // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified
+ #define BOOST_STATIC_ASSERT( expr ) \
+ void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] )
+ #else
+ // Some other compilers fail when declaring same function multiple times in class,
+ // so differentiate them by line
+ #define BOOST_STATIC_ASSERT( expr ) \
+ void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] )
+ #endif
+#endif
+
+// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1,
+// compiler is assumed to support bool. If undefined, availability is determined.
+#ifndef BLARGG_COMPILER_HAS_BOOL
+ #if defined (__MWERKS__)
+ #if !__option(bool)
+ #define BLARGG_COMPILER_HAS_BOOL 0
+ #endif
+ #elif defined (_MSC_VER)
+ #if _MSC_VER < 1100
+ #define BLARGG_COMPILER_HAS_BOOL 0
+ #endif
+ #elif defined (__GNUC__)
+ // supports bool
+ #elif __cplusplus < 199711
+ #define BLARGG_COMPILER_HAS_BOOL 0
+ #endif
+#endif
+#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
+ // If you get errors here, modify your blargg_config.h file
+ typedef int bool;
+ const bool true = 1;
+ const bool false = 0;
+#endif
+
+// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough
+
+#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF
+ typedef long blargg_long;
+#else
+ typedef int blargg_long;
+#endif
+
+#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF
+ typedef unsigned long blargg_ulong;
+#else
+ typedef unsigned blargg_ulong;
+#endif
+
+// BOOST::int8_t etc.
+
+// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
+#if defined (HAVE_STDINT_H)
+ #include <stdint.h>
+ #define BOOST
+
+// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
+#elif defined (HAVE_INTTYPES_H)
+ #include <inttypes.h>
+ #define BOOST
+
+#else
+ struct BOOST
+ {
+ #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F
+ typedef signed char int8_t;
+ typedef unsigned char uint8_t;
+ #else
+ // No suitable 8-bit type available
+ typedef struct see_blargg_common_h int8_t;
+ typedef struct see_blargg_common_h uint8_t;
+ #endif
+
+ #if USHRT_MAX == 0xFFFF
+ typedef short int16_t;
+ typedef unsigned short uint16_t;
+ #else
+ // No suitable 16-bit type available
+ typedef struct see_blargg_common_h int16_t;
+ typedef struct see_blargg_common_h uint16_t;
+ #endif
+
+ #if ULONG_MAX == 0xFFFFFFFF
+ typedef long int32_t;
+ typedef unsigned long uint32_t;
+ #elif UINT_MAX == 0xFFFFFFFF
+ typedef int int32_t;
+ typedef unsigned int uint32_t;
+ #else
+ // No suitable 32-bit type available
+ typedef struct see_blargg_common_h int32_t;
+ typedef struct see_blargg_common_h uint32_t;
+ #endif
+ };
+#endif
+
+#if __GNUC__ >= 3
+ #define BLARGG_DEPRECATED __attribute__ ((deprecated))
+#else
+ #define BLARGG_DEPRECATED
+#endif
+
+// Use in place of "= 0;" for a pure virtual, since these cause calls to std C++ lib.
+// During development, BLARGG_PURE( x ) expands to = 0;
+// virtual int func() BLARGG_PURE( { return 0; } )
+#ifndef BLARGG_PURE
+ #define BLARGG_PURE( def ) def
+#endif
+
+#endif
+#endif
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/blargg_config.h
@@ -1,1 +1,34 @@
+// $package user configuration file. Don't replace when updating library.
+#ifndef BLARGG_CONFIG_H
+#define BLARGG_CONFIG_H
+
+// Uncomment to have Gb_Apu run at 4x normal clock rate (16777216 Hz), useful in
+// a Game Boy Advance emulator.
+#define GB_APU_OVERCLOCK 4
+
+#define GB_APU_CUSTOM_STATE 1
+
+// Uncomment to enable platform-specific (and possibly non-portable) optimizations.
+//#define BLARGG_NONPORTABLE 1
+
+// Uncomment if automatic byte-order determination doesn't work
+//#define BLARGG_BIG_ENDIAN 1
+
+// Uncomment to use zlib for transparent decompression of gzipped files
+//#define HAVE_ZLIB_H
+
+// Uncomment if you get errors in the bool section of blargg_common.h
+//#define BLARGG_COMPILER_HAS_BOOL 1
+
+// Uncomment to disable out-of-memory exceptions
+//#include <memory>
+//#define BLARGG_NEW new (std::nothrow)
+
+// Use standard config.h if present
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#endif
+
--- /dev/null
+++ b/src/in_gsf/vbam/apu/blargg_source.h
@@ -1,1 +1,93 @@
+/* Included at the beginning of library source files, AFTER all other #include lines.
+Sets up helpful macros and services used in my source code. Since this is only "active"
+in my source code, I don't have to worry about polluting the global namespace with
+unprefixed names. */
+// Gb_Snd_Emu 0.2.0
+#ifndef BLARGG_SOURCE_H
+#define BLARGG_SOURCE_H
+
+// The following four macros are for debugging only. Some or all might be defined
+// to do nothing, depending on the circumstances. Described is what happens when
+// a particular macro is defined to do something. When defined to do nothing, the
+// macros do NOT evaluate their argument(s).
+
+// If expr is false, prints file and line number, then aborts program. Meant for
+// checking internal state and consistency. A failed assertion indicates a bug
+// in MY code.
+//
+// void assert( bool expr );
+#include <assert.h>
+
+// If expr is false, prints file and line number, then aborts program. Meant for
+// checking caller-supplied parameters and operations that are outside the control
+// of the module. A failed requirement probably indicates a bug in YOUR code.
+//
+// void require( bool expr );
+#undef require
+#define require( expr ) assert( expr )
+
+// Like printf() except output goes to debugging console/file.
+//
+// void dprintf( const char* format, ... );
+static inline void blargg_dprintf_( const char*, ... ) { }
+#undef dprintf
+#define dprintf (1) ? (void) 0 : blargg_dprintf_
+
+// If expr is false, prints file and line number to debug console/log, then
+// continues execution normally. Meant for flagging potential problems or things
+// that should be looked into, but that aren't serious problems.
+//
+// void check( bool expr );
+#undef check
+#define check( expr ) ((void) 0)
+
+// If expr yields non-NULL error string, returns it from current function,
+// otherwise continues normally.
+#undef RETURN_ERR
+#define RETURN_ERR( expr ) do { \
+ blargg_err_t blargg_return_err_ = (expr); \
+ if ( blargg_return_err_ ) return blargg_return_err_; \
+ } while ( 0 )
+
+// If ptr is NULL, returns "Out of memory" error string, otherwise continues normally.
+#undef CHECK_ALLOC
+#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 )
+
+// The usual min/max functions for built-in types.
+//
+// template<typename T> T min( T x, T y ) { return x < y ? x : y; }
+// template<typename T> T max( T x, T y ) { return x > y ? x : y; }
+#define BLARGG_DEF_MIN_MAX( type ) \
+ static inline type blargg_min( type x, type y ) { if ( y < x ) x = y; return x; }\
+ static inline type blargg_max( type x, type y ) { if ( x < y ) x = y; return x; }
+
+BLARGG_DEF_MIN_MAX( int )
+BLARGG_DEF_MIN_MAX( unsigned )
+BLARGG_DEF_MIN_MAX( long )
+BLARGG_DEF_MIN_MAX( unsigned long )
+BLARGG_DEF_MIN_MAX( float )
+BLARGG_DEF_MIN_MAX( double )
+
+#undef min
+#define min blargg_min
+
+#undef max
+#define max blargg_max
+
+// typedef unsigned char byte;
+typedef unsigned char blargg_byte;
+#undef byte
+#define byte blargg_byte
+
+// deprecated
+#define BLARGG_CHECK_ALLOC CHECK_ALLOC
+#define BLARGG_RETURN_ERR RETURN_ERR
+
+// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check
+#ifdef BLARGG_SOURCE_BEGIN
+ #include BLARGG_SOURCE_BEGIN
+#endif
+
+#endif
+
--- /dev/null
+++ b/src/in_gsf/vbam/common/Port.h
@@ -1,1 +1,59 @@
+#ifndef PORT_H
+#define PORT_H
+#include "Types.h"
+
+// swaps a 16-bit value
+static inline u16 swap16(u16 v)
+{
+ return (v<<8)|(v>>8);
+}
+
+// swaps a 32-bit value
+static inline u32 swap32(u32 v)
+{
+ return (v<<24)|((v<<8)&0xff0000)|((v>>8)&0xff00)|(v>>24);
+}
+
+#ifdef WORDS_BIGENDIAN
+#if defined(__GNUC__) && defined(__ppc__)
+
+#define READ16LE(base) \
+ ({ unsigned short lhbrxResult; \
+ __asm__ ("lhbrx %0, 0, %1" : "=r" (lhbrxResult) : "r" (base) : "memory"); \
+ lhbrxResult; })
+
+#define READ32LE(base) \
+ ({ unsigned long lwbrxResult; \
+ __asm__ ("lwbrx %0, 0, %1" : "=r" (lwbrxResult) : "r" (base) : "memory"); \
+ lwbrxResult; })
+
+#define WRITE16LE(base, value) \
+ __asm__ ("sthbrx %0, 0, %1" : : "r" (value), "r" (base) : "memory")
+
+#define WRITE32LE(base, value) \
+ __asm__ ("stwbrx %0, 0, %1" : : "r" (value), "r" (base) : "memory")
+
+#else
+#define READ16LE(x) \
+ swap16(*((u16 *)(x)))
+#define READ32LE(x) \
+ swap32(*((u32 *)(x)))
+#define WRITE16LE(x,v) \
+ *((u16 *)x) = swap16((v))
+#define WRITE32LE(x,v) \
+ *((u32 *)x) = swap32((v))
+#endif
+#else
+#define READ16LE(x) \
+ *((u16 *)x)
+#define READ32LE(x) \
+ *((u32 *)x)
+#define WRITE16LE(x,v) \
+ *((u16 *)x) = (v)
+#define WRITE32LE(x,v) \
+ *((u32 *)x) = (v)
+#endif
+
+#endif // PORT_H
+
--- /dev/null
+++ b/src/in_gsf/vbam/common/SoundDriver.h
@@ -1,1 +1,66 @@
+// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
+// Copyright (C) 2008 VBA-M development team
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or(at your option)
+// any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef __VBA_SOUND_DRIVER_H__
+#define __VBA_SOUND_DRIVER_H__
+
+#include "Types.h"
+
+/**
+ * Sound driver abstract interface for the core to use to output sound.
+ * Subclass this to implement a new sound driver.
+ */
+class SoundDriver
+{
+public:
+
+ /**
+ * Destructor. Free the resources allocated by the sound driver.
+ */
+ virtual ~SoundDriver() { };
+
+ /**
+ * Initialize the sound driver.
+ * @param sampleRate In Hertz
+ */
+ virtual bool init(long sampleRate) = 0;
+
+ /**
+ * Tell the driver that the sound stream has paused
+ */
+ virtual void pause() = 0;
+
+ /**
+ * Reset the sound driver
+ */
+ virtual void reset() = 0;
+
+ /**
+ * Tell the driver that the sound stream has resumed
+ */
+ virtual void resume() = 0;
+
+ /**
+ * Write length bytes of data from the finalWave buffer to the driver output buffer.
+ */
+ virtual void write(u16 * finalWave, int length) = 0;
+
+ virtual void setThrottle(unsigned short throttle) { };
+};
+
+#endif // __VBA_SOUND_DRIVER_H__
+
--- /dev/null
+++ b/src/in_gsf/vbam/common/Types.h
@@ -1,1 +1,34 @@
+// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
+// Copyright (C) 2008 VBA-M development team
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or(at your option)
+// any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef __VBA_TYPES_H__
+#define __VBA_TYPES_H__
+
+#include <stdint.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+typedef int64_t s64;
+
+#endif // __VBA_TYPES_H__
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/GBA-arm.cpp
@@ -1,1 +1,2951 @@
-
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "GBA.h"
+#include "GBAcpu.h"
+#include "GBAinline.h"
+#include "Globals.h"
+//#include "EEprom.h"
+//#include "Flash.h"
+#include "Sound.h"
+//#include "Sram.h"
+#include "bios.h"
+//#include "Cheats.h"
+//#include "../NLS.h"
+//#include "elf.h"
+//#include "../Util.h"
+//#include "../System.h"
+//#include "agbprint.h"
+#ifdef PROFILING
+#include "prof/prof.h"
+#endif
+
+#ifdef _MSC_VER
+ // Disable "empty statement" warnings
+ #pragma warning(disable: 4390)
+ // Visual C's inline assembler treats "offset" as a reserved word, so we
+ // tell it otherwise. If you want to use it, write "OFFSET" in capitals.
+ #define offset offset_
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+
+static int clockTicks;
+
+static INSN_REGPARM void armUnknownInsn(u32 opcode)
+{
+#ifdef GBA_LOGGING
+ if (systemVerbose & VERBOSE_UNDEFINED) {
+ log("Undefined ARM instruction %08x at %08x\n", opcode,
+ armNextPC-4);
+ }
+#endif
+ CPUUndefinedException();
+}
+
+#ifdef BKPT_SUPPORT
+static INSN_REGPARM void armBreakpoint(u32 opcode)
+{
+ reg[15].I -= 4;
+ armNextPC -= 4;
+ dbgSignal(5, (opcode & 0x0f) | ((opcode>>4) & 0xfff0));
+ clockTicks = -1;
+}
+#endif
+
+
+// Subroutine to count instructions (for debugging/optimizing)
+//#define INSN_COUNTER // comment out if you don't want it
+#ifdef INSN_COUNTER
+static void count(u32 opcode, int cond_res)
+{
+ static int insncount = 0; // number of insns seen
+ static int executed = 0; // number of insns executed
+ static int mergewith[4096]; // map instructions to routines
+ static int count[4096]; // count of each 12-bit code
+ int index = ((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F);
+ static FILE *outfile = NULL;
+
+ if (!insncount) {
+ for (int i = 0; i < 4096; i++) {
+ for (int j = 0; j < i; j++) {
+ if (armInsnTable[i] == armInsnTable[j])
+ break;
+ }
+ mergewith[i] = j;
+ }
+ outfile = fopen("VBA-armcount.txt", "w");
+ }
+ if (cond_res) {
+ count[mergewith[index]]++;
+ executed++;
+ }
+ insncount++;
+ if (outfile && insncount%1000000 == 0) {
+ fprintf(outfile, "Total instructions: %d\n", insncount);
+ fprintf(outfile, "Instructions executed: %d\n", executed);
+ for (int i = 0; i < 4096; i++) {
+ if (count[i])
+ fprintf(outfile, "arm%03X: %d\n", i, count[i]);
+ }
+ }
+}
+#endif
+
+// Common macros //////////////////////////////////////////////////////////
+
+#ifdef BKPT_SUPPORT
+#define CONSOLE_OUTPUT(a,b) do { \
+ if ((opcode == 0xe0000000) && (reg[0].I == 0xC0DED00D)) { \
+ dbgOutput((a), (b)); \
+} while (0)
+#else
+#define CONSOLE_OUTPUT(a,b) /* nothing */
+#endif
+
+#define NEG(i) ((i) >> 31)
+#define POS(i) ((~(i)) >> 31)
+
+// The following macros are used for optimization; any not defined for a
+// particular compiler/CPU combination default to the C core versions.
+//
+// ALU_INIT_C: Used at the beginning of ALU instructions (AND/EOR/...).
+// (ALU_INIT_NC) Can consist of variable declarations, like the C core,
+// or the start of a continued assembly block, like the
+// x86-optimized version. The _C version is used when the
+// carry flag from the shift operation is needed (logical
+// operations that set condition codes, like ANDS); the
+// _NC version is used when the carry result is ignored.
+// VALUE_XXX: Retrieve the second operand's value for an ALU instruction.
+// The _C and _NC versions are used the same way as ALU_INIT.
+// OP_XXX: ALU operations. XXX is the instruction name.
+// ALU_FINISH: Appended to all ALU instructions. Usually empty, but if
+// ALU_INIT started a block ALU_FINISH can be used to end it
+// (as with the asm(...) statement in the x86 core).
+// SETCOND_NONE: Used in multiply instructions in place of SETCOND_MUL
+// when the condition codes are not set. Usually empty.
+// SETCOND_MUL: Used in multiply instructions to set the condition codes.
+// ROR_IMM_MSR: Used to rotate the immediate operand for MSR.
+// ROR_OFFSET: Used to rotate the `offset' parameter for LDR and STR
+// instructions.
+// RRX_OFFSET: Used to rotate (RRX) the `offset' parameter for LDR and
+// STR instructions.
+
+#ifndef C_CORE
+
+#if 0 // definitions have changed
+//#ifdef __POWERPC__
+ #define OP_SUBS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_RSBS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subfco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_ADDS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_ADCS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("mtspr xer, %4\n" \
+ "addeo. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value), \
+ "r" (C_FLAG << 29) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_SBCS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("mtspr xer, %4\n" \
+ "subfeo. %0, %3, %2\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value), \
+ "r" (C_FLAG << 29) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_RSCS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("mtspr xer, %4\n" \
+ "subfeo. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value), \
+ "r" (C_FLAG << 29) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_CMP \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value) \
+ ); \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_CMN \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value) \
+ ); \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+
+#else // !__POWERPC__
+
+// Macros to emit instructions in the format used by the particular compiler.
+// We use GNU assembler syntax: "op src, dest" rather than "op dest, src"
+
+#ifdef __GNUC__
+ #define ALU_HEADER asm("mov %%ecx, %%edi; "
+ #define ALU_TRAILER : "=D" (opcode) : "c" (opcode) : "eax", "ebx", "edx", "esi")
+ #define EMIT0(op) #op"; "
+ #define EMIT1(op,arg) #op" "arg"; "
+ #define EMIT2(op,src,dest) #op" "src", "dest"; "
+ #define KONST(val) "$"#val
+ #define ASMVAR(cvar) ASMVAR2 (__USER_LABEL_PREFIX__, cvar)
+ #define ASMVAR2(prefix,cvar) STRING (prefix) cvar
+ #define STRING(x) #x
+ #define VAR(var) ASMVAR(#var)
+ #define VARL(var) ASMVAR(#var)
+ #define REGREF1(index) ASMVAR("reg("index")")
+ #define REGREF2(index,scale) ASMVAR("reg(,"index","#scale")")
+ #define LABEL(n) #n": "
+ #define LABELREF(n,dir) #n#dir
+ #define al "%%al"
+ #define ah "%%ah"
+ #define eax "%%eax"
+ #define bl "%%bl"
+ #define bh "%%bh"
+ #define ebx "%%ebx"
+ #define cl "%%cl"
+ #define ch "%%ch"
+ #define ecx "%%ecx"
+ #define dl "%%dl"
+ #define dh "%%dh"
+ #define edx "%%edx"
+ #define esp "%%esp"
+ #define ebp "%%ebp"
+ #define esi "%%esi"
+ #define edi "%%edi"
+ #define movzx movzb
+#else
+ #define ALU_HEADER __asm { __asm mov ecx, opcode
+ #define ALU_TRAILER }
+ #define EMIT0(op) __asm op
+ #define EMIT1(op,arg) __asm op arg
+ #define EMIT2(op,src,dest) __asm op dest, src
+ #define KONST(val) val
+ #define VAR(var) var
+ #define VARL(var) dword ptr var
+ #define REGREF1(index) reg[index]
+ #define REGREF2(index,scale) reg[index*scale]
+ #define LABEL(n) __asm l##n:
+ #define LABELREF(n,dir) l##n
+#endif
+
+//X//#ifndef _MSC_VER
+// ALU op register usage:
+// EAX -> 2nd operand value, result (RSB/RSC)
+// EBX -> C_OUT (carry flag from shift/rotate)
+// ECX -> opcode (input), shift/rotate count
+// EDX -> Rn (base) value, result (all except RSB/RSC)
+// ESI -> Rd (destination) index * 4
+
+// Helper macros for loading value / shift count
+#define VALUE_LOAD_IMM \
+ EMIT2(and, KONST(0x0F), eax) \
+ EMIT2(mov, REGREF2(eax,4), eax) \
+ EMIT2(shr, KONST(7), ecx) \
+ EMIT2(and, KONST(0x1F), ecx)
+#define VALUE_LOAD_REG \
+ EMIT2(and, KONST(0x0F), eax) \
+ EMIT2(mov, REGREF2(eax,4), eax) \
+ EMIT2(movzx, ch, ecx) \
+ EMIT2(and, KONST(0x0F), ecx) \
+ EMIT2(mov, REGREF2(ecx,4), ecx)
+
+// Helper macros for setting flags
+#define SETCOND_LOGICAL \
+ EMIT1(sets, VAR(N_FLAG)) \
+ EMIT1(setz, VAR(Z_FLAG)) \
+ EMIT2(mov, bl, VAR(C_FLAG))
+#define SETCOND_ADD \
+ EMIT1(sets, VAR(N_FLAG)) \
+ EMIT1(setz, VAR(Z_FLAG)) \
+ EMIT1(seto, VAR(V_FLAG)) \
+ EMIT1(setc, VAR(C_FLAG))
+#define SETCOND_SUB \
+ EMIT1(sets, VAR(N_FLAG)) \
+ EMIT1(setz, VAR(Z_FLAG)) \
+ EMIT1(seto, VAR(V_FLAG)) \
+ EMIT1(setnc, VAR(C_FLAG))
+
+// ALU initialization
+#define ALU_INIT(LOAD_C_FLAG) \
+ ALU_HEADER \
+ LOAD_C_FLAG \
+ EMIT2(mov, ecx, edx) \
+ EMIT2(shr, KONST(14), edx) \
+ EMIT2(mov, ecx, eax) \
+ EMIT2(mov, ecx, esi) \
+ EMIT2(shr, KONST(10), esi) \
+ EMIT2(and, KONST(0x3C), edx) \
+ EMIT2(mov, REGREF1(edx), edx) \
+ EMIT2(and, KONST(0x3C), esi)
+
+#define LOAD_C_FLAG_YES EMIT2(mov, VAR(C_FLAG), bl)
+#define LOAD_C_FLAG_NO /*nothing*/
+#define ALU_INIT_C ALU_INIT(LOAD_C_FLAG_YES)
+#define ALU_INIT_NC ALU_INIT(LOAD_C_FLAG_NO)
+
+// Macros to load the value operand for an ALU op; these all set N/Z
+// according to the value
+
+// OP Rd,Rb,Rm LSL #
+#define VALUE_LSL_IMM_C \
+ VALUE_LOAD_IMM \
+ EMIT1(jnz, LABELREF(1,f)) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(shl, cl, eax) \
+ EMIT1(setc, bl) \
+ LABEL(0)
+#define VALUE_LSL_IMM_NC \
+ VALUE_LOAD_IMM \
+ EMIT2(shl, cl, eax)
+
+// OP Rd,Rb,Rm LSL Rs
+#define VALUE_LSL_REG_C \
+ VALUE_LOAD_REG \
+ EMIT2(test, cl, cl) \
+ EMIT1(jz, LABELREF(0,f)) \
+ EMIT2(cmp, KONST(0x20), cl) \
+ EMIT1(je, LABELREF(1,f)) \
+ EMIT1(ja, LABELREF(2,f)) \
+ EMIT2(shl, cl, eax) \
+ EMIT1(setc, bl) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(test, KONST(1), al) \
+ EMIT1(setnz, bl) \
+ EMIT2(xor, eax, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(2) \
+ EMIT2(xor, ebx, ebx) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+#define VALUE_LSL_REG_NC \
+ VALUE_LOAD_REG \
+ EMIT2(cmp, KONST(0x20), cl) \
+ EMIT1(jae, LABELREF(1,f)) \
+ EMIT2(shl, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm LSR #
+#define VALUE_LSR_IMM_C \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(shr, cl, eax) \
+ EMIT1(setc, bl) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(test, eax, eax) \
+ EMIT1(sets, bl) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+#define VALUE_LSR_IMM_NC \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(shr, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm LSR Rs
+#define VALUE_LSR_REG_C \
+ VALUE_LOAD_REG \
+ EMIT2(test, cl, cl) \
+ EMIT1(jz, LABELREF(0,f)) \
+ EMIT2(cmp, KONST(0x20), cl) \
+ EMIT1(je, LABELREF(1,f)) \
+ EMIT1(ja, LABELREF(2,f)) \
+ EMIT2(shr, cl, eax) \
+ EMIT1(setc, bl) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(test, eax, eax) \
+ EMIT1(sets, bl) \
+ EMIT2(xor, eax, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(2) \
+ EMIT2(xor, ebx, ebx) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+#define VALUE_LSR_REG_NC \
+ VALUE_LOAD_REG \
+ EMIT2(cmp, KONST(0x20), cl) \
+ EMIT1(jae, LABELREF(1,f)) \
+ EMIT2(shr, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm ASR #
+#define VALUE_ASR_IMM_C \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(sar, cl, eax) \
+ EMIT1(setc, bl) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(sar, KONST(31), eax) \
+ EMIT1(sets, bl) \
+ LABEL(0)
+#define VALUE_ASR_IMM_NC \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(sar, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(sar, KONST(31), eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm ASR Rs
+#define VALUE_ASR_REG_C \
+ VALUE_LOAD_REG \
+ EMIT2(test, cl, cl) \
+ EMIT1(jz, LABELREF(0,f)) \
+ EMIT2(cmp, KONST(0x20), cl) \
+ EMIT1(jae, LABELREF(1,f)) \
+ EMIT2(sar, cl, eax) \
+ EMIT1(setc, bl) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(sar, KONST(31), eax) \
+ EMIT1(sets, bl) \
+ LABEL(0)
+#define VALUE_ASR_REG_NC \
+ VALUE_LOAD_REG \
+ EMIT2(cmp, KONST(0x20), cl) \
+ EMIT1(jae, LABELREF(1,f)) \
+ EMIT2(sar, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(sar, KONST(31), eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm ROR #
+#define VALUE_ROR_IMM_C \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(ror, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(bt, KONST(0), ebx) \
+ EMIT2(rcr, KONST(1), eax) \
+ LABEL(0) \
+ EMIT1(setc, bl)
+#define VALUE_ROR_IMM_NC \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(ror, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(bt, KONST(0), VARL(C_FLAG)) \
+ EMIT2(rcr, KONST(1), eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm ROR Rs
+#define VALUE_ROR_REG_C \
+ VALUE_LOAD_REG \
+ EMIT2(bt, KONST(0), ebx) \
+ EMIT2(ror, cl, eax) \
+ EMIT1(setc, bl)
+#define VALUE_ROR_REG_NC \
+ VALUE_LOAD_REG \
+ EMIT2(ror, cl, eax)
+
+// OP Rd,Rb,# ROR #
+#define VALUE_IMM_C \
+ EMIT2(movzx, ch, ecx) \
+ EMIT2(add, ecx, ecx) \
+ EMIT2(movzx, al, eax) \
+ EMIT2(bt, KONST(0), ebx) \
+ EMIT2(ror, cl, eax) \
+ EMIT1(setc, bl)
+#define VALUE_IMM_NC \
+ EMIT2(movzx, ch, ecx) \
+ EMIT2(add, ecx, ecx) \
+ EMIT2(movzx, al, eax) \
+ EMIT2(ror, cl, eax)
+
+// Macros to perform ALU ops
+
+// Set condition codes iff the destination register is not R15 (PC)
+#define CHECK_PC(OP, SETCOND) \
+ EMIT2(cmp, KONST(0x3C), esi) \
+ EMIT1(je, LABELREF(8,f)) \
+ OP SETCOND \
+ EMIT1(jmp, LABELREF(9,f)) \
+ LABEL(8) \
+ OP \
+ LABEL(9)
+
+#define OP_AND \
+ EMIT2(and, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_ANDS CHECK_PC(OP_AND, SETCOND_LOGICAL)
+#define OP_EOR \
+ EMIT2(xor, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_EORS CHECK_PC(OP_EOR, SETCOND_LOGICAL)
+#define OP_SUB \
+ EMIT2(sub, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_SUBS CHECK_PC(OP_SUB, SETCOND_SUB)
+#define OP_RSB \
+ EMIT2(sub, edx, eax) \
+ EMIT2(mov, eax, REGREF1(esi))
+#define OP_RSBS CHECK_PC(OP_RSB, SETCOND_SUB)
+#define OP_ADD \
+ EMIT2(add, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_ADDS CHECK_PC(OP_ADD, SETCOND_ADD)
+#define OP_ADC \
+ EMIT2(bt, KONST(0), VARL(C_FLAG)) \
+ EMIT2(adc, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_ADCS CHECK_PC(OP_ADC, SETCOND_ADD)
+#define OP_SBC \
+ EMIT2(bt, KONST(0), VARL(C_FLAG)) \
+ EMIT0(cmc) \
+ EMIT2(sbb, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_SBCS CHECK_PC(OP_SBC, SETCOND_SUB)
+#define OP_RSC \
+ EMIT2(bt, KONST(0), VARL(C_FLAG)) \
+ EMIT0(cmc) \
+ EMIT2(sbb, edx, eax) \
+ EMIT2(mov, eax, REGREF1(esi))
+#define OP_RSCS CHECK_PC(OP_RSC, SETCOND_SUB)
+#define OP_TST \
+ EMIT2(and, eax, edx) \
+ SETCOND_LOGICAL
+#define OP_TEQ \
+ EMIT2(xor, eax, edx) \
+ SETCOND_LOGICAL
+#define OP_CMP \
+ EMIT2(sub, eax, edx) \
+ SETCOND_SUB
+#define OP_CMN \
+ EMIT2(add, eax, edx) \
+ SETCOND_ADD
+#define OP_ORR \
+ EMIT2(or, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_ORRS CHECK_PC(OP_ORR, SETCOND_LOGICAL)
+#define OP_MOV \
+ EMIT2(mov, eax, REGREF1(esi))
+#define OP_MOVS CHECK_PC(EMIT2(test,eax,eax) EMIT2(mov,eax,REGREF1(esi)), SETCOND_LOGICAL)
+#define OP_BIC \
+ EMIT1(not, eax) \
+ EMIT2(and, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_BICS CHECK_PC(OP_BIC, SETCOND_LOGICAL)
+#define OP_MVN \
+ EMIT1(not, eax) \
+ EMIT2(mov, eax, REGREF1(esi))
+#define OP_MVNS CHECK_PC(OP_MVN EMIT2(test,eax,eax), SETCOND_LOGICAL)
+
+// ALU cleanup macro
+#define ALU_FINISH ALU_TRAILER
+
+// End of ALU macros
+//X//#endif //_MSC_VER
+
+#ifdef __GNUC__
+
+#define ROR_IMM_MSR \
+ asm ("ror %%cl, %%eax;" \
+ : "=a" (value) \
+ : "a" (opcode & 0xFF), "c" (shift));
+
+#define ROR_OFFSET \
+ asm("ror %%cl, %0" \
+ : "=r" (offset) \
+ : "0" (offset), "c" (shift));
+
+#define RRX_OFFSET \
+ asm(EMIT2(btl,KONST(0),VAR(C_FLAG)) \
+ "rcr $1, %0" \
+ : "=r" (offset) \
+ : "0" (offset));
+
+#else // !__GNUC__, i.e. Visual C++
+
+#define ROR_IMM_MSR \
+ __asm { \
+ __asm mov ecx, shift \
+ __asm ror value, cl \
+ }
+
+
+#define ROR_OFFSET \
+ __asm { \
+ __asm mov ecx, shift \
+ __asm ror offset, cl \
+ }
+
+#define RRX_OFFSET \
+ __asm { \
+ __asm bt dword ptr C_FLAG, 0 \
+ __asm rcr offset, 1 \
+ }
+
+#endif // !__GNUC__
+
+#endif // !__POWERPC__
+#endif // !C_CORE
+
+// C core
+
+#define C_SETCOND_LOGICAL \
+ N_FLAG = ((s32)res < 0) ? true : false; \
+ Z_FLAG = (res == 0) ? true : false; \
+ C_FLAG = C_OUT;
+#define C_SETCOND_ADD \
+ N_FLAG = ((s32)res < 0) ? true : false; \
+ Z_FLAG = (res == 0) ? true : false; \
+ V_FLAG = ((NEG(lhs) & NEG(rhs) & POS(res)) | \
+ (POS(lhs) & POS(rhs) & NEG(res))) ? true : false;\
+ C_FLAG = ((NEG(lhs) & NEG(rhs)) | \
+ (NEG(lhs) & POS(res)) | \
+ (NEG(rhs) & POS(res))) ? true : false;
+#define C_SETCOND_SUB \
+ N_FLAG = ((s32)res < 0) ? true : false; \
+ Z_FLAG = (res == 0) ? true : false; \
+ V_FLAG = ((NEG(lhs) & POS(rhs) & POS(res)) | \
+ (POS(lhs) & NEG(rhs) & NEG(res))) ? true : false;\
+ C_FLAG = ((NEG(lhs) & POS(rhs)) | \
+ (NEG(lhs) & POS(res)) | \
+ (POS(rhs) & POS(res))) ? true : false;
+
+#ifndef ALU_INIT_C
+ #define ALU_INIT_C \
+ int dest = (opcode>>12) & 15; \
+ bool C_OUT = C_FLAG; \
+ u32 value;
+#endif
+// OP Rd,Rb,Rm LSL #
+#ifndef VALUE_LSL_IMM_C
+ #define VALUE_LSL_IMM_C \
+ unsigned int shift = (opcode >> 7) & 0x1F; \
+ if (LIKELY(!shift)) { /* LSL #0 most common? */ \
+ value = reg[opcode & 0x0F].I; \
+ } else { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (32 - shift)) & 1 ? true : false; \
+ value = v << shift; \
+ }
+#endif
+// OP Rd,Rb,Rm LSL Rs
+#ifndef VALUE_LSL_REG_C
+ #define VALUE_LSL_REG_C \
+ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
+ if (LIKELY(shift)) { \
+ if (shift == 32) { \
+ value = 0; \
+ C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\
+ } else if (LIKELY(shift < 32)) { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (32 - shift)) & 1 ? true : false;\
+ value = v << shift; \
+ } else { \
+ value = 0; \
+ C_OUT = false; \
+ } \
+ } else { \
+ value = reg[opcode & 0x0F].I; \
+ }
+#endif
+// OP Rd,Rb,Rm LSR #
+#ifndef VALUE_LSR_IMM_C
+ #define VALUE_LSR_IMM_C \
+ unsigned int shift = (opcode >> 7) & 0x1F; \
+ if (LIKELY(shift)) { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
+ value = v >> shift; \
+ } else { \
+ value = 0; \
+ C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false;\
+ }
+#endif
+// OP Rd,Rb,Rm LSR Rs
+#ifndef VALUE_LSR_REG_C
+ #define VALUE_LSR_REG_C \
+ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
+ if (LIKELY(shift)) { \
+ if (shift == 32) { \
+ value = 0; \
+ C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\
+ } else if (LIKELY(shift < 32)) { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (shift - 1)) & 1 ? true : false;\
+ value = v >> shift; \
+ } else { \
+ value = 0; \
+ C_OUT = false; \
+ } \
+ } else { \
+ value = reg[opcode & 0x0F].I; \
+ }
+#endif
+// OP Rd,Rb,Rm ASR #
+#ifndef VALUE_ASR_IMM_C
+ #define VALUE_ASR_IMM_C \
+ unsigned int shift = (opcode >> 7) & 0x1F; \
+ if (LIKELY(shift)) { \
+ /* VC++ BUG: u32 v; (s32)v>>n is optimized to shr! */ \
+ s32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\
+ value = v >> (int)shift; \
+ } else { \
+ if (reg[opcode & 0x0F].I & 0x80000000) { \
+ value = 0xFFFFFFFF; \
+ C_OUT = true; \
+ } else { \
+ value = 0; \
+ C_OUT = false; \
+ } \
+ }
+#endif
+// OP Rd,Rb,Rm ASR Rs
+#ifndef VALUE_ASR_REG_C
+ #define VALUE_ASR_REG_C \
+ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
+ if (LIKELY(shift < 32)) { \
+ if (LIKELY(shift)) { \
+ s32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\
+ value = v >> (int)shift; \
+ } else { \
+ value = reg[opcode & 0x0F].I; \
+ } \
+ } else { \
+ if (reg[opcode & 0x0F].I & 0x80000000) { \
+ value = 0xFFFFFFFF; \
+ C_OUT = true; \
+ } else { \
+ value = 0; \
+ C_OUT = false; \
+ } \
+ }
+#endif
+// OP Rd,Rb,Rm ROR #
+#ifndef VALUE_ROR_IMM_C
+ #define VALUE_ROR_IMM_C \
+ unsigned int shift = (opcode >> 7) & 0x1F; \
+ if (LIKELY(shift)) { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
+ value = ((v << (32 - shift)) | \
+ (v >> shift)); \
+ } else { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v & 1) ? true : false; \
+ value = ((v >> 1) | \
+ (C_FLAG << 31)); \
+ }
+#endif
+// OP Rd,Rb,Rm ROR Rs
+#ifndef VALUE_ROR_REG_C
+ #define VALUE_ROR_REG_C \
+ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
+ if (LIKELY(shift & 0x1F)) { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
+ value = ((v << (32 - shift)) | \
+ (v >> shift)); \
+ } else { \
+ value = reg[opcode & 0x0F].I; \
+ if (shift) \
+ C_OUT = (value & 0x80000000 ? true : false);\
+ }
+#endif
+// OP Rd,Rb,# ROR #
+#ifndef VALUE_IMM_C
+ #define VALUE_IMM_C \
+ int shift = (opcode & 0xF00) >> 7; \
+ if (UNLIKELY(shift)) { \
+ u32 v = opcode & 0xFF; \
+ C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
+ value = ((v << (32 - shift)) | \
+ (v >> shift)); \
+ } else { \
+ value = opcode & 0xFF; \
+ }
+#endif
+
+// Make the non-carry versions default to the carry versions
+// (this is fine for C--the compiler will optimize the dead code out)
+#ifndef ALU_INIT_NC
+ #define ALU_INIT_NC ALU_INIT_C
+#endif
+#ifndef VALUE_LSL_IMM_NC
+ #define VALUE_LSL_IMM_NC VALUE_LSL_IMM_C
+#endif
+#ifndef VALUE_LSL_REG_NC
+ #define VALUE_LSL_REG_NC VALUE_LSL_REG_C
+#endif
+#ifndef VALUE_LSR_IMM_NC
+ #define VALUE_LSR_IMM_NC VALUE_LSR_IMM_C
+#endif
+#ifndef VALUE_LSR_REG_NC
+ #define VALUE_LSR_REG_NC VALUE_LSR_REG_C
+#endif
+#ifndef VALUE_ASR_IMM_NC
+ #define VALUE_ASR_IMM_NC VALUE_ASR_IMM_C
+#endif
+#ifndef VALUE_ASR_REG_NC
+ #define VALUE_ASR_REG_NC VALUE_ASR_REG_C
+#endif
+#ifndef VALUE_ROR_IMM_NC
+ #define VALUE_ROR_IMM_NC VALUE_ROR_IMM_C
+#endif
+#ifndef VALUE_ROR_REG_NC
+ #define VALUE_ROR_REG_NC VALUE_ROR_REG_C
+#endif
+#ifndef VALUE_IMM_NC
+ #define VALUE_IMM_NC VALUE_IMM_C
+#endif
+
+#define C_CHECK_PC(SETCOND) if (LIKELY(dest != 15)) { SETCOND }
+#ifndef OP_AND
+ #define OP_AND \
+ u32 res = reg[(opcode>>16)&15].I & value; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_ANDS
+ #define OP_ANDS OP_AND C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+#ifndef OP_EOR
+ #define OP_EOR \
+ u32 res = reg[(opcode>>16)&15].I ^ value; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_EORS
+ #define OP_EORS OP_EOR C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+#ifndef OP_SUB
+ #define OP_SUB \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs - rhs; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_SUBS
+ #define OP_SUBS OP_SUB C_CHECK_PC(C_SETCOND_SUB)
+#endif
+#ifndef OP_RSB
+ #define OP_RSB \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = rhs - lhs; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_RSBS
+ #define OP_RSBS OP_RSB C_CHECK_PC(C_SETCOND_SUB)
+#endif
+#ifndef OP_ADD
+ #define OP_ADD \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs + rhs; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_ADDS
+ #define OP_ADDS OP_ADD C_CHECK_PC(C_SETCOND_ADD)
+#endif
+#ifndef OP_ADC
+ #define OP_ADC \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs + rhs + (u32)C_FLAG; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_ADCS
+ #define OP_ADCS OP_ADC C_CHECK_PC(C_SETCOND_ADD)
+#endif
+#ifndef OP_SBC
+ #define OP_SBC \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs - rhs - !((u32)C_FLAG); \
+ reg[dest].I = res;
+#endif
+#ifndef OP_SBCS
+ #define OP_SBCS OP_SBC C_CHECK_PC(C_SETCOND_SUB)
+#endif
+#ifndef OP_RSC
+ #define OP_RSC \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = rhs - lhs - !((u32)C_FLAG); \
+ reg[dest].I = res;
+#endif
+#ifndef OP_RSCS
+ #define OP_RSCS OP_RSC C_CHECK_PC(C_SETCOND_SUB)
+#endif
+#ifndef OP_TST
+ #define OP_TST \
+ u32 res = reg[(opcode >> 16) & 0x0F].I & value; \
+ C_SETCOND_LOGICAL;
+#endif
+#ifndef OP_TEQ
+ #define OP_TEQ \
+ u32 res = reg[(opcode >> 16) & 0x0F].I ^ value; \
+ C_SETCOND_LOGICAL;
+#endif
+#ifndef OP_CMP
+ #define OP_CMP \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs - rhs; \
+ C_SETCOND_SUB;
+#endif
+#ifndef OP_CMN
+ #define OP_CMN \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs + rhs; \
+ C_SETCOND_ADD;
+#endif
+#ifndef OP_ORR
+ #define OP_ORR \
+ u32 res = reg[(opcode >> 16) & 0x0F].I | value; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_ORRS
+ #define OP_ORRS OP_ORR C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+#ifndef OP_MOV
+ #define OP_MOV \
+ u32 res = value; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_MOVS
+ #define OP_MOVS OP_MOV C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+#ifndef OP_BIC
+ #define OP_BIC \
+ u32 res = reg[(opcode >> 16) & 0x0F].I & (~value); \
+ reg[dest].I = res;
+#endif
+#ifndef OP_BICS
+ #define OP_BICS OP_BIC C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+#ifndef OP_MVN
+ #define OP_MVN \
+ u32 res = ~value; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_MVNS
+ #define OP_MVNS OP_MVN C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+
+#ifndef SETCOND_NONE
+ #define SETCOND_NONE /*nothing*/
+#endif
+#ifndef SETCOND_MUL
+ #define SETCOND_MUL \
+ N_FLAG = ((s32)reg[dest].I < 0) ? true : false; \
+ Z_FLAG = reg[dest].I ? false : true;
+#endif
+#ifndef SETCOND_MULL
+ #define SETCOND_MULL \
+ N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\
+ Z_FLAG = reg[dest].I || reg[acc].I ? false : true;
+#endif
+
+#ifndef ALU_FINISH
+ #define ALU_FINISH /*nothing*/
+#endif
+
+#ifndef ROR_IMM_MSR
+ #define ROR_IMM_MSR \
+ u32 v = opcode & 0xff; \
+ value = ((v << (32 - shift)) | (v >> shift));
+#endif
+#ifndef ROR_OFFSET
+ #define ROR_OFFSET \
+ offset = ((offset << (32 - shift)) | (offset >> shift));
+#endif
+#ifndef RRX_OFFSET
+ #define RRX_OFFSET \
+ offset = ((offset >> 1) | ((int)C_FLAG << 31));
+#endif
+
+// ALU ops (except multiply) //////////////////////////////////////////////
+
+// ALU_INIT: init code (ALU_INIT_C or ALU_INIT_NC)
+// GETVALUE: load value and shift/rotate (VALUE_XXX)
+// OP: ALU operation (OP_XXX)
+// MODECHANGE: MODECHANGE_NO or MODECHANGE_YES
+// ISREGSHIFT: 1 for insns of the form ...,Rn LSL/etc Rs; 0 otherwise
+// ALU_INIT, GETVALUE, OP, and ALU_FINISH are concatenated in order.
+#define ALU_INSN(ALU_INIT, GETVALUE, OP, MODECHANGE, ISREGSHIFT) \
+ ALU_INIT GETVALUE OP ALU_FINISH; \
+ if (LIKELY((opcode & 0x0000F000) != 0x0000F000)) { \
+ clockTicks = 1 + ISREGSHIFT \
+ + codeTicksAccessSeq32(armNextPC); \
+ } else { \
+ MODECHANGE; \
+ if (armState) { \
+ reg[15].I &= 0xFFFFFFFC; \
+ armNextPC = reg[15].I; \
+ reg[15].I += 4; \
+ ARM_PREFETCH; \
+ } else { \
+ reg[15].I &= 0xFFFFFFFE; \
+ armNextPC = reg[15].I; \
+ reg[15].I += 2; \
+ THUMB_PREFETCH; \
+ } \
+ clockTicks = 3 + ISREGSHIFT \
+ + codeTicksAccess32(armNextPC) \
+ + codeTicksAccessSeq32(armNextPC) \
+ + codeTicksAccessSeq32(armNextPC); \
+ }
+
+#define MODECHANGE_NO /*nothing*/
+#define MODECHANGE_YES CPUSwitchMode(reg[17].I & 0x1f, false);
+
+#define DEFINE_ALU_INSN_C(CODE1, CODE2, OP, MODECHANGE) \
+ static INSN_REGPARM void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE2##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }
+#define DEFINE_ALU_INSN_NC(CODE1, CODE2, OP, MODECHANGE) \
+ static INSN_REGPARM void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE2##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }
+
+// AND
+DEFINE_ALU_INSN_NC(00, 20, AND, NO)
+// ANDS
+DEFINE_ALU_INSN_C (01, 21, ANDS, YES)
+
+// EOR
+DEFINE_ALU_INSN_NC(02, 22, EOR, NO)
+// EORS
+DEFINE_ALU_INSN_C (03, 23, EORS, YES)
+
+// SUB
+DEFINE_ALU_INSN_NC(04, 24, SUB, NO)
+// SUBS
+DEFINE_ALU_INSN_NC(05, 25, SUBS, YES)
+
+// RSB
+DEFINE_ALU_INSN_NC(06, 26, RSB, NO)
+// RSBS
+DEFINE_ALU_INSN_NC(07, 27, RSBS, YES)
+
+// ADD
+DEFINE_ALU_INSN_NC(08, 28, ADD, NO)
+// ADDS
+DEFINE_ALU_INSN_NC(09, 29, ADDS, YES)
+
+// ADC
+DEFINE_ALU_INSN_NC(0A, 2A, ADC, NO)
+// ADCS
+DEFINE_ALU_INSN_NC(0B, 2B, ADCS, YES)
+
+// SBC
+DEFINE_ALU_INSN_NC(0C, 2C, SBC, NO)
+// SBCS
+DEFINE_ALU_INSN_NC(0D, 2D, SBCS, YES)
+
+// RSC
+DEFINE_ALU_INSN_NC(0E, 2E, RSC, NO)
+// RSCS
+DEFINE_ALU_INSN_NC(0F, 2F, RSCS, YES)
+
+// TST
+DEFINE_ALU_INSN_C (11, 31, TST, NO)
+
+// TEQ
+DEFINE_ALU_INSN_C (13, 33, TEQ, NO)
+
+// CMP
+DEFINE_ALU_INSN_NC(15, 35, CMP, NO)
+
+// CMN
+DEFINE_ALU_INSN_NC(17, 37, CMN, NO)
+
+// ORR
+DEFINE_ALU_INSN_NC(18, 38, ORR, NO)
+// ORRS
+DEFINE_ALU_INSN_C (19, 39, ORRS, YES)
+
+// MOV
+DEFINE_ALU_INSN_NC(1A, 3A, MOV, NO)
+// MOVS
+DEFINE_ALU_INSN_C (1B, 3B, MOVS, YES)
+
+// BIC
+DEFINE_ALU_INSN_NC(1C, 3C, BIC, NO)
+// BICS
+DEFINE_ALU_INSN_C (1D, 3D, BICS, YES)
+
+// MVN
+DEFINE_ALU_INSN_NC(1E, 3E, MVN, NO)
+// MVNS
+DEFINE_ALU_INSN_C (1F, 3F, MVNS, YES)
+
+// Multiply instructions //////////////////////////////////////////////////
+
+// OP: OP_MUL, OP_MLA etc.
+// SETCOND: SETCOND_NONE, SETCOND_MUL, or SETCOND_MULL
+// CYCLES: base cycle count (1, 2, or 3)
+#define MUL_INSN(OP, SETCOND, CYCLES) \
+ int mult = (opcode & 0x0F); \
+ u32 rs = reg[(opcode >> 8) & 0x0F].I; \
+ int acc = (opcode >> 12) & 0x0F; /* or destLo */ \
+ int dest = (opcode >> 16) & 0x0F; /* or destHi */ \
+ OP; \
+ SETCOND; \
+ if ((s32)rs < 0) \
+ rs = ~rs; \
+ if ((rs & 0xFFFFFF00) == 0) \
+ clockTicks += 0; \
+ else if ((rs & 0xFFFF0000) == 0) \
+ clockTicks += 1; \
+ else if ((rs & 0xFF000000) == 0) \
+ clockTicks += 2; \
+ else \
+ clockTicks += 3; \
+ if (busPrefetchCount == 0) \
+ busPrefetchCount = ((busPrefetchCount+1)<<clockTicks) - 1; \
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+
+#define OP_MUL \
+ reg[dest].I = reg[mult].I * rs;
+#define OP_MLA \
+ reg[dest].I = reg[mult].I * rs + reg[acc].I;
+#define OP_MULL(SIGN) \
+ SIGN##64 res = (SIGN##64)(SIGN##32)reg[mult].I \
+ * (SIGN##64)(SIGN##32)rs; \
+ reg[acc].I = (u32)res; \
+ reg[dest].I = (u32)(res >> 32);
+#define OP_MLAL(SIGN) \
+ SIGN##64 res = ((SIGN##64)reg[dest].I<<32 | reg[acc].I)\
+ + ((SIGN##64)(SIGN##32)reg[mult].I \
+ * (SIGN##64)(SIGN##32)rs); \
+ reg[acc].I = (u32)res; \
+ reg[dest].I = (u32)(res >> 32);
+#define OP_UMULL OP_MULL(u)
+#define OP_UMLAL OP_MLAL(u)
+#define OP_SMULL OP_MULL(s)
+#define OP_SMLAL OP_MLAL(s)
+
+// MUL Rd, Rm, Rs
+static INSN_REGPARM void arm009(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_NONE, 1); }
+// MULS Rd, Rm, Rs
+static INSN_REGPARM void arm019(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_MUL, 1); }
+
+// MLA Rd, Rm, Rs, Rn
+static INSN_REGPARM void arm029(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_NONE, 2); }
+// MLAS Rd, Rm, Rs, Rn
+static INSN_REGPARM void arm039(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_MUL, 2); }
+
+// UMULL RdLo, RdHi, Rn, Rs
+static INSN_REGPARM void arm089(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_NONE, 2); }
+// UMULLS RdLo, RdHi, Rn, Rs
+static INSN_REGPARM void arm099(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_MULL, 2); }
+
+// UMLAL RdLo, RdHi, Rn, Rs
+static INSN_REGPARM void arm0A9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_NONE, 3); }
+// UMLALS RdLo, RdHi, Rn, Rs
+static INSN_REGPARM void arm0B9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_MULL, 3); }
+
+// SMULL RdLo, RdHi, Rm, Rs
+static INSN_REGPARM void arm0C9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_NONE, 2); }
+// SMULLS RdLo, RdHi, Rm, Rs
+static INSN_REGPARM void arm0D9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_MULL, 2); }
+
+// SMLAL RdLo, RdHi, Rm, Rs
+static INSN_REGPARM void arm0E9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_NONE, 3); }
+// SMLALS RdLo, RdHi, Rm, Rs
+static INSN_REGPARM void arm0F9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_MULL, 3); }
+
+// Misc instructions //////////////////////////////////////////////////////
+
+// SWP Rd, Rm, [Rn]
+static INSN_REGPARM void arm109(u32 opcode)
+{
+ u32 address = reg[(opcode >> 16) & 15].I;
+ u32 temp = CPUReadMemory(address);
+ CPUWriteMemory(address, reg[opcode&15].I);
+ reg[(opcode >> 12) & 15].I = temp;
+ clockTicks = 4 + dataTicksAccess32(address) + dataTicksAccess32(address)
+ + codeTicksAccess32(armNextPC);
+}
+
+// SWPB Rd, Rm, [Rn]
+static INSN_REGPARM void arm149(u32 opcode)
+{
+ u32 address = reg[(opcode >> 16) & 15].I;
+ u32 temp = CPUReadByte(address);
+ CPUWriteByte(address, reg[opcode&15].B.B0);
+ reg[(opcode>>12)&15].I = temp;
+ clockTicks = 4 + dataTicksAccess32(address) + dataTicksAccess32(address)
+ + codeTicksAccess32(armNextPC);
+}
+
+// MRS Rd, CPSR
+static INSN_REGPARM void arm100(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FFF0FFF) == 0x010F0000)) {
+ CPUUpdateCPSR();
+ reg[(opcode >> 12) & 0x0F].I = reg[16].I;
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// MRS Rd, SPSR
+static INSN_REGPARM void arm140(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FFF0FFF) == 0x014F0000)) {
+ reg[(opcode >> 12) & 0x0F].I = reg[17].I;
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// MSR CPSR_fields, Rm
+static INSN_REGPARM void arm120(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FF0FFF0) == 0x0120F000)) {
+ CPUUpdateCPSR();
+ u32 value = reg[opcode & 15].I;
+ u32 newValue = reg[16].I;
+ if (armMode > 0x10) {
+ if (opcode & 0x00010000)
+ newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF);
+ if (opcode & 0x00020000)
+ newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00);
+ if (opcode & 0x00040000)
+ newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000);
+ }
+ if (opcode & 0x00080000)
+ newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000);
+ newValue |= 0x10;
+ CPUSwitchMode(newValue & 0x1F, false);
+ reg[16].I = newValue;
+ CPUUpdateFlags();
+ if (!armState) { // this should not be allowed, but it seems to work
+ THUMB_PREFETCH;
+ reg[15].I = armNextPC + 2;
+ }
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// MSR SPSR_fields, Rm
+static INSN_REGPARM void arm160(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FF0FFF0) == 0x0160F000)) {
+ u32 value = reg[opcode & 15].I;
+ if (armMode > 0x10 && armMode < 0x1F) {
+ if (opcode & 0x00010000)
+ reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF);
+ if (opcode & 0x00020000)
+ reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00);
+ if (opcode & 0x00040000)
+ reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000);
+ if (opcode & 0x00080000)
+ reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000);
+ }
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// MSR CPSR_fields, #
+static INSN_REGPARM void arm320(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FF0F000) == 0x0320F000)) {
+ CPUUpdateCPSR();
+ u32 value = opcode & 0xFF;
+ int shift = (opcode & 0xF00) >> 7;
+ if (shift) {
+ ROR_IMM_MSR;
+ }
+ u32 newValue = reg[16].I;
+ if (armMode > 0x10) {
+ if (opcode & 0x00010000)
+ newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF);
+ if (opcode & 0x00020000)
+ newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00);
+ if (opcode & 0x00040000)
+ newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000);
+ }
+ if (opcode & 0x00080000)
+ newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000);
+
+ newValue |= 0x10;
+
+ CPUSwitchMode(newValue & 0x1F, false);
+ reg[16].I = newValue;
+ CPUUpdateFlags();
+ if (!armState) { // this should not be allowed, but it seems to work
+ THUMB_PREFETCH;
+ reg[15].I = armNextPC + 2;
+ }
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// MSR SPSR_fields, #
+static INSN_REGPARM void arm360(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FF0F000) == 0x0360F000)) {
+ if (armMode > 0x10 && armMode < 0x1F) {
+ u32 value = opcode & 0xFF;
+ int shift = (opcode & 0xF00) >> 7;
+ if (shift) {
+ ROR_IMM_MSR;
+ }
+ if (opcode & 0x00010000)
+ reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF);
+ if (opcode & 0x00020000)
+ reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00);
+ if (opcode & 0x00040000)
+ reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000);
+ if (opcode & 0x00080000)
+ reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000);
+ }
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// BX Rm
+static INSN_REGPARM void arm121(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FFFFFF0) == 0x012FFF10)) {
+ int base = opcode & 0x0F;
+ busPrefetchCount = 0;
+ armState = reg[base].I & 1 ? false : true;
+ if (armState) {
+ reg[15].I = reg[base].I & 0xFFFFFFFC;
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+ ARM_PREFETCH;
+ clockTicks = 3 + codeTicksAccessSeq32(armNextPC)
+ + codeTicksAccessSeq32(armNextPC)
+ + codeTicksAccess32(armNextPC);
+ } else {
+ reg[15].I = reg[base].I & 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = 3 + codeTicksAccessSeq16(armNextPC)
+ + codeTicksAccessSeq16(armNextPC)
+ + codeTicksAccess16(armNextPC);
+ }
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// Load/store /////////////////////////////////////////////////////////////
+
+#define OFFSET_IMM \
+ int offset = opcode & 0xFFF;
+#define OFFSET_IMM8 \
+ int offset = ((opcode & 0x0F) | ((opcode>>4) & 0xF0));
+#define OFFSET_REG \
+ int offset = reg[opcode & 15].I;
+#define OFFSET_LSL \
+ int offset = reg[opcode & 15].I << ((opcode>>7) & 31);
+#define OFFSET_LSR \
+ int shift = (opcode >> 7) & 31; \
+ int offset = shift ? reg[opcode & 15].I >> shift : 0;
+#define OFFSET_ASR \
+ int shift = (opcode >> 7) & 31; \
+ int offset; \
+ if (shift) \
+ offset = (int)((s32)reg[opcode & 15].I >> shift);\
+ else if (reg[opcode & 15].I & 0x80000000) \
+ offset = 0xFFFFFFFF; \
+ else \
+ offset = 0;
+#define OFFSET_ROR \
+ int shift = (opcode >> 7) & 31; \
+ u32 offset = reg[opcode & 15].I; \
+ if (shift) { \
+ ROR_OFFSET; \
+ } else { \
+ RRX_OFFSET; \
+ }
+
+#define ADDRESS_POST (reg[base].I)
+#define ADDRESS_PREDEC (reg[base].I - offset)
+#define ADDRESS_PREINC (reg[base].I + offset)
+
+#define OP_STR CPUWriteMemory(address, reg[dest].I)
+#define OP_STRH CPUWriteHalfWord(address, reg[dest].W.W0)
+#define OP_STRB CPUWriteByte(address, reg[dest].B.B0)
+#define OP_LDR reg[dest].I = CPUReadMemory(address)
+#define OP_LDRH reg[dest].I = CPUReadHalfWord(address)
+#define OP_LDRB reg[dest].I = CPUReadByte(address)
+#define OP_LDRSH reg[dest].I = (s16)CPUReadHalfWordSigned(address)
+#define OP_LDRSB reg[dest].I = (s8)CPUReadByte(address)
+
+#define WRITEBACK_NONE /*nothing*/
+#define WRITEBACK_PRE reg[base].I = address
+#define WRITEBACK_POSTDEC reg[base].I = address - offset
+#define WRITEBACK_POSTINC reg[base].I = address + offset
+
+#define LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS) \
+ if (busPrefetchCount == 0) \
+ busPrefetch = busPrefetchEnable; \
+ int dest = (opcode >> 12) & 15; \
+ int base = (opcode >> 16) & 15; \
+ CALC_OFFSET; \
+ u32 address = CALC_ADDRESS;
+
+#define STR(CALC_OFFSET, CALC_ADDRESS, STORE_DATA, WRITEBACK1, WRITEBACK2, SIZE) \
+ LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \
+ WRITEBACK1; \
+ STORE_DATA; \
+ WRITEBACK2; \
+ clockTicks = 2 + dataTicksAccess##SIZE(address) \
+ + codeTicksAccess32(armNextPC);
+#define LDR(CALC_OFFSET, CALC_ADDRESS, LOAD_DATA, WRITEBACK, SIZE) \
+ LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \
+ LOAD_DATA; \
+ if (dest != base) \
+ { \
+ WRITEBACK; \
+ } \
+ clockTicks = 0; \
+ if (dest == 15) { \
+ reg[15].I &= 0xFFFFFFFC; \
+ armNextPC = reg[15].I; \
+ reg[15].I += 4; \
+ ARM_PREFETCH; \
+ clockTicks += 2 + dataTicksAccessSeq32(address) \
+ + dataTicksAccessSeq32(address);\
+ } \
+ clockTicks += 3 + dataTicksAccess##SIZE(address) \
+ + codeTicksAccess32(armNextPC);
+#define STR_POSTDEC(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_POST, STORE_DATA, WRITEBACK_NONE, WRITEBACK_POSTDEC, SIZE)
+#define STR_POSTINC(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_POST, STORE_DATA, WRITEBACK_NONE, WRITEBACK_POSTINC, SIZE)
+#define STR_PREDEC(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_PREDEC, STORE_DATA, WRITEBACK_NONE, WRITEBACK_NONE, SIZE)
+#define STR_PREDEC_WB(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_PREDEC, STORE_DATA, WRITEBACK_PRE, WRITEBACK_NONE, SIZE)
+#define STR_PREINC(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_PREINC, STORE_DATA, WRITEBACK_NONE, WRITEBACK_NONE, SIZE)
+#define STR_PREINC_WB(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_PREINC, STORE_DATA, WRITEBACK_PRE, WRITEBACK_NONE, SIZE)
+#define LDR_POSTDEC(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_POST, LOAD_DATA, WRITEBACK_POSTDEC, SIZE)
+#define LDR_POSTINC(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_POST, LOAD_DATA, WRITEBACK_POSTINC, SIZE)
+#define LDR_PREDEC(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_PREDEC, LOAD_DATA, WRITEBACK_NONE, SIZE)
+#define LDR_PREDEC_WB(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_PREDEC, LOAD_DATA, WRITEBACK_PRE, SIZE)
+#define LDR_PREINC(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_PREINC, LOAD_DATA, WRITEBACK_NONE, SIZE)
+#define LDR_PREINC_WB(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_PREINC, LOAD_DATA, WRITEBACK_PRE, SIZE)
+
+// STRH Rd, [Rn], -Rm
+static INSN_REGPARM void arm00B(u32 opcode) { STR_POSTDEC(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn], #-offset
+static INSN_REGPARM void arm04B(u32 opcode) { STR_POSTDEC(OFFSET_IMM8, OP_STRH, 16); }
+// STRH Rd, [Rn], Rm
+static INSN_REGPARM void arm08B(u32 opcode) { STR_POSTINC(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn], #offset
+static INSN_REGPARM void arm0CB(u32 opcode) { STR_POSTINC(OFFSET_IMM8, OP_STRH, 16); }
+// STRH Rd, [Rn, -Rm]
+static INSN_REGPARM void arm10B(u32 opcode) { STR_PREDEC(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn, -Rm]!
+static INSN_REGPARM void arm12B(u32 opcode) { STR_PREDEC_WB(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn, -#offset]
+static INSN_REGPARM void arm14B(u32 opcode) { STR_PREDEC(OFFSET_IMM8, OP_STRH, 16); }
+// STRH Rd, [Rn, -#offset]!
+static INSN_REGPARM void arm16B(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM8, OP_STRH, 16); }
+// STRH Rd, [Rn, Rm]
+static INSN_REGPARM void arm18B(u32 opcode) { STR_PREINC(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn, Rm]!
+static INSN_REGPARM void arm1AB(u32 opcode) { STR_PREINC_WB(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn, #offset]
+static INSN_REGPARM void arm1CB(u32 opcode) { STR_PREINC(OFFSET_IMM8, OP_STRH, 16); }
+// STRH Rd, [Rn, #offset]!
+static INSN_REGPARM void arm1EB(u32 opcode) { STR_PREINC_WB(OFFSET_IMM8, OP_STRH, 16); }
+
+// LDRH Rd, [Rn], -Rm
+static INSN_REGPARM void arm01B(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn], #-offset
+static INSN_REGPARM void arm05B(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRH, 16); }
+// LDRH Rd, [Rn], Rm
+static INSN_REGPARM void arm09B(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn], #offset
+static INSN_REGPARM void arm0DB(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRH, 16); }
+// LDRH Rd, [Rn, -Rm]
+static INSN_REGPARM void arm11B(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn, -Rm]!
+static INSN_REGPARM void arm13B(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn, -#offset]
+static INSN_REGPARM void arm15B(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRH, 16); }
+// LDRH Rd, [Rn, -#offset]!
+static INSN_REGPARM void arm17B(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRH, 16); }
+// LDRH Rd, [Rn, Rm]
+static INSN_REGPARM void arm19B(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn, Rm]!
+static INSN_REGPARM void arm1BB(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn, #offset]
+static INSN_REGPARM void arm1DB(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRH, 16); }
+// LDRH Rd, [Rn, #offset]!
+static INSN_REGPARM void arm1FB(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRH, 16); }
+
+// LDRSB Rd, [Rn], -Rm
+static INSN_REGPARM void arm01D(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn], #-offset
+static INSN_REGPARM void arm05D(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn], Rm
+static INSN_REGPARM void arm09D(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn], #offset
+static INSN_REGPARM void arm0DD(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, -Rm]
+static INSN_REGPARM void arm11D(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, -Rm]!
+static INSN_REGPARM void arm13D(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, -#offset]
+static INSN_REGPARM void arm15D(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, -#offset]!
+static INSN_REGPARM void arm17D(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, Rm]
+static INSN_REGPARM void arm19D(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, Rm]!
+static INSN_REGPARM void arm1BD(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, #offset]
+static INSN_REGPARM void arm1DD(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, #offset]!
+static INSN_REGPARM void arm1FD(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSB, 16); }
+
+// LDRSH Rd, [Rn], -Rm
+static INSN_REGPARM void arm01F(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn], #-offset
+static INSN_REGPARM void arm05F(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn], Rm
+static INSN_REGPARM void arm09F(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn], #offset
+static INSN_REGPARM void arm0DF(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, -Rm]
+static INSN_REGPARM void arm11F(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, -Rm]!
+static INSN_REGPARM void arm13F(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, -#offset]
+static INSN_REGPARM void arm15F(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, -#offset]!
+static INSN_REGPARM void arm17F(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, Rm]
+static INSN_REGPARM void arm19F(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, Rm]!
+static INSN_REGPARM void arm1BF(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, #offset]
+static INSN_REGPARM void arm1DF(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, #offset]!
+static INSN_REGPARM void arm1FF(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSH, 16); }
+
+// STR[T] Rd, [Rn], -#
+// Note: STR and STRT do the same thing on the GBA (likewise for LDR/LDRT etc)
+static INSN_REGPARM void arm400(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STR, 32); }
+// LDR[T] Rd, [Rn], -#
+static INSN_REGPARM void arm410(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDR, 32); }
+// STRB[T] Rd, [Rn], -#
+static INSN_REGPARM void arm440(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STRB, 16); }
+// LDRB[T] Rd, [Rn], -#
+static INSN_REGPARM void arm450(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDRB, 16); }
+// STR[T] Rd, [Rn], #
+static INSN_REGPARM void arm480(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STR, 32); }
+// LDR Rd, [Rn], #
+static INSN_REGPARM void arm490(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDR, 32); }
+// STRB[T] Rd, [Rn], #
+static INSN_REGPARM void arm4C0(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STRB, 16); }
+// LDRB[T] Rd, [Rn], #
+static INSN_REGPARM void arm4D0(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDRB, 16); }
+// STR Rd, [Rn, -#]
+static INSN_REGPARM void arm500(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STR, 32); }
+// LDR Rd, [Rn, -#]
+static INSN_REGPARM void arm510(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDR, 32); }
+// STR Rd, [Rn, -#]!
+static INSN_REGPARM void arm520(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STR, 32); }
+// LDR Rd, [Rn, -#]!
+static INSN_REGPARM void arm530(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDR, 32); }
+// STRB Rd, [Rn, -#]
+static INSN_REGPARM void arm540(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STRB, 16); }
+// LDRB Rd, [Rn, -#]
+static INSN_REGPARM void arm550(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDRB, 16); }
+// STRB Rd, [Rn, -#]!
+static INSN_REGPARM void arm560(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STRB, 16); }
+// LDRB Rd, [Rn, -#]!
+static INSN_REGPARM void arm570(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDRB, 16); }
+// STR Rd, [Rn, #]
+static INSN_REGPARM void arm580(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STR, 32); }
+// LDR Rd, [Rn, #]
+static INSN_REGPARM void arm590(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDR, 32); }
+// STR Rd, [Rn, #]!
+static INSN_REGPARM void arm5A0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STR, 32); }
+// LDR Rd, [Rn, #]!
+static INSN_REGPARM void arm5B0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDR, 32); }
+// STRB Rd, [Rn, #]
+static INSN_REGPARM void arm5C0(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STRB, 16); }
+// LDRB Rd, [Rn, #]
+static INSN_REGPARM void arm5D0(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDRB, 16); }
+// STRB Rd, [Rn, #]!
+static INSN_REGPARM void arm5E0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STRB, 16); }
+// LDRB Rd, [Rn, #]!
+static INSN_REGPARM void arm5F0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDRB, 16); }
+
+// STR[T] Rd, [Rn], -Rm, LSL #
+static INSN_REGPARM void arm600(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STR, 32); }
+// STR[T] Rd, [Rn], -Rm, LSR #
+static INSN_REGPARM void arm602(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STR, 32); }
+// STR[T] Rd, [Rn], -Rm, ASR #
+static INSN_REGPARM void arm604(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STR, 32); }
+// STR[T] Rd, [Rn], -Rm, ROR #
+static INSN_REGPARM void arm606(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STR, 32); }
+// LDR[T] Rd, [Rn], -Rm, LSL #
+static INSN_REGPARM void arm610(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], -Rm, LSR #
+static INSN_REGPARM void arm612(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], -Rm, ASR #
+static INSN_REGPARM void arm614(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], -Rm, ROR #
+static INSN_REGPARM void arm616(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDR, 32); }
+// STRB[T] Rd, [Rn], -Rm, LSL #
+static INSN_REGPARM void arm640(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], -Rm, LSR #
+static INSN_REGPARM void arm642(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], -Rm, ASR #
+static INSN_REGPARM void arm644(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], -Rm, ROR #
+static INSN_REGPARM void arm646(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STRB, 16); }
+// LDRB[T] Rd, [Rn], -Rm, LSL #
+static INSN_REGPARM void arm650(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB[T] Rd, [Rn], -Rm, LSR #
+static INSN_REGPARM void arm652(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB[T] Rd, [Rn], -Rm, ASR #
+static INSN_REGPARM void arm654(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB Rd, [Rn], -Rm, ROR #
+static INSN_REGPARM void arm656(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDRB, 16); }
+// STR[T] Rd, [Rn], Rm, LSL #
+static INSN_REGPARM void arm680(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STR, 32); }
+// STR[T] Rd, [Rn], Rm, LSR #
+static INSN_REGPARM void arm682(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STR, 32); }
+// STR[T] Rd, [Rn], Rm, ASR #
+static INSN_REGPARM void arm684(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STR, 32); }
+// STR[T] Rd, [Rn], Rm, ROR #
+static INSN_REGPARM void arm686(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STR, 32); }
+// LDR[T] Rd, [Rn], Rm, LSL #
+static INSN_REGPARM void arm690(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], Rm, LSR #
+static INSN_REGPARM void arm692(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], Rm, ASR #
+static INSN_REGPARM void arm694(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], Rm, ROR #
+static INSN_REGPARM void arm696(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDR, 32); }
+// STRB[T] Rd, [Rn], Rm, LSL #
+static INSN_REGPARM void arm6C0(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], Rm, LSR #
+static INSN_REGPARM void arm6C2(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], Rm, ASR #
+static INSN_REGPARM void arm6C4(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], Rm, ROR #
+static INSN_REGPARM void arm6C6(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STRB, 16); }
+// LDRB[T] Rd, [Rn], Rm, LSL #
+static INSN_REGPARM void arm6D0(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB[T] Rd, [Rn], Rm, LSR #
+static INSN_REGPARM void arm6D2(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB[T] Rd, [Rn], Rm, ASR #
+static INSN_REGPARM void arm6D4(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB[T] Rd, [Rn], Rm, ROR #
+static INSN_REGPARM void arm6D6(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDRB, 16); }
+// STR Rd, [Rn, -Rm, LSL #]
+static INSN_REGPARM void arm700(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, LSR #]
+static INSN_REGPARM void arm702(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, ASR #]
+static INSN_REGPARM void arm704(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, ROR #]
+static INSN_REGPARM void arm706(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STR, 32); }
+// LDR Rd, [Rn, -Rm, LSL #]
+static INSN_REGPARM void arm710(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, LSR #]
+static INSN_REGPARM void arm712(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, ASR #]
+static INSN_REGPARM void arm714(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, ROR #]
+static INSN_REGPARM void arm716(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDR, 32); }
+// STR Rd, [Rn, -Rm, LSL #]!
+static INSN_REGPARM void arm720(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, LSR #]!
+static INSN_REGPARM void arm722(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, ASR #]!
+static INSN_REGPARM void arm724(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, ROR #]!
+static INSN_REGPARM void arm726(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STR, 32); }
+// LDR Rd, [Rn, -Rm, LSL #]!
+static INSN_REGPARM void arm730(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, LSR #]!
+static INSN_REGPARM void arm732(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, ASR #]!
+static INSN_REGPARM void arm734(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, ROR #]!
+static INSN_REGPARM void arm736(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDR, 32); }
+// STRB Rd, [Rn, -Rm, LSL #]
+static INSN_REGPARM void arm740(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, LSR #]
+static INSN_REGPARM void arm742(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, ASR #]
+static INSN_REGPARM void arm744(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, ROR #]
+static INSN_REGPARM void arm746(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STRB, 16); }
+// LDRB Rd, [Rn, -Rm, LSL #]
+static INSN_REGPARM void arm750(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, LSR #]
+static INSN_REGPARM void arm752(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, ASR #]
+static INSN_REGPARM void arm754(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, ROR #]
+static INSN_REGPARM void arm756(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDRB, 16); }
+// STRB Rd, [Rn, -Rm, LSL #]!
+static INSN_REGPARM void arm760(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, LSR #]!
+static INSN_REGPARM void arm762(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, ASR #]!
+static INSN_REGPARM void arm764(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, ROR #]!
+static INSN_REGPARM void arm766(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STRB, 16); }
+// LDRB Rd, [Rn, -Rm, LSL #]!
+static INSN_REGPARM void arm770(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, LSR #]!
+static INSN_REGPARM void arm772(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, ASR #]!
+static INSN_REGPARM void arm774(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, ROR #]!
+static INSN_REGPARM void arm776(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDRB, 16); }
+// STR Rd, [Rn, Rm, LSL #]
+static INSN_REGPARM void arm780(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STR, 32); }
+// STR Rd, [Rn, Rm, LSR #]
+static INSN_REGPARM void arm782(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STR, 32); }
+// STR Rd, [Rn, Rm, ASR #]
+static INSN_REGPARM void arm784(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STR, 32); }
+// STR Rd, [Rn, Rm, ROR #]
+static INSN_REGPARM void arm786(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STR, 32); }
+// LDR Rd, [Rn, Rm, LSL #]
+static INSN_REGPARM void arm790(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, LSR #]
+static INSN_REGPARM void arm792(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, ASR #]
+static INSN_REGPARM void arm794(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, ROR #]
+static INSN_REGPARM void arm796(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDR, 32); }
+// STR Rd, [Rn, Rm, LSL #]!
+static INSN_REGPARM void arm7A0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STR, 32); }
+// STR Rd, [Rn, Rm, LSR #]!
+static INSN_REGPARM void arm7A2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STR, 32); }
+// STR Rd, [Rn, Rm, ASR #]!
+static INSN_REGPARM void arm7A4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STR, 32); }
+// STR Rd, [Rn, Rm, ROR #]!
+static INSN_REGPARM void arm7A6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STR, 32); }
+// LDR Rd, [Rn, Rm, LSL #]!
+static INSN_REGPARM void arm7B0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, LSR #]!
+static INSN_REGPARM void arm7B2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, ASR #]!
+static INSN_REGPARM void arm7B4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, ROR #]!
+static INSN_REGPARM void arm7B6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDR, 32); }
+// STRB Rd, [Rn, Rm, LSL #]
+static INSN_REGPARM void arm7C0(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, LSR #]
+static INSN_REGPARM void arm7C2(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, ASR #]
+static INSN_REGPARM void arm7C4(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, ROR #]
+static INSN_REGPARM void arm7C6(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STRB, 16); }
+// LDRB Rd, [Rn, Rm, LSL #]
+static INSN_REGPARM void arm7D0(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, LSR #]
+static INSN_REGPARM void arm7D2(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, ASR #]
+static INSN_REGPARM void arm7D4(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, ROR #]
+static INSN_REGPARM void arm7D6(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDRB, 16); }
+// STRB Rd, [Rn, Rm, LSL #]!
+static INSN_REGPARM void arm7E0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, LSR #]!
+static INSN_REGPARM void arm7E2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, ASR #]!
+static INSN_REGPARM void arm7E4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, ROR #]!
+static INSN_REGPARM void arm7E6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STRB, 16); }
+// LDRB Rd, [Rn, Rm, LSL #]!
+static INSN_REGPARM void arm7F0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, LSR #]!
+static INSN_REGPARM void arm7F2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, ASR #]!
+static INSN_REGPARM void arm7F4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, ROR #]!
+static INSN_REGPARM void arm7F6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDRB, 16); }
+
+// STM/LDM ////////////////////////////////////////////////////////////////
+
+#define STM_REG(bit,num) \
+ if (opcode & (1U<<(bit))) { \
+ CPUWriteMemory(address, reg[(num)].I); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ count++; \
+ address += 4; \
+ }
+#define STMW_REG(bit,num) \
+ if (opcode & (1U<<(bit))) { \
+ CPUWriteMemory(address, reg[(num)].I); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ reg[base].I = temp; \
+ count++; \
+ address += 4; \
+ }
+#define LDM_REG(bit,num) \
+ if (opcode & (1U<<(bit))) { \
+ reg[(num)].I = CPUReadMemory(address); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ count++; \
+ address += 4; \
+ }
+#define STM_LOW(STORE_REG) \
+ STORE_REG(0, 0); \
+ STORE_REG(1, 1); \
+ STORE_REG(2, 2); \
+ STORE_REG(3, 3); \
+ STORE_REG(4, 4); \
+ STORE_REG(5, 5); \
+ STORE_REG(6, 6); \
+ STORE_REG(7, 7);
+#define STM_HIGH(STORE_REG) \
+ STORE_REG(8, 8); \
+ STORE_REG(9, 9); \
+ STORE_REG(10, 10); \
+ STORE_REG(11, 11); \
+ STORE_REG(12, 12); \
+ STORE_REG(13, 13); \
+ STORE_REG(14, 14);
+#define STM_HIGH_2(STORE_REG) \
+ if (armMode == 0x11) { \
+ STORE_REG(8, R8_FIQ); \
+ STORE_REG(9, R9_FIQ); \
+ STORE_REG(10, R10_FIQ); \
+ STORE_REG(11, R11_FIQ); \
+ STORE_REG(12, R12_FIQ); \
+ } else { \
+ STORE_REG(8, 8); \
+ STORE_REG(9, 9); \
+ STORE_REG(10, 10); \
+ STORE_REG(11, 11); \
+ STORE_REG(12, 12); \
+ } \
+ if (armMode != 0x10 && armMode != 0x1F) { \
+ STORE_REG(13, R13_USR); \
+ STORE_REG(14, R14_USR); \
+ } else { \
+ STORE_REG(13, 13); \
+ STORE_REG(14, 14); \
+ }
+#define STM_PC \
+ if (opcode & (1U<<15)) { \
+ CPUWriteMemory(address, reg[15].I+4); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ count++; \
+ }
+#define STMW_PC \
+ if (opcode & (1U<<15)) { \
+ CPUWriteMemory(address, reg[15].I+4); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ reg[base].I = temp; \
+ count++; \
+ }
+#define LDM_LOW \
+ LDM_REG(0, 0); \
+ LDM_REG(1, 1); \
+ LDM_REG(2, 2); \
+ LDM_REG(3, 3); \
+ LDM_REG(4, 4); \
+ LDM_REG(5, 5); \
+ LDM_REG(6, 6); \
+ LDM_REG(7, 7);
+#define LDM_HIGH \
+ LDM_REG(8, 8); \
+ LDM_REG(9, 9); \
+ LDM_REG(10, 10); \
+ LDM_REG(11, 11); \
+ LDM_REG(12, 12); \
+ LDM_REG(13, 13); \
+ LDM_REG(14, 14);
+#define LDM_HIGH_2 \
+ if (armMode == 0x11) { \
+ LDM_REG(8, R8_FIQ); \
+ LDM_REG(9, R9_FIQ); \
+ LDM_REG(10, R10_FIQ); \
+ LDM_REG(11, R11_FIQ); \
+ LDM_REG(12, R12_FIQ); \
+ } else { \
+ LDM_REG(8, 8); \
+ LDM_REG(9, 9); \
+ LDM_REG(10, 10); \
+ LDM_REG(11, 11); \
+ LDM_REG(12, 12); \
+ } \
+ if (armMode != 0x10 && armMode != 0x1F) { \
+ LDM_REG(13, R13_USR); \
+ LDM_REG(14, R14_USR); \
+ } else { \
+ LDM_REG(13, 13); \
+ LDM_REG(14, 14); \
+ }
+#define STM_ALL \
+ STM_LOW(STM_REG); \
+ STM_HIGH(STM_REG); \
+ STM_PC;
+#define STMW_ALL \
+ STM_LOW(STMW_REG); \
+ STM_HIGH(STMW_REG); \
+ STMW_PC;
+#define LDM_ALL \
+ LDM_LOW; \
+ LDM_HIGH; \
+ if (opcode & (1U<<15)) { \
+ reg[15].I = CPUReadMemory(address); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ count++; \
+ } \
+ if (opcode & (1U<<15)) { \
+ armNextPC = reg[15].I; \
+ reg[15].I += 4; \
+ ARM_PREFETCH; \
+ clockTicks += 1 + codeTicksAccessSeq32(armNextPC);\
+ }
+#define STM_ALL_2 \
+ STM_LOW(STM_REG); \
+ STM_HIGH_2(STM_REG); \
+ STM_PC;
+#define STMW_ALL_2 \
+ STM_LOW(STMW_REG); \
+ STM_HIGH_2(STMW_REG); \
+ STMW_PC;
+#define LDM_ALL_2 \
+ LDM_LOW; \
+ if (opcode & (1U<<15)) { \
+ LDM_HIGH; \
+ reg[15].I = CPUReadMemory(address); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address); \
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address); \
+ } \
+ count++; \
+ } else { \
+ LDM_HIGH_2; \
+ }
+#define LDM_ALL_2B \
+ if (opcode & (1U<<15)) { \
+ CPUSwitchMode(reg[17].I & 0x1F, false); \
+ if (armState) { \
+ armNextPC = reg[15].I & 0xFFFFFFFC; \
+ reg[15].I = armNextPC + 4; \
+ ARM_PREFETCH; \
+ } else { \
+ armNextPC = reg[15].I & 0xFFFFFFFE; \
+ reg[15].I = armNextPC + 2; \
+ THUMB_PREFETCH; \
+ } \
+ clockTicks += 1 + codeTicksAccessSeq32(armNextPC);\
+ }
+
+
+// STMDA Rn, {Rlist}
+static INSN_REGPARM void arm800(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp + 4) & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDA Rn, {Rlist}
+static INSN_REGPARM void arm810(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp + 4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMDA Rn!, {Rlist}
+static INSN_REGPARM void arm820(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp+4) & 0xFFFFFFFC;
+ int count = 0;
+ STMW_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDA Rn!, {Rlist}
+static INSN_REGPARM void arm830(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp + 4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+}
+
+// STMDA Rn, {Rlist}^
+static INSN_REGPARM void arm840(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp+4) & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDA Rn, {Rlist}^
+static INSN_REGPARM void arm850(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp + 4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMDA Rn!, {Rlist}^
+static INSN_REGPARM void arm860(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp+4) & 0xFFFFFFFC;
+ int count = 0;
+ STMW_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDA Rn!, {Rlist}^
+static INSN_REGPARM void arm870(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp + 4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIA Rn, {Rlist}
+static INSN_REGPARM void arm880(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIA Rn, {Rlist}
+static INSN_REGPARM void arm890(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIA Rn!, {Rlist}
+static INSN_REGPARM void arm8A0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]);
+ STMW_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIA Rn!, {Rlist}
+static INSN_REGPARM void arm8B0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+}
+
+// STMIA Rn, {Rlist}^
+static INSN_REGPARM void arm8C0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIA Rn, {Rlist}^
+static INSN_REGPARM void arm8D0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIA Rn!, {Rlist}^
+static INSN_REGPARM void arm8E0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]);
+ STMW_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIA Rn!, {Rlist}^
+static INSN_REGPARM void arm8F0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMDB Rn, {Rlist}
+static INSN_REGPARM void arm900(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDB Rn, {Rlist}
+static INSN_REGPARM void arm910(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMDB Rn!, {Rlist}
+static INSN_REGPARM void arm920(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ STMW_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDB Rn!, {Rlist}
+static INSN_REGPARM void arm930(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+}
+
+// STMDB Rn, {Rlist}^
+static INSN_REGPARM void arm940(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDB Rn, {Rlist}^
+static INSN_REGPARM void arm950(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMDB Rn!, {Rlist}^
+static INSN_REGPARM void arm960(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ STMW_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDB Rn!, {Rlist}^
+static INSN_REGPARM void arm970(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIB Rn, {Rlist}
+static INSN_REGPARM void arm980(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIB Rn, {Rlist}
+static INSN_REGPARM void arm990(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIB Rn!, {Rlist}
+static INSN_REGPARM void arm9A0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]);
+ STMW_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIB Rn!, {Rlist}
+static INSN_REGPARM void arm9B0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+}
+
+// STMIB Rn, {Rlist}^
+static INSN_REGPARM void arm9C0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIB Rn, {Rlist}^
+static INSN_REGPARM void arm9D0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIB Rn!, {Rlist}^
+static INSN_REGPARM void arm9E0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]);
+ STMW_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIB Rn!, {Rlist}^
+static INSN_REGPARM void arm9F0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// B/BL/SWI and (unimplemented) coproc support ////////////////////////////
+
+// B <offset>
+static INSN_REGPARM void armA00(u32 opcode)
+{
+ int offset = opcode & 0x00FFFFFF;
+ if (offset & 0x00800000)
+ offset |= 0xFF000000; // negative offset
+ reg[15].I += offset<<2;
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+ ARM_PREFETCH;
+ clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
+ clockTicks += 2 + codeTicksAccess32(armNextPC)
+ + codeTicksAccessSeq32(armNextPC);
+ busPrefetchCount = 0;
+}
+
+// BL <offset>
+static INSN_REGPARM void armB00(u32 opcode)
+{
+ int offset = opcode & 0x00FFFFFF;
+ if (offset & 0x00800000)
+ offset |= 0xFF000000; // negative offset
+ reg[14].I = reg[15].I - 4;
+ reg[15].I += offset<<2;
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+ ARM_PREFETCH;
+ clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
+ clockTicks += 2 + codeTicksAccess32(armNextPC)
+ + codeTicksAccessSeq32(armNextPC);
+ busPrefetchCount = 0;
+}
+
+
+#ifdef GP_SUPPORT
+// MRC
+static INSN_REGPARM void armE01(u32 opcode)
+{
+}
+#else
+ #define armE01 armUnknownInsn
+#endif
+
+
+// SWI <comment>
+static INSN_REGPARM void armF00(u32 opcode)
+{
+ clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
+ clockTicks += 2 + codeTicksAccess32(armNextPC)
+ + codeTicksAccessSeq32(armNextPC);
+ busPrefetchCount = 0;
+ CPUSoftwareInterrupt(opcode & 0x00FFFFFF);
+}
+
+// Instruction table //////////////////////////////////////////////////////
+
+typedef INSN_REGPARM void (*insnfunc_t)(u32 opcode);
+#define REP16(insn) \
+ insn,insn,insn,insn,insn,insn,insn,insn,\
+ insn,insn,insn,insn,insn,insn,insn,insn
+#define REP256(insn) \
+ REP16(insn),REP16(insn),REP16(insn),REP16(insn),\
+ REP16(insn),REP16(insn),REP16(insn),REP16(insn),\
+ REP16(insn),REP16(insn),REP16(insn),REP16(insn),\
+ REP16(insn),REP16(insn),REP16(insn),REP16(insn)
+#define arm_UI armUnknownInsn
+#ifdef BKPT_SUPPORT
+ #define arm_BP armBreakpoint
+#else
+ #define arm_BP armUnknownInsn
+#endif
+static insnfunc_t armInsnTable[4096] = {
+ arm000,arm001,arm002,arm003,arm004,arm005,arm006,arm007, // 000
+ arm000,arm009,arm002,arm00B,arm004,arm_UI,arm006,arm_UI, // 008
+ arm010,arm011,arm012,arm013,arm014,arm015,arm016,arm017, // 010
+ arm010,arm019,arm012,arm01B,arm014,arm01D,arm016,arm01F, // 018
+ arm020,arm021,arm022,arm023,arm024,arm025,arm026,arm027, // 020
+ arm020,arm029,arm022,arm_UI,arm024,arm_UI,arm026,arm_UI, // 028
+ arm030,arm031,arm032,arm033,arm034,arm035,arm036,arm037, // 030
+ arm030,arm039,arm032,arm_UI,arm034,arm01D,arm036,arm01F, // 038
+ arm040,arm041,arm042,arm043,arm044,arm045,arm046,arm047, // 040
+ arm040,arm_UI,arm042,arm04B,arm044,arm_UI,arm046,arm_UI, // 048
+ arm050,arm051,arm052,arm053,arm054,arm055,arm056,arm057, // 050
+ arm050,arm_UI,arm052,arm05B,arm054,arm05D,arm056,arm05F, // 058
+ arm060,arm061,arm062,arm063,arm064,arm065,arm066,arm067, // 060
+ arm060,arm_UI,arm062,arm_UI,arm064,arm_UI,arm066,arm_UI, // 068
+ arm070,arm071,arm072,arm073,arm074,arm075,arm076,arm077, // 070
+ arm070,arm_UI,arm072,arm_UI,arm074,arm05D,arm076,arm05F, // 078
+ arm080,arm081,arm082,arm083,arm084,arm085,arm086,arm087, // 080
+ arm080,arm089,arm082,arm08B,arm084,arm_UI,arm086,arm_UI, // 088
+ arm090,arm091,arm092,arm093,arm094,arm095,arm096,arm097, // 090
+ arm090,arm099,arm092,arm09B,arm094,arm09D,arm096,arm09F, // 098
+ arm0A0,arm0A1,arm0A2,arm0A3,arm0A4,arm0A5,arm0A6,arm0A7, // 0A0
+ arm0A0,arm0A9,arm0A2,arm_UI,arm0A4,arm_UI,arm0A6,arm_UI, // 0A8
+ arm0B0,arm0B1,arm0B2,arm0B3,arm0B4,arm0B5,arm0B6,arm0B7, // 0B0
+ arm0B0,arm0B9,arm0B2,arm_UI,arm0B4,arm09D,arm0B6,arm09F, // 0B8
+ arm0C0,arm0C1,arm0C2,arm0C3,arm0C4,arm0C5,arm0C6,arm0C7, // 0C0
+ arm0C0,arm0C9,arm0C2,arm0CB,arm0C4,arm_UI,arm0C6,arm_UI, // 0C8
+ arm0D0,arm0D1,arm0D2,arm0D3,arm0D4,arm0D5,arm0D6,arm0D7, // 0D0
+ arm0D0,arm0D9,arm0D2,arm0DB,arm0D4,arm0DD,arm0D6,arm0DF, // 0D8
+ arm0E0,arm0E1,arm0E2,arm0E3,arm0E4,arm0E5,arm0E6,arm0E7, // 0E0
+ arm0E0,arm0E9,arm0E2,arm_UI,arm0E4,arm_UI,arm0E6,arm_UI, // 0E8
+ arm0F0,arm0F1,arm0F2,arm0F3,arm0F4,arm0F5,arm0F6,arm0F7, // 0F0
+ arm0F0,arm0F9,arm0F2,arm_UI,arm0F4,arm0DD,arm0F6,arm0DF, // 0F8
+
+ arm100,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 100
+ arm_UI,arm109,arm_UI,arm10B,arm_UI,arm_UI,arm_UI,arm_UI, // 108
+ arm110,arm111,arm112,arm113,arm114,arm115,arm116,arm117, // 110
+ arm110,arm_UI,arm112,arm11B,arm114,arm11D,arm116,arm11F, // 118
+ arm120,arm121,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_BP, // 120
+ arm_UI,arm_UI,arm_UI,arm12B,arm_UI,arm_UI,arm_UI,arm_UI, // 128
+ arm130,arm131,arm132,arm133,arm134,arm135,arm136,arm137, // 130
+ arm130,arm_UI,arm132,arm13B,arm134,arm13D,arm136,arm13F, // 138
+ arm140,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 140
+ arm_UI,arm149,arm_UI,arm14B,arm_UI,arm_UI,arm_UI,arm_UI, // 148
+ arm150,arm151,arm152,arm153,arm154,arm155,arm156,arm157, // 150
+ arm150,arm_UI,arm152,arm15B,arm154,arm15D,arm156,arm15F, // 158
+ arm160,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 160
+ arm_UI,arm_UI,arm_UI,arm16B,arm_UI,arm_UI,arm_UI,arm_UI, // 168
+ arm170,arm171,arm172,arm173,arm174,arm175,arm176,arm177, // 170
+ arm170,arm_UI,arm172,arm17B,arm174,arm17D,arm176,arm17F, // 178
+ arm180,arm181,arm182,arm183,arm184,arm185,arm186,arm187, // 180
+ arm180,arm_UI,arm182,arm18B,arm184,arm_UI,arm186,arm_UI, // 188
+ arm190,arm191,arm192,arm193,arm194,arm195,arm196,arm197, // 190
+ arm190,arm_UI,arm192,arm19B,arm194,arm19D,arm196,arm19F, // 198
+ arm1A0,arm1A1,arm1A2,arm1A3,arm1A4,arm1A5,arm1A6,arm1A7, // 1A0
+ arm1A0,arm_UI,arm1A2,arm1AB,arm1A4,arm_UI,arm1A6,arm_UI, // 1A8
+ arm1B0,arm1B1,arm1B2,arm1B3,arm1B4,arm1B5,arm1B6,arm1B7, // 1B0
+ arm1B0,arm_UI,arm1B2,arm1BB,arm1B4,arm1BD,arm1B6,arm1BF, // 1B8
+ arm1C0,arm1C1,arm1C2,arm1C3,arm1C4,arm1C5,arm1C6,arm1C7, // 1C0
+ arm1C0,arm_UI,arm1C2,arm1CB,arm1C4,arm_UI,arm1C6,arm_UI, // 1C8
+ arm1D0,arm1D1,arm1D2,arm1D3,arm1D4,arm1D5,arm1D6,arm1D7, // 1D0
+ arm1D0,arm_UI,arm1D2,arm1DB,arm1D4,arm1DD,arm1D6,arm1DF, // 1D8
+ arm1E0,arm1E1,arm1E2,arm1E3,arm1E4,arm1E5,arm1E6,arm1E7, // 1E0
+ arm1E0,arm_UI,arm1E2,arm1EB,arm1E4,arm_UI,arm1E6,arm_UI, // 1E8
+ arm1F0,arm1F1,arm1F2,arm1F3,arm1F4,arm1F5,arm1F6,arm1F7, // 1F0
+ arm1F0,arm_UI,arm1F2,arm1FB,arm1F4,arm1FD,arm1F6,arm1FF, // 1F8
+
+ REP16(arm200),REP16(arm210),REP16(arm220),REP16(arm230), // 200
+ REP16(arm240),REP16(arm250),REP16(arm260),REP16(arm270), // 240
+ REP16(arm280),REP16(arm290),REP16(arm2A0),REP16(arm2B0), // 280
+ REP16(arm2C0),REP16(arm2D0),REP16(arm2E0),REP16(arm2F0), // 2C0
+ REP16(arm_UI),REP16(arm310),REP16(arm320),REP16(arm330), // 300
+ REP16(arm_UI),REP16(arm350),REP16(arm360),REP16(arm370), // 340
+ REP16(arm380),REP16(arm390),REP16(arm3A0),REP16(arm3B0), // 380
+ REP16(arm3C0),REP16(arm3D0),REP16(arm3E0),REP16(arm3F0), // 3C0
+
+ REP16(arm400),REP16(arm410),REP16(arm400),REP16(arm410), // 400
+ REP16(arm440),REP16(arm450),REP16(arm440),REP16(arm450), // 440
+ REP16(arm480),REP16(arm490),REP16(arm480),REP16(arm490), // 480
+ REP16(arm4C0),REP16(arm4D0),REP16(arm4C0),REP16(arm4D0), // 4C0
+ REP16(arm500),REP16(arm510),REP16(arm520),REP16(arm530), // 500
+ REP16(arm540),REP16(arm550),REP16(arm560),REP16(arm570), // 540
+ REP16(arm580),REP16(arm590),REP16(arm5A0),REP16(arm5B0), // 580
+ REP16(arm5C0),REP16(arm5D0),REP16(arm5E0),REP16(arm5F0), // 5C0
+
+ arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 600
+ arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 608
+ arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 610
+ arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 618
+ arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 620
+ arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 628
+ arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 630
+ arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 638
+ arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 640
+ arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 648
+ arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 650
+ arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 658
+ arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 660
+ arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 668
+ arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 670
+ arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 678
+ arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 680
+ arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 688
+ arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 690
+ arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 698
+ arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 6A0
+ arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 6A8
+ arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 6B0
+ arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 6B8
+ arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6C0
+ arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6C8
+ arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6D0
+ arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6D8
+ arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6E0
+ arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6E8
+ arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6F0
+ arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6F8
+
+ arm700,arm_UI,arm702,arm_UI,arm704,arm_UI,arm706,arm_UI, // 700
+ arm700,arm_UI,arm702,arm_UI,arm704,arm_UI,arm706,arm_UI, // 708
+ arm710,arm_UI,arm712,arm_UI,arm714,arm_UI,arm716,arm_UI, // 710
+ arm710,arm_UI,arm712,arm_UI,arm714,arm_UI,arm716,arm_UI, // 718
+ arm720,arm_UI,arm722,arm_UI,arm724,arm_UI,arm726,arm_UI, // 720
+ arm720,arm_UI,arm722,arm_UI,arm724,arm_UI,arm726,arm_UI, // 728
+ arm730,arm_UI,arm732,arm_UI,arm734,arm_UI,arm736,arm_UI, // 730
+ arm730,arm_UI,arm732,arm_UI,arm734,arm_UI,arm736,arm_UI, // 738
+ arm740,arm_UI,arm742,arm_UI,arm744,arm_UI,arm746,arm_UI, // 740
+ arm740,arm_UI,arm742,arm_UI,arm744,arm_UI,arm746,arm_UI, // 748
+ arm750,arm_UI,arm752,arm_UI,arm754,arm_UI,arm756,arm_UI, // 750
+ arm750,arm_UI,arm752,arm_UI,arm754,arm_UI,arm756,arm_UI, // 758
+ arm760,arm_UI,arm762,arm_UI,arm764,arm_UI,arm766,arm_UI, // 760
+ arm760,arm_UI,arm762,arm_UI,arm764,arm_UI,arm766,arm_UI, // 768
+ arm770,arm_UI,arm772,arm_UI,arm774,arm_UI,arm776,arm_UI, // 770
+ arm770,arm_UI,arm772,arm_UI,arm774,arm_UI,arm776,arm_UI, // 778
+ arm780,arm_UI,arm782,arm_UI,arm784,arm_UI,arm786,arm_UI, // 780
+ arm780,arm_UI,arm782,arm_UI,arm784,arm_UI,arm786,arm_UI, // 788
+ arm790,arm_UI,arm792,arm_UI,arm794,arm_UI,arm796,arm_UI, // 790
+ arm790,arm_UI,arm792,arm_UI,arm794,arm_UI,arm796,arm_UI, // 798
+ arm7A0,arm_UI,arm7A2,arm_UI,arm7A4,arm_UI,arm7A6,arm_UI, // 7A0
+ arm7A0,arm_UI,arm7A2,arm_UI,arm7A4,arm_UI,arm7A6,arm_UI, // 7A8
+ arm7B0,arm_UI,arm7B2,arm_UI,arm7B4,arm_UI,arm7B6,arm_UI, // 7B0
+ arm7B0,arm_UI,arm7B2,arm_UI,arm7B4,arm_UI,arm7B6,arm_UI, // 7B8
+ arm7C0,arm_UI,arm7C2,arm_UI,arm7C4,arm_UI,arm7C6,arm_UI, // 7C0
+ arm7C0,arm_UI,arm7C2,arm_UI,arm7C4,arm_UI,arm7C6,arm_UI, // 7C8
+ arm7D0,arm_UI,arm7D2,arm_UI,arm7D4,arm_UI,arm7D6,arm_UI, // 7D0
+ arm7D0,arm_UI,arm7D2,arm_UI,arm7D4,arm_UI,arm7D6,arm_UI, // 7D8
+ arm7E0,arm_UI,arm7E2,arm_UI,arm7E4,arm_UI,arm7E6,arm_UI, // 7E0
+ arm7E0,arm_UI,arm7E2,arm_UI,arm7E4,arm_UI,arm7E6,arm_UI, // 7E8
+ arm7F0,arm_UI,arm7F2,arm_UI,arm7F4,arm_UI,arm7F6,arm_UI, // 7F0
+ arm7F0,arm_UI,arm7F2,arm_UI,arm7F4,arm_UI,arm7F6,arm_BP, // 7F8
+
+ REP16(arm800),REP16(arm810),REP16(arm820),REP16(arm830), // 800
+ REP16(arm840),REP16(arm850),REP16(arm860),REP16(arm870), // 840
+ REP16(arm880),REP16(arm890),REP16(arm8A0),REP16(arm8B0), // 880
+ REP16(arm8C0),REP16(arm8D0),REP16(arm8E0),REP16(arm8F0), // 8C0
+ REP16(arm900),REP16(arm910),REP16(arm920),REP16(arm930), // 900
+ REP16(arm940),REP16(arm950),REP16(arm960),REP16(arm970), // 940
+ REP16(arm980),REP16(arm990),REP16(arm9A0),REP16(arm9B0), // 980
+ REP16(arm9C0),REP16(arm9D0),REP16(arm9E0),REP16(arm9F0), // 9C0
+
+ REP256(armA00), // A00
+ REP256(armB00), // B00
+ REP256(arm_UI), // C00
+ REP256(arm_UI), // D00
+
+ arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E00
+ arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E08
+ arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E10
+ arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E18
+ REP16(arm_UI), // E20
+ REP16(arm_UI), // E30
+ REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // E40
+ REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // E80
+ REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // EC0
+
+ REP256(armF00), // F00
+};
+
+// Wrapper routine (execution loop) ///////////////////////////////////////
+
+#if 0
+#include<time.h>
+static void tester(void) {
+ static int ran=0;if(ran)return;ran=1;
+ FILE*f=fopen("p:\\timing.txt","w");if(!f)return;
+ for (int op=/*0*/9; op</*0xF00*/10;op++){if(armInsnTable[op]==arm_UI)continue;
+ int i;for(i=0;i<op;i++)if(armInsnTable[op]==armInsnTable[i])break;if(i<op)continue;
+ for(i=0;i<16;i++)reg[i].I=0x3100000;
+ clock_t s=clock();for(i=0;i<10000000;i++)armInsnTable[op](0);clock_t e=clock();
+ fprintf(f,"arm%03X %6ld\n",op,e-s);fflush(f);
+ }fclose(f);
+}
+#endif
+
+int armExecute()
+{
+ do {
+ /*if( cheatsEnabled ) {
+ cpuMasterCodeCheck();
+ }*/
+
+ if ((armNextPC & 0x0803FFFF) == 0x08020000)
+ busPrefetchCount = 0x100;
+
+ u32 opcode = cpuPrefetch[0];
+ cpuPrefetch[0] = cpuPrefetch[1];
+
+ busPrefetch = false;
+ if (busPrefetchCount & 0xFFFFFE00)
+ busPrefetchCount = 0x100 | (busPrefetchCount & 0xFF);
+
+ clockTicks = 0;
+ int oldArmNextPC = armNextPC;
+
+#ifndef FINAL_VERSION
+ if (armNextPC == stop) {
+ armNextPC++;
+ }
+#endif
+
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+ ARM_PREFETCH_NEXT;
+
+ int cond = opcode >> 28;
+ bool cond_res = true;
+ if (UNLIKELY(cond != 0x0E)) { // most opcodes are AL (always)
+ switch(cond) {
+ case 0x00: // EQ
+ cond_res = Z_FLAG;
+ break;
+ case 0x01: // NE
+ cond_res = !Z_FLAG;
+ break;
+ case 0x02: // CS
+ cond_res = C_FLAG;
+ break;
+ case 0x03: // CC
+ cond_res = !C_FLAG;
+ break;
+ case 0x04: // MI
+ cond_res = N_FLAG;
+ break;
+ case 0x05: // PL
+ cond_res = !N_FLAG;
+ break;
+ case 0x06: // VS
+ cond_res = V_FLAG;
+ break;
+ case 0x07: // VC
+ cond_res = !V_FLAG;
+ break;
+ case 0x08: // HI
+ cond_res = C_FLAG && !Z_FLAG;
+ break;
+ case 0x09: // LS
+ cond_res = !C_FLAG || Z_FLAG;
+ break;
+ case 0x0A: // GE
+ cond_res = N_FLAG == V_FLAG;
+ break;
+ case 0x0B: // LT
+ cond_res = N_FLAG != V_FLAG;
+ break;
+ case 0x0C: // GT
+ cond_res = !Z_FLAG &&(N_FLAG == V_FLAG);
+ break;
+ case 0x0D: // LE
+ cond_res = Z_FLAG || (N_FLAG != V_FLAG);
+ break;
+ case 0x0E: // AL (impossible, checked above)
+ cond_res = true;
+ break;
+ case 0x0F:
+ default:
+ // ???
+ cond_res = false;
+ break;
+ }
+ }
+
+ if (cond_res)
+ (*armInsnTable[((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F)])(opcode);
+#ifdef INSN_COUNTER
+ count(opcode, cond_res);
+#endif
+ if (clockTicks < 0)
+ return 0;
+ if (clockTicks == 0)
+ clockTicks = 1 + codeTicksAccessSeq32(oldArmNextPC);
+ cpuTotalTicks += clockTicks;
+
+ } while (cpuTotalTicks<cpuNextEvent && armState && !holdState && !SWITicks);
+
+ return 1;
+}
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/GBA-thumb.cpp
@@ -1,1 +1,2324 @@
-
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "GBA.h"
+#include "GBAcpu.h"
+#include "GBAinline.h"
+#include "Globals.h"
+//#include "EEprom.h"
+//#include "Flash.h"
+#include "Sound.h"
+//#include "Sram.h"
+#include "bios.h"
+//#include "Cheats.h"
+//#include "../NLS.h"
+//#include "elf.h"
+//#include "../Util.h"
+//#include "../System.h"
+//#include "agbprint.h"
+#ifdef PROFILING
+#include "prof/prof.h"
+#endif
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+
+static int clockTicks;
+
+static INSN_REGPARM void thumbUnknownInsn(u32 opcode)
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_UNDEFINED)
+ log("Undefined THUMB instruction %04x at %08x\n", opcode, armNextPC-2);
+#endif
+ CPUUndefinedException();
+}
+
+#ifdef BKPT_SUPPORT
+static INSN_REGPARM void thumbBreakpoint(u32 opcode)
+{
+ reg[15].I -= 2;
+ armNextPC -= 2;
+ dbgSignal(5, opcode & 255);
+ clockTicks = -1;
+}
+#endif
+
+// Common macros //////////////////////////////////////////////////////////
+
+#ifdef BKPT_SUPPORT
+# define THUMB_CONSOLE_OUTPUT(a,b) do { \
+ if ((opcode == 0x4000) && (reg[0].I == 0xC0DED00D)) { \
+ dbgOutput((a), (b)); \
+ } \
+} while (0)
+# define UPDATE_OLDREG do { \
+ if (debugger_last) { \
+ snprintf(oldbuffer, sizeof(oldbuffer), "%08X", \
+ armState ? reg[15].I - 4 : reg[15].I - 2); \
+ int i; \
+ for (i = 0; i < 18; i++) { \
+ oldreg[i] = reg[i].I; \
+ } \
+ } \
+} while (0)
+#else
+# define THUMB_CONSOLE_OUTPUT(a,b)
+# define UPDATE_OLDREG
+#endif
+
+#define NEG(i) ((i) >> 31)
+#define POS(i) ((~(i)) >> 31)
+
+#ifndef C_CORE
+#ifdef __GNUC__
+#ifdef __POWERPC__
+ #define ADD_RD_RS_RN(N) \
+ { \
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[source].I), \
+ "r" (reg[N].I) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define ADD_RD_RS_O3(N) \
+ { \
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[source].I), \
+ "r" (N) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define ADD_RD_RS_O3_0 ADD_RD_RS_O3
+ #define ADD_RN_O8(d) \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[(d)].I), \
+ "r" (opcode & 255) \
+ ); \
+ reg[(d)].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define CMN_RD_RS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[dest].I), \
+ "r" (value) \
+ ); \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define ADC_RD_RS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("mtspr 1, %4\n" \ /* reg 1 is xer */
+ "addeo. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[dest].I), \
+ "r" (value), \
+ "r" (C_FLAG << 29) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define SUB_RD_RS_RN(N) \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[source].I), \
+ "r" (reg[N].I) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define SUB_RD_RS_O3(N) \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[source].I), \
+ "r" (N) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define SUB_RD_RS_O3_0 SUB_RD_RS_O3
+ #define SUB_RN_O8(d) \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[(d)].I), \
+ "r" (opcode & 255) \
+ ); \
+ reg[(d)].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define CMP_RN_O8(d) \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[(d)].I), \
+ "r" (opcode & 255) \
+ ); \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define SBC_RD_RS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("mtspr 1, %4\n" \ /* reg 1 is xer */
+ "subfeo. %0, %3, %2\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[dest].I), \
+ "r" (value), \
+ "r" (C_FLAG << 29) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define NEG_RD_RS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subfco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[source].I), \
+ "r" (0) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define CMP_RD_RS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[dest].I), \
+ "r" (value) \
+ ); \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+#else
+ #define EMIT1(op,arg) #op" "arg"; "
+ #define EMIT2(op,src,dest) #op" "src", "dest"; "
+ #define KONST(val) "$"#val
+ #define ASMVAR(cvar) ASMVAR2 (__USER_LABEL_PREFIX__, cvar)
+ #define ASMVAR2(prefix,cvar) STRING (prefix) cvar
+ #define STRING(x) #x
+ #define VAR(var) ASMVAR(#var)
+ #define REGREF1(index) ASMVAR("reg("index")")
+ #define REGREF2(index,scale) ASMVAR("reg(,"index","#scale")")
+ #define eax "%%eax"
+ #define ecx "%%ecx"
+ #define edx "%%edx"
+ #define ADD_RN_O8(d) \
+ asm ("andl $0xFF, %%eax;"\
+ "addl %%eax, %0;"\
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT1(setcb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG)) \
+ : "=m" (reg[(d)].I));
+ #define CMN_RD_RS \
+ asm ("add %0, %1;"\
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT1(setcb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG)) \
+ : \
+ : "r" (value), "r" (reg[dest].I):"1");
+ #define ADC_RD_RS \
+ asm (EMIT2(bt,KONST(0),VAR(C_FLAG)) \
+ "adc %1, %%ebx;"\
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT1(setcb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG)) \
+ : "=b" (reg[dest].I)\
+ : "r" (value), "b" (reg[dest].I));
+ #define SUB_RN_O8(d) \
+ asm ("andl $0xFF, %%eax;"\
+ "subl %%eax, %0;"\
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT1(setncb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG)) \
+ : "=m" (reg[(d)].I));
+ #define MOV_RN_O8(d) \
+ asm ("andl $0xFF, %%eax;"\
+ EMIT2(movb,KONST(0),VAR(N_FLAG)) \
+ "movl %%eax, %0;"\
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ : "=m" (reg[(d)].I));
+ #define CMP_RN_O8(d) \
+ asm ("andl $0xFF, %%eax;"\
+ "cmpl %%eax, %0;"\
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT1(setncb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG)) \
+ : \
+ : "m" (reg[(d)].I));
+ #define SBC_RD_RS \
+ asm volatile (EMIT2(bt,KONST(0),VAR(C_FLAG)) \
+ "cmc;"\
+ "sbb %1, %%ebx;"\
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT1(setncb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG)) \
+ : "=b" (reg[dest].I)\
+ : "r" (value), "b" (reg[dest].I) : "cc", "memory");
+ #define LSL_RD_RS \
+ asm ("shl %%cl, %%eax;"\
+ EMIT1(setcb, VAR(C_FLAG)) \
+ : "=a" (value)\
+ : "a" (reg[dest].I), "c" (value));
+ #define LSR_RD_RS \
+ asm ("shr %%cl, %%eax;"\
+ EMIT1(setcb, VAR(C_FLAG)) \
+ : "=a" (value)\
+ : "a" (reg[dest].I), "c" (value));
+ #define ASR_RD_RS \
+ asm ("sar %%cl, %%eax;"\
+ EMIT1(setcb, VAR(C_FLAG)) \
+ : "=a" (value)\
+ : "a" (reg[dest].I), "c" (value));
+ #define ROR_RD_RS \
+ asm ("ror %%cl, %%eax;"\
+ EMIT1(setcb, VAR(C_FLAG)) \
+ : "=a" (value)\
+ : "a" (reg[dest].I), "c" (value));
+ #define NEG_RD_RS \
+ asm ("neg %%ebx;"\
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT1(setncb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG)) \
+ : "=b" (reg[dest].I)\
+ : "b" (reg[source].I));
+ #define CMP_RD_RS \
+ asm ("sub %0, %1;"\
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT1(setncb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG)) \
+ : \
+ : "r" (value), "r" (reg[dest].I):"1");
+ #define IMM5_INSN(OP,N) \
+ asm("movl %%eax,%%ecx;" \
+ "shrl $1,%%eax;" \
+ "andl $7,%%ecx;" \
+ "andl $0x1C,%%eax;" \
+ EMIT2(movl, REGREF1(eax), edx) \
+ OP \
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT2(movl, edx, REGREF2(ecx,4)) \
+ : : "i" (N))
+ #define IMM5_INSN_0(OP) \
+ asm("movl %%eax,%%ecx;" \
+ "shrl $1,%%eax;" \
+ "andl $7,%%ecx;" \
+ "andl $0x1C,%%eax;" \
+ EMIT2(movl, REGREF1(eax), edx) \
+ OP \
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT2(movl, edx, REGREF2(ecx,4)) \
+ : : )
+ #define IMM5_LSL \
+ "shll %0,%%edx;"\
+ EMIT1(setcb, VAR(C_FLAG))
+ #define IMM5_LSL_0 \
+ "testl %%edx,%%edx;"
+ #define IMM5_LSR \
+ "shrl %0,%%edx;"\
+ EMIT1(setcb, VAR(C_FLAG))
+ #define IMM5_LSR_0 \
+ "testl %%edx,%%edx;"\
+ EMIT1(setsb, VAR(C_FLAG)) \
+ "xorl %%edx,%%edx;"
+ #define IMM5_ASR \
+ "sarl %0,%%edx;"\
+ EMIT1(setcb, VAR(C_FLAG))
+ #define IMM5_ASR_0 \
+ "sarl $31,%%edx;"\
+ EMIT1(setsb, VAR(C_FLAG))
+ #define THREEARG_INSN(OP,N) \
+ asm("movl %%eax,%%edx;" \
+ "shrl $1,%%edx;" \
+ "andl $0x1C,%%edx;" \
+ "andl $7,%%eax;" \
+ EMIT2(movl, REGREF1(edx), ecx) \
+ OP(N) \
+ EMIT1(setsb, VAR(N_FLAG)) \
+ EMIT1(setzb, VAR(Z_FLAG)) \
+ EMIT2(movl, ecx, REGREF2(eax,4)) \
+ : : )
+ #define ADD_RD_RS_RN(N) \
+ EMIT2(add,VAR(reg)"+"#N"*4",ecx) \
+ EMIT1(setcb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG))
+ #define ADD_RD_RS_O3(N) \
+ "add $"#N",%%ecx;" \
+ EMIT1(setcb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG))
+ #define ADD_RD_RS_O3_0(N) \
+ EMIT2(movb,KONST(0),VAR(C_FLAG)) \
+ "add $0,%%ecx;" \
+ EMIT2(movb,KONST(0),VAR(V_FLAG))
+ #define SUB_RD_RS_RN(N) \
+ EMIT2(sub,VAR(reg)"+"#N"*4",ecx) \
+ EMIT1(setncb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG))
+ #define SUB_RD_RS_O3(N) \
+ "sub $"#N",%%ecx;" \
+ EMIT1(setncb, VAR(C_FLAG)) \
+ EMIT1(setob, VAR(V_FLAG))
+ #define SUB_RD_RS_O3_0(N) \
+ EMIT2(movb,KONST(1),VAR(C_FLAG)) \
+ "sub $0,%%ecx;" \
+ EMIT2(movb,KONST(0),VAR(V_FLAG))
+#endif
+#else // !__GNUC__
+ #define ADD_RD_RS_RN(N) \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm add ebx, dword ptr [OFFSET reg+4*N]\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define ADD_RD_RS_O3(N) \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm add ebx, N\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define ADD_RD_RS_O3_0 \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm add ebx, 0\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm mov byte ptr C_FLAG, 0\
+ __asm mov byte ptr V_FLAG, 0\
+ }
+ #define ADD_RN_O8(d) \
+ {\
+ __asm mov ebx, opcode\
+ __asm and ebx, 255\
+ __asm add dword ptr [OFFSET reg+4*(d)], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define CMN_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm add ebx, value\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define ADC_RD_RS \
+ {\
+ __asm mov ebx, dest\
+ __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
+ __asm bt word ptr C_FLAG, 0\
+ __asm adc ebx, value\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define SUB_RD_RS_RN(N) \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm sub ebx, dword ptr [OFFSET reg+4*N]\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define SUB_RD_RS_O3(N) \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm sub ebx, N\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define SUB_RD_RS_O3_0 \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm sub ebx, 0\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm mov byte ptr C_FLAG, 1\
+ __asm mov byte ptr V_FLAG, 0\
+ }
+ #define SUB_RN_O8(d) \
+ {\
+ __asm mov ebx, opcode\
+ __asm and ebx, 255\
+ __asm sub dword ptr [OFFSET reg + 4*(d)], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define MOV_RN_O8(d) \
+ {\
+ __asm mov eax, opcode\
+ __asm and eax, 255\
+ __asm mov dword ptr [OFFSET reg+4*(d)], eax\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ }
+ #define CMP_RN_O8(d) \
+ {\
+ __asm mov eax, dword ptr [OFFSET reg+4*(d)]\
+ __asm mov ebx, opcode\
+ __asm and ebx, 255\
+ __asm sub eax, ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define SBC_RD_RS \
+ {\
+ __asm mov ebx, dest\
+ __asm mov ebx, dword ptr [OFFSET reg + 4*ebx]\
+ __asm mov eax, value\
+ __asm bt word ptr C_FLAG, 0\
+ __asm cmc\
+ __asm sbb ebx, eax\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg + 4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define LSL_RD_RM_I5 \
+ {\
+ __asm mov eax, source\
+ __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
+ __asm mov cl, byte ptr shift\
+ __asm shl eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define LSL_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
+ __asm mov cl, byte ptr value\
+ __asm shl eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define LSR_RD_RM_I5 \
+ {\
+ __asm mov eax, source\
+ __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
+ __asm mov cl, byte ptr shift\
+ __asm shr eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define LSR_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
+ __asm mov cl, byte ptr value\
+ __asm shr eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define ASR_RD_RM_I5 \
+ {\
+ __asm mov eax, source\
+ __asm mov eax, dword ptr [OFFSET reg + 4*eax]\
+ __asm mov cl, byte ptr shift\
+ __asm sar eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define ASR_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov eax, dword ptr [OFFSET reg + 4*eax]\
+ __asm mov cl, byte ptr value\
+ __asm sar eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define ROR_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov eax, dword ptr [OFFSET reg + 4*eax]\
+ __asm mov cl, byte ptr value\
+ __asm ror eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define NEG_RD_RS \
+ {\
+ __asm mov ebx, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
+ __asm neg ebx\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax],ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define CMP_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm sub ebx, value\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+#endif
+#endif
+
+// C core
+#ifndef ADDCARRY
+ #define ADDCARRY(a, b, c) \
+ C_FLAG = ((NEG(a) & NEG(b)) |\
+ (NEG(a) & POS(c)) |\
+ (NEG(b) & POS(c))) ? true : false;
+#endif
+#ifndef ADDOVERFLOW
+ #define ADDOVERFLOW(a, b, c) \
+ V_FLAG = ((NEG(a) & NEG(b) & POS(c)) |\
+ (POS(a) & POS(b) & NEG(c))) ? true : false;
+#endif
+#ifndef SUBCARRY
+ #define SUBCARRY(a, b, c) \
+ C_FLAG = ((NEG(a) & POS(b)) |\
+ (NEG(a) & POS(c)) |\
+ (POS(b) & POS(c))) ? true : false;
+#endif
+#ifndef SUBOVERFLOW
+ #define SUBOVERFLOW(a, b, c)\
+ V_FLAG = ((NEG(a) & POS(b) & POS(c)) |\
+ (POS(a) & NEG(b) & NEG(c))) ? true : false;
+#endif
+#ifndef ADD_RD_RS_RN
+ #define ADD_RD_RS_RN(N) \
+ {\
+ u32 lhs = reg[source].I;\
+ u32 rhs = reg[N].I;\
+ u32 res = lhs + rhs;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ ADDCARRY(lhs, rhs, res);\
+ ADDOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef ADD_RD_RS_O3
+ #define ADD_RD_RS_O3(N) \
+ {\
+ u32 lhs = reg[source].I;\
+ u32 rhs = N;\
+ u32 res = lhs + rhs;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ ADDCARRY(lhs, rhs, res);\
+ ADDOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef ADD_RD_RS_O3_0
+# define ADD_RD_RS_O3_0 ADD_RD_RS_O3
+#endif
+#ifndef ADD_RN_O8
+ #define ADD_RN_O8(d) \
+ {\
+ u32 lhs = reg[(d)].I;\
+ u32 rhs = (opcode & 255);\
+ u32 res = lhs + rhs;\
+ reg[(d)].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ ADDCARRY(lhs, rhs, res);\
+ ADDOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef CMN_RD_RS
+ #define CMN_RD_RS \
+ {\
+ u32 lhs = reg[dest].I;\
+ u32 rhs = value;\
+ u32 res = lhs + rhs;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ ADDCARRY(lhs, rhs, res);\
+ ADDOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef ADC_RD_RS
+ #define ADC_RD_RS \
+ {\
+ u32 lhs = reg[dest].I;\
+ u32 rhs = value;\
+ u32 res = lhs + rhs + (u32)C_FLAG;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ ADDCARRY(lhs, rhs, res);\
+ ADDOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef SUB_RD_RS_RN
+ #define SUB_RD_RS_RN(N) \
+ {\
+ u32 lhs = reg[source].I;\
+ u32 rhs = reg[N].I;\
+ u32 res = lhs - rhs;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef SUB_RD_RS_O3
+ #define SUB_RD_RS_O3(N) \
+ {\
+ u32 lhs = reg[source].I;\
+ u32 rhs = N;\
+ u32 res = lhs - rhs;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef SUB_RD_RS_O3_0
+# define SUB_RD_RS_O3_0 SUB_RD_RS_O3
+#endif
+#ifndef SUB_RN_O8
+ #define SUB_RN_O8(d) \
+ {\
+ u32 lhs = reg[(d)].I;\
+ u32 rhs = (opcode & 255);\
+ u32 res = lhs - rhs;\
+ reg[(d)].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef MOV_RN_O8
+ #define MOV_RN_O8(d) \
+ {\
+ reg[d].I = opcode & 255;\
+ N_FLAG = false;\
+ Z_FLAG = (reg[d].I ? false : true);\
+ }
+#endif
+#ifndef CMP_RN_O8
+ #define CMP_RN_O8(d) \
+ {\
+ u32 lhs = reg[(d)].I;\
+ u32 rhs = (opcode & 255);\
+ u32 res = lhs - rhs;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef SBC_RD_RS
+ #define SBC_RD_RS \
+ {\
+ u32 lhs = reg[dest].I;\
+ u32 rhs = value;\
+ u32 res = lhs - rhs - !((u32)C_FLAG);\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef LSL_RD_RM_I5
+ #define LSL_RD_RM_I5 \
+ {\
+ C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false;\
+ value = reg[source].I << shift;\
+ }
+#endif
+#ifndef LSL_RD_RS
+ #define LSL_RD_RS \
+ {\
+ C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false;\
+ value = reg[dest].I << value;\
+ }
+#endif
+#ifndef LSR_RD_RM_I5
+ #define LSR_RD_RM_I5 \
+ {\
+ C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false;\
+ value = reg[source].I >> shift;\
+ }
+#endif
+#ifndef LSR_RD_RS
+ #define LSR_RD_RS \
+ {\
+ C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\
+ value = reg[dest].I >> value;\
+ }
+#endif
+#ifndef ASR_RD_RM_I5
+ #define ASR_RD_RM_I5 \
+ {\
+ C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false;\
+ value = (s32)reg[source].I >> (int)shift;\
+ }
+#endif
+#ifndef ASR_RD_RS
+ #define ASR_RD_RS \
+ {\
+ C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false;\
+ value = (s32)reg[dest].I >> (int)value;\
+ }
+#endif
+#ifndef ROR_RD_RS
+ #define ROR_RD_RS \
+ {\
+ C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\
+ value = ((reg[dest].I << (32 - value)) |\
+ (reg[dest].I >> value));\
+ }
+#endif
+#ifndef NEG_RD_RS
+ #define NEG_RD_RS \
+ {\
+ u32 lhs = reg[source].I;\
+ u32 rhs = 0;\
+ u32 res = rhs - lhs;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(rhs, lhs, res);\
+ SUBOVERFLOW(rhs, lhs, res);\
+ }
+#endif
+#ifndef CMP_RD_RS
+ #define CMP_RD_RS \
+ {\
+ u32 lhs = reg[dest].I;\
+ u32 rhs = value;\
+ u32 res = lhs - rhs;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef IMM5_INSN
+ #define IMM5_INSN(OP,N) \
+ int dest = opcode & 0x07;\
+ int source = (opcode >> 3) & 0x07;\
+ u32 value;\
+ OP(N);\
+ reg[dest].I = value;\
+ N_FLAG = (value & 0x80000000 ? true : false);\
+ Z_FLAG = (value ? false : true);
+ #define IMM5_INSN_0(OP) \
+ int dest = opcode & 0x07;\
+ int source = (opcode >> 3) & 0x07;\
+ u32 value;\
+ OP;\
+ reg[dest].I = value;\
+ N_FLAG = (value & 0x80000000 ? true : false);\
+ Z_FLAG = (value ? false : true);
+ #define IMM5_LSL(N) \
+ int shift = N;\
+ LSL_RD_RM_I5;
+ #define IMM5_LSL_0 \
+ value = reg[source].I;
+ #define IMM5_LSR(N) \
+ int shift = N;\
+ LSR_RD_RM_I5;
+ #define IMM5_LSR_0 \
+ C_FLAG = reg[source].I & 0x80000000 ? true : false;\
+ value = 0;
+ #define IMM5_ASR(N) \
+ int shift = N;\
+ ASR_RD_RM_I5;
+ #define IMM5_ASR_0 \
+ if(reg[source].I & 0x80000000) {\
+ value = 0xFFFFFFFF;\
+ C_FLAG = true;\
+ } else {\
+ value = 0;\
+ C_FLAG = false;\
+ }
+#endif
+#ifndef THREEARG_INSN
+ #define THREEARG_INSN(OP,N) \
+ int dest = opcode & 0x07; \
+ int source = (opcode >> 3) & 0x07; \
+ OP(N);
+#endif
+
+// Shift instructions /////////////////////////////////////////////////////
+
+#define DEFINE_IMM5_INSN(OP,BASE) \
+ static INSN_REGPARM void thumb##BASE##_00(u32 opcode) { IMM5_INSN_0(OP##_0); } \
+ static INSN_REGPARM void thumb##BASE##_01(u32 opcode) { IMM5_INSN(OP, 1); } \
+ static INSN_REGPARM void thumb##BASE##_02(u32 opcode) { IMM5_INSN(OP, 2); } \
+ static INSN_REGPARM void thumb##BASE##_03(u32 opcode) { IMM5_INSN(OP, 3); } \
+ static INSN_REGPARM void thumb##BASE##_04(u32 opcode) { IMM5_INSN(OP, 4); } \
+ static INSN_REGPARM void thumb##BASE##_05(u32 opcode) { IMM5_INSN(OP, 5); } \
+ static INSN_REGPARM void thumb##BASE##_06(u32 opcode) { IMM5_INSN(OP, 6); } \
+ static INSN_REGPARM void thumb##BASE##_07(u32 opcode) { IMM5_INSN(OP, 7); } \
+ static INSN_REGPARM void thumb##BASE##_08(u32 opcode) { IMM5_INSN(OP, 8); } \
+ static INSN_REGPARM void thumb##BASE##_09(u32 opcode) { IMM5_INSN(OP, 9); } \
+ static INSN_REGPARM void thumb##BASE##_0A(u32 opcode) { IMM5_INSN(OP,10); } \
+ static INSN_REGPARM void thumb##BASE##_0B(u32 opcode) { IMM5_INSN(OP,11); } \
+ static INSN_REGPARM void thumb##BASE##_0C(u32 opcode) { IMM5_INSN(OP,12); } \
+ static INSN_REGPARM void thumb##BASE##_0D(u32 opcode) { IMM5_INSN(OP,13); } \
+ static INSN_REGPARM void thumb##BASE##_0E(u32 opcode) { IMM5_INSN(OP,14); } \
+ static INSN_REGPARM void thumb##BASE##_0F(u32 opcode) { IMM5_INSN(OP,15); } \
+ static INSN_REGPARM void thumb##BASE##_10(u32 opcode) { IMM5_INSN(OP,16); } \
+ static INSN_REGPARM void thumb##BASE##_11(u32 opcode) { IMM5_INSN(OP,17); } \
+ static INSN_REGPARM void thumb##BASE##_12(u32 opcode) { IMM5_INSN(OP,18); } \
+ static INSN_REGPARM void thumb##BASE##_13(u32 opcode) { IMM5_INSN(OP,19); } \
+ static INSN_REGPARM void thumb##BASE##_14(u32 opcode) { IMM5_INSN(OP,20); } \
+ static INSN_REGPARM void thumb##BASE##_15(u32 opcode) { IMM5_INSN(OP,21); } \
+ static INSN_REGPARM void thumb##BASE##_16(u32 opcode) { IMM5_INSN(OP,22); } \
+ static INSN_REGPARM void thumb##BASE##_17(u32 opcode) { IMM5_INSN(OP,23); } \
+ static INSN_REGPARM void thumb##BASE##_18(u32 opcode) { IMM5_INSN(OP,24); } \
+ static INSN_REGPARM void thumb##BASE##_19(u32 opcode) { IMM5_INSN(OP,25); } \
+ static INSN_REGPARM void thumb##BASE##_1A(u32 opcode) { IMM5_INSN(OP,26); } \
+ static INSN_REGPARM void thumb##BASE##_1B(u32 opcode) { IMM5_INSN(OP,27); } \
+ static INSN_REGPARM void thumb##BASE##_1C(u32 opcode) { IMM5_INSN(OP,28); } \
+ static INSN_REGPARM void thumb##BASE##_1D(u32 opcode) { IMM5_INSN(OP,29); } \
+ static INSN_REGPARM void thumb##BASE##_1E(u32 opcode) { IMM5_INSN(OP,30); } \
+ static INSN_REGPARM void thumb##BASE##_1F(u32 opcode) { IMM5_INSN(OP,31); }
+
+// LSL Rd, Rm, #Imm 5
+DEFINE_IMM5_INSN(IMM5_LSL,00)
+// LSR Rd, Rm, #Imm 5
+DEFINE_IMM5_INSN(IMM5_LSR,08)
+// ASR Rd, Rm, #Imm 5
+DEFINE_IMM5_INSN(IMM5_ASR,10)
+
+// 3-argument ADD/SUB /////////////////////////////////////////////////////
+
+#define DEFINE_REG3_INSN(OP,BASE) \
+ static INSN_REGPARM void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP,0); } \
+ static INSN_REGPARM void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \
+ static INSN_REGPARM void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \
+ static INSN_REGPARM void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \
+ static INSN_REGPARM void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \
+ static INSN_REGPARM void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \
+ static INSN_REGPARM void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \
+ static INSN_REGPARM void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); }
+
+#define DEFINE_IMM3_INSN(OP,BASE) \
+ static INSN_REGPARM void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP##_0,0); } \
+ static INSN_REGPARM void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \
+ static INSN_REGPARM void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \
+ static INSN_REGPARM void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \
+ static INSN_REGPARM void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \
+ static INSN_REGPARM void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \
+ static INSN_REGPARM void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \
+ static INSN_REGPARM void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); }
+
+// ADD Rd, Rs, Rn
+DEFINE_REG3_INSN(ADD_RD_RS_RN,18)
+// SUB Rd, Rs, Rn
+DEFINE_REG3_INSN(SUB_RD_RS_RN,1A)
+// ADD Rd, Rs, #Offset3
+DEFINE_IMM3_INSN(ADD_RD_RS_O3,1C)
+// SUB Rd, Rs, #Offset3
+DEFINE_IMM3_INSN(SUB_RD_RS_O3,1E)
+
+// MOV/CMP/ADD/SUB immediate //////////////////////////////////////////////
+
+// MOV R0, #Offset8
+static INSN_REGPARM void thumb20(u32 opcode) { MOV_RN_O8(0); }
+// MOV R1, #Offset8
+static INSN_REGPARM void thumb21(u32 opcode) { MOV_RN_O8(1); }
+// MOV R2, #Offset8
+static INSN_REGPARM void thumb22(u32 opcode) { MOV_RN_O8(2); }
+// MOV R3, #Offset8
+static INSN_REGPARM void thumb23(u32 opcode) { MOV_RN_O8(3); }
+// MOV R4, #Offset8
+static INSN_REGPARM void thumb24(u32 opcode) { MOV_RN_O8(4); }
+// MOV R5, #Offset8
+static INSN_REGPARM void thumb25(u32 opcode) { MOV_RN_O8(5); }
+// MOV R6, #Offset8
+static INSN_REGPARM void thumb26(u32 opcode) { MOV_RN_O8(6); }
+// MOV R7, #Offset8
+static INSN_REGPARM void thumb27(u32 opcode) { MOV_RN_O8(7); }
+
+// CMP R0, #Offset8
+static INSN_REGPARM void thumb28(u32 opcode) { CMP_RN_O8(0); }
+// CMP R1, #Offset8
+static INSN_REGPARM void thumb29(u32 opcode) { CMP_RN_O8(1); }
+// CMP R2, #Offset8
+static INSN_REGPARM void thumb2A(u32 opcode) { CMP_RN_O8(2); }
+// CMP R3, #Offset8
+static INSN_REGPARM void thumb2B(u32 opcode) { CMP_RN_O8(3); }
+// CMP R4, #Offset8
+static INSN_REGPARM void thumb2C(u32 opcode) { CMP_RN_O8(4); }
+// CMP R5, #Offset8
+static INSN_REGPARM void thumb2D(u32 opcode) { CMP_RN_O8(5); }
+// CMP R6, #Offset8
+static INSN_REGPARM void thumb2E(u32 opcode) { CMP_RN_O8(6); }
+// CMP R7, #Offset8
+static INSN_REGPARM void thumb2F(u32 opcode) { CMP_RN_O8(7); }
+
+// ADD R0,#Offset8
+static INSN_REGPARM void thumb30(u32 opcode) { ADD_RN_O8(0); }
+// ADD R1,#Offset8
+static INSN_REGPARM void thumb31(u32 opcode) { ADD_RN_O8(1); }
+// ADD R2,#Offset8
+static INSN_REGPARM void thumb32(u32 opcode) { ADD_RN_O8(2); }
+// ADD R3,#Offset8
+static INSN_REGPARM void thumb33(u32 opcode) { ADD_RN_O8(3); }
+// ADD R4,#Offset8
+static INSN_REGPARM void thumb34(u32 opcode) { ADD_RN_O8(4); }
+// ADD R5,#Offset8
+static INSN_REGPARM void thumb35(u32 opcode) { ADD_RN_O8(5); }
+// ADD R6,#Offset8
+static INSN_REGPARM void thumb36(u32 opcode) { ADD_RN_O8(6); }
+// ADD R7,#Offset8
+static INSN_REGPARM void thumb37(u32 opcode) { ADD_RN_O8(7); }
+
+// SUB R0,#Offset8
+static INSN_REGPARM void thumb38(u32 opcode) { SUB_RN_O8(0); }
+// SUB R1,#Offset8
+static INSN_REGPARM void thumb39(u32 opcode) { SUB_RN_O8(1); }
+// SUB R2,#Offset8
+static INSN_REGPARM void thumb3A(u32 opcode) { SUB_RN_O8(2); }
+// SUB R3,#Offset8
+static INSN_REGPARM void thumb3B(u32 opcode) { SUB_RN_O8(3); }
+// SUB R4,#Offset8
+static INSN_REGPARM void thumb3C(u32 opcode) { SUB_RN_O8(4); }
+// SUB R5,#Offset8
+static INSN_REGPARM void thumb3D(u32 opcode) { SUB_RN_O8(5); }
+// SUB R6,#Offset8
+static INSN_REGPARM void thumb3E(u32 opcode) { SUB_RN_O8(6); }
+// SUB R7,#Offset8
+static INSN_REGPARM void thumb3F(u32 opcode) { SUB_RN_O8(7); }
+
+// ALU operations /////////////////////////////////////////////////////////
+
+// AND Rd, Rs
+static INSN_REGPARM void thumb40_0(u32 opcode)
+{
+ int dest = opcode & 7;
+ reg[dest].I &= reg[(opcode >> 3)&7].I;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+ THUMB_CONSOLE_OUTPUT(NULL, reg[2].I);
+}
+
+// EOR Rd, Rs
+static INSN_REGPARM void thumb40_1(u32 opcode)
+{
+ int dest = opcode & 7;
+ reg[dest].I ^= reg[(opcode >> 3)&7].I;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+}
+
+// LSL Rd, Rs
+static INSN_REGPARM void thumb40_2(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].B.B0;
+ if(value) {
+ if(value == 32) {
+ value = 0;
+ C_FLAG = (reg[dest].I & 1 ? true : false);
+ } else if(value < 32) {
+ LSL_RD_RS;
+ } else {
+ value = 0;
+ C_FLAG = false;
+ }
+ reg[dest].I = value;
+ }
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+ clockTicks = codeTicksAccess16(armNextPC)+2;
+}
+
+// LSR Rd, Rs
+static INSN_REGPARM void thumb40_3(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].B.B0;
+ if(value) {
+ if(value == 32) {
+ value = 0;
+ C_FLAG = (reg[dest].I & 0x80000000 ? true : false);
+ } else if(value < 32) {
+ LSR_RD_RS;
+ } else {
+ value = 0;
+ C_FLAG = false;
+ }
+ reg[dest].I = value;
+ }
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+ clockTicks = codeTicksAccess16(armNextPC)+2;
+}
+
+// ASR Rd, Rs
+static INSN_REGPARM void thumb41_0(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].B.B0;
+ if(value) {
+ if(value < 32) {
+ ASR_RD_RS;
+ reg[dest].I = value;
+ } else {
+ if(reg[dest].I & 0x80000000){
+ reg[dest].I = 0xFFFFFFFF;
+ C_FLAG = true;
+ } else {
+ reg[dest].I = 0x00000000;
+ C_FLAG = false;
+ }
+ }
+ }
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+ clockTicks = codeTicksAccess16(armNextPC)+2;
+}
+
+// ADC Rd, Rs
+static INSN_REGPARM void thumb41_1(u32 opcode)
+{
+ int dest = opcode & 0x07;
+ u32 value = reg[(opcode >> 3)&7].I;
+ ADC_RD_RS;
+}
+
+// SBC Rd, Rs
+static INSN_REGPARM void thumb41_2(u32 opcode)
+{
+ int dest = opcode & 0x07;
+ u32 value = reg[(opcode >> 3)&7].I;
+ SBC_RD_RS;
+}
+
+// ROR Rd, Rs
+static INSN_REGPARM void thumb41_3(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].B.B0;
+
+ if(value) {
+ value = value & 0x1f;
+ if(value == 0) {
+ C_FLAG = (reg[dest].I & 0x80000000 ? true : false);
+ } else {
+ ROR_RD_RS;
+ reg[dest].I = value;
+ }
+ }
+ clockTicks = codeTicksAccess16(armNextPC)+2;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+}
+
+// TST Rd, Rs
+static INSN_REGPARM void thumb42_0(u32 opcode)
+{
+ u32 value = reg[opcode & 7].I & reg[(opcode >> 3) & 7].I;
+ N_FLAG = value & 0x80000000 ? true : false;
+ Z_FLAG = value ? false : true;
+}
+
+// NEG Rd, Rs
+static INSN_REGPARM void thumb42_1(u32 opcode)
+{
+ int dest = opcode & 7;
+ int source = (opcode >> 3) & 7;
+ NEG_RD_RS;
+}
+
+// CMP Rd, Rs
+static INSN_REGPARM void thumb42_2(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].I;
+ CMP_RD_RS;
+}
+
+// CMN Rd, Rs
+static INSN_REGPARM void thumb42_3(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].I;
+ CMN_RD_RS;
+}
+
+// ORR Rd, Rs
+static INSN_REGPARM void thumb43_0(u32 opcode)
+{
+ int dest = opcode & 7;
+ reg[dest].I |= reg[(opcode >> 3) & 7].I;
+ Z_FLAG = reg[dest].I ? false : true;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+}
+
+// MUL Rd, Rs
+static INSN_REGPARM void thumb43_1(u32 opcode)
+{
+ clockTicks = 1;
+ int dest = opcode & 7;
+ u32 rm = reg[dest].I;
+ reg[dest].I = reg[(opcode >> 3) & 7].I * rm;
+ if (((s32)rm) < 0)
+ rm = ~rm;
+ if ((rm & 0xFFFFFF00) == 0)
+ clockTicks += 0;
+ else if ((rm & 0xFFFF0000) == 0)
+ clockTicks += 1;
+ else if ((rm & 0xFF000000) == 0)
+ clockTicks += 2;
+ else
+ clockTicks += 3;
+ busPrefetchCount = (busPrefetchCount<<clockTicks) | (0xFF>>(8-clockTicks));
+ clockTicks += codeTicksAccess16(armNextPC) + 1;
+ Z_FLAG = reg[dest].I ? false : true;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+}
+
+// BIC Rd, Rs
+static INSN_REGPARM void thumb43_2(u32 opcode)
+{
+ int dest = opcode & 7;
+ reg[dest].I &= (~reg[(opcode >> 3) & 7].I);
+ Z_FLAG = reg[dest].I ? false : true;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+}
+
+// MVN Rd, Rs
+static INSN_REGPARM void thumb43_3(u32 opcode)
+{
+ int dest = opcode & 7;
+ reg[dest].I = ~reg[(opcode >> 3) & 7].I;
+ Z_FLAG = reg[dest].I ? false : true;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+}
+
+// High-register instructions and BX //////////////////////////////////////
+
+// ADD Rd, Hs
+static INSN_REGPARM void thumb44_1(u32 opcode)
+{
+ reg[opcode&7].I += reg[((opcode>>3)&7)+8].I;
+}
+
+// ADD Hd, Rs
+static INSN_REGPARM void thumb44_2(u32 opcode)
+{
+ reg[(opcode&7)+8].I += reg[(opcode>>3)&7].I;
+ if((opcode&7) == 7) {
+ reg[15].I &= 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC)*2
+ + codeTicksAccess16(armNextPC) + 3;
+ }
+}
+
+// ADD Hd, Hs
+static INSN_REGPARM void thumb44_3(u32 opcode)
+{
+ reg[(opcode&7)+8].I += reg[((opcode>>3)&7)+8].I;
+ if((opcode&7) == 7) {
+ reg[15].I &= 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC)*2
+ + codeTicksAccess16(armNextPC) + 3;
+ }
+}
+
+// CMP Rd, Hs
+static INSN_REGPARM void thumb45_1(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[((opcode>>3)&7)+8].I;
+ CMP_RD_RS;
+}
+
+// CMP Hd, Rs
+static INSN_REGPARM void thumb45_2(u32 opcode)
+{
+ int dest = (opcode & 7) + 8;
+ u32 value = reg[(opcode>>3)&7].I;
+ CMP_RD_RS;
+}
+
+// CMP Hd, Hs
+static INSN_REGPARM void thumb45_3(u32 opcode)
+{
+ int dest = (opcode & 7) + 8;
+ u32 value = reg[((opcode>>3)&7)+8].I;
+ CMP_RD_RS;
+}
+
+// MOV Rd, Hs
+static INSN_REGPARM void thumb46_1(u32 opcode)
+{
+ reg[opcode&7].I = reg[((opcode>>3)&7)+8].I;
+}
+
+// MOV Hd, Rs
+static INSN_REGPARM void thumb46_2(u32 opcode)
+{
+ reg[(opcode&7)+8].I = reg[(opcode>>3)&7].I;
+ if((opcode&7) == 7) {
+ UPDATE_OLDREG;
+ reg[15].I &= 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC)*2
+ + codeTicksAccess16(armNextPC) + 3;
+ }
+}
+
+// MOV Hd, Hs
+static INSN_REGPARM void thumb46_3(u32 opcode)
+{
+ reg[(opcode&7)+8].I = reg[((opcode>>3)&7)+8].I;
+ if((opcode&7) == 7) {
+ UPDATE_OLDREG;
+ reg[15].I &= 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC)*2
+ + codeTicksAccess16(armNextPC) + 3;
+ }
+}
+
+
+// BX Rs
+static INSN_REGPARM void thumb47(u32 opcode)
+{
+ int base = (opcode >> 3) & 15;
+ busPrefetchCount=0;
+ UPDATE_OLDREG;
+ reg[15].I = reg[base].I;
+ if(reg[base].I & 1) {
+ armState = false;
+ reg[15].I &= 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC)
+ + codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 3;
+ } else {
+ armState = true;
+ reg[15].I &= 0xFFFFFFFC;
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+ ARM_PREFETCH;
+ clockTicks = codeTicksAccessSeq32(armNextPC)
+ + codeTicksAccessSeq32(armNextPC) + codeTicksAccess32(armNextPC) + 3;
+ }
+}
+
+// Load/store instructions ////////////////////////////////////////////////
+
+// LDR R0~R7,[PC, #Imm]
+static INSN_REGPARM void thumb48(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
+ reg[regist].I = CPUReadMemoryQuick(address);
+ busPrefetchCount=0;
+ clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC);
+}
+
+// STR Rd, [Rs, Rn]
+static INSN_REGPARM void thumb50(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ CPUWriteMemory(address, reg[opcode & 7].I);
+ clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// STRH Rd, [Rs, Rn]
+static INSN_REGPARM void thumb52(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ CPUWriteHalfWord(address, reg[opcode&7].W.W0);
+ clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// STRB Rd, [Rs, Rn]
+static INSN_REGPARM void thumb54(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode >>6)&7].I;
+ CPUWriteByte(address, reg[opcode & 7].B.B0);
+ clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// LDSB Rd, [Rs, Rn]
+static INSN_REGPARM void thumb56(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ reg[opcode&7].I = (s8)CPUReadByte(address);
+ clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
+}
+
+// LDR Rd, [Rs, Rn]
+static INSN_REGPARM void thumb58(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ reg[opcode&7].I = CPUReadMemory(address);
+ clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC);
+}
+
+// LDRH Rd, [Rs, Rn]
+static INSN_REGPARM void thumb5A(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ reg[opcode&7].I = CPUReadHalfWord(address);
+ clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC);
+}
+
+// LDRB Rd, [Rs, Rn]
+static INSN_REGPARM void thumb5C(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ reg[opcode&7].I = CPUReadByte(address);
+ clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
+}
+
+// LDSH Rd, [Rs, Rn]
+static INSN_REGPARM void thumb5E(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ reg[opcode&7].I = (s16)CPUReadHalfWordSigned(address);
+ clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
+}
+
+// STR Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb60(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2);
+ CPUWriteMemory(address, reg[opcode&7].I);
+ clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// LDR Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb68(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2);
+ reg[opcode&7].I = CPUReadMemory(address);
+ clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC);
+}
+
+// STRB Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb70(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31));
+ CPUWriteByte(address, reg[opcode&7].B.B0);
+ clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// LDRB Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb78(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31));
+ reg[opcode&7].I = CPUReadByte(address);
+ clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
+}
+
+// STRH Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb80(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1);
+ CPUWriteHalfWord(address, reg[opcode&7].W.W0);
+ clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// LDRH Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb88(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1);
+ reg[opcode&7].I = CPUReadHalfWord(address);
+ clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
+}
+
+// STR R0~R7, [SP, #Imm]
+static INSN_REGPARM void thumb90(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[13].I + ((opcode&255)<<2);
+ CPUWriteMemory(address, reg[regist].I);
+ clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// LDR R0~R7, [SP, #Imm]
+static INSN_REGPARM void thumb98(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[13].I + ((opcode&255)<<2);
+ reg[regist].I = CPUReadMemoryQuick(address);
+ clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC);
+}
+
+// PC/stack-related ///////////////////////////////////////////////////////
+
+// ADD R0~R7, PC, Imm
+static INSN_REGPARM void thumbA0(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ reg[regist].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
+}
+
+// ADD R0~R7, SP, Imm
+static INSN_REGPARM void thumbA8(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ reg[regist].I = reg[13].I + ((opcode&255)<<2);
+}
+
+// ADD SP, Imm
+static INSN_REGPARM void thumbB0(u32 opcode)
+{
+ int offset = (opcode & 127) << 2;
+ if(opcode & 0x80)
+ offset = -offset;
+ reg[13].I += offset;
+}
+
+// Push and pop ///////////////////////////////////////////////////////////
+
+#define PUSH_REG(val, r) \
+ if (opcode & (val)) { \
+ CPUWriteMemory(address, reg[(r)].I); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address); \
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address); \
+ } \
+ count++; \
+ address += 4; \
+ }
+
+#define POP_REG(val, r) \
+ if (opcode & (val)) { \
+ reg[(r)].I = CPUReadMemory(address); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address); \
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address); \
+ } \
+ count++; \
+ address += 4; \
+ }
+
+// PUSH {Rlist}
+static INSN_REGPARM void thumbB4(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int count = 0;
+ u32 temp = reg[13].I - 4 * cpuBitsSet[opcode & 0xff];
+ u32 address = temp & 0xFFFFFFFC;
+ PUSH_REG(1, 0);
+ PUSH_REG(2, 1);
+ PUSH_REG(4, 2);
+ PUSH_REG(8, 3);
+ PUSH_REG(16, 4);
+ PUSH_REG(32, 5);
+ PUSH_REG(64, 6);
+ PUSH_REG(128, 7);
+ clockTicks += 1 + codeTicksAccess16(armNextPC);
+ reg[13].I = temp;
+}
+
+// PUSH {Rlist, LR}
+static INSN_REGPARM void thumbB5(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int count = 0;
+ u32 temp = reg[13].I - 4 - 4 * cpuBitsSet[opcode & 0xff];
+ u32 address = temp & 0xFFFFFFFC;
+ PUSH_REG(1, 0);
+ PUSH_REG(2, 1);
+ PUSH_REG(4, 2);
+ PUSH_REG(8, 3);
+ PUSH_REG(16, 4);
+ PUSH_REG(32, 5);
+ PUSH_REG(64, 6);
+ PUSH_REG(128, 7);
+ PUSH_REG(256, 14);
+ clockTicks += 1 + codeTicksAccess16(armNextPC);
+ reg[13].I = temp;
+}
+
+// POP {Rlist}
+static INSN_REGPARM void thumbBC(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int count = 0;
+ u32 address = reg[13].I & 0xFFFFFFFC;
+ u32 temp = reg[13].I + 4*cpuBitsSet[opcode & 0xFF];
+ POP_REG(1, 0);
+ POP_REG(2, 1);
+ POP_REG(4, 2);
+ POP_REG(8, 3);
+ POP_REG(16, 4);
+ POP_REG(32, 5);
+ POP_REG(64, 6);
+ POP_REG(128, 7);
+ reg[13].I = temp;
+ clockTicks = 2 + codeTicksAccess16(armNextPC);
+}
+
+// POP {Rlist, PC}
+static INSN_REGPARM void thumbBD(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int count = 0;
+ u32 address = reg[13].I & 0xFFFFFFFC;
+ u32 temp = reg[13].I + 4 + 4*cpuBitsSet[opcode & 0xFF];
+ POP_REG(1, 0);
+ POP_REG(2, 1);
+ POP_REG(4, 2);
+ POP_REG(8, 3);
+ POP_REG(16, 4);
+ POP_REG(32, 5);
+ POP_REG(64, 6);
+ POP_REG(128, 7);
+ reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE);
+ if (!count) {
+ clockTicks += 1 + dataTicksAccess32(address);
+ } else {
+ clockTicks += 1 + dataTicksAccessSeq32(address);
+ }
+ count++;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ reg[13].I = temp;
+ THUMB_PREFETCH;
+ busPrefetchCount = 0;
+ clockTicks += 3 + codeTicksAccess16(armNextPC) + codeTicksAccess16(armNextPC);
+}
+
+// Load/store multiple ////////////////////////////////////////////////////
+
+#define THUMB_STM_REG(val,r,b) \
+ if(opcode & (val)) { \
+ CPUWriteMemory(address, reg[(r)].I); \
+ reg[(b)].I = temp; \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address); \
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address); \
+ } \
+ count++; \
+ address += 4; \
+ }
+
+#define THUMB_LDM_REG(val,r) \
+ if(opcode & (val)) { \
+ reg[(r)].I = CPUReadMemory(address); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address); \
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address); \
+ } \
+ count++; \
+ address += 4; \
+ }
+
+// STM R0~7!, {Rlist}
+static INSN_REGPARM void thumbC0(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[regist].I & 0xFFFFFFFC;
+ u32 temp = reg[regist].I + 4*cpuBitsSet[opcode & 0xff];
+ int count = 0;
+ // store
+ THUMB_STM_REG(1, 0, regist);
+ THUMB_STM_REG(2, 1, regist);
+ THUMB_STM_REG(4, 2, regist);
+ THUMB_STM_REG(8, 3, regist);
+ THUMB_STM_REG(16, 4, regist);
+ THUMB_STM_REG(32, 5, regist);
+ THUMB_STM_REG(64, 6, regist);
+ THUMB_STM_REG(128, 7, regist);
+ clockTicks = 1 + codeTicksAccess16(armNextPC);
+}
+
+// LDM R0~R7!, {Rlist}
+static INSN_REGPARM void thumbC8(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[regist].I & 0xFFFFFFFC;
+ u32 temp = reg[regist].I + 4*cpuBitsSet[opcode & 0xFF];
+ int count = 0;
+ // load
+ THUMB_LDM_REG(1, 0);
+ THUMB_LDM_REG(2, 1);
+ THUMB_LDM_REG(4, 2);
+ THUMB_LDM_REG(8, 3);
+ THUMB_LDM_REG(16, 4);
+ THUMB_LDM_REG(32, 5);
+ THUMB_LDM_REG(64, 6);
+ THUMB_LDM_REG(128, 7);
+ clockTicks = 2 + codeTicksAccess16(armNextPC);
+ if(!(opcode & (1<<regist)))
+ reg[regist].I = temp;
+}
+
+// Conditional branches ///////////////////////////////////////////////////
+
+// BEQ offset
+static INSN_REGPARM void thumbD0(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(Z_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BNE offset
+static INSN_REGPARM void thumbD1(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(!Z_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BCS offset
+static INSN_REGPARM void thumbD2(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(C_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BCC offset
+static INSN_REGPARM void thumbD3(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(!C_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BMI offset
+static INSN_REGPARM void thumbD4(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(N_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BPL offset
+static INSN_REGPARM void thumbD5(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(!N_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BVS offset
+static INSN_REGPARM void thumbD6(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(V_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BVC offset
+static INSN_REGPARM void thumbD7(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(!V_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BHI offset
+static INSN_REGPARM void thumbD8(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(C_FLAG && !Z_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BLS offset
+static INSN_REGPARM void thumbD9(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(!C_FLAG || Z_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BGE offset
+static INSN_REGPARM void thumbDA(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(N_FLAG == V_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BLT offset
+static INSN_REGPARM void thumbDB(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(N_FLAG != V_FLAG) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BGT offset
+static INSN_REGPARM void thumbDC(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(!Z_FLAG && (N_FLAG == V_FLAG)) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// BLE offset
+static INSN_REGPARM void thumbDD(u32 opcode)
+{
+ UPDATE_OLDREG;
+ if(Z_FLAG || (N_FLAG != V_FLAG)) {
+ reg[15].I += ((s8)(opcode & 0xFF)) << 1;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC)+3;
+ busPrefetchCount=0;
+ }
+}
+
+// SWI, B, BL /////////////////////////////////////////////////////////////
+
+// SWI #comment
+static INSN_REGPARM void thumbDF(u32 opcode)
+{
+ u32 address = 0;
+ clockTicks = codeTicksAccessSeq16(address) + codeTicksAccessSeq16(address) +
+ codeTicksAccess16(address)+3;
+ busPrefetchCount=0;
+ CPUSoftwareInterrupt(opcode & 0xFF);
+}
+
+// B offset
+static INSN_REGPARM void thumbE0(u32 opcode)
+{
+ int offset = (opcode & 0x3FF) << 1;
+ if(opcode & 0x0400)
+ offset |= 0xFFFFF800;
+ reg[15].I += offset;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC) + 3;
+ busPrefetchCount=0;
+}
+
+// BLL #offset (forward)
+static INSN_REGPARM void thumbF0(u32 opcode)
+{
+ int offset = (opcode & 0x7FF);
+ reg[14].I = reg[15].I + (offset << 12);
+ clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
+}
+
+// BLL #offset (backward)
+static INSN_REGPARM void thumbF4(u32 opcode)
+{
+ int offset = (opcode & 0x7FF);
+ reg[14].I = reg[15].I + ((offset << 12) | 0xFF800000);
+ clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
+}
+
+// BLH #offset
+static INSN_REGPARM void thumbF8(u32 opcode)
+{
+ int offset = (opcode & 0x7FF);
+ u32 temp = reg[15].I-2;
+ reg[15].I = (reg[14].I + (offset<<1))&0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ reg[14].I = temp|1;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC) +
+ codeTicksAccess16(armNextPC) + codeTicksAccessSeq16(armNextPC) + 3;
+ busPrefetchCount = 0;
+}
+
+// Instruction table //////////////////////////////////////////////////////
+
+typedef INSN_REGPARM void (*insnfunc_t)(u32 opcode);
+#define thumbUI thumbUnknownInsn
+#ifdef BKPT_SUPPORT
+ #define thumbBP thumbBreakpoint
+#else
+ #define thumbBP thumbUnknownInsn
+#endif
+static insnfunc_t thumbInsnTable[1024] = {
+ thumb00_00,thumb00_01,thumb00_02,thumb00_03,thumb00_04,thumb00_05,thumb00_06,thumb00_07, // 00
+ thumb00_08,thumb00_09,thumb00_0A,thumb00_0B,thumb00_0C,thumb00_0D,thumb00_0E,thumb00_0F,
+ thumb00_10,thumb00_11,thumb00_12,thumb00_13,thumb00_14,thumb00_15,thumb00_16,thumb00_17,
+ thumb00_18,thumb00_19,thumb00_1A,thumb00_1B,thumb00_1C,thumb00_1D,thumb00_1E,thumb00_1F,
+ thumb08_00,thumb08_01,thumb08_02,thumb08_03,thumb08_04,thumb08_05,thumb08_06,thumb08_07, // 08
+ thumb08_08,thumb08_09,thumb08_0A,thumb08_0B,thumb08_0C,thumb08_0D,thumb08_0E,thumb08_0F,
+ thumb08_10,thumb08_11,thumb08_12,thumb08_13,thumb08_14,thumb08_15,thumb08_16,thumb08_17,
+ thumb08_18,thumb08_19,thumb08_1A,thumb08_1B,thumb08_1C,thumb08_1D,thumb08_1E,thumb08_1F,
+ thumb10_00,thumb10_01,thumb10_02,thumb10_03,thumb10_04,thumb10_05,thumb10_06,thumb10_07, // 10
+ thumb10_08,thumb10_09,thumb10_0A,thumb10_0B,thumb10_0C,thumb10_0D,thumb10_0E,thumb10_0F,
+ thumb10_10,thumb10_11,thumb10_12,thumb10_13,thumb10_14,thumb10_15,thumb10_16,thumb10_17,
+ thumb10_18,thumb10_19,thumb10_1A,thumb10_1B,thumb10_1C,thumb10_1D,thumb10_1E,thumb10_1F,
+ thumb18_0,thumb18_1,thumb18_2,thumb18_3,thumb18_4,thumb18_5,thumb18_6,thumb18_7, // 18
+ thumb1A_0,thumb1A_1,thumb1A_2,thumb1A_3,thumb1A_4,thumb1A_5,thumb1A_6,thumb1A_7,
+ thumb1C_0,thumb1C_1,thumb1C_2,thumb1C_3,thumb1C_4,thumb1C_5,thumb1C_6,thumb1C_7,
+ thumb1E_0,thumb1E_1,thumb1E_2,thumb1E_3,thumb1E_4,thumb1E_5,thumb1E_6,thumb1E_7,
+ thumb20,thumb20,thumb20,thumb20,thumb21,thumb21,thumb21,thumb21, // 20
+ thumb22,thumb22,thumb22,thumb22,thumb23,thumb23,thumb23,thumb23,
+ thumb24,thumb24,thumb24,thumb24,thumb25,thumb25,thumb25,thumb25,
+ thumb26,thumb26,thumb26,thumb26,thumb27,thumb27,thumb27,thumb27,
+ thumb28,thumb28,thumb28,thumb28,thumb29,thumb29,thumb29,thumb29, // 28
+ thumb2A,thumb2A,thumb2A,thumb2A,thumb2B,thumb2B,thumb2B,thumb2B,
+ thumb2C,thumb2C,thumb2C,thumb2C,thumb2D,thumb2D,thumb2D,thumb2D,
+ thumb2E,thumb2E,thumb2E,thumb2E,thumb2F,thumb2F,thumb2F,thumb2F,
+ thumb30,thumb30,thumb30,thumb30,thumb31,thumb31,thumb31,thumb31, // 30
+ thumb32,thumb32,thumb32,thumb32,thumb33,thumb33,thumb33,thumb33,
+ thumb34,thumb34,thumb34,thumb34,thumb35,thumb35,thumb35,thumb35,
+ thumb36,thumb36,thumb36,thumb36,thumb37,thumb37,thumb37,thumb37,
+ thumb38,thumb38,thumb38,thumb38,thumb39,thumb39,thumb39,thumb39, // 38
+ thumb3A,thumb3A,thumb3A,thumb3A,thumb3B,thumb3B,thumb3B,thumb3B,
+ thumb3C,thumb3C,thumb3C,thumb3C,thumb3D,thumb3D,thumb3D,thumb3D,
+ thumb3E,thumb3E,thumb3E,thumb3E,thumb3F,thumb3F,thumb3F,thumb3F,
+ thumb40_0,thumb40_1,thumb40_2,thumb40_3,thumb41_0,thumb41_1,thumb41_2,thumb41_3, // 40
+ thumb42_0,thumb42_1,thumb42_2,thumb42_3,thumb43_0,thumb43_1,thumb43_2,thumb43_3,
+ thumbUI,thumb44_1,thumb44_2,thumb44_3,thumbUI,thumb45_1,thumb45_2,thumb45_3,
+ thumbUI,thumb46_1,thumb46_2,thumb46_3,thumb47,thumb47,thumbUI,thumbUI,
+ thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48, // 48
+ thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,
+ thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,
+ thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,
+ thumb50,thumb50,thumb50,thumb50,thumb50,thumb50,thumb50,thumb50, // 50
+ thumb52,thumb52,thumb52,thumb52,thumb52,thumb52,thumb52,thumb52,
+ thumb54,thumb54,thumb54,thumb54,thumb54,thumb54,thumb54,thumb54,
+ thumb56,thumb56,thumb56,thumb56,thumb56,thumb56,thumb56,thumb56,
+ thumb58,thumb58,thumb58,thumb58,thumb58,thumb58,thumb58,thumb58, // 58
+ thumb5A,thumb5A,thumb5A,thumb5A,thumb5A,thumb5A,thumb5A,thumb5A,
+ thumb5C,thumb5C,thumb5C,thumb5C,thumb5C,thumb5C,thumb5C,thumb5C,
+ thumb5E,thumb5E,thumb5E,thumb5E,thumb5E,thumb5E,thumb5E,thumb5E,
+ thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,thumb60, // 60
+ thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,
+ thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,
+ thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,thumb60,
+ thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,thumb68, // 68
+ thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,
+ thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,
+ thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,thumb68,
+ thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,thumb70, // 70
+ thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,
+ thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,
+ thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,thumb70,
+ thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,thumb78, // 78
+ thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,
+ thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,
+ thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,thumb78,
+ thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,thumb80, // 80
+ thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,
+ thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,
+ thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,thumb80,
+ thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,thumb88, // 88
+ thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,
+ thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,
+ thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,thumb88,
+ thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,thumb90, // 90
+ thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,
+ thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,
+ thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,thumb90,
+ thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,thumb98, // 98
+ thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,
+ thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,
+ thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,thumb98,
+ thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0, // A0
+ thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,
+ thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,
+ thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,thumbA0,
+ thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8, // A8
+ thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,
+ thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,
+ thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,thumbA8,
+ thumbB0,thumbB0,thumbB0,thumbB0,thumbUI,thumbUI,thumbUI,thumbUI, // B0
+ thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,
+ thumbB4,thumbB4,thumbB4,thumbB4,thumbB5,thumbB5,thumbB5,thumbB5,
+ thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,
+ thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI, // B8
+ thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,
+ thumbBC,thumbBC,thumbBC,thumbBC,thumbBD,thumbBD,thumbBD,thumbBD,
+ thumbBP,thumbBP,thumbBP,thumbBP,thumbUI,thumbUI,thumbUI,thumbUI,
+ thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0, // C0
+ thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,
+ thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,
+ thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,thumbC0,
+ thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8, // C8
+ thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,
+ thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,
+ thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,thumbC8,
+ thumbD0,thumbD0,thumbD0,thumbD0,thumbD1,thumbD1,thumbD1,thumbD1, // D0
+ thumbD2,thumbD2,thumbD2,thumbD2,thumbD3,thumbD3,thumbD3,thumbD3,
+ thumbD4,thumbD4,thumbD4,thumbD4,thumbD5,thumbD5,thumbD5,thumbD5,
+ thumbD6,thumbD6,thumbD6,thumbD6,thumbD7,thumbD7,thumbD7,thumbD7,
+ thumbD8,thumbD8,thumbD8,thumbD8,thumbD9,thumbD9,thumbD9,thumbD9, // D8
+ thumbDA,thumbDA,thumbDA,thumbDA,thumbDB,thumbDB,thumbDB,thumbDB,
+ thumbDC,thumbDC,thumbDC,thumbDC,thumbDD,thumbDD,thumbDD,thumbDD,
+ thumbUI,thumbUI,thumbUI,thumbUI,thumbDF,thumbDF,thumbDF,thumbDF,
+ thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0, // E0
+ thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,
+ thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,
+ thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,thumbE0,
+ thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI, // E8
+ thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,
+ thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,
+ thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,thumbUI,
+ thumbF0,thumbF0,thumbF0,thumbF0,thumbF0,thumbF0,thumbF0,thumbF0, // F0
+ thumbF0,thumbF0,thumbF0,thumbF0,thumbF0,thumbF0,thumbF0,thumbF0,
+ thumbF4,thumbF4,thumbF4,thumbF4,thumbF4,thumbF4,thumbF4,thumbF4,
+ thumbF4,thumbF4,thumbF4,thumbF4,thumbF4,thumbF4,thumbF4,thumbF4,
+ thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8, // F8
+ thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,
+ thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,
+ thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,thumbF8,
+};
+
+// Wrapper routine (execution loop) ///////////////////////////////////////
+
+int thumbExecute()
+{
+ do {
+ /*if( cheatsEnabled ) {
+ cpuMasterCodeCheck();
+ }*/
+
+ //if ((armNextPC & 0x0803FFFF) == 0x08020000)
+ // busPrefetchCount=0x100;
+
+ u32 opcode = cpuPrefetch[0];
+ cpuPrefetch[0] = cpuPrefetch[1];
+
+ busPrefetch = false;
+ if (busPrefetchCount & 0xFFFFFF00)
+ busPrefetchCount = 0x100 | (busPrefetchCount & 0xFF);
+ clockTicks = 0;
+ u32 oldArmNextPC = armNextPC;
+#ifndef FINAL_VERSION
+ if(armNextPC == stop) {
+ armNextPC++;
+ }
+#endif
+
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH_NEXT;
+
+ (*thumbInsnTable[opcode>>6])(opcode);
+
+ if (clockTicks < 0)
+ return 0;
+ if (clockTicks==0)
+ clockTicks = codeTicksAccessSeq16(oldArmNextPC) + 1;
+ cpuTotalTicks += clockTicks;
+
+ } while (cpuTotalTicks < cpuNextEvent && !armState && !holdState && !SWITicks);
+ return 1;
+}
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/GBA.cpp
@@ -1,1 +1,4026 @@
-
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <string.h>
+#include "GBA.h"
+#include "GBAcpu.h"
+#include "GBAinline.h"
+#include "Globals.h"
+//#include "GBAGfx.h"
+//#include "EEprom.h"
+//#include "Flash.h"
+#include "Sound.h"
+//#include "Sram.h"
+#include "bios.h"
+//#include "Cheats.h"
+//#include "../NLS.h"
+//#include "elf.h"
+//#include "../Util.h"
+#include "../common/Port.h"
+//#include "../System.h"
+//#include "agbprint.h"
+//#include "GBALink.h"
+
+extern int mapgsf(u8* a, int l, int &s);
+
+#ifdef PROFILING
+#include "prof/prof.h"
+#endif
+
+#ifdef __GNUC__
+#define _stricmp strcasecmp
+#endif
+
+extern int emulating;
+
+int SWITicks = 0;
+int IRQTicks = 0;
+
+u32 mastercode = 0;
+int layerEnableDelay = 0;
+bool busPrefetch = false;
+bool busPrefetchEnable = false;
+u32 busPrefetchCount = 0;
+int cpuDmaTicksToUpdate = 0;
+int cpuDmaCount = 0;
+bool cpuDmaHack = false;
+u32 cpuDmaLast = 0;
+int dummyAddress = 0;
+
+bool cpuBreakLoop = false;
+int cpuNextEvent = 0;
+
+int gbaSaveType = 0; // used to remember the save type on reset
+bool intState = false;
+bool stopState = false;
+bool holdState = false;
+int holdType = 0;
+bool cpuSramEnabled = true;
+bool cpuFlashEnabled = true;
+bool cpuEEPROMEnabled = true;
+bool cpuEEPROMSensorEnabled = false;
+
+u32 cpuPrefetch[2];
+
+int cpuTotalTicks = 0;
+#ifdef PROFILING
+int profilingTicks = 0;
+int profilingTicksReload = 0;
+static profile_segment *profilSegment = NULL;
+#endif
+
+#ifdef BKPT_SUPPORT
+u8 freezeWorkRAM[0x40000];
+u8 freezeInternalRAM[0x8000];
+u8 freezeVRAM[0x18000];
+u8 freezePRAM[0x400];
+u8 freezeOAM[0x400];
+bool debugger_last;
+#endif
+
+int lcdTicks = (useBios && !skipBios) ? 1008 : 208;
+u8 timerOnOffDelay = 0;
+u16 timer0Value = 0;
+bool timer0On = false;
+int timer0Ticks = 0;
+int timer0Reload = 0;
+int timer0ClockReload = 0;
+u16 timer1Value = 0;
+bool timer1On = false;
+int timer1Ticks = 0;
+int timer1Reload = 0;
+int timer1ClockReload = 0;
+u16 timer2Value = 0;
+bool timer2On = false;
+int timer2Ticks = 0;
+int timer2Reload = 0;
+int timer2ClockReload = 0;
+u16 timer3Value = 0;
+bool timer3On = false;
+int timer3Ticks = 0;
+int timer3Reload = 0;
+int timer3ClockReload = 0;
+u32 dma0Source = 0;
+u32 dma0Dest = 0;
+u32 dma1Source = 0;
+u32 dma1Dest = 0;
+u32 dma2Source = 0;
+u32 dma2Dest = 0;
+u32 dma3Source = 0;
+u32 dma3Dest = 0;
+//void (*cpuSaveGameFunc)(u32,u8) = /*flashSaveDecide*/0;
+//void (*renderLine)() = /*mode0RenderLine*/0;
+bool fxOn = false;
+bool windowOn = false;
+int frameCount = 0;
+char buffer[1024];
+u32 lastTime = 0;
+int count = 0;
+
+int capture = 0;
+int capturePrevious = 0;
+int captureNumber = 0;
+
+const int TIMER_TICKS[4] = {
+ 0,
+ 6,
+ 8,
+ 10
+};
+
+const u32 objTilesAddress [3] = {0x010000, 0x014000, 0x014000};
+const u8 gamepakRamWaitState[4] = { 4, 3, 2, 8 };
+const u8 gamepakWaitState[4] = { 4, 3, 2, 8 };
+const u8 gamepakWaitState0[2] = { 2, 1 };
+const u8 gamepakWaitState1[2] = { 4, 1 };
+const u8 gamepakWaitState2[2] = { 8, 1 };
+const bool isInRom [16]=
+ { false, false, false, false, false, false, false, false,
+ true, true, true, true, true, true, false, false };
+
+u8 memoryWait[16] =
+ { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
+u8 memoryWait32[16] =
+ { 0, 0, 5, 0, 0, 1, 1, 0, 7, 7, 9, 9, 13, 13, 4, 0 };
+u8 memoryWaitSeq[16] =
+ { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 };
+u8 memoryWaitSeq32[16] =
+ { 0, 0, 5, 0, 0, 1, 1, 0, 5, 5, 9, 9, 17, 17, 4, 0 };
+
+// The videoMemoryWait constants are used to add some waitstates
+// if the opcode access video memory data outside of vblank/hblank
+// It seems to happen on only one ticks for each pixel.
+// Not used for now (too problematic with current code).
+//const u8 videoMemoryWait[16] =
+// {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+
+u8 biosProtected[4];
+
+#ifdef WORDS_BIGENDIAN
+bool cpuBiosSwapped = false;
+#endif
+
+u32 myROM[] = {
+0xEA000006,
+0xEA000093,
+0xEA000006,
+0x00000000,
+0x00000000,
+0x00000000,
+0xEA000088,
+0x00000000,
+0xE3A00302,
+0xE1A0F000,
+0xE92D5800,
+0xE55EC002,
+0xE28FB03C,
+0xE79BC10C,
+0xE14FB000,
+0xE92D0800,
+0xE20BB080,
+0xE38BB01F,
+0xE129F00B,
+0xE92D4004,
+0xE1A0E00F,
+0xE12FFF1C,
+0xE8BD4004,
+0xE3A0C0D3,
+0xE129F00C,
+0xE8BD0800,
+0xE169F00B,
+0xE8BD5800,
+0xE1B0F00E,
+0x0000009C,
+0x0000009C,
+0x0000009C,
+0x0000009C,
+0x000001F8,
+0x000001F0,
+0x000000AC,
+0x000000A0,
+0x000000FC,
+0x00000168,
+0xE12FFF1E,
+0xE1A03000,
+0xE1A00001,
+0xE1A01003,
+0xE2113102,
+0x42611000,
+0xE033C040,
+0x22600000,
+0xE1B02001,
+0xE15200A0,
+0x91A02082,
+0x3AFFFFFC,
+0xE1500002,
+0xE0A33003,
+0x20400002,
+0xE1320001,
+0x11A020A2,
+0x1AFFFFF9,
+0xE1A01000,
+0xE1A00003,
+0xE1B0C08C,
+0x22600000,
+0x42611000,
+0xE12FFF1E,
+0xE92D0010,
+0xE1A0C000,
+0xE3A01001,
+0xE1500001,
+0x81A000A0,
+0x81A01081,
+0x8AFFFFFB,
+0xE1A0000C,
+0xE1A04001,
+0xE3A03000,
+0xE1A02001,
+0xE15200A0,
+0x91A02082,
+0x3AFFFFFC,
+0xE1500002,
+0xE0A33003,
+0x20400002,
+0xE1320001,
+0x11A020A2,
+0x1AFFFFF9,
+0xE0811003,
+0xE1B010A1,
+0xE1510004,
+0x3AFFFFEE,
+0xE1A00004,
+0xE8BD0010,
+0xE12FFF1E,
+0xE0010090,
+0xE1A01741,
+0xE2611000,
+0xE3A030A9,
+0xE0030391,
+0xE1A03743,
+0xE2833E39,
+0xE0030391,
+0xE1A03743,
+0xE2833C09,
+0xE283301C,
+0xE0030391,
+0xE1A03743,
+0xE2833C0F,
+0xE28330B6,
+0xE0030391,
+0xE1A03743,
+0xE2833C16,
+0xE28330AA,
+0xE0030391,
+0xE1A03743,
+0xE2833A02,
+0xE2833081,
+0xE0030391,
+0xE1A03743,
+0xE2833C36,
+0xE2833051,
+0xE0030391,
+0xE1A03743,
+0xE2833CA2,
+0xE28330F9,
+0xE0000093,
+0xE1A00840,
+0xE12FFF1E,
+0xE3A00001,
+0xE3A01001,
+0xE92D4010,
+0xE3A03000,
+0xE3A04001,
+0xE3500000,
+0x1B000004,
+0xE5CC3301,
+0xEB000002,
+0x0AFFFFFC,
+0xE8BD4010,
+0xE12FFF1E,
+0xE3A0C301,
+0xE5CC3208,
+0xE15C20B8,
+0xE0110002,
+0x10222000,
+0x114C20B8,
+0xE5CC4208,
+0xE12FFF1E,
+0xE92D500F,
+0xE3A00301,
+0xE1A0E00F,
+0xE510F004,
+0xE8BD500F,
+0xE25EF004,
+0xE59FD044,
+0xE92D5000,
+0xE14FC000,
+0xE10FE000,
+0xE92D5000,
+0xE3A0C302,
+0xE5DCE09C,
+0xE35E00A5,
+0x1A000004,
+0x05DCE0B4,
+0x021EE080,
+0xE28FE004,
+0x159FF018,
+0x059FF018,
+0xE59FD018,
+0xE8BD5000,
+0xE169F00C,
+0xE8BD5000,
+0xE25EF004,
+0x03007FF0,
+0x09FE2000,
+0x09FFC000,
+0x03007FE0
+};
+
+/*variable_desc saveGameStruct[] = {
+ { &DISPCNT , sizeof(u16) },
+ { &DISPSTAT , sizeof(u16) },
+ { &VCOUNT , sizeof(u16) },
+ { &BG0CNT , sizeof(u16) },
+ { &BG1CNT , sizeof(u16) },
+ { &BG2CNT , sizeof(u16) },
+ { &BG3CNT , sizeof(u16) },
+ { &BG0HOFS , sizeof(u16) },
+ { &BG0VOFS , sizeof(u16) },
+ { &BG1HOFS , sizeof(u16) },
+ { &BG1VOFS , sizeof(u16) },
+ { &BG2HOFS , sizeof(u16) },
+ { &BG2VOFS , sizeof(u16) },
+ { &BG3HOFS , sizeof(u16) },
+ { &BG3VOFS , sizeof(u16) },
+ { &BG2PA , sizeof(u16) },
+ { &BG2PB , sizeof(u16) },
+ { &BG2PC , sizeof(u16) },
+ { &BG2PD , sizeof(u16) },
+ { &BG2X_L , sizeof(u16) },
+ { &BG2X_H , sizeof(u16) },
+ { &BG2Y_L , sizeof(u16) },
+ { &BG2Y_H , sizeof(u16) },
+ { &BG3PA , sizeof(u16) },
+ { &BG3PB , sizeof(u16) },
+ { &BG3PC , sizeof(u16) },
+ { &BG3PD , sizeof(u16) },
+ { &BG3X_L , sizeof(u16) },
+ { &BG3X_H , sizeof(u16) },
+ { &BG3Y_L , sizeof(u16) },
+ { &BG3Y_H , sizeof(u16) },
+ { &WIN0H , sizeof(u16) },
+ { &WIN1H , sizeof(u16) },
+ { &WIN0V , sizeof(u16) },
+ { &WIN1V , sizeof(u16) },
+ { &WININ , sizeof(u16) },
+ { &WINOUT , sizeof(u16) },
+ { &MOSAIC , sizeof(u16) },
+ { &BLDMOD , sizeof(u16) },
+ { &COLEV , sizeof(u16) },
+ { &COLY , sizeof(u16) },
+ { &DM0SAD_L , sizeof(u16) },
+ { &DM0SAD_H , sizeof(u16) },
+ { &DM0DAD_L , sizeof(u16) },
+ { &DM0DAD_H , sizeof(u16) },
+ { &DM0CNT_L , sizeof(u16) },
+ { &DM0CNT_H , sizeof(u16) },
+ { &DM1SAD_L , sizeof(u16) },
+ { &DM1SAD_H , sizeof(u16) },
+ { &DM1DAD_L , sizeof(u16) },
+ { &DM1DAD_H , sizeof(u16) },
+ { &DM1CNT_L , sizeof(u16) },
+ { &DM1CNT_H , sizeof(u16) },
+ { &DM2SAD_L , sizeof(u16) },
+ { &DM2SAD_H , sizeof(u16) },
+ { &DM2DAD_L , sizeof(u16) },
+ { &DM2DAD_H , sizeof(u16) },
+ { &DM2CNT_L , sizeof(u16) },
+ { &DM2CNT_H , sizeof(u16) },
+ { &DM3SAD_L , sizeof(u16) },
+ { &DM3SAD_H , sizeof(u16) },
+ { &DM3DAD_L , sizeof(u16) },
+ { &DM3DAD_H , sizeof(u16) },
+ { &DM3CNT_L , sizeof(u16) },
+ { &DM3CNT_H , sizeof(u16) },
+ { &TM0D , sizeof(u16) },
+ { &TM0CNT , sizeof(u16) },
+ { &TM1D , sizeof(u16) },
+ { &TM1CNT , sizeof(u16) },
+ { &TM2D , sizeof(u16) },
+ { &TM2CNT , sizeof(u16) },
+ { &TM3D , sizeof(u16) },
+ { &TM3CNT , sizeof(u16) },
+ { &P1 , sizeof(u16) },
+ { &IE , sizeof(u16) },
+ { &IF , sizeof(u16) },
+ { &IME , sizeof(u16) },
+ { &holdState, sizeof(bool) },
+ { &holdType, sizeof(int) },
+ { &lcdTicks, sizeof(int) },
+ { &timer0On , sizeof(bool) },
+ { &timer0Ticks , sizeof(int) },
+ { &timer0Reload , sizeof(int) },
+ { &timer0ClockReload , sizeof(int) },
+ { &timer1On , sizeof(bool) },
+ { &timer1Ticks , sizeof(int) },
+ { &timer1Reload , sizeof(int) },
+ { &timer1ClockReload , sizeof(int) },
+ { &timer2On , sizeof(bool) },
+ { &timer2Ticks , sizeof(int) },
+ { &timer2Reload , sizeof(int) },
+ { &timer2ClockReload , sizeof(int) },
+ { &timer3On , sizeof(bool) },
+ { &timer3Ticks , sizeof(int) },
+ { &timer3Reload , sizeof(int) },
+ { &timer3ClockReload , sizeof(int) },
+ { &dma0Source , sizeof(u32) },
+ { &dma0Dest , sizeof(u32) },
+ { &dma1Source , sizeof(u32) },
+ { &dma1Dest , sizeof(u32) },
+ { &dma2Source , sizeof(u32) },
+ { &dma2Dest , sizeof(u32) },
+ { &dma3Source , sizeof(u32) },
+ { &dma3Dest , sizeof(u32) },
+ { &fxOn, sizeof(bool) },
+ { &windowOn, sizeof(bool) },
+ { &N_FLAG , sizeof(bool) },
+ { &C_FLAG , sizeof(bool) },
+ { &Z_FLAG , sizeof(bool) },
+ { &V_FLAG , sizeof(bool) },
+ { &armState , sizeof(bool) },
+ { &armIrqEnable , sizeof(bool) },
+ { &armNextPC , sizeof(u32) },
+ { &armMode , sizeof(int) },
+ { &saveType , sizeof(int) },
+ { NULL, 0 }
+};*/
+
+static int romSize = 0x2000000;
+
+#ifdef PROFILING
+void cpuProfil(profile_segment *seg)
+{
+ profilSegment = seg;
+}
+
+void cpuEnableProfiling(int hz)
+{
+ if(hz == 0)
+ hz = 100;
+ profilingTicks = profilingTicksReload = 16777216 / hz;
+ profSetHertz(hz);
+}
+#endif
+
+
+inline int CPUUpdateTicks()
+{
+ int cpuLoopTicks = lcdTicks;
+
+ if(soundTicks < cpuLoopTicks)
+ cpuLoopTicks = soundTicks;
+
+ if(timer0On && (timer0Ticks < cpuLoopTicks)) {
+ cpuLoopTicks = timer0Ticks;
+ }
+ if(timer1On && !(TM1CNT & 4) && (timer1Ticks < cpuLoopTicks)) {
+ cpuLoopTicks = timer1Ticks;
+ }
+ if(timer2On && !(TM2CNT & 4) && (timer2Ticks < cpuLoopTicks)) {
+ cpuLoopTicks = timer2Ticks;
+ }
+ if(timer3On && !(TM3CNT & 4) && (timer3Ticks < cpuLoopTicks)) {
+ cpuLoopTicks = timer3Ticks;
+ }
+#ifdef PROFILING
+ if(profilingTicksReload != 0) {
+ if(profilingTicks < cpuLoopTicks) {
+ cpuLoopTicks = profilingTicks;
+ }
+ }
+#endif
+
+ if (SWITicks) {
+ if (SWITicks < cpuLoopTicks)
+ cpuLoopTicks = SWITicks;
+ }
+
+ if (IRQTicks) {
+ if (IRQTicks < cpuLoopTicks)
+ cpuLoopTicks = IRQTicks;
+ }
+
+ return cpuLoopTicks;
+}
+
+/*void CPUUpdateWindow0()
+{
+ int x00 = WIN0H>>8;
+ int x01 = WIN0H & 255;
+
+ if(x00 <= x01) {
+ for(int i = 0; i < 240; i++) {
+ gfxInWin0[i] = (i >= x00 && i < x01);
+ }
+ } else {
+ for(int i = 0; i < 240; i++) {
+ gfxInWin0[i] = (i >= x00 || i < x01);
+ }
+ }
+}*/
+
+/*void CPUUpdateWindow1()
+{
+ int x00 = WIN1H>>8;
+ int x01 = WIN1H & 255;
+
+ if(x00 <= x01) {
+ for(int i = 0; i < 240; i++) {
+ gfxInWin1[i] = (i >= x00 && i < x01);
+ }
+ } else {
+ for(int i = 0; i < 240; i++) {
+ gfxInWin1[i] = (i >= x00 || i < x01);
+ }
+ }
+}*/
+
+extern u32 line0[240];
+extern u32 line1[240];
+extern u32 line2[240];
+extern u32 line3[240];
+
+#define CLEAR_ARRAY(a) \
+ {\
+ u32 *array = (a);\
+ for(int i = 0; i < 240; i++) {\
+ *array++ = 0x80000000;\
+ }\
+ }\
+
+/*void CPUUpdateRenderBuffers(bool force)
+{
+ if(!(layerEnable & 0x0100) || force) {
+ CLEAR_ARRAY(line0);
+ }
+ if(!(layerEnable & 0x0200) || force) {
+ CLEAR_ARRAY(line1);
+ }
+ if(!(layerEnable & 0x0400) || force) {
+ CLEAR_ARRAY(line2);
+ }
+ if(!(layerEnable & 0x0800) || force) {
+ CLEAR_ARRAY(line3);
+ }
+}*/
+
+/*static bool CPUWriteState(gzFile gzFile)
+{
+ utilWriteInt(gzFile, SAVE_GAME_VERSION);
+
+ utilGzWrite(gzFile, &rom[0xa0], 16);
+
+ utilWriteInt(gzFile, useBios);
+
+ utilGzWrite(gzFile, ®[0], sizeof(reg));
+
+ utilWriteData(gzFile, saveGameStruct);
+
+ // new to version 0.7.1
+ utilWriteInt(gzFile, stopState);
+ // new to version 0.8
+ utilWriteInt(gzFile, IRQTicks);
+
+ utilGzWrite(gzFile, internalRAM, 0x8000);
+ utilGzWrite(gzFile, paletteRAM, 0x400);
+ utilGzWrite(gzFile, workRAM, 0x40000);
+ utilGzWrite(gzFile, vram, 0x20000);
+ utilGzWrite(gzFile, oam, 0x400);
+ utilGzWrite(gzFile, pix, 4*241*162);
+ utilGzWrite(gzFile, ioMem, 0x400);
+
+ eepromSaveGame(gzFile);
+ flashSaveGame(gzFile);
+ soundSaveGame(gzFile);
+
+ cheatsSaveGame(gzFile);
+
+ // version 1.5
+ rtcSaveGame(gzFile);
+
+ return true;
+}
+
+bool CPUWriteState(const char *file)
+{
+ gzFile gzFile = utilGzOpen(file, "wb");
+
+ if(gzFile == NULL) {
+ systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), file);
+ return false;
+ }
+
+ bool res = CPUWriteState(gzFile);
+
+ utilGzClose(gzFile);
+
+ return res;
+}
+
+bool CPUWriteMemState(char *memory, int available)
+{
+ gzFile gzFile = utilMemGzOpen(memory, available, "w");
+
+ if(gzFile == NULL) {
+ return false;
+ }
+
+ bool res = CPUWriteState(gzFile);
+
+ long pos = utilGzMemTell(gzFile)+8;
+
+ if(pos >= (available))
+ res = false;
+
+ utilGzClose(gzFile);
+
+ return res;
+}
+
+static bool CPUReadState(gzFile gzFile)
+{
+ int version = utilReadInt(gzFile);
+
+ if(version > SAVE_GAME_VERSION || version < SAVE_GAME_VERSION_1) {
+ systemMessage(MSG_UNSUPPORTED_VBA_SGM,
+ N_("Unsupported VisualBoyAdvance save game version %d"),
+ version);
+ return false;
+ }
+
+ u8 romname[17];
+
+ utilGzRead(gzFile, romname, 16);
+
+ if(memcmp(&rom[0xa0], romname, 16) != 0) {
+ romname[16]=0;
+ for(int i = 0; i < 16; i++)
+ if(romname[i] < 32)
+ romname[i] = 32;
+ systemMessage(MSG_CANNOT_LOAD_SGM, N_("Cannot load save game for %s"), romname);
+ return false;
+ }
+
+ bool ub = utilReadInt(gzFile) ? true : false;
+
+ if(ub != useBios) {
+ if(useBios)
+ systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS,
+ N_("Save game is not using the BIOS files"));
+ else
+ systemMessage(MSG_SAVE_GAME_USING_BIOS,
+ N_("Save game is using the BIOS file"));
+ return false;
+ }
+
+ utilGzRead(gzFile, ®[0], sizeof(reg));
+
+ utilReadData(gzFile, saveGameStruct);
+
+ if(version < SAVE_GAME_VERSION_3)
+ stopState = false;
+ else
+ stopState = utilReadInt(gzFile) ? true : false;
+
+ if(version < SAVE_GAME_VERSION_4)
+ {
+ IRQTicks = 0;
+ intState = false;
+ }
+ else
+ {
+ IRQTicks = utilReadInt(gzFile);
+ if (IRQTicks>0)
+ intState = true;
+ else
+ {
+ intState = false;
+ IRQTicks = 0;
+ }
+ }
+
+ utilGzRead(gzFile, internalRAM, 0x8000);
+ utilGzRead(gzFile, paletteRAM, 0x400);
+ utilGzRead(gzFile, workRAM, 0x40000);
+ utilGzRead(gzFile, vram, 0x20000);
+ utilGzRead(gzFile, oam, 0x400);
+ if(version < SAVE_GAME_VERSION_6)
+ utilGzRead(gzFile, pix, 4*240*160);
+ else
+ utilGzRead(gzFile, pix, 4*241*162);
+ utilGzRead(gzFile, ioMem, 0x400);
+
+ if(skipSaveGameBattery) {
+ // skip eeprom data
+ eepromReadGameSkip(gzFile, version);
+ // skip flash data
+ flashReadGameSkip(gzFile, version);
+ } else {
+ eepromReadGame(gzFile, version);
+ flashReadGame(gzFile, version);
+ }
+ soundReadGame(gzFile, version);
+
+ if(version > SAVE_GAME_VERSION_1) {
+ if(skipSaveGameCheats) {
+ // skip cheats list data
+ cheatsReadGameSkip(gzFile, version);
+ } else {
+ cheatsReadGame(gzFile, version);
+ }
+ }
+ if(version > SAVE_GAME_VERSION_6) {
+ rtcReadGame(gzFile);
+ }
+
+ if(version <= SAVE_GAME_VERSION_7) {
+ u32 temp;
+#define SWAP(a,b,c) \
+ temp = (a);\
+ (a) = (b)<<16|(c);\
+ (b) = (temp) >> 16;\
+ (c) = (temp) & 0xFFFF;
+
+ SWAP(dma0Source, DM0SAD_H, DM0SAD_L);
+ SWAP(dma0Dest, DM0DAD_H, DM0DAD_L);
+ SWAP(dma1Source, DM1SAD_H, DM1SAD_L);
+ SWAP(dma1Dest, DM1DAD_H, DM1DAD_L);
+ SWAP(dma2Source, DM2SAD_H, DM2SAD_L);
+ SWAP(dma2Dest, DM2DAD_H, DM2DAD_L);
+ SWAP(dma3Source, DM3SAD_H, DM3SAD_L);
+ SWAP(dma3Dest, DM3DAD_H, DM3DAD_L);
+ }
+
+ if(version <= SAVE_GAME_VERSION_8) {
+ timer0ClockReload = TIMER_TICKS[TM0CNT & 3];
+ timer1ClockReload = TIMER_TICKS[TM1CNT & 3];
+ timer2ClockReload = TIMER_TICKS[TM2CNT & 3];
+ timer3ClockReload = TIMER_TICKS[TM3CNT & 3];
+
+ timer0Ticks = ((0x10000 - TM0D) << timer0ClockReload) - timer0Ticks;
+ timer1Ticks = ((0x10000 - TM1D) << timer1ClockReload) - timer1Ticks;
+ timer2Ticks = ((0x10000 - TM2D) << timer2ClockReload) - timer2Ticks;
+ timer3Ticks = ((0x10000 - TM3D) << timer3ClockReload) - timer3Ticks;
+ interp_rate();
+ }
+
+ // set pointers!
+ layerEnable = layerSettings & DISPCNT;
+
+ CPUUpdateRender();
+ //CPUUpdateRenderBuffers(true);
+ //CPUUpdateWindow0();
+ //CPUUpdateWindow1();
+ gbaSaveType = 0;
+ switch(saveType) {
+ case 0:
+ cpuSaveGameFunc = flashSaveDecide;
+ break;
+ case 1:
+ cpuSaveGameFunc = sramWrite;
+ gbaSaveType = 1;
+ break;
+ case 2:
+ cpuSaveGameFunc = flashWrite;
+ gbaSaveType = 2;
+ break;
+ case 3:
+ break;
+ case 5:
+ gbaSaveType = 5;
+ break;
+ default:
+ systemMessage(MSG_UNSUPPORTED_SAVE_TYPE,
+ N_("Unsupported save type %d"), saveType);
+ break;
+ }
+ if(eepromInUse)
+ gbaSaveType = 3;
+
+ systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
+ if(armState) {
+ ARM_PREFETCH;
+ } else {
+ THUMB_PREFETCH;
+ }
+
+ CPUUpdateRegister(0x204, CPUReadHalfWordQuick(0x4000204));
+
+ return true;
+}
+
+bool CPUReadMemState(char *memory, int available)
+{
+ gzFile gzFile = utilMemGzOpen(memory, available, "r");
+
+ bool res = CPUReadState(gzFile);
+
+ utilGzClose(gzFile);
+
+ return res;
+}
+
+bool CPUReadState(const char * file)
+{
+ gzFile gzFile = utilGzOpen(file, "rb");
+
+ if(gzFile == NULL)
+ return false;
+
+ bool res = CPUReadState(gzFile);
+
+ utilGzClose(gzFile);
+
+ return res;
+}
+
+bool CPUExportEepromFile(const char *fileName)
+{
+ if(eepromInUse) {
+ FILE *file = fopen(fileName, "wb");
+
+ if(!file) {
+ systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
+ fileName);
+ return false;
+ }
+
+ for(int i = 0; i < eepromSize;) {
+ for(int j = 0; j < 8; j++) {
+ if(fwrite(&eepromData[i+7-j], 1, 1, file) != 1) {
+ fclose(file);
+ return false;
+ }
+ }
+ i += 8;
+ }
+ fclose(file);
+ }
+ return true;
+}
+
+bool CPUWriteBatteryFile(const char *fileName)
+{
+ if(gbaSaveType == 0) {
+ if(eepromInUse)
+ gbaSaveType = 3;
+ else switch(saveType) {
+ case 1:
+ gbaSaveType = 1;
+ break;
+ case 2:
+ gbaSaveType = 2;
+ break;
+ }
+ }
+
+ if((gbaSaveType) && (gbaSaveType!=5)) {
+ FILE *file = fopen(fileName, "wb");
+
+ if(!file) {
+ systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"),
+ fileName);
+ return false;
+ }
+
+ // only save if Flash/Sram in use or EEprom in use
+ if(gbaSaveType != 3) {
+ if(gbaSaveType == 2) {
+ if(fwrite(flashSaveMemory, 1, flashSize, file) != (size_t)flashSize) {
+ fclose(file);
+ return false;
+ }
+ } else {
+ if(fwrite(flashSaveMemory, 1, 0x10000, file) != 0x10000) {
+ fclose(file);
+ return false;
+ }
+ }
+ } else {
+ if(fwrite(eepromData, 1, eepromSize, file) != (size_t)eepromSize) {
+ fclose(file);
+ return false;
+ }
+ }
+ fclose(file);
+ }
+ return true;
+}
+
+bool CPUReadGSASnapshot(const char *fileName)
+{
+ int i;
+ FILE *file = fopen(fileName, "rb");
+
+ if(!file) {
+ systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
+ return false;
+ }
+
+ // check file size to know what we should read
+ fseek(file, 0, SEEK_END);
+
+ // long size = ftell(file);
+ fseek(file, 0x0, SEEK_SET);
+ fread(&i, 1, 4, file);
+ fseek(file, i, SEEK_CUR); // Skip SharkPortSave
+ fseek(file, 4, SEEK_CUR); // skip some sort of flag
+ fread(&i, 1, 4, file); // name length
+ fseek(file, i, SEEK_CUR); // skip name
+ fread(&i, 1, 4, file); // desc length
+ fseek(file, i, SEEK_CUR); // skip desc
+ fread(&i, 1, 4, file); // notes length
+ fseek(file, i, SEEK_CUR); // skip notes
+ int saveSize;
+ fread(&saveSize, 1, 4, file); // read length
+ saveSize -= 0x1c; // remove header size
+ char buffer[17];
+ char buffer2[17];
+ fread(buffer, 1, 16, file);
+ buffer[16] = 0;
+ for(i = 0; i < 16; i++)
+ if(buffer[i] < 32)
+ buffer[i] = 32;
+ memcpy(buffer2, &rom[0xa0], 16);
+ buffer2[16] = 0;
+ for(i = 0; i < 16; i++)
+ if(buffer2[i] < 32)
+ buffer2[i] = 32;
+ if(memcmp(buffer, buffer2, 16)) {
+ systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR,
+ N_("Cannot import snapshot for %s. Current game is %s"),
+ buffer,
+ buffer2);
+ fclose(file);
+ return false;
+ }
+ fseek(file, 12, SEEK_CUR); // skip some flags
+ if(saveSize >= 65536) {
+ if(fread(flashSaveMemory, 1, saveSize, file) != (size_t)saveSize) {
+ fclose(file);
+ return false;
+ }
+ } else {
+ systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE,
+ N_("Unsupported snapshot file %s"),
+ fileName);
+ fclose(file);
+ return false;
+ }
+ fclose(file);
+ CPUReset();
+ return true;
+}
+
+bool CPUReadGSASPSnapshot(const char *fileName)
+{
+ const char gsvfooter[] = "xV4\x12";
+ const size_t namepos=0x0c, namesz=12;
+ const size_t footerpos=0x42c, footersz=4;
+
+ char footer[footersz+1], romname[namesz+1], savename[namesz+1];;
+ FILE *file = fopen(fileName, "rb");
+
+ if(!file) {
+ systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
+ return false;
+ }
+
+ // read save name
+ fseek(file, namepos, SEEK_SET);
+ fread(savename, 1, namesz, file);
+ savename[namesz] = 0;
+
+ memcpy(romname, &rom[0xa0], namesz);
+ romname[namesz] = 0;
+
+ if(memcmp(romname, savename, namesz)) {
+ systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR,
+ N_("Cannot import snapshot for %s. Current game is %s"),
+ savename,
+ romname);
+ fclose(file);
+ return false;
+ }
+
+ // read footer tag
+ fseek(file, footerpos, SEEK_SET);
+ fread(footer, 1, footersz, file);
+ footer[footersz] = 0;
+
+ if(memcmp(footer, gsvfooter, footersz)) {
+ systemMessage(0,
+ N_("Unsupported snapshot file %s. Footer '%s' at %u should be '%s'"),
+ fileName,
+ footer,
+ footerpos,
+ gsvfooter);
+ fclose(file);
+ return false;
+ }
+
+ // Read up to 128k save
+ fread(flashSaveMemory, 1, FLASH_128K_SZ, file);
+
+ fclose(file);
+ CPUReset();
+ return true;
+}
+
+
+bool CPUWriteGSASnapshot(const char *fileName,
+ const char *title,
+ const char *desc,
+ const char *notes)
+{
+ FILE *file = fopen(fileName, "wb");
+
+ if(!file) {
+ systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);
+ return false;
+ }
+
+ u8 buffer[17];
+
+ utilPutDword(buffer, 0x0d); // SharkPortSave length
+ fwrite(buffer, 1, 4, file);
+ fwrite("SharkPortSave", 1, 0x0d, file);
+ utilPutDword(buffer, 0x000f0000);
+ fwrite(buffer, 1, 4, file); // save type 0x000f0000 = GBA save
+ utilPutDword(buffer, (u32)strlen(title));
+ fwrite(buffer, 1, 4, file); // title length
+ fwrite(title, 1, strlen(title), file);
+ utilPutDword(buffer, (u32)strlen(desc));
+ fwrite(buffer, 1, 4, file); // desc length
+ fwrite(desc, 1, strlen(desc), file);
+ utilPutDword(buffer, (u32)strlen(notes));
+ fwrite(buffer, 1, 4, file); // notes length
+ fwrite(notes, 1, strlen(notes), file);
+ int saveSize = 0x10000;
+ if(gbaSaveType == 2)
+ saveSize = flashSize;
+ int totalSize = saveSize + 0x1c;
+
+ utilPutDword(buffer, totalSize); // length of remainder of save - CRC
+ fwrite(buffer, 1, 4, file);
+
+ char *temp = new char[0x2001c];
+ memset(temp, 0, 28);
+ memcpy(temp, &rom[0xa0], 16); // copy internal name
+ temp[0x10] = rom[0xbe]; // reserved area (old checksum)
+ temp[0x11] = rom[0xbf]; // reserved area (old checksum)
+ temp[0x12] = rom[0xbd]; // complement check
+ temp[0x13] = rom[0xb0]; // maker
+ temp[0x14] = 1; // 1 save ?
+ memcpy(&temp[0x1c], flashSaveMemory, saveSize); // copy save
+ fwrite(temp, 1, totalSize, file); // write save + header
+ u32 crc = 0;
+
+ for(int i = 0; i < totalSize; i++) {
+ crc += ((u32)temp[i] << (crc % 0x18));
+ }
+
+ utilPutDword(buffer, crc);
+ fwrite(buffer, 1, 4, file); // CRC?
+
+ fclose(file);
+ delete [] temp;
+ return true;
+}
+
+bool CPUImportEepromFile(const char *fileName)
+{
+ FILE *file = fopen(fileName, "rb");
+
+ if(!file)
+ return false;
+
+ // check file size to know what we should read
+ fseek(file, 0, SEEK_END);
+
+ long size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+ if(size == 512 || size == 0x2000) {
+ if(fread(eepromData, 1, size, file) != (size_t)size) {
+ fclose(file);
+ return false;
+ }
+ for(int i = 0; i < size;) {
+ u8 tmp = eepromData[i];
+ eepromData[i] = eepromData[7-i];
+ eepromData[7-i] = tmp;
+ i++;
+ tmp = eepromData[i];
+ eepromData[i] = eepromData[7-i];
+ eepromData[7-i] = tmp;
+ i++;
+ tmp = eepromData[i];
+ eepromData[i] = eepromData[7-i];
+ eepromData[7-i] = tmp;
+ i++;
+ tmp = eepromData[i];
+ eepromData[i] = eepromData[7-i];
+ eepromData[7-i] = tmp;
+ i++;
+ i += 4;
+ }
+ } else {
+ fclose(file);
+ return false;
+ }
+ fclose(file);
+ return true;
+}
+
+bool CPUReadBatteryFile(const char *fileName)
+{
+ FILE *file = fopen(fileName, "rb");
+
+ if(!file)
+ return false;
+
+ // check file size to know what we should read
+ fseek(file, 0, SEEK_END);
+
+ long size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+ systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
+
+ if(size == 512 || size == 0x2000) {
+ if(fread(eepromData, 1, size, file) != (size_t)size) {
+ fclose(file);
+ return false;
+ }
+ } else {
+ if(size == 0x20000) {
+ if(fread(flashSaveMemory, 1, 0x20000, file) != 0x20000) {
+ fclose(file);
+ return false;
+ }
+ flashSetSize(0x20000);
+ } else {
+ if(fread(flashSaveMemory, 1, 0x10000, file) != 0x10000) {
+ fclose(file);
+ return false;
+ }
+ flashSetSize(0x10000);
+ }
+ }
+ fclose(file);
+ return true;
+}
+
+bool CPUWritePNGFile(const char *fileName)
+{
+ return utilWritePNGFile(fileName, 240, 160, pix);
+}
+
+bool CPUWriteBMPFile(const char *fileName)
+{
+ return utilWriteBMPFile(fileName, 240, 160, pix);
+}*/
+
+bool CPUIsZipFile(const char * file)
+{
+ if(strlen(file) > 4) {
+ const char * p = strrchr(file,'.');
+
+ if(p != NULL) {
+ if(_stricmp(p, ".zip") == 0)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CPUIsGBAImage(const char * file)
+{
+ cpuIsMultiBoot = false;
+ if(strlen(file) > 4) {
+ const char * p = strrchr(file,'.');
+
+ if(p != NULL) {
+ if(_stricmp(p, ".gba") == 0)
+ return true;
+ if(_stricmp(p, ".agb") == 0)
+ return true;
+ if(_stricmp(p, ".bin") == 0)
+ return true;
+ if(_stricmp(p, ".elf") == 0)
+ return true;
+ if(_stricmp(p, ".mb") == 0) {
+ cpuIsMultiBoot = true;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool CPUIsGBABios(const char * file)
+{
+ if(strlen(file) > 4) {
+ const char * p = strrchr(file,'.');
+
+ if(p != NULL) {
+ if(_stricmp(p, ".gba") == 0)
+ return true;
+ if(_stricmp(p, ".agb") == 0)
+ return true;
+ if(_stricmp(p, ".bin") == 0)
+ return true;
+ if(_stricmp(p, ".bios") == 0)
+ return true;
+ if(_stricmp(p, ".rom") == 0)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CPUIsELF(const char *file)
+{
+ if(file == NULL)
+ return false;
+
+ if(strlen(file) > 4) {
+ const char * p = strrchr(file,'.');
+
+ if(p != NULL) {
+ if(_stricmp(p, ".elf") == 0)
+ return true;
+ }
+ }
+ return false;
+}
+
+void CPUCleanUp()
+{
+#ifdef PROFILING
+ if(profilingTicksReload) {
+ profCleanup();
+ }
+#endif
+
+ if(rom != NULL) {
+ free(rom);
+ rom = NULL;
+ }
+
+ if(vram != NULL) {
+ free(vram);
+ vram = NULL;
+ }
+
+ if(paletteRAM != NULL) {
+ free(paletteRAM);
+ paletteRAM = NULL;
+ }
+
+ if(internalRAM != NULL) {
+ free(internalRAM);
+ internalRAM = NULL;
+ }
+
+ if(workRAM != NULL) {
+ free(workRAM);
+ workRAM = NULL;
+ }
+
+ if(bios != NULL) {
+ free(bios);
+ bios = NULL;
+ }
+
+ if(pix != NULL) {
+ free(pix);
+ pix = NULL;
+ }
+
+ if(oam != NULL) {
+ free(oam);
+ oam = NULL;
+ }
+
+ if(ioMem != NULL) {
+ free(ioMem);
+ ioMem = NULL;
+ }
+
+#ifndef NO_DEBUGGER
+ elfCleanUp();
+#endif //NO_DEBUGGER
+
+ //systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
+
+ //emulating = 0;
+}
+
+int CPULoadRom(const char *szFile)
+{
+ romSize = 0x2000000;
+ if(rom != NULL) {
+ CPUCleanUp();
+ }
+
+ //systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
+
+ rom = (u8 *)malloc(0x2000000);
+ if(rom == NULL) {
+ /*systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
+ "ROM");*/
+ return 0;
+ }
+ workRAM = (u8 *)calloc(1, 0x40000);
+ if(workRAM == NULL) {
+ /*systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
+ "WRAM");*/
+ return 0;
+ }
+
+ u8 *whereToLoad = cpuIsMultiBoot ? workRAM : rom;
+
+#ifndef NO_DEBUGGER
+ if(CPUIsELF(szFile)) {
+ FILE *f = fopen(szFile, "rb");
+ if(!f) {
+ systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"),
+ szFile);
+ free(rom);
+ rom = NULL;
+ free(workRAM);
+ workRAM = NULL;
+ return 0;
+ }
+ bool res = elfRead(szFile, romSize, f);
+ if(!res || romSize == 0) {
+ free(rom);
+ rom = NULL;
+ free(workRAM);
+ workRAM = NULL;
+ elfCleanUp();
+ return 0;
+ }
+ } else
+#endif //NO_DEBUGGER
+ /*if(szFile!=NULL)
+ {
+ if(!utilLoad(szFile,
+ utilIsGBAImage,
+ whereToLoad,
+ romSize)) {
+ free(rom);
+ rom = NULL;
+ free(workRAM);
+ workRAM = NULL;
+ return 0;
+ }
+ }*/
+ if (cpuIsMultiBoot)
+ mapgsf(workRAM,0x40000,romSize);
+ else
+ mapgsf(rom, 0x2000000,romSize);
+
+ u16 *temp = (u16 *)(rom+((romSize+1)&~1));
+ int i;
+ for(i = (romSize+1)&~1; i < 0x2000000; i+=2) {
+ WRITE16LE(temp, (i >> 1) & 0xFFFF);
+ temp++;
+ }
+
+ bios = (u8 *)calloc(1,0x4000);
+ if(bios == NULL) {
+ /*systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
+ "BIOS");*/
+ CPUCleanUp();
+ return 0;
+ }
+ internalRAM = (u8 *)calloc(1,0x8000);
+ if(internalRAM == NULL) {
+ /*systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
+ "IRAM");*/
+ CPUCleanUp();
+ return 0;
+ }
+ paletteRAM = (u8 *)calloc(1,0x400);
+ if(paletteRAM == NULL) {
+ /*systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
+ "PRAM");*/
+ CPUCleanUp();
+ return 0;
+ }
+ vram = (u8 *)calloc(1, 0x20000);
+ if(vram == NULL) {
+ /*systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
+ "VRAM");*/
+ CPUCleanUp();
+ return 0;
+ }
+ oam = (u8 *)calloc(1, 0x400);
+ if(oam == NULL) {
+ /*systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
+ "OAM");*/
+ CPUCleanUp();
+ return 0;
+ }
+ pix = (u8 *)calloc(1, 4 * 241 * 162);
+ if(pix == NULL) {
+ /*systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
+ "PIX");*/
+ CPUCleanUp();
+ return 0;
+ }
+ ioMem = (u8 *)calloc(1, 0x400);
+ if(ioMem == NULL) {
+ /*systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
+ "IO");*/
+ CPUCleanUp();
+ return 0;
+ }
+
+ //flashInit();
+ //eepromInit();
+
+ //CPUUpdateRenderBuffers(true);
+
+ return romSize;
+}
+
+void doMirroring (bool b)
+{
+ u32 mirroredRomSize = (((romSize)>>20) & 0x3F)<<20;
+ u32 mirroredRomAddress = romSize;
+ if ((mirroredRomSize <=0x800000) && (b))
+ {
+ mirroredRomAddress = mirroredRomSize;
+ if (mirroredRomSize==0)
+ mirroredRomSize=0x100000;
+ while (mirroredRomAddress<0x01000000)
+ {
+ memcpy ((u16 *)(rom+mirroredRomAddress), (u16 *)(rom), mirroredRomSize);
+ mirroredRomAddress+=mirroredRomSize;
+ }
+ }
+}
+
+/*void CPUUpdateRender()
+{
+ switch(DISPCNT & 7) {
+ case 0:
+ if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
+ cpuDisableSfx)
+ renderLine = mode0RenderLine;
+ else if(fxOn && !windowOn && !(layerEnable & 0x8000))
+ renderLine = mode0RenderLineNoWindow;
+ else
+ renderLine = mode0RenderLineAll;
+ break;
+ case 1:
+ if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
+ cpuDisableSfx)
+ renderLine = mode1RenderLine;
+ else if(fxOn && !windowOn && !(layerEnable & 0x8000))
+ renderLine = mode1RenderLineNoWindow;
+ else
+ renderLine = mode1RenderLineAll;
+ break;
+ case 2:
+ if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
+ cpuDisableSfx)
+ renderLine = mode2RenderLine;
+ else if(fxOn && !windowOn && !(layerEnable & 0x8000))
+ renderLine = mode2RenderLineNoWindow;
+ else
+ renderLine = mode2RenderLineAll;
+ break;
+ case 3:
+ if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
+ cpuDisableSfx)
+ renderLine = mode3RenderLine;
+ else if(fxOn && !windowOn && !(layerEnable & 0x8000))
+ renderLine = mode3RenderLineNoWindow;
+ else
+ renderLine = mode3RenderLineAll;
+ break;
+ case 4:
+ if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
+ cpuDisableSfx)
+ renderLine = mode4RenderLine;
+ else if(fxOn && !windowOn && !(layerEnable & 0x8000))
+ renderLine = mode4RenderLineNoWindow;
+ else
+ renderLine = mode4RenderLineAll;
+ break;
+ case 5:
+ if((!fxOn && !windowOn && !(layerEnable & 0x8000)) ||
+ cpuDisableSfx)
+ renderLine = mode5RenderLine;
+ else if(fxOn && !windowOn && !(layerEnable & 0x8000))
+ renderLine = mode5RenderLineNoWindow;
+ else
+ renderLine = mode5RenderLineAll;
+ default:
+ break;
+ }
+}*/
+
+void CPUUpdateCPSR()
+{
+ u32 CPSR = reg[16].I & 0x40;
+ if(N_FLAG)
+ CPSR |= 0x80000000;
+ if(Z_FLAG)
+ CPSR |= 0x40000000;
+ if(C_FLAG)
+ CPSR |= 0x20000000;
+ if(V_FLAG)
+ CPSR |= 0x10000000;
+ if(!armState)
+ CPSR |= 0x00000020;
+ if(!armIrqEnable)
+ CPSR |= 0x80;
+ CPSR |= (armMode & 0x1F);
+ reg[16].I = CPSR;
+}
+
+void CPUUpdateFlags(bool breakLoop)
+{
+ u32 CPSR = reg[16].I;
+
+ N_FLAG = (CPSR & 0x80000000) ? true: false;
+ Z_FLAG = (CPSR & 0x40000000) ? true: false;
+ C_FLAG = (CPSR & 0x20000000) ? true: false;
+ V_FLAG = (CPSR & 0x10000000) ? true: false;
+ armState = (CPSR & 0x20) ? false : true;
+ armIrqEnable = (CPSR & 0x80) ? false : true;
+ if(breakLoop) {
+ if (armIrqEnable && (IF & IE) && (IME & 1))
+ cpuNextEvent = cpuTotalTicks;
+ }
+}
+
+void CPUUpdateFlags()
+{
+ CPUUpdateFlags(true);
+}
+
+#ifdef WORDS_BIGENDIAN
+static void CPUSwap(volatile u32 *a, volatile u32 *b)
+{
+ volatile u32 c = *b;
+ *b = *a;
+ *a = c;
+}
+#else
+static void CPUSwap(u32 *a, u32 *b)
+{
+ u32 c = *b;
+ *b = *a;
+ *a = c;
+}
+#endif
+
+void CPUSwitchMode(int mode, bool saveState, bool breakLoop)
+{
+ // if(armMode == mode)
+ // return;
+
+ CPUUpdateCPSR();
+
+ switch(armMode) {
+ case 0x10:
+ case 0x1F:
+ reg[R13_USR].I = reg[13].I;
+ reg[R14_USR].I = reg[14].I;
+ reg[17].I = reg[16].I;
+ break;
+ case 0x11:
+ CPUSwap(®[R8_FIQ].I, ®[8].I);
+ CPUSwap(®[R9_FIQ].I, ®[9].I);
+ CPUSwap(®[R10_FIQ].I, ®[10].I);
+ CPUSwap(®[R11_FIQ].I, ®[11].I);
+ CPUSwap(®[R12_FIQ].I, ®[12].I);
+ reg[R13_FIQ].I = reg[13].I;
+ reg[R14_FIQ].I = reg[14].I;
+ reg[SPSR_FIQ].I = reg[17].I;
+ break;
+ case 0x12:
+ reg[R13_IRQ].I = reg[13].I;
+ reg[R14_IRQ].I = reg[14].I;
+ reg[SPSR_IRQ].I = reg[17].I;
+ break;
+ case 0x13:
+ reg[R13_SVC].I = reg[13].I;
+ reg[R14_SVC].I = reg[14].I;
+ reg[SPSR_SVC].I = reg[17].I;
+ break;
+ case 0x17:
+ reg[R13_ABT].I = reg[13].I;
+ reg[R14_ABT].I = reg[14].I;
+ reg[SPSR_ABT].I = reg[17].I;
+ break;
+ case 0x1b:
+ reg[R13_UND].I = reg[13].I;
+ reg[R14_UND].I = reg[14].I;
+ reg[SPSR_UND].I = reg[17].I;
+ break;
+ }
+
+ u32 CPSR = reg[16].I;
+ u32 SPSR = reg[17].I;
+
+ switch(mode) {
+ case 0x10:
+ case 0x1F:
+ reg[13].I = reg[R13_USR].I;
+ reg[14].I = reg[R14_USR].I;
+ reg[16].I = SPSR;
+ break;
+ case 0x11:
+ CPUSwap(®[8].I, ®[R8_FIQ].I);
+ CPUSwap(®[9].I, ®[R9_FIQ].I);
+ CPUSwap(®[10].I, ®[R10_FIQ].I);
+ CPUSwap(®[11].I, ®[R11_FIQ].I);
+ CPUSwap(®[12].I, ®[R12_FIQ].I);
+ reg[13].I = reg[R13_FIQ].I;
+ reg[14].I = reg[R14_FIQ].I;
+ if(saveState)
+ reg[17].I = CPSR;
+ else
+ reg[17].I = reg[SPSR_FIQ].I;
+ break;
+ case 0x12:
+ reg[13].I = reg[R13_IRQ].I;
+ reg[14].I = reg[R14_IRQ].I;
+ reg[16].I = SPSR;
+ if(saveState)
+ reg[17].I = CPSR;
+ else
+ reg[17].I = reg[SPSR_IRQ].I;
+ break;
+ case 0x13:
+ reg[13].I = reg[R13_SVC].I;
+ reg[14].I = reg[R14_SVC].I;
+ reg[16].I = SPSR;
+ if(saveState)
+ reg[17].I = CPSR;
+ else
+ reg[17].I = reg[SPSR_SVC].I;
+ break;
+ case 0x17:
+ reg[13].I = reg[R13_ABT].I;
+ reg[14].I = reg[R14_ABT].I;
+ reg[16].I = SPSR;
+ if(saveState)
+ reg[17].I = CPSR;
+ else
+ reg[17].I = reg[SPSR_ABT].I;
+ break;
+ case 0x1b:
+ reg[13].I = reg[R13_UND].I;
+ reg[14].I = reg[R14_UND].I;
+ reg[16].I = SPSR;
+ if(saveState)
+ reg[17].I = CPSR;
+ else
+ reg[17].I = reg[SPSR_UND].I;
+ break;
+ default:
+ //systemMessage(MSG_UNSUPPORTED_ARM_MODE, N_("Unsupported ARM mode %02x"), mode);
+ break;
+ }
+ armMode = mode;
+ CPUUpdateFlags(breakLoop);
+ CPUUpdateCPSR();
+}
+
+void CPUSwitchMode(int mode, bool saveState)
+{
+ CPUSwitchMode(mode, saveState, true);
+}
+
+void CPUUndefinedException()
+{
+ u32 PC = reg[15].I;
+ bool savedArmState = armState;
+ CPUSwitchMode(0x1b, true, false);
+ reg[14].I = PC - (savedArmState ? 4 : 2);
+ reg[15].I = 0x04;
+ armState = true;
+ armIrqEnable = false;
+ armNextPC = 0x04;
+ ARM_PREFETCH;
+ reg[15].I += 4;
+}
+
+void CPUSoftwareInterrupt()
+{
+ u32 PC = reg[15].I;
+ bool savedArmState = armState;
+ CPUSwitchMode(0x13, true, false);
+ reg[14].I = PC - (savedArmState ? 4 : 2);
+ reg[15].I = 0x08;
+ armState = true;
+ armIrqEnable = false;
+ armNextPC = 0x08;
+ ARM_PREFETCH;
+ reg[15].I += 4;
+}
+
+void CPUSoftwareInterrupt(int comment)
+{
+ static bool disableMessage = false;
+ if(armState) comment >>= 16;
+#ifdef BKPT_SUPPORT
+ if(comment == 0xff) {
+ dbgOutput(NULL, reg[0].I);
+ return;
+ }
+#endif
+#ifdef PROFILING
+ if(comment == 0xfe) {
+ profStartup(reg[0].I, reg[1].I);
+ return;
+ }
+ if(comment == 0xfd) {
+ profControl(reg[0].I);
+ return;
+ }
+ if(comment == 0xfc) {
+ profCleanup();
+ return;
+ }
+ if(comment == 0xfb) {
+ profCount();
+ return;
+ }
+#endif
+ if(comment == 0xfa) {
+ //agbPrintFlush();
+ return;
+ }
+#ifdef SDL
+ if(comment == 0xf9) {
+ emulating = 0;
+ cpuNextEvent = cpuTotalTicks;
+ cpuBreakLoop = true;
+ return;
+ }
+#endif
+ if(useBios) {
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
+ armState ? armNextPC - 4: armNextPC -2,
+ reg[0].I,
+ reg[1].I,
+ reg[2].I,
+ VCOUNT);
+ }
+#endif
+ CPUSoftwareInterrupt();
+ return;
+ }
+ // This would be correct, but it causes problems if uncommented
+ // else {
+ // biosProtected = 0xe3a02004;
+ // }
+
+ switch(comment) {
+ case 0x00:
+ BIOS_SoftReset();
+ ARM_PREFETCH;
+ break;
+ case 0x01:
+ BIOS_RegisterRamReset();
+ break;
+ case 0x02:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("Halt: (VCOUNT = %2d)\n",
+ VCOUNT);
+ }
+#endif
+ holdState = true;
+ holdType = -1;
+ cpuNextEvent = cpuTotalTicks;
+ break;
+ case 0x03:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("Stop: (VCOUNT = %2d)\n",
+ VCOUNT);
+ }
+#endif
+ holdState = true;
+ holdType = -1;
+ stopState = true;
+ cpuNextEvent = cpuTotalTicks;
+ break;
+ case 0x04:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n",
+ reg[0].I,
+ reg[1].I,
+ VCOUNT);
+ }
+#endif
+ CPUSoftwareInterrupt();
+ break;
+ case 0x05:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("VBlankIntrWait: (VCOUNT = %2d)\n",
+ VCOUNT);
+ }
+#endif
+ CPUSoftwareInterrupt();
+ break;
+ case 0x06:
+ CPUSoftwareInterrupt();
+ break;
+ case 0x07:
+ CPUSoftwareInterrupt();
+ break;
+ case 0x08:
+ BIOS_Sqrt();
+ break;
+ case 0x09:
+ BIOS_ArcTan();
+ break;
+ case 0x0A:
+ BIOS_ArcTan2();
+ break;
+ case 0x0B:
+ {
+ int len = (reg[2].I & 0x1FFFFF) >>1;
+ if (!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + len) & 0xe000000) == 0))
+ {
+ if ((reg[2].I >> 24) & 1)
+ {
+ if ((reg[2].I >> 26) & 1)
+ SWITicks = (7 + memoryWait32[(reg[1].I>>24) & 0xF]) * (len>>1);
+ else
+ SWITicks = (8 + memoryWait[(reg[1].I>>24) & 0xF]) * (len);
+ }
+ else
+ {
+ if ((reg[2].I >> 26) & 1)
+ SWITicks = (10 + memoryWait32[(reg[0].I>>24) & 0xF] +
+ memoryWait32[(reg[1].I>>24) & 0xF]) * (len>>1);
+ else
+ SWITicks = (11 + memoryWait[(reg[0].I>>24) & 0xF] +
+ memoryWait[(reg[1].I>>24) & 0xF]) * len;
+ }
+ }
+ }
+ BIOS_CpuSet();
+ break;
+ case 0x0C:
+ {
+ int len = (reg[2].I & 0x1FFFFF) >>5;
+ if (!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + len) & 0xe000000) == 0))
+ {
+ if ((reg[2].I >> 24) & 1)
+ SWITicks = (6 + memoryWait32[(reg[1].I>>24) & 0xF] +
+ 7 * (memoryWaitSeq32[(reg[1].I>>24) & 0xF] + 1)) * len;
+ else
+ SWITicks = (9 + memoryWait32[(reg[0].I>>24) & 0xF] +
+ memoryWait32[(reg[1].I>>24) & 0xF] +
+ 7 * (memoryWaitSeq32[(reg[0].I>>24) & 0xF] +
+ memoryWaitSeq32[(reg[1].I>>24) & 0xF] + 2)) * len;
+ }
+ }
+ BIOS_CpuFastSet();
+ break;
+ case 0x0D:
+ BIOS_GetBiosChecksum();
+ break;
+ case 0x0E:
+ BIOS_BgAffineSet();
+ break;
+ case 0x0F:
+ BIOS_ObjAffineSet();
+ break;
+ case 0x10:
+ {
+ int len = CPUReadHalfWord(reg[2].I);
+ if (!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + len) & 0xe000000) == 0))
+ SWITicks = (32 + memoryWait[(reg[0].I>>24) & 0xF]) * len;
+ }
+ BIOS_BitUnPack();
+ break;
+ case 0x11:
+ {
+ u32 len = CPUReadMemory(reg[0].I) >> 8;
+ if(!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
+ SWITicks = (9 + memoryWait[(reg[1].I>>24) & 0xF]) * len;
+ }
+ BIOS_LZ77UnCompWram();
+ break;
+ case 0x12:
+ {
+ u32 len = CPUReadMemory(reg[0].I) >> 8;
+ if(!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
+ SWITicks = (19 + memoryWait[(reg[1].I>>24) & 0xF]) * len;
+ }
+ BIOS_LZ77UnCompVram();
+ break;
+ case 0x13:
+ {
+ u32 len = CPUReadMemory(reg[0].I) >> 8;
+ if(!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
+ SWITicks = (29 + (memoryWait[(reg[0].I>>24) & 0xF]<<1)) * len;
+ }
+ BIOS_HuffUnComp();
+ break;
+ case 0x14:
+ {
+ u32 len = CPUReadMemory(reg[0].I) >> 8;
+ if(!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
+ SWITicks = (11 + memoryWait[(reg[0].I>>24) & 0xF] +
+ memoryWait[(reg[1].I>>24) & 0xF]) * len;
+ }
+ BIOS_RLUnCompWram();
+ break;
+ case 0x15:
+ {
+ u32 len = CPUReadMemory(reg[0].I) >> 9;
+ if(!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
+ SWITicks = (34 + (memoryWait[(reg[0].I>>24) & 0xF] << 1) +
+ memoryWait[(reg[1].I>>24) & 0xF]) * len;
+ }
+ BIOS_RLUnCompVram();
+ break;
+ case 0x16:
+ {
+ u32 len = CPUReadMemory(reg[0].I) >> 8;
+ if(!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
+ SWITicks = (13 + memoryWait[(reg[0].I>>24) & 0xF] +
+ memoryWait[(reg[1].I>>24) & 0xF]) * len;
+ }
+ BIOS_Diff8bitUnFilterWram();
+ break;
+ case 0x17:
+ {
+ u32 len = CPUReadMemory(reg[0].I) >> 9;
+ if(!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
+ SWITicks = (39 + (memoryWait[(reg[0].I>>24) & 0xF]<<1) +
+ memoryWait[(reg[1].I>>24) & 0xF]) * len;
+ }
+ BIOS_Diff8bitUnFilterVram();
+ break;
+ case 0x18:
+ {
+ u32 len = CPUReadMemory(reg[0].I) >> 9;
+ if(!(((reg[0].I & 0xe000000) == 0) ||
+ ((reg[0].I + (len & 0x1fffff)) & 0xe000000) == 0))
+ SWITicks = (13 + memoryWait[(reg[0].I>>24) & 0xF] +
+ memoryWait[(reg[1].I>>24) & 0xF]) * len;
+ }
+ BIOS_Diff16bitUnFilter();
+ break;
+ case 0x19:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n",
+ reg[0].I,
+ VCOUNT);
+ }
+#endif
+ if(reg[0].I)
+ soundPause();
+ else
+ soundResume();
+ break;
+ case 0x1F:
+ BIOS_MidiKey2Freq();
+ break;
+ case 0x2A:
+ BIOS_SndDriverJmpTableCopy();
+ // let it go, because we don't really emulate this function
+ default:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment,
+ armState ? armNextPC - 4: armNextPC -2,
+ reg[0].I,
+ reg[1].I,
+ reg[2].I,
+ VCOUNT);
+ }
+#endif
+
+ if(!disableMessage) {
+ /*systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION,
+ N_("Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."),
+ comment,
+ armMode ? armNextPC - 4: armNextPC - 2);*/
+ disableMessage = true;
+ }
+ break;
+ }
+}
+
+void CPUCompareVCOUNT()
+{
+ if(VCOUNT == (DISPSTAT >> 8)) {
+ DISPSTAT |= 4;
+ UPDATE_REG(0x04, DISPSTAT);
+
+ if(DISPSTAT & 0x20) {
+ IF |= 4;
+ UPDATE_REG(0x202, IF);
+ }
+ } else {
+ DISPSTAT &= 0xFFFB;
+ UPDATE_REG(0x4, DISPSTAT);
+ }
+ if (layerEnableDelay>0)
+ {
+ layerEnableDelay--;
+ if (layerEnableDelay==1)
+ layerEnable = layerSettings & DISPCNT;
+ }
+
+}
+
+void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32)
+{
+ int sm = s >> 24;
+ int dm = d >> 24;
+ int sw = 0;
+ int dw = 0;
+ int sc = c;
+
+ cpuDmaCount = c;
+ // This is done to get the correct waitstates.
+ if (sm>15)
+ sm=15;
+ if (dm>15)
+ dm=15;
+
+ //if ((sm>=0x05) && (sm<=0x07) || (dm>=0x05) && (dm <=0x07))
+ // blank = (((DISPSTAT | ((DISPSTAT>>1)&1))==1) ? true : false);
+
+ if(transfer32) {
+ s &= 0xFFFFFFFC;
+ if(s < 0x02000000 && (reg[15].I >> 24)) {
+ while(c != 0) {
+ CPUWriteMemory(d, 0);
+ d += di;
+ c--;
+ }
+ } else {
+ while(c != 0) {
+ cpuDmaLast = CPUReadMemory(s);
+ CPUWriteMemory(d, cpuDmaLast);
+ d += di;
+ s += si;
+ c--;
+ }
+ }
+ } else {
+ s &= 0xFFFFFFFE;
+ si = (int)si >> 1;
+ di = (int)di >> 1;
+ if(s < 0x02000000 && (reg[15].I >> 24)) {
+ while(c != 0) {
+ CPUWriteHalfWord(d, 0);
+ d += di;
+ c--;
+ }
+ } else {
+ while(c != 0) {
+ cpuDmaLast = CPUReadHalfWord(s);
+ CPUWriteHalfWord(d, cpuDmaLast);
+ cpuDmaLast |= (cpuDmaLast<<16);
+ d += di;
+ s += si;
+ c--;
+ }
+ }
+ }
+
+ cpuDmaCount = 0;
+
+ int totalTicks = 0;
+
+ if(transfer32) {
+ sw =1+memoryWaitSeq32[sm & 15];
+ dw =1+memoryWaitSeq32[dm & 15];
+ totalTicks = (sw+dw)*(sc-1) + 6 + memoryWait32[sm & 15] +
+ memoryWaitSeq32[dm & 15];
+ }
+ else
+ {
+ sw = 1+memoryWaitSeq[sm & 15];
+ dw = 1+memoryWaitSeq[dm & 15];
+ totalTicks = (sw+dw)*(sc-1) + 6 + memoryWait[sm & 15] +
+ memoryWaitSeq[dm & 15];
+ }
+
+ cpuDmaTicksToUpdate += totalTicks;
+
+}
+
+void CPUCheckDMA(int reason, int dmamask)
+{
+ // DMA 0
+ if((DM0CNT_H & 0x8000) && (dmamask & 1)) {
+ if(((DM0CNT_H >> 12) & 3) == reason) {
+ u32 sourceIncrement = 4;
+ u32 destIncrement = 4;
+ switch((DM0CNT_H >> 7) & 3) {
+ case 0:
+ break;
+ case 1:
+ sourceIncrement = (u32)-4;
+ break;
+ case 2:
+ sourceIncrement = 0;
+ break;
+ }
+ switch((DM0CNT_H >> 5) & 3) {
+ case 0:
+ break;
+ case 1:
+ destIncrement = (u32)-4;
+ break;
+ case 2:
+ destIncrement = 0;
+ break;
+ }
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_DMA0) {
+ int count = (DM0CNT_L ? DM0CNT_L : 0x4000) << 1;
+ if(DM0CNT_H & 0x0400)
+ count <<= 1;
+ log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source, dma0Dest,
+ DM0CNT_H,
+ count);
+ }
+#endif
+ doDMA(dma0Source, dma0Dest, sourceIncrement, destIncrement,
+ DM0CNT_L ? DM0CNT_L : 0x4000,
+ DM0CNT_H & 0x0400);
+ cpuDmaHack = true;
+
+ if(DM0CNT_H & 0x4000) {
+ IF |= 0x0100;
+ UPDATE_REG(0x202, IF);
+ cpuNextEvent = cpuTotalTicks;
+ }
+
+ if(((DM0CNT_H >> 5) & 3) == 3) {
+ dma0Dest = DM0DAD_L | (DM0DAD_H << 16);
+ }
+
+ if(!(DM0CNT_H & 0x0200) || (reason == 0)) {
+ DM0CNT_H &= 0x7FFF;
+ UPDATE_REG(0xBA, DM0CNT_H);
+ }
+ }
+ }
+
+ // DMA 1
+ if((DM1CNT_H & 0x8000) && (dmamask & 2)) {
+ if(((DM1CNT_H >> 12) & 3) == reason) {
+ u32 sourceIncrement = 4;
+ u32 destIncrement = 4;
+ switch((DM1CNT_H >> 7) & 3) {
+ case 0:
+ break;
+ case 1:
+ sourceIncrement = (u32)-4;
+ break;
+ case 2:
+ sourceIncrement = 0;
+ break;
+ }
+ switch((DM1CNT_H >> 5) & 3) {
+ case 0:
+ break;
+ case 1:
+ destIncrement = (u32)-4;
+ break;
+ case 2:
+ destIncrement = 0;
+ break;
+ }
+ if(reason == 3) {
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_DMA1) {
+ log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest,
+ DM1CNT_H,
+ 16);
+ }
+#endif
+ doDMA(dma1Source, dma1Dest, sourceIncrement, 0, 4,
+ 0x0400);
+ } else {
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_DMA1) {
+ int count = (DM1CNT_L ? DM1CNT_L : 0x4000) << 1;
+ if(DM1CNT_H & 0x0400)
+ count <<= 1;
+ log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source, dma1Dest,
+ DM1CNT_H,
+ count);
+ }
+#endif
+ doDMA(dma1Source, dma1Dest, sourceIncrement, destIncrement,
+ DM1CNT_L ? DM1CNT_L : 0x4000,
+ DM1CNT_H & 0x0400);
+ }
+ cpuDmaHack = true;
+
+ if(DM1CNT_H & 0x4000) {
+ IF |= 0x0200;
+ UPDATE_REG(0x202, IF);
+ cpuNextEvent = cpuTotalTicks;
+ }
+
+ if(((DM1CNT_H >> 5) & 3) == 3) {
+ dma1Dest = DM1DAD_L | (DM1DAD_H << 16);
+ }
+
+ if(!(DM1CNT_H & 0x0200) || (reason == 0)) {
+ DM1CNT_H &= 0x7FFF;
+ UPDATE_REG(0xC6, DM1CNT_H);
+ }
+ }
+ }
+
+ // DMA 2
+ if((DM2CNT_H & 0x8000) && (dmamask & 4)) {
+ if(((DM2CNT_H >> 12) & 3) == reason) {
+ u32 sourceIncrement = 4;
+ u32 destIncrement = 4;
+ switch((DM2CNT_H >> 7) & 3) {
+ case 0:
+ break;
+ case 1:
+ sourceIncrement = (u32)-4;
+ break;
+ case 2:
+ sourceIncrement = 0;
+ break;
+ }
+ switch((DM2CNT_H >> 5) & 3) {
+ case 0:
+ break;
+ case 1:
+ destIncrement = (u32)-4;
+ break;
+ case 2:
+ destIncrement = 0;
+ break;
+ }
+ if(reason == 3) {
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_DMA2) {
+ int count = (4) << 2;
+ log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest,
+ DM2CNT_H,
+ count);
+ }
+#endif
+ doDMA(dma2Source, dma2Dest, sourceIncrement, 0, 4,
+ 0x0400);
+ } else {
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_DMA2) {
+ int count = (DM2CNT_L ? DM2CNT_L : 0x4000) << 1;
+ if(DM2CNT_H & 0x0400)
+ count <<= 1;
+ log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source, dma2Dest,
+ DM2CNT_H,
+ count);
+ }
+#endif
+ doDMA(dma2Source, dma2Dest, sourceIncrement, destIncrement,
+ DM2CNT_L ? DM2CNT_L : 0x4000,
+ DM2CNT_H & 0x0400);
+ }
+ cpuDmaHack = true;
+
+ if(DM2CNT_H & 0x4000) {
+ IF |= 0x0400;
+ UPDATE_REG(0x202, IF);
+ cpuNextEvent = cpuTotalTicks;
+ }
+
+ if(((DM2CNT_H >> 5) & 3) == 3) {
+ dma2Dest = DM2DAD_L | (DM2DAD_H << 16);
+ }
+
+ if(!(DM2CNT_H & 0x0200) || (reason == 0)) {
+ DM2CNT_H &= 0x7FFF;
+ UPDATE_REG(0xD2, DM2CNT_H);
+ }
+ }
+ }
+
+ // DMA 3
+ if((DM3CNT_H & 0x8000) && (dmamask & 8)) {
+ if(((DM3CNT_H >> 12) & 3) == reason) {
+ u32 sourceIncrement = 4;
+ u32 destIncrement = 4;
+ switch((DM3CNT_H >> 7) & 3) {
+ case 0:
+ break;
+ case 1:
+ sourceIncrement = (u32)-4;
+ break;
+ case 2:
+ sourceIncrement = 0;
+ break;
+ }
+ switch((DM3CNT_H >> 5) & 3) {
+ case 0:
+ break;
+ case 1:
+ destIncrement = (u32)-4;
+ break;
+ case 2:
+ destIncrement = 0;
+ break;
+ }
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_DMA3) {
+ int count = (DM3CNT_L ? DM3CNT_L : 0x10000) << 1;
+ if(DM3CNT_H & 0x0400)
+ count <<= 1;
+ log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source, dma3Dest,
+ DM3CNT_H,
+ count);
+ }
+#endif
+ doDMA(dma3Source, dma3Dest, sourceIncrement, destIncrement,
+ DM3CNT_L ? DM3CNT_L : 0x10000,
+ DM3CNT_H & 0x0400);
+ if(DM3CNT_H & 0x4000) {
+ IF |= 0x0800;
+ UPDATE_REG(0x202, IF);
+ cpuNextEvent = cpuTotalTicks;
+ }
+
+ if(((DM3CNT_H >> 5) & 3) == 3) {
+ dma3Dest = DM3DAD_L | (DM3DAD_H << 16);
+ }
+
+ if(!(DM3CNT_H & 0x0200) || (reason == 0)) {
+ DM3CNT_H &= 0x7FFF;
+ UPDATE_REG(0xDE, DM3CNT_H);
+ }
+ }
+ }
+}
+
+void CPUUpdateRegister(u32 address, u16 value)
+{
+ switch(address)
+ {
+ case 0x00:
+ { // we need to place the following code in { } because we declare & initialize variables in a case statement
+ if((value & 7) > 5) {
+ // display modes above 0-5 are prohibited
+ DISPCNT = (value & 7);
+ }
+ bool change = (0 != ((DISPCNT ^ value) & 0x80));
+ bool changeBG = (0 != ((DISPCNT ^ value) & 0x0F00));
+ u16 changeBGon = ((~DISPCNT) & value) & 0x0F00; // these layers are being activated
+
+ DISPCNT = (value & 0xFFF7); // bit 3 can only be accessed by the BIOS to enable GBC mode
+ UPDATE_REG(0x00, DISPCNT);
+
+ if(changeBGon) {
+ layerEnableDelay = 4;
+ layerEnable = layerSettings & value & (~changeBGon);
+ } else {
+ layerEnable = layerSettings & value;
+ // CPUUpdateTicks();
+ }
+
+ windowOn = (layerEnable & 0x6000) ? true : false;
+ if(change && !((value & 0x80))) {
+ if(!(DISPSTAT & 1)) {
+ lcdTicks = 1008;
+ // VCOUNT = 0;
+ // UPDATE_REG(0x06, VCOUNT);
+ DISPSTAT &= 0xFFFC;
+ UPDATE_REG(0x04, DISPSTAT);
+ CPUCompareVCOUNT();
+ }
+ // (*renderLine)();
+ }
+ //CPUUpdateRender();
+ // we only care about changes in BG0-BG3
+ if(changeBG) {
+ //CPUUpdateRenderBuffers(false);
+ }
+ break;
+ }
+ case 0x04:
+ DISPSTAT = (value & 0xFF38) | (DISPSTAT & 7);
+ UPDATE_REG(0x04, DISPSTAT);
+ break;
+ case 0x06:
+ // not writable
+ break;
+ case 0x08:
+ BG0CNT = (value & 0xDFCF);
+ UPDATE_REG(0x08, BG0CNT);
+ break;
+ case 0x0A:
+ BG1CNT = (value & 0xDFCF);
+ UPDATE_REG(0x0A, BG1CNT);
+ break;
+ case 0x0C:
+ BG2CNT = (value & 0xFFCF);
+ UPDATE_REG(0x0C, BG2CNT);
+ break;
+ case 0x0E:
+ BG3CNT = (value & 0xFFCF);
+ UPDATE_REG(0x0E, BG3CNT);
+ break;
+ case 0x10:
+ BG0HOFS = value & 511;
+ UPDATE_REG(0x10, BG0HOFS);
+ break;
+ case 0x12:
+ BG0VOFS = value & 511;
+ UPDATE_REG(0x12, BG0VOFS);
+ break;
+ case 0x14:
+ BG1HOFS = value & 511;
+ UPDATE_REG(0x14, BG1HOFS);
+ break;
+ case 0x16:
+ BG1VOFS = value & 511;
+ UPDATE_REG(0x16, BG1VOFS);
+ break;
+ case 0x18:
+ BG2HOFS = value & 511;
+ UPDATE_REG(0x18, BG2HOFS);
+ break;
+ case 0x1A:
+ BG2VOFS = value & 511;
+ UPDATE_REG(0x1A, BG2VOFS);
+ break;
+ case 0x1C:
+ BG3HOFS = value & 511;
+ UPDATE_REG(0x1C, BG3HOFS);
+ break;
+ case 0x1E:
+ BG3VOFS = value & 511;
+ UPDATE_REG(0x1E, BG3VOFS);
+ break;
+ case 0x20:
+ BG2PA = value;
+ UPDATE_REG(0x20, BG2PA);
+ break;
+ case 0x22:
+ BG2PB = value;
+ UPDATE_REG(0x22, BG2PB);
+ break;
+ case 0x24:
+ BG2PC = value;
+ UPDATE_REG(0x24, BG2PC);
+ break;
+ case 0x26:
+ BG2PD = value;
+ UPDATE_REG(0x26, BG2PD);
+ break;
+ case 0x28:
+ BG2X_L = value;
+ UPDATE_REG(0x28, BG2X_L);
+ //gfxBG2Changed |= 1;
+ break;
+ case 0x2A:
+ BG2X_H = (value & 0xFFF);
+ UPDATE_REG(0x2A, BG2X_H);
+ //gfxBG2Changed |= 1;
+ break;
+ case 0x2C:
+ BG2Y_L = value;
+ UPDATE_REG(0x2C, BG2Y_L);
+ //gfxBG2Changed |= 2;
+ break;
+ case 0x2E:
+ BG2Y_H = value & 0xFFF;
+ UPDATE_REG(0x2E, BG2Y_H);
+ //gfxBG2Changed |= 2;
+ break;
+ case 0x30:
+ BG3PA = value;
+ UPDATE_REG(0x30, BG3PA);
+ break;
+ case 0x32:
+ BG3PB = value;
+ UPDATE_REG(0x32, BG3PB);
+ break;
+ case 0x34:
+ BG3PC = value;
+ UPDATE_REG(0x34, BG3PC);
+ break;
+ case 0x36:
+ BG3PD = value;
+ UPDATE_REG(0x36, BG3PD);
+ break;
+ case 0x38:
+ BG3X_L = value;
+ UPDATE_REG(0x38, BG3X_L);
+ //gfxBG3Changed |= 1;
+ break;
+ case 0x3A:
+ BG3X_H = value & 0xFFF;
+ UPDATE_REG(0x3A, BG3X_H);
+ //gfxBG3Changed |= 1;
+ break;
+ case 0x3C:
+ BG3Y_L = value;
+ UPDATE_REG(0x3C, BG3Y_L);
+ //gfxBG3Changed |= 2;
+ break;
+ case 0x3E:
+ BG3Y_H = value & 0xFFF;
+ UPDATE_REG(0x3E, BG3Y_H);
+ //gfxBG3Changed |= 2;
+ break;
+ case 0x40:
+ WIN0H = value;
+ UPDATE_REG(0x40, WIN0H);
+ //CPUUpdateWindow0();
+ break;
+ case 0x42:
+ WIN1H = value;
+ UPDATE_REG(0x42, WIN1H);
+ //CPUUpdateWindow1();
+ break;
+ case 0x44:
+ WIN0V = value;
+ UPDATE_REG(0x44, WIN0V);
+ break;
+ case 0x46:
+ WIN1V = value;
+ UPDATE_REG(0x46, WIN1V);
+ break;
+ case 0x48:
+ WININ = value & 0x3F3F;
+ UPDATE_REG(0x48, WININ);
+ break;
+ case 0x4A:
+ WINOUT = value & 0x3F3F;
+ UPDATE_REG(0x4A, WINOUT);
+ break;
+ case 0x4C:
+ MOSAIC = value;
+ UPDATE_REG(0x4C, MOSAIC);
+ break;
+ case 0x50:
+ BLDMOD = value & 0x3FFF;
+ UPDATE_REG(0x50, BLDMOD);
+ fxOn = ((BLDMOD>>6)&3) != 0;
+ //CPUUpdateRender();
+ break;
+ case 0x52:
+ COLEV = value & 0x1F1F;
+ UPDATE_REG(0x52, COLEV);
+ break;
+ case 0x54:
+ COLY = value & 0x1F;
+ UPDATE_REG(0x54, COLY);
+ break;
+ case 0x60:
+ case 0x62:
+ case 0x64:
+ case 0x68:
+ case 0x6c:
+ case 0x70:
+ case 0x72:
+ case 0x74:
+ case 0x78:
+ case 0x7c:
+ case 0x80:
+ case 0x84:
+ soundEvent(address&0xFF, (u8)(value & 0xFF));
+ soundEvent((address&0xFF)+1, (u8)(value>>8));
+ break;
+ case 0x82:
+ case 0x88:
+ case 0xa0:
+ case 0xa2:
+ case 0xa4:
+ case 0xa6:
+ case 0x90:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0x98:
+ case 0x9a:
+ case 0x9c:
+ case 0x9e:
+ soundEvent(address&0xFF, value);
+ break;
+ case 0xB0:
+ DM0SAD_L = value;
+ UPDATE_REG(0xB0, DM0SAD_L);
+ break;
+ case 0xB2:
+ DM0SAD_H = value & 0x07FF;
+ UPDATE_REG(0xB2, DM0SAD_H);
+ break;
+ case 0xB4:
+ DM0DAD_L = value;
+ UPDATE_REG(0xB4, DM0DAD_L);
+ break;
+ case 0xB6:
+ DM0DAD_H = value & 0x07FF;
+ UPDATE_REG(0xB6, DM0DAD_H);
+ break;
+ case 0xB8:
+ DM0CNT_L = value & 0x3FFF;
+ UPDATE_REG(0xB8, 0);
+ break;
+ case 0xBA:
+ {
+ bool start = ((DM0CNT_H ^ value) & 0x8000) ? true : false;
+ value &= 0xF7E0;
+
+ DM0CNT_H = value;
+ UPDATE_REG(0xBA, DM0CNT_H);
+
+ if(start && (value & 0x8000)) {
+ dma0Source = DM0SAD_L | (DM0SAD_H << 16);
+ dma0Dest = DM0DAD_L | (DM0DAD_H << 16);
+ CPUCheckDMA(0, 1);
+ }
+ }
+ break;
+ case 0xBC:
+ DM1SAD_L = value;
+ UPDATE_REG(0xBC, DM1SAD_L);
+ break;
+ case 0xBE:
+ DM1SAD_H = value & 0x0FFF;
+ UPDATE_REG(0xBE, DM1SAD_H);
+ break;
+ case 0xC0:
+ DM1DAD_L = value;
+ UPDATE_REG(0xC0, DM1DAD_L);
+ break;
+ case 0xC2:
+ DM1DAD_H = value & 0x07FF;
+ UPDATE_REG(0xC2, DM1DAD_H);
+ break;
+ case 0xC4:
+ DM1CNT_L = value & 0x3FFF;
+ UPDATE_REG(0xC4, 0);
+ break;
+ case 0xC6:
+ {
+ bool start = ((DM1CNT_H ^ value) & 0x8000) ? true : false;
+ value &= 0xF7E0;
+
+ DM1CNT_H = value;
+ UPDATE_REG(0xC6, DM1CNT_H);
+
+ if(start && (value & 0x8000)) {
+ dma1Source = DM1SAD_L | (DM1SAD_H << 16);
+ dma1Dest = DM1DAD_L | (DM1DAD_H << 16);
+ CPUCheckDMA(0, 2);
+ }
+ }
+ break;
+ case 0xC8:
+ DM2SAD_L = value;
+ UPDATE_REG(0xC8, DM2SAD_L);
+ break;
+ case 0xCA:
+ DM2SAD_H = value & 0x0FFF;
+ UPDATE_REG(0xCA, DM2SAD_H);
+ break;
+ case 0xCC:
+ DM2DAD_L = value;
+ UPDATE_REG(0xCC, DM2DAD_L);
+ break;
+ case 0xCE:
+ DM2DAD_H = value & 0x07FF;
+ UPDATE_REG(0xCE, DM2DAD_H);
+ break;
+ case 0xD0:
+ DM2CNT_L = value & 0x3FFF;
+ UPDATE_REG(0xD0, 0);
+ break;
+ case 0xD2:
+ {
+ bool start = ((DM2CNT_H ^ value) & 0x8000) ? true : false;
+
+ value &= 0xF7E0;
+
+ DM2CNT_H = value;
+ UPDATE_REG(0xD2, DM2CNT_H);
+
+ if(start && (value & 0x8000)) {
+ dma2Source = DM2SAD_L | (DM2SAD_H << 16);
+ dma2Dest = DM2DAD_L | (DM2DAD_H << 16);
+
+ CPUCheckDMA(0, 4);
+ }
+ }
+ break;
+ case 0xD4:
+ DM3SAD_L = value;
+ UPDATE_REG(0xD4, DM3SAD_L);
+ break;
+ case 0xD6:
+ DM3SAD_H = value & 0x0FFF;
+ UPDATE_REG(0xD6, DM3SAD_H);
+ break;
+ case 0xD8:
+ DM3DAD_L = value;
+ UPDATE_REG(0xD8, DM3DAD_L);
+ break;
+ case 0xDA:
+ DM3DAD_H = value & 0x0FFF;
+ UPDATE_REG(0xDA, DM3DAD_H);
+ break;
+ case 0xDC:
+ DM3CNT_L = value;
+ UPDATE_REG(0xDC, 0);
+ break;
+ case 0xDE:
+ {
+ bool start = ((DM3CNT_H ^ value) & 0x8000) ? true : false;
+
+ value &= 0xFFE0;
+
+ DM3CNT_H = value;
+ UPDATE_REG(0xDE, DM3CNT_H);
+
+ if(start && (value & 0x8000)) {
+ dma3Source = DM3SAD_L | (DM3SAD_H << 16);
+ dma3Dest = DM3DAD_L | (DM3DAD_H << 16);
+ CPUCheckDMA(0,8);
+ }
+ }
+ break;
+ case 0x100:
+ timer0Reload = value;
+ interp_rate();
+ break;
+ case 0x102:
+ timer0Value = value;
+ timerOnOffDelay|=1;
+ cpuNextEvent = cpuTotalTicks;
+ break;
+ case 0x104:
+ timer1Reload = value;
+ interp_rate();
+ break;
+ case 0x106:
+ timer1Value = value;
+ timerOnOffDelay|=2;
+ cpuNextEvent = cpuTotalTicks;
+ break;
+ case 0x108:
+ timer2Reload = value;
+ break;
+ case 0x10A:
+ timer2Value = value;
+ timerOnOffDelay|=4;
+ cpuNextEvent = cpuTotalTicks;
+ break;
+ case 0x10C:
+ timer3Reload = value;
+ break;
+ case 0x10E:
+ timer3Value = value;
+ timerOnOffDelay|=8;
+ cpuNextEvent = cpuTotalTicks;
+ break;
+
+
+ /*case COMM_SIOCNT:
+ StartLink(value);
+ break;
+
+ case COMM_SIODATA8:
+ if (gba_link_enabled)
+ LinkSSend(value);
+ UPDATE_REG(COMM_SIODATA8, value);
+ break;*/
+
+ case 0x130:
+ P1 |= (value & 0x3FF);
+ UPDATE_REG(0x130, P1);
+ break;
+
+ case 0x132:
+ UPDATE_REG(0x132, value & 0xC3FF);
+ break;
+
+ /*case COMM_RCNT:
+ StartGPLink(value);
+ break;
+
+ case COMM_JOYCNT:
+ {
+ u16 cur = READ16LE(&ioMem[COMM_JOYCNT]);
+
+ if (value & JOYCNT_RESET) cur &= ~JOYCNT_RESET;
+ if (value & JOYCNT_RECV_COMPLETE) cur &= ~JOYCNT_RECV_COMPLETE;
+ if (value & JOYCNT_SEND_COMPLETE) cur &= ~JOYCNT_SEND_COMPLETE;
+ if (value & JOYCNT_INT_ENABLE) cur |= JOYCNT_INT_ENABLE;
+
+ UPDATE_REG(COMM_JOYCNT, cur);
+ }
+ break;
+
+ case COMM_JOY_RECV_L:
+ UPDATE_REG(COMM_JOY_RECV_L, value);
+ break;
+ case COMM_JOY_RECV_H:
+ UPDATE_REG(COMM_JOY_RECV_H, value);
+ break;
+
+ case COMM_JOY_TRANS_L:
+ UPDATE_REG(COMM_JOY_TRANS_L, value);
+ UPDATE_REG(COMM_JOYSTAT, READ16LE(&ioMem[COMM_JOYSTAT]) | JOYSTAT_SEND);
+ break;
+ case COMM_JOY_TRANS_H:
+ UPDATE_REG(COMM_JOY_TRANS_H, value);
+ break;
+
+ case COMM_JOYSTAT:
+ UPDATE_REG(COMM_JOYSTAT, (READ16LE(&ioMem[COMM_JOYSTAT]) & 0xf) | (value & 0xf0));
+ break;*/
+
+ case 0x200:
+ IE = value & 0x3FFF;
+ UPDATE_REG(0x200, IE);
+ if ((IME & 1) && (IF & IE) && armIrqEnable)
+ cpuNextEvent = cpuTotalTicks;
+ break;
+ case 0x202:
+ IF ^= (value & IF);
+ UPDATE_REG(0x202, IF);
+ break;
+ case 0x204:
+ {
+ memoryWait[0x0e] = memoryWaitSeq[0x0e] = gamepakRamWaitState[value & 3];
+
+ if(!speedHack) {
+ memoryWait[0x08] = memoryWait[0x09] = gamepakWaitState[(value >> 2) & 3];
+ memoryWaitSeq[0x08] = memoryWaitSeq[0x09] =
+ gamepakWaitState0[(value >> 4) & 1];
+
+ memoryWait[0x0a] = memoryWait[0x0b] = gamepakWaitState[(value >> 5) & 3];
+ memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] =
+ gamepakWaitState1[(value >> 7) & 1];
+
+ memoryWait[0x0c] = memoryWait[0x0d] = gamepakWaitState[(value >> 8) & 3];
+ memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] =
+ gamepakWaitState2[(value >> 10) & 1];
+ } else {
+ memoryWait[0x08] = memoryWait[0x09] = 3;
+ memoryWaitSeq[0x08] = memoryWaitSeq[0x09] = 1;
+
+ memoryWait[0x0a] = memoryWait[0x0b] = 3;
+ memoryWaitSeq[0x0a] = memoryWaitSeq[0x0b] = 1;
+
+ memoryWait[0x0c] = memoryWait[0x0d] = 3;
+ memoryWaitSeq[0x0c] = memoryWaitSeq[0x0d] = 1;
+ }
+
+ for(int i = 8; i < 15; i++) {
+ memoryWait32[i] = memoryWait[i] + memoryWaitSeq[i] + 1;
+ memoryWaitSeq32[i] = memoryWaitSeq[i]*2 + 1;
+ }
+
+ if((value & 0x4000) == 0x4000) {
+ busPrefetchEnable = true;
+ busPrefetch = false;
+ busPrefetchCount = 0;
+ } else {
+ busPrefetchEnable = false;
+ busPrefetch = false;
+ busPrefetchCount = 0;
+ }
+ UPDATE_REG(0x204, value & 0x7FFF);
+
+ }
+ break;
+ case 0x208:
+ IME = value & 1;
+ UPDATE_REG(0x208, IME);
+ if ((IME & 1) && (IF & IE) && armIrqEnable)
+ cpuNextEvent = cpuTotalTicks;
+ break;
+ case 0x300:
+ if(value != 0)
+ value &= 0xFFFE;
+ UPDATE_REG(0x300, value);
+ break;
+ default:
+ UPDATE_REG(address&0x3FE, value);
+ break;
+ }
+}
+
+void applyTimer ()
+{
+ if (timerOnOffDelay & 1)
+ {
+ timer0ClockReload = TIMER_TICKS[timer0Value & 3];
+ if(!timer0On && (timer0Value & 0x80)) {
+ // reload the counter
+ TM0D = timer0Reload;
+ timer0Ticks = (0x10000 - TM0D) << timer0ClockReload;
+ UPDATE_REG(0x100, TM0D);
+ }
+ timer0On = timer0Value & 0x80 ? true : false;
+ TM0CNT = timer0Value & 0xC7;
+ interp_rate();
+ UPDATE_REG(0x102, TM0CNT);
+ // CPUUpdateTicks();
+ }
+ if (timerOnOffDelay & 2)
+ {
+ timer1ClockReload = TIMER_TICKS[timer1Value & 3];
+ if(!timer1On && (timer1Value & 0x80)) {
+ // reload the counter
+ TM1D = timer1Reload;
+ timer1Ticks = (0x10000 - TM1D) << timer1ClockReload;
+ UPDATE_REG(0x104, TM1D);
+ }
+ timer1On = timer1Value & 0x80 ? true : false;
+ TM1CNT = timer1Value & 0xC7;
+ interp_rate();
+ UPDATE_REG(0x106, TM1CNT);
+ }
+ if (timerOnOffDelay & 4)
+ {
+ timer2ClockReload = TIMER_TICKS[timer2Value & 3];
+ if(!timer2On && (timer2Value & 0x80)) {
+ // reload the counter
+ TM2D = timer2Reload;
+ timer2Ticks = (0x10000 - TM2D) << timer2ClockReload;
+ UPDATE_REG(0x108, TM2D);
+ }
+ timer2On = timer2Value & 0x80 ? true : false;
+ TM2CNT = timer2Value & 0xC7;
+ UPDATE_REG(0x10A, TM2CNT);
+ }
+ if (timerOnOffDelay & 8)
+ {
+ timer3ClockReload = TIMER_TICKS[timer3Value & 3];
+ if(!timer3On && (timer3Value & 0x80)) {
+ // reload the counter
+ TM3D = timer3Reload;
+ timer3Ticks = (0x10000 - TM3D) << timer3ClockReload;
+ UPDATE_REG(0x10C, TM3D);
+ }
+ timer3On = timer3Value & 0x80 ? true : false;
+ TM3CNT = timer3Value & 0xC7;
+ UPDATE_REG(0x10E, TM3CNT);
+ }
+ cpuNextEvent = CPUUpdateTicks();
+ timerOnOffDelay = 0;
+}
+
+u8 cpuBitsSet[256];
+u8 cpuLowestBitSet[256];
+
+void CPUInit(const char *biosFileName, bool useBiosFile)
+{
+#ifdef WORDS_BIGENDIAN
+ if(!cpuBiosSwapped) {
+ for(unsigned int i = 0; i < sizeof(myROM)/4; i++) {
+ WRITE32LE(&myROM[i], myROM[i]);
+ }
+ cpuBiosSwapped = true;
+ }
+#endif
+ gbaSaveType = 0;
+ //eepromInUse = 0;
+ saveType = 0;
+ useBios = false;
+
+ /*if(useBiosFile) {
+ int size = 0x4000;
+ if(utilLoad(biosFileName,
+ CPUIsGBABios,
+ bios,
+ size)) {
+ if(size == 0x4000)
+ useBios = true;
+ else
+ systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BIOS file size"));
+ }
+ }*/
+
+ if(!useBios) {
+ memcpy(bios, myROM, sizeof(myROM));
+ }
+
+ int i = 0;
+
+ biosProtected[0] = 0x00;
+ biosProtected[1] = 0xf0;
+ biosProtected[2] = 0x29;
+ biosProtected[3] = 0xe1;
+
+ for(i = 0; i < 256; i++) {
+ int count = 0;
+ int j;
+ for(j = 0; j < 8; j++)
+ if(i & (1 << j))
+ count++;
+ cpuBitsSet[i] = count;
+
+ for(j = 0; j < 8; j++)
+ if(i & (1 << j))
+ break;
+ cpuLowestBitSet[i] = j;
+ }
+
+ for(i = 0; i < 0x400; i++)
+ ioReadable[i] = true;
+ for(i = 0x10; i < 0x48; i++)
+ ioReadable[i] = false;
+ for(i = 0x4c; i < 0x50; i++)
+ ioReadable[i] = false;
+ for(i = 0x54; i < 0x60; i++)
+ ioReadable[i] = false;
+ for(i = 0x8c; i < 0x90; i++)
+ ioReadable[i] = false;
+ for(i = 0xa0; i < 0xb8; i++)
+ ioReadable[i] = false;
+ for(i = 0xbc; i < 0xc4; i++)
+ ioReadable[i] = false;
+ for(i = 0xc8; i < 0xd0; i++)
+ ioReadable[i] = false;
+ for(i = 0xd4; i < 0xdc; i++)
+ ioReadable[i] = false;
+ for(i = 0xe0; i < 0x100; i++)
+ ioReadable[i] = false;
+ for(i = 0x110; i < 0x120; i++)
+ ioReadable[i] = false;
+ for(i = 0x12c; i < 0x130; i++)
+ ioReadable[i] = false;
+ for(i = 0x138; i < 0x140; i++)
+ ioReadable[i] = false;
+ for(i = 0x144; i < 0x150; i++)
+ ioReadable[i] = false;
+ for(i = 0x15c; i < 0x200; i++)
+ ioReadable[i] = false;
+ for(i = 0x20c; i < 0x300; i++)
+ ioReadable[i] = false;
+ for(i = 0x304; i < 0x400; i++)
+ ioReadable[i] = false;
+
+ if(romSize < 0x1fe2000) {
+ *((u16 *)&rom[0x1fe209c]) = 0xdffa; // SWI 0xFA
+ *((u16 *)&rom[0x1fe209e]) = 0x4770; // BX LR
+ } else {
+ //agbPrintEnable(false);
+ }
+}
+
+void CPUReset()
+{
+ /*if(gbaSaveType == 0) {
+ if(eepromInUse)
+ gbaSaveType = 3;
+ else
+ switch(saveType) {
+ case 1:
+ gbaSaveType = 1;
+ break;
+ case 2:
+ gbaSaveType = 2;
+ break;
+ }
+ }
+ rtcReset();*/
+ // clean registers
+ memset(®[0], 0, sizeof(reg));
+ // clean OAM
+ memset(oam, 0, 0x400);
+ // clean palette
+ memset(paletteRAM, 0, 0x400);
+ // clean picture
+ memset(pix, 0, 4*160*240);
+ // clean vram
+ memset(vram, 0, 0x20000);
+ // clean io memory
+ memset(ioMem, 0, 0x400);
+
+ DISPCNT = 0x0080;
+ DISPSTAT = 0x0000;
+ VCOUNT = (useBios && !skipBios) ? 0 :0x007E;
+ BG0CNT = 0x0000;
+ BG1CNT = 0x0000;
+ BG2CNT = 0x0000;
+ BG3CNT = 0x0000;
+ BG0HOFS = 0x0000;
+ BG0VOFS = 0x0000;
+ BG1HOFS = 0x0000;
+ BG1VOFS = 0x0000;
+ BG2HOFS = 0x0000;
+ BG2VOFS = 0x0000;
+ BG3HOFS = 0x0000;
+ BG3VOFS = 0x0000;
+ BG2PA = 0x0100;
+ BG2PB = 0x0000;
+ BG2PC = 0x0000;
+ BG2PD = 0x0100;
+ BG2X_L = 0x0000;
+ BG2X_H = 0x0000;
+ BG2Y_L = 0x0000;
+ BG2Y_H = 0x0000;
+ BG3PA = 0x0100;
+ BG3PB = 0x0000;
+ BG3PC = 0x0000;
+ BG3PD = 0x0100;
+ BG3X_L = 0x0000;
+ BG3X_H = 0x0000;
+ BG3Y_L = 0x0000;
+ BG3Y_H = 0x0000;
+ WIN0H = 0x0000;
+ WIN1H = 0x0000;
+ WIN0V = 0x0000;
+ WIN1V = 0x0000;
+ WININ = 0x0000;
+ WINOUT = 0x0000;
+ MOSAIC = 0x0000;
+ BLDMOD = 0x0000;
+ COLEV = 0x0000;
+ COLY = 0x0000;
+ DM0SAD_L = 0x0000;
+ DM0SAD_H = 0x0000;
+ DM0DAD_L = 0x0000;
+ DM0DAD_H = 0x0000;
+ DM0CNT_L = 0x0000;
+ DM0CNT_H = 0x0000;
+ DM1SAD_L = 0x0000;
+ DM1SAD_H = 0x0000;
+ DM1DAD_L = 0x0000;
+ DM1DAD_H = 0x0000;
+ DM1CNT_L = 0x0000;
+ DM1CNT_H = 0x0000;
+ DM2SAD_L = 0x0000;
+ DM2SAD_H = 0x0000;
+ DM2DAD_L = 0x0000;
+ DM2DAD_H = 0x0000;
+ DM2CNT_L = 0x0000;
+ DM2CNT_H = 0x0000;
+ DM3SAD_L = 0x0000;
+ DM3SAD_H = 0x0000;
+ DM3DAD_L = 0x0000;
+ DM3DAD_H = 0x0000;
+ DM3CNT_L = 0x0000;
+ DM3CNT_H = 0x0000;
+ TM0D = 0x0000;
+ TM0CNT = 0x0000;
+ TM1D = 0x0000;
+ TM1CNT = 0x0000;
+ TM2D = 0x0000;
+ TM2CNT = 0x0000;
+ TM3D = 0x0000;
+ TM3CNT = 0x0000;
+ P1 = 0x03FF;
+ IE = 0x0000;
+ IF = 0x0000;
+ IME = 0x0000;
+
+ armMode = 0x1F;
+
+ if(cpuIsMultiBoot) {
+ reg[13].I = 0x03007F00;
+ reg[15].I = 0x02000000;
+ reg[16].I = 0x00000000;
+ reg[R13_IRQ].I = 0x03007FA0;
+ reg[R13_SVC].I = 0x03007FE0;
+ armIrqEnable = true;
+ } else {
+ if(useBios && !skipBios) {
+ reg[15].I = 0x00000000;
+ armMode = 0x13;
+ armIrqEnable = false;
+ } else {
+ reg[13].I = 0x03007F00;
+ reg[15].I = 0x08000000;
+ reg[16].I = 0x00000000;
+ reg[R13_IRQ].I = 0x03007FA0;
+ reg[R13_SVC].I = 0x03007FE0;
+ armIrqEnable = true;
+ }
+ }
+ armState = true;
+ C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false;
+ UPDATE_REG(0x00, DISPCNT);
+ UPDATE_REG(0x06, VCOUNT);
+ UPDATE_REG(0x20, BG2PA);
+ UPDATE_REG(0x26, BG2PD);
+ UPDATE_REG(0x30, BG3PA);
+ UPDATE_REG(0x36, BG3PD);
+ UPDATE_REG(0x130, P1);
+ UPDATE_REG(0x88, 0x200);
+
+ // disable FIQ
+ reg[16].I |= 0x40;
+
+ CPUUpdateCPSR();
+
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+
+ // reset internal state
+ holdState = false;
+ holdType = 0;
+
+ biosProtected[0] = 0x00;
+ biosProtected[1] = 0xf0;
+ biosProtected[2] = 0x29;
+ biosProtected[3] = 0xe1;
+
+ lcdTicks = (useBios && !skipBios) ? 1008 : 208;
+ timer0On = false;
+ timer0Ticks = 0;
+ timer0Reload = 0;
+ timer0ClockReload = 0;
+ timer1On = false;
+ timer1Ticks = 0;
+ timer1Reload = 0;
+ timer1ClockReload = 0;
+ timer2On = false;
+ timer2Ticks = 0;
+ timer2Reload = 0;
+ timer2ClockReload = 0;
+ timer3On = false;
+ timer3Ticks = 0;
+ timer3Reload = 0;
+ timer3ClockReload = 0;
+ dma0Source = 0;
+ dma0Dest = 0;
+ dma1Source = 0;
+ dma1Dest = 0;
+ dma2Source = 0;
+ dma2Dest = 0;
+ dma3Source = 0;
+ dma3Dest = 0;
+ //cpuSaveGameFunc = flashSaveDecide;
+ //renderLine = mode0RenderLine;
+ fxOn = false;
+ windowOn = false;
+ frameCount = 0;
+ saveType = 0;
+ layerEnable = DISPCNT & layerSettings;
+
+ //CPUUpdateRenderBuffers(true);
+
+ for(int i = 0; i < 256; i++) {
+ map[i].address = (u8 *)&dummyAddress;
+ map[i].mask = 0;
+ }
+
+ map[0].address = bios;
+ map[0].mask = 0x3FFF;
+ map[2].address = workRAM;
+ map[2].mask = 0x3FFFF;
+ map[3].address = internalRAM;
+ map[3].mask = 0x7FFF;
+ map[4].address = ioMem;
+ map[4].mask = 0x3FF;
+ map[5].address = paletteRAM;
+ map[5].mask = 0x3FF;
+ map[6].address = vram;
+ map[6].mask = 0x1FFFF;
+ map[7].address = oam;
+ map[7].mask = 0x3FF;
+ map[8].address = rom;
+ map[8].mask = 0x1FFFFFF;
+ map[9].address = rom;
+ map[9].mask = 0x1FFFFFF;
+ map[10].address = rom;
+ map[10].mask = 0x1FFFFFF;
+ map[12].address = rom;
+ map[12].mask = 0x1FFFFFF;
+ map[14].address = /*flashSaveMemory*/0;
+ map[14].mask = 0xFFFF;
+
+ //eepromReset();
+ //flashReset();
+
+ soundReset();
+
+ //CPUUpdateWindow0();
+ //CPUUpdateWindow1();
+
+ // make sure registers are correctly initialized if not using BIOS
+ if(!useBios) {
+ if(cpuIsMultiBoot)
+ BIOS_RegisterRamReset(0xfe);
+ else
+ BIOS_RegisterRamReset(0xff);
+ } else {
+ if(cpuIsMultiBoot)
+ BIOS_RegisterRamReset(0xfe);
+ }
+
+ /*switch(cpuSaveType) {
+ case 0: // automatic
+ cpuSramEnabled = true;
+ cpuFlashEnabled = true;
+ cpuEEPROMEnabled = true;
+ cpuEEPROMSensorEnabled = false;
+ saveType = gbaSaveType = 0;
+ break;
+ case 1: // EEPROM
+ cpuSramEnabled = false;
+ cpuFlashEnabled = false;
+ cpuEEPROMEnabled = true;
+ cpuEEPROMSensorEnabled = false;
+ saveType = gbaSaveType = 3;
+ // EEPROM usage is automatically detected
+ break;
+ case 2: // SRAM
+ cpuSramEnabled = true;
+ cpuFlashEnabled = false;
+ cpuEEPROMEnabled = false;
+ cpuEEPROMSensorEnabled = false;
+ cpuSaveGameFunc = sramDelayedWrite; // to insure we detect the write
+ saveType = gbaSaveType = 1;
+ break;
+ case 3: // FLASH
+ cpuSramEnabled = false;
+ cpuFlashEnabled = true;
+ cpuEEPROMEnabled = false;
+ cpuEEPROMSensorEnabled = false;
+ cpuSaveGameFunc = flashDelayedWrite; // to insure we detect the write
+ saveType = gbaSaveType = 2;
+ break;
+ case 4: // EEPROM+Sensor
+ cpuSramEnabled = false;
+ cpuFlashEnabled = false;
+ cpuEEPROMEnabled = true;
+ cpuEEPROMSensorEnabled = true;
+ // EEPROM usage is automatically detected
+ saveType = gbaSaveType = 3;
+ break;
+ case 5: // NONE
+ cpuSramEnabled = false;
+ cpuFlashEnabled = false;
+ cpuEEPROMEnabled = false;
+ cpuEEPROMSensorEnabled = false;
+ // no save at all
+ saveType = gbaSaveType = 5;
+ break;
+ }*/
+
+ ARM_PREFETCH;
+
+ //systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
+
+ cpuDmaHack = false;
+
+ lastTime = /*systemGetClock()*/0;
+
+ SWITicks = 0;
+}
+
+void CPUInterrupt()
+{
+ u32 PC = reg[15].I;
+ bool savedState = armState;
+ CPUSwitchMode(0x12, true, false);
+ reg[14].I = PC;
+ if(!savedState)
+ reg[14].I += 2;
+ reg[15].I = 0x18;
+ armState = true;
+ armIrqEnable = false;
+
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+ ARM_PREFETCH;
+
+ // if(!holdState)
+ biosProtected[0] = 0x02;
+ biosProtected[1] = 0xc0;
+ biosProtected[2] = 0x5e;
+ biosProtected[3] = 0xe5;
+}
+
+void CPULoop(int ticks)
+{
+ int clockTicks;
+ int timerOverflow = 0;
+ // variable used by the CPU core
+ cpuTotalTicks = 0;
+
+ // shuffle2: what's the purpose?
+ /*if(gba_link_enabled)
+ cpuNextEvent = 1;*/
+
+ cpuBreakLoop = false;
+ cpuNextEvent = CPUUpdateTicks();
+ if(cpuNextEvent > ticks)
+ cpuNextEvent = ticks;
+
+
+ for(;;) {
+#ifndef FINAL_VERSION
+ if(systemDebug) {
+ if(systemDebug >= 10 && !holdState) {
+ CPUUpdateCPSR();
+#ifdef BKPT_SUPPORT
+ if (debugger_last)
+ {
+ winlog("R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n",
+ oldreg[0], oldreg[1], oldreg[2], oldreg[3], oldreg[4], oldreg[5],
+ oldreg[6], oldreg[7], oldreg[8], oldreg[9], oldreg[10], oldreg[11],
+ oldreg[12], oldreg[13], oldreg[14], oldreg[15], oldreg[16],
+ oldreg[17]);
+ }
+#endif
+ winlog("R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n",
+ reg[0].I, reg[1].I, reg[2].I, reg[3].I, reg[4].I, reg[5].I,
+ reg[6].I, reg[7].I, reg[8].I, reg[9].I, reg[10].I, reg[11].I,
+ reg[12].I, reg[13].I, reg[14].I, reg[15].I, reg[16].I,
+ reg[17].I);
+ } else if(!holdState) {
+ winlog("PC=%08x\n", armNextPC);
+ }
+ }
+#endif /* FINAL_VERSION */
+
+ if(!holdState && !SWITicks) {
+ if(armState) {
+ if (!armExecute())
+ return;
+ } else {
+ if (!thumbExecute())
+ return;
+ }
+ clockTicks = 0;
+ } else
+ clockTicks = CPUUpdateTicks();
+
+ cpuTotalTicks += clockTicks;
+
+
+ if(cpuTotalTicks >= cpuNextEvent) {
+ int remainingTicks = cpuTotalTicks - cpuNextEvent;
+
+ if (SWITicks)
+ {
+ SWITicks-=clockTicks;
+ if (SWITicks<0)
+ SWITicks = 0;
+ }
+
+ clockTicks = cpuNextEvent;
+ cpuTotalTicks = 0;
+ cpuDmaHack = false;
+
+ updateLoop:
+
+ if (IRQTicks)
+ {
+ IRQTicks -= clockTicks;
+ if (IRQTicks<0)
+ IRQTicks = 0;
+ }
+
+ lcdTicks -= clockTicks;
+
+
+ if(lcdTicks <= 0) {
+ if(DISPSTAT & 1) { // V-BLANK
+ // if in V-Blank mode, keep computing...
+ if(DISPSTAT & 2) {
+ lcdTicks += 1008;
+ VCOUNT++;
+ UPDATE_REG(0x06, VCOUNT);
+ DISPSTAT &= 0xFFFD;
+ UPDATE_REG(0x04, DISPSTAT);
+ CPUCompareVCOUNT();
+ } else {
+ lcdTicks += 224;
+ DISPSTAT |= 2;
+ UPDATE_REG(0x04, DISPSTAT);
+ if(DISPSTAT & 16) {
+ IF |= 2;
+ UPDATE_REG(0x202, IF);
+ }
+ }
+
+ if(VCOUNT >= 228) { //Reaching last line
+ DISPSTAT &= 0xFFFC;
+ UPDATE_REG(0x04, DISPSTAT);
+ VCOUNT = 0;
+ UPDATE_REG(0x06, VCOUNT);
+ CPUCompareVCOUNT();
+ }
+ } else {
+ int framesToSkip = /*systemFrameSkip*/0;
+ if(speedup)
+ framesToSkip = 9; // try 6 FPS during speedup
+
+ if(DISPSTAT & 2) {
+ // if in H-Blank, leave it and move to drawing mode
+ VCOUNT++;
+ UPDATE_REG(0x06, VCOUNT);
+
+ lcdTicks += 1008;
+ DISPSTAT &= 0xFFFD;
+ if(VCOUNT == 160) {
+ count++;
+ //systemFrame();
+
+ if((count % 10) == 0) {
+ //system10Frames(60);
+ }
+ if(count == 60) {
+ u32 time = /*systemGetClock()*/0;
+ if(time != lastTime) {
+ u32 t = 100000/(time - lastTime);
+ //systemShowSpeed(t);
+ } else
+ //systemShowSpeed(0);
+ lastTime = time;
+ count = 0;
+ }
+ u32 joy = 0;
+ // update joystick information
+ /*if(systemReadJoypads())
+ // read default joystick
+ joy = systemReadJoypad(-1);*/
+ P1 = 0x03FF ^ (joy & 0x3FF);
+ /*if(cpuEEPROMSensorEnabled)
+ systemUpdateMotionSensor();*/
+ UPDATE_REG(0x130, P1);
+ u16 P1CNT = READ16LE(((u16 *)&ioMem[0x132]));
+ // this seems wrong, but there are cases where the game
+ // can enter the stop state without requesting an IRQ from
+ // the joypad.
+ if((P1CNT & 0x4000) || stopState) {
+ u16 p1 = (0x3FF ^ P1) & 0x3FF;
+ if(P1CNT & 0x8000) {
+ if(p1 == (P1CNT & 0x3FF)) {
+ IF |= 0x1000;
+ UPDATE_REG(0x202, IF);
+ }
+ } else {
+ if(p1 & P1CNT) {
+ IF |= 0x1000;
+ UPDATE_REG(0x202, IF);
+ }
+ }
+ }
+
+ u32 ext = (joy >> 10);
+ // If no (m) code is enabled, apply the cheats at each LCDline
+ /*if((cheatsEnabled) && (mastercode==0))
+ remainingTicks += cheatsCheckKeys(P1^0x3FF, ext);*/
+ speedup = (ext & 1) ? true : false;
+ capture = (ext & 2) ? true : false;
+
+ if(capture && !capturePrevious) {
+ captureNumber++;
+ //systemScreenCapture(captureNumber);
+ }
+ capturePrevious = capture;
+
+ DISPSTAT |= 1;
+ DISPSTAT &= 0xFFFD;
+ UPDATE_REG(0x04, DISPSTAT);
+ if(DISPSTAT & 0x0008) {
+ IF |= 1;
+ UPDATE_REG(0x202, IF);
+ }
+ CPUCheckDMA(1, 0x0f);
+ if(frameCount >= framesToSkip) {
+ //systemDrawScreen();
+ frameCount = 0;
+ } else
+ frameCount++;
+ /*if(systemPauseOnFrame())
+ ticks = 0;*/
+ }
+
+ UPDATE_REG(0x04, DISPSTAT);
+ CPUCompareVCOUNT();
+
+ } else {
+ if(frameCount >= framesToSkip)
+ {
+ /*(*renderLine)();
+ switch(systemColorDepth) {
+ case 16:
+ {
+ u16 *dest = (u16 *)pix + 242 * (VCOUNT+1);
+ for(int x = 0; x < 240;) {
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ *dest++ = systemColorMap16[lineMix[x++]&0xFFFF];
+ }
+ // for filters that read past the screen
+ *dest++ = 0;
+ }
+ break;
+ case 24:
+ {
+ u8 *dest = (u8 *)pix + 240 * VCOUNT * 3;
+ for(int x = 0; x < 240;) {
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ *((u32 *)dest) = systemColorMap32[lineMix[x++] & 0xFFFF];
+ dest += 3;
+ }
+ }
+ break;
+ case 32:
+ {
+ u32 *dest = (u32 *)pix + 241 * (VCOUNT+1);
+ for(int x = 0; x < 240; ) {
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ *dest++ = systemColorMap32[lineMix[x++] & 0xFFFF];
+ }
+ }
+ break;
+ }*/
+ }
+ // entering H-Blank
+ DISPSTAT |= 2;
+ UPDATE_REG(0x04, DISPSTAT);
+ lcdTicks += 224;
+ CPUCheckDMA(2, 0x0f);
+ if(DISPSTAT & 16) {
+ IF |= 2;
+ UPDATE_REG(0x202, IF);
+ }
+ }
+ }
+ }
+
+ // we shouldn't be doing sound in stop state, but we loose synchronization
+ // if sound is disabled, so in stop state, soundTick will just produce
+ // mute sound
+ soundTicks -= clockTicks;
+ if(soundTicks <= 0) {
+ psoundTickfn();
+ soundTicks += SOUND_CLOCK_TICKS;
+ }
+
+ if(!stopState) {
+ if(timer0On) {
+ timer0Ticks -= clockTicks;
+ if(timer0Ticks <= 0) {
+ timer0Ticks += (0x10000 - timer0Reload) << timer0ClockReload;
+ timerOverflow |= 1;
+ soundTimerOverflow(0);
+ if(TM0CNT & 0x40) {
+ IF |= 0x08;
+ UPDATE_REG(0x202, IF);
+ }
+ }
+ TM0D = 0xFFFF - (timer0Ticks >> timer0ClockReload);
+ UPDATE_REG(0x100, TM0D);
+ }
+
+ if(timer1On) {
+ if(TM1CNT & 4) {
+ if(timerOverflow & 1) {
+ TM1D++;
+ if(TM1D == 0) {
+ TM1D += timer1Reload;
+ timerOverflow |= 2;
+ soundTimerOverflow(1);
+ if(TM1CNT & 0x40) {
+ IF |= 0x10;
+ UPDATE_REG(0x202, IF);
+ }
+ }
+ UPDATE_REG(0x104, TM1D);
+ }
+ } else {
+ timer1Ticks -= clockTicks;
+ if(timer1Ticks <= 0) {
+ timer1Ticks += (0x10000 - timer1Reload) << timer1ClockReload;
+ timerOverflow |= 2;
+ soundTimerOverflow(1);
+ if(TM1CNT & 0x40) {
+ IF |= 0x10;
+ UPDATE_REG(0x202, IF);
+ }
+ }
+ TM1D = 0xFFFF - (timer1Ticks >> timer1ClockReload);
+ UPDATE_REG(0x104, TM1D);
+ }
+ }
+
+ if(timer2On) {
+ if(TM2CNT & 4) {
+ if(timerOverflow & 2) {
+ TM2D++;
+ if(TM2D == 0) {
+ TM2D += timer2Reload;
+ timerOverflow |= 4;
+ if(TM2CNT & 0x40) {
+ IF |= 0x20;
+ UPDATE_REG(0x202, IF);
+ }
+ }
+ UPDATE_REG(0x108, TM2D);
+ }
+ } else {
+ timer2Ticks -= clockTicks;
+ if(timer2Ticks <= 0) {
+ timer2Ticks += (0x10000 - timer2Reload) << timer2ClockReload;
+ timerOverflow |= 4;
+ if(TM2CNT & 0x40) {
+ IF |= 0x20;
+ UPDATE_REG(0x202, IF);
+ }
+ }
+ TM2D = 0xFFFF - (timer2Ticks >> timer2ClockReload);
+ UPDATE_REG(0x108, TM2D);
+ }
+ }
+
+ if(timer3On) {
+ if(TM3CNT & 4) {
+ if(timerOverflow & 4) {
+ TM3D++;
+ if(TM3D == 0) {
+ TM3D += timer3Reload;
+ if(TM3CNT & 0x40) {
+ IF |= 0x40;
+ UPDATE_REG(0x202, IF);
+ }
+ }
+ UPDATE_REG(0x10C, TM3D);
+ }
+ } else {
+ timer3Ticks -= clockTicks;
+ if(timer3Ticks <= 0) {
+ timer3Ticks += (0x10000 - timer3Reload) << timer3ClockReload;
+ if(TM3CNT & 0x40) {
+ IF |= 0x40;
+ UPDATE_REG(0x202, IF);
+ }
+ }
+ TM3D = 0xFFFF - (timer3Ticks >> timer3ClockReload);
+ UPDATE_REG(0x10C, TM3D);
+ }
+ }
+ }
+
+ timerOverflow = 0;
+
+
+
+#ifdef PROFILING
+ profilingTicks -= clockTicks;
+ if(profilingTicks <= 0) {
+ profilingTicks += profilingTicksReload;
+ if(profilSegment) {
+ profile_segment *seg = profilSegment;
+ do {
+ u16 *b = (u16 *)seg->sbuf;
+ int pc = ((reg[15].I - seg->s_lowpc) * seg->s_scale)/0x10000;
+ if(pc >= 0 && pc < seg->ssiz) {
+ b[pc]++;
+ break;
+ }
+
+ seg = seg->next;
+ } while(seg);
+ }
+ }
+#endif
+
+ ticks -= clockTicks;
+
+ /*if (gba_joybus_enabled)
+ JoyBusUpdate(clockTicks);
+
+ if (gba_link_enabled)
+ LinkUpdate(clockTicks);*/
+
+ cpuNextEvent = CPUUpdateTicks();
+
+ if(cpuDmaTicksToUpdate > 0) {
+ if(cpuDmaTicksToUpdate > cpuNextEvent)
+ clockTicks = cpuNextEvent;
+ else
+ clockTicks = cpuDmaTicksToUpdate;
+ cpuDmaTicksToUpdate -= clockTicks;
+ if(cpuDmaTicksToUpdate < 0)
+ cpuDmaTicksToUpdate = 0;
+ cpuDmaHack = true;
+ goto updateLoop;
+ }
+
+ // shuffle2: what's the purpose?
+ /*if(gba_link_enabled)
+ cpuNextEvent = 1;*/
+
+ if(IF && (IME & 1) && armIrqEnable) {
+ int res = IF & IE;
+ if(stopState)
+ res &= 0x3080;
+ if(res) {
+ if (intState)
+ {
+ if (!IRQTicks)
+ {
+ CPUInterrupt();
+ intState = false;
+ holdState = false;
+ stopState = false;
+ holdType = 0;
+ }
+ }
+ else
+ {
+ if (!holdState)
+ {
+ intState = true;
+ IRQTicks=7;
+ if (cpuNextEvent> IRQTicks)
+ cpuNextEvent = IRQTicks;
+ }
+ else
+ {
+ CPUInterrupt();
+ holdState = false;
+ stopState = false;
+ holdType = 0;
+ }
+ }
+
+ // Stops the SWI Ticks emulation if an IRQ is executed
+ //(to avoid problems with nested IRQ/SWI)
+ if (SWITicks)
+ SWITicks = 0;
+ }
+ }
+
+ if(remainingTicks > 0) {
+ if(remainingTicks > cpuNextEvent)
+ clockTicks = cpuNextEvent;
+ else
+ clockTicks = remainingTicks;
+ remainingTicks -= clockTicks;
+ if(remainingTicks < 0)
+ remainingTicks = 0;
+ goto updateLoop;
+ }
+
+ if (timerOnOffDelay)
+ applyTimer();
+
+ if(cpuNextEvent > ticks)
+ cpuNextEvent = ticks;
+
+ if(ticks <= 0 || cpuBreakLoop)
+ break;
+
+ }
+ }
+}
+
+
+
+/*struct EmulatedSystem GBASystem = {
+ // emuMain
+ CPULoop,
+ // emuReset
+ CPUReset,
+ // emuCleanUp
+ CPUCleanUp,
+ // emuReadBattery
+ CPUReadBatteryFile,
+ // emuWriteBattery
+ CPUWriteBatteryFile,
+ // emuReadState
+ CPUReadState,
+ // emuWriteState
+ CPUWriteState,
+ // emuReadMemState
+ CPUReadMemState,
+ // emuWriteMemState
+ CPUWriteMemState,
+ // emuWritePNG
+ CPUWritePNGFile,
+ // emuWriteBMP
+ CPUWriteBMPFile,
+ // emuUpdateCPSR
+ CPUUpdateCPSR,
+ // emuHasDebugger
+ true,
+ // emuCount
+#ifdef FINAL_VERSION
+ 250000
+#else
+ 5000
+#endif
+};*/
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/GBA.h
@@ -1,1 +1,144 @@
+#ifndef GBA_H
+#define GBA_H
+//#include "../System.h"
+#include "../common/Types.h"
+
+#define SAVE_GAME_VERSION_1 1
+#define SAVE_GAME_VERSION_2 2
+#define SAVE_GAME_VERSION_3 3
+#define SAVE_GAME_VERSION_4 4
+#define SAVE_GAME_VERSION_5 5
+#define SAVE_GAME_VERSION_6 6
+#define SAVE_GAME_VERSION_7 7
+#define SAVE_GAME_VERSION_8 8
+#define SAVE_GAME_VERSION_9 9
+#define SAVE_GAME_VERSION_10 10
+#define SAVE_GAME_VERSION SAVE_GAME_VERSION_10
+
+typedef struct {
+ u8 *address;
+ u32 mask;
+} memoryMap;
+
+typedef union {
+ struct {
+#ifdef WORDS_BIGENDIAN
+ u8 B3;
+ u8 B2;
+ u8 B1;
+ u8 B0;
+#else
+ u8 B0;
+ u8 B1;
+ u8 B2;
+ u8 B3;
+#endif
+ } B;
+ struct {
+#ifdef WORDS_BIGENDIAN
+ u16 W1;
+ u16 W0;
+#else
+ u16 W0;
+ u16 W1;
+#endif
+ } W;
+#ifdef WORDS_BIGENDIAN
+ volatile u32 I;
+#else
+ u32 I;
+#endif
+} reg_pair;
+
+#ifndef NO_GBA_MAP
+extern memoryMap map[256];
+#endif
+
+extern reg_pair reg[45];
+extern u8 biosProtected[4];
+
+extern bool N_FLAG;
+extern bool Z_FLAG;
+extern bool C_FLAG;
+extern bool V_FLAG;
+extern bool armIrqEnable;
+extern bool armState;
+extern int armMode;
+//extern void (*cpuSaveGameFunc)(u32,u8);
+
+#ifdef BKPT_SUPPORT
+extern u8 freezeWorkRAM[0x40000];
+extern u8 freezeInternalRAM[0x8000];
+extern u8 freezeVRAM[0x18000];
+extern u8 freezeOAM[0x400];
+extern u8 freezePRAM[0x400];
+extern bool debugger_last;
+extern int oldreg[18];
+extern char oldbuffer[10];
+#endif
+
+extern bool CPUReadGSASnapshot(const char *);
+extern bool CPUReadGSASPSnapshot(const char *);
+extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *);
+extern bool CPUWriteBatteryFile(const char *);
+extern bool CPUReadBatteryFile(const char *);
+extern bool CPUExportEepromFile(const char *);
+extern bool CPUImportEepromFile(const char *);
+extern bool CPUWritePNGFile(const char *);
+extern bool CPUWriteBMPFile(const char *);
+extern void CPUCleanUp();
+//extern void CPUUpdateRender();
+//extern void CPUUpdateRenderBuffers(bool);
+extern bool CPUReadMemState(char *, int);
+extern bool CPUReadState(const char *);
+extern bool CPUWriteMemState(char *, int);
+extern bool CPUWriteState(const char *);
+extern int CPULoadRom(const char *);
+extern void doMirroring(bool);
+extern void CPUUpdateRegister(u32, u16);
+extern void applyTimer ();
+extern void CPUInit(const char *,bool);
+extern void CPUReset();
+extern void CPULoop(int);
+extern void CPUCheckDMA(int,int);
+extern bool CPUIsGBAImage(const char *);
+extern bool CPUIsZipFile(const char *);
+#ifdef PROFILING
+#include "prof/prof.h"
+extern void cpuProfil(profile_segment *seg);
+extern void cpuEnableProfiling(int hz);
+#endif
+
+extern struct EmulatedSystem GBASystem;
+
+#define R13_IRQ 18
+#define R14_IRQ 19
+#define SPSR_IRQ 20
+#define R13_USR 26
+#define R14_USR 27
+#define R13_SVC 28
+#define R14_SVC 29
+#define SPSR_SVC 30
+#define R13_ABT 31
+#define R14_ABT 32
+#define SPSR_ABT 33
+#define R13_UND 34
+#define R14_UND 35
+#define SPSR_UND 36
+#define R8_FIQ 37
+#define R9_FIQ 38
+#define R10_FIQ 39
+#define R11_FIQ 40
+#define R12_FIQ 41
+#define R13_FIQ 42
+#define R14_FIQ 43
+#define SPSR_FIQ 44
+
+//#include "Cheats.h"
+#include "Globals.h"
+//#include "EEprom.h"
+//#include "Flash.h"
+
+#endif // GBA_H
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/GBAcpu.h
@@ -1,1 +1,288 @@
-
+#ifndef GBACPU_H
+#define GBACPU_H
+
+extern int armExecute();
+extern int thumbExecute();
+
+#ifdef __GNUC__
+#ifndef __APPLE__
+# define INSN_REGPARM __attribute__((regparm(1)))
+#else
+# define INSN_REGPARM /*nothing*/
+#endif
+# define LIKELY(x) __builtin_expect(!!(x),1)
+# define UNLIKELY(x) __builtin_expect(!!(x),0)
+#else
+# define INSN_REGPARM /*nothing*/
+# define LIKELY(x) (x)
+# define UNLIKELY(x) (x)
+#endif
+
+#define UPDATE_REG(address, value)\
+ {\
+ WRITE16LE(((u16 *)&ioMem[address]),value);\
+ }\
+
+#define ARM_PREFETCH \
+ {\
+ cpuPrefetch[0] = CPUReadMemoryQuick(armNextPC);\
+ cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);\
+ }
+
+#define THUMB_PREFETCH \
+ {\
+ cpuPrefetch[0] = CPUReadHalfWordQuick(armNextPC);\
+ cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);\
+ }
+
+#define ARM_PREFETCH_NEXT \
+ cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);
+
+#define THUMB_PREFETCH_NEXT\
+ cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);
+
+
+extern int SWITicks;
+extern u32 mastercode;
+extern bool busPrefetch;
+extern bool busPrefetchEnable;
+extern u32 busPrefetchCount;
+extern int cpuNextEvent;
+extern bool holdState;
+extern u32 cpuPrefetch[2];
+extern int cpuTotalTicks;
+extern u8 memoryWait[16];
+extern u8 memoryWait32[16];
+extern u8 memoryWaitSeq[16];
+extern u8 memoryWaitSeq32[16];
+extern u8 cpuBitsSet[256];
+extern u8 cpuLowestBitSet[256];
+extern void CPUSwitchMode(int mode, bool saveState, bool breakLoop);
+extern void CPUSwitchMode(int mode, bool saveState);
+extern void CPUUpdateCPSR();
+extern void CPUUpdateFlags(bool breakLoop);
+extern void CPUUpdateFlags();
+extern void CPUUndefinedException();
+extern void CPUSoftwareInterrupt();
+extern void CPUSoftwareInterrupt(int comment);
+
+
+// Waitstates when accessing data
+inline int dataTicksAccess16(u32 address) // DATA 8/16bits NON SEQ
+{
+ int addr = (address>>24)&15;
+ int value = memoryWait[addr];
+
+ if ((addr>=0x08) || (addr < 0x02))
+ {
+ busPrefetchCount=0;
+ busPrefetch=false;
+ }
+ else if (busPrefetch)
+ {
+ int waitState = value;
+ if (!waitState)
+ waitState = 1;
+ busPrefetchCount = ((busPrefetchCount+1)<<waitState) - 1;
+ }
+
+ return value;
+}
+
+inline int dataTicksAccess32(u32 address) // DATA 32bits NON SEQ
+{
+ int addr = (address>>24)&15;
+ int value = memoryWait32[addr];
+
+ if ((addr>=0x08) || (addr < 0x02))
+ {
+ busPrefetchCount=0;
+ busPrefetch=false;
+ }
+ else if (busPrefetch)
+ {
+ int waitState = value;
+ if (!waitState)
+ waitState = 1;
+ busPrefetchCount = ((busPrefetchCount+1)<<waitState) - 1;
+ }
+
+ return value;
+}
+
+inline int dataTicksAccessSeq16(u32 address)// DATA 8/16bits SEQ
+{
+ int addr = (address>>24)&15;
+ int value = memoryWaitSeq[addr];
+
+ if ((addr>=0x08) || (addr < 0x02))
+ {
+ busPrefetchCount=0;
+ busPrefetch=false;
+ }
+ else if (busPrefetch)
+ {
+ int waitState = value;
+ if (!waitState)
+ waitState = 1;
+ busPrefetchCount = ((busPrefetchCount+1)<<waitState) - 1;
+ }
+
+ return value;
+}
+
+inline int dataTicksAccessSeq32(u32 address)// DATA 32bits SEQ
+{
+ int addr = (address>>24)&15;
+ int value = memoryWaitSeq32[addr];
+
+ if ((addr>=0x08) || (addr < 0x02))
+ {
+ busPrefetchCount=0;
+ busPrefetch=false;
+ }
+ else if (busPrefetch)
+ {
+ int waitState = value;
+ if (!waitState)
+ waitState = 1;
+ busPrefetchCount = ((busPrefetchCount+1)<<waitState) - 1;
+ }
+
+ return value;
+}
+
+
+// Waitstates when executing opcode
+inline int codeTicksAccess16(u32 address) // THUMB NON SEQ
+{
+ int addr = (address>>24)&15;
+
+ if ((addr>=0x08) && (addr<=0x0D))
+ {
+ if (busPrefetchCount&0x1)
+ {
+ if (busPrefetchCount&0x2)
+ {
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
+ return 0;
+ }
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
+ return memoryWaitSeq[addr]-1;
+ }
+ else
+ {
+ busPrefetchCount=0;
+ return memoryWait[addr];
+ }
+ }
+ else
+ {
+ busPrefetchCount = 0;
+ return memoryWait[addr];
+ }
+}
+
+inline int codeTicksAccess32(u32 address) // ARM NON SEQ
+{
+ int addr = (address>>24)&15;
+
+ if ((addr>=0x08) && (addr<=0x0D))
+ {
+ if (busPrefetchCount&0x1)
+ {
+ if (busPrefetchCount&0x2)
+ {
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
+ return 0;
+ }
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
+ return memoryWaitSeq[addr] - 1;
+ }
+ else
+ {
+ busPrefetchCount = 0;
+ return memoryWait32[addr];
+ }
+ }
+ else
+ {
+ busPrefetchCount = 0;
+ return memoryWait32[addr];
+ }
+}
+
+inline int codeTicksAccessSeq16(u32 address) // THUMB SEQ
+{
+ int addr = (address>>24)&15;
+
+ if ((addr>=0x08) && (addr<=0x0D))
+ {
+ if (busPrefetchCount&0x1)
+ {
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
+ return 0;
+ }
+ else
+ if (busPrefetchCount>0xFF)
+ {
+ busPrefetchCount=0;
+ return memoryWait[addr];
+ }
+ else
+ return memoryWaitSeq[addr];
+ }
+ else
+ {
+ busPrefetchCount = 0;
+ return memoryWaitSeq[addr];
+ }
+}
+
+inline int codeTicksAccessSeq32(u32 address) // ARM SEQ
+{
+ int addr = (address>>24)&15;
+
+ if ((addr>=0x08) && (addr<=0x0D))
+ {
+ if (busPrefetchCount&0x1)
+ {
+ if (busPrefetchCount&0x2)
+ {
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
+ return 0;
+ }
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
+ return memoryWaitSeq[addr];
+ }
+ else
+ if (busPrefetchCount>0xFF)
+ {
+ busPrefetchCount=0;
+ return memoryWait32[addr];
+ }
+ else
+ return memoryWaitSeq32[addr];
+ }
+ else
+ {
+ return memoryWaitSeq32[addr];
+ }
+}
+
+
+// Emulates the Cheat System (m) code
+/*inline void cpuMasterCodeCheck()
+{
+ if((mastercode) && (mastercode == armNextPC))
+ {
+ u32 joy = 0;
+ if(systemReadJoypads())
+ joy = systemReadJoypad(-1);
+ u32 ext = (joy >> 10);
+ cpuTotalTicks += cheatsCheckKeys(P1^0x3FF, ext);
+ }
+}*/
+
+#endif // GBACPU_H
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/GBAinline.h
@@ -1,1 +1,725 @@
-
+#ifndef GBAINLINE_H
+#define GBAINLINE_H
+
+//#include "../System.h"
+#include "../common/Port.h"
+//#include "RTC.h"
+#include "Sound.h"
+//#include "agbprint.h"
+#include "GBAcpu.h"
+//#include "GBALink.h"
+
+extern const u32 objTilesAddress[3];
+
+extern bool stopState;
+extern bool holdState;
+extern int holdType;
+extern int cpuNextEvent;
+extern bool cpuSramEnabled;
+extern bool cpuFlashEnabled;
+extern bool cpuEEPROMEnabled;
+extern bool cpuEEPROMSensorEnabled;
+extern bool cpuDmaHack;
+extern u32 cpuDmaLast;
+extern bool timer0On;
+extern int timer0Ticks;
+extern int timer0ClockReload;
+extern bool timer1On;
+extern int timer1Ticks;
+extern int timer1ClockReload;
+extern bool timer2On;
+extern int timer2Ticks;
+extern int timer2ClockReload;
+extern bool timer3On;
+extern int timer3Ticks;
+extern int timer3ClockReload;
+extern int cpuTotalTicks;
+
+#define CPUReadByteQuick(addr) \
+ map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
+
+#define CPUReadHalfWordQuick(addr) \
+ READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
+
+#define CPUReadMemoryQuick(addr) \
+ READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
+
+static inline u32 CPUReadMemory(u32 address)
+{
+#ifdef GBA_LOGGING
+ if(address & 3) {
+ if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
+ log("Unaligned word read: %08x at %08x\n", address, armMode ?
+ armNextPC - 4 : armNextPC - 2);
+ }
+ }
+#endif
+
+ u32 value;
+ switch(address >> 24) {
+ case 0:
+ if(reg[15].I >> 24) {
+ if(address < 0x4000) {
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_ILLEGAL_READ) {
+ log("Illegal word read: %08x at %08x\n", address, armMode ?
+ armNextPC - 4 : armNextPC - 2);
+ }
+#endif
+
+ value = READ32LE(((u32 *)&biosProtected));
+ }
+ else goto unreadable;
+ } else
+ value = READ32LE(((u32 *)&bios[address & 0x3FFC]));
+ break;
+ case 2:
+ value = READ32LE(((u32 *)&workRAM[address & 0x3FFFC]));
+ break;
+ case 3:
+ value = READ32LE(((u32 *)&internalRAM[address & 0x7ffC]));
+ break;
+ case 4:
+ if((address < 0x4000400) && ioReadable[address & 0x3fc]) {
+ if(ioReadable[(address & 0x3fc) + 2]) {
+ value = READ32LE(((u32 *)&ioMem[address & 0x3fC]));
+ /*if ((address & 0x3fc) == COMM_JOY_RECV_L)
+ UPDATE_REG(COMM_JOYSTAT, READ16LE(&ioMem[COMM_JOYSTAT]) & ~JOYSTAT_RECV);*/
+ } else {
+ value = READ16LE(((u16 *)&ioMem[address & 0x3fc]));
+ }
+ }
+ else
+ goto unreadable;
+ break;
+ case 5:
+ value = READ32LE(((u32 *)&paletteRAM[address & 0x3fC]));
+ break;
+ case 6:
+ address = (address & 0x1fffc);
+ if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
+ {
+ value = 0;
+ break;
+ }
+ if ((address & 0x18000) == 0x18000)
+ address &= 0x17fff;
+ value = READ32LE(((u32 *)&vram[address]));
+ break;
+ case 7:
+ value = READ32LE(((u32 *)&oam[address & 0x3FC]));
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ value = READ32LE(((u32 *)&rom[address&0x1FFFFFC]));
+ break;
+ case 13:
+ if(cpuEEPROMEnabled)
+ // no need to swap this
+ return /*eepromRead(address)*/0;
+ goto unreadable;
+ case 14:
+ if(cpuFlashEnabled | cpuSramEnabled)
+ // no need to swap this
+ return /*flashRead(address)*/0;
+ // default
+ default:
+unreadable:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_ILLEGAL_READ) {
+ log("Illegal word read: %08x at %08x\n", address, armMode ?
+ armNextPC - 4 : armNextPC - 2);
+ }
+#endif
+
+ if(cpuDmaHack) {
+ value = cpuDmaLast;
+ } else {
+ if(armState) {
+ value = CPUReadMemoryQuick(reg[15].I);
+ } else {
+ value = CPUReadHalfWordQuick(reg[15].I) |
+ CPUReadHalfWordQuick(reg[15].I) << 16;
+ }
+ }
+ }
+
+ if(address & 3) {
+#ifdef C_CORE
+ int shift = (address & 3) << 3;
+ value = (value >> shift) | (value << (32 - shift));
+#else
+#ifdef __GNUC__
+ asm("and $3, %%ecx;"
+ "shl $3 ,%%ecx;"
+ "ror %%cl, %0"
+ : "=r" (value)
+ : "r" (value), "c" (address));
+#else
+ __asm {
+ mov ecx, address;
+ and ecx, 3;
+ shl ecx, 3;
+ ror [dword ptr value], cl;
+ }
+#endif
+#endif
+ }
+ return value;
+}
+
+extern u32 myROM[];
+
+static inline u32 CPUReadHalfWord(u32 address)
+{
+#ifdef GBA_LOGGING
+ if(address & 1) {
+ if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
+ log("Unaligned halfword read: %08x at %08x\n", address, armMode ?
+ armNextPC - 4 : armNextPC - 2);
+ }
+ }
+#endif
+
+ u32 value;
+
+ switch(address >> 24) {
+ case 0:
+ if (reg[15].I >> 24) {
+ if(address < 0x4000) {
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_ILLEGAL_READ) {
+ log("Illegal halfword read: %08x at %08x\n", address, armMode ?
+ armNextPC - 4 : armNextPC - 2);
+ }
+#endif
+ value = READ16LE(((u16 *)&biosProtected[address&2]));
+ } else goto unreadable;
+ } else
+ value = READ16LE(((u16 *)&bios[address & 0x3FFE]));
+ break;
+ case 2:
+ value = READ16LE(((u16 *)&workRAM[address & 0x3FFFE]));
+ break;
+ case 3:
+ value = READ16LE(((u16 *)&internalRAM[address & 0x7ffe]));
+ break;
+ case 4:
+ if((address < 0x4000400) && ioReadable[address & 0x3fe])
+ {
+ value = READ16LE(((u16 *)&ioMem[address & 0x3fe]));
+ if (((address & 0x3fe)>0xFF) && ((address & 0x3fe)<0x10E))
+ {
+ if (((address & 0x3fe) == 0x100) && timer0On)
+ value = 0xFFFF - ((timer0Ticks-cpuTotalTicks) >> timer0ClockReload);
+ else
+ if (((address & 0x3fe) == 0x104) && timer1On && !(TM1CNT & 4))
+ value = 0xFFFF - ((timer1Ticks-cpuTotalTicks) >> timer1ClockReload);
+ else
+ if (((address & 0x3fe) == 0x108) && timer2On && !(TM2CNT & 4))
+ value = 0xFFFF - ((timer2Ticks-cpuTotalTicks) >> timer2ClockReload);
+ else
+ if (((address & 0x3fe) == 0x10C) && timer3On && !(TM3CNT & 4))
+ value = 0xFFFF - ((timer3Ticks-cpuTotalTicks) >> timer3ClockReload);
+ }
+ }
+ else goto unreadable;
+ break;
+ case 5:
+ value = READ16LE(((u16 *)&paletteRAM[address & 0x3fe]));
+ break;
+ case 6:
+ address = (address & 0x1fffe);
+ if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
+ {
+ value = 0;
+ break;
+ }
+ if ((address & 0x18000) == 0x18000)
+ address &= 0x17fff;
+ value = READ16LE(((u16 *)&vram[address]));
+ break;
+ case 7:
+ value = READ16LE(((u16 *)&oam[address & 0x3fe]));
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8)
+ value = /*rtcRead(address)*/0;
+ else
+ value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE]));
+ break;
+ case 13:
+ if(cpuEEPROMEnabled)
+ // no need to swap this
+ return /*eepromRead(address)*/0;
+ goto unreadable;
+ case 14:
+ if(cpuFlashEnabled | cpuSramEnabled)
+ // no need to swap this
+ return /*flashRead(address)*/0;
+ // default
+ default:
+unreadable:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_ILLEGAL_READ) {
+ log("Illegal halfword read: %08x at %08x\n", address, armMode ?
+ armNextPC - 4 : armNextPC - 2);
+ }
+#endif
+ if(cpuDmaHack) {
+ value = cpuDmaLast & 0xFFFF;
+ } else {
+ if(armState) {
+ value = CPUReadHalfWordQuick(reg[15].I + (address & 2));
+ } else {
+ value = CPUReadHalfWordQuick(reg[15].I);
+ }
+ }
+ break;
+ }
+
+ if(address & 1) {
+ value = (value >> 8) | (value << 24);
+ }
+
+ return value;
+}
+
+static inline u16 CPUReadHalfWordSigned(u32 address)
+{
+ u16 value = CPUReadHalfWord(address);
+ if((address & 1))
+ value = (s8)value;
+ return value;
+}
+
+static inline u8 CPUReadByte(u32 address)
+{
+ switch(address >> 24) {
+ case 0:
+ if (reg[15].I >> 24) {
+ if(address < 0x4000) {
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_ILLEGAL_READ) {
+ log("Illegal byte read: %08x at %08x\n", address, armMode ?
+ armNextPC - 4 : armNextPC - 2);
+ }
+#endif
+ return biosProtected[address & 3];
+ } else goto unreadable;
+ }
+ return bios[address & 0x3FFF];
+ case 2:
+ return workRAM[address & 0x3FFFF];
+ case 3:
+ return internalRAM[address & 0x7fff];
+ case 4:
+ if((address < 0x4000400) && ioReadable[address & 0x3ff])
+ return ioMem[address & 0x3ff];
+ else goto unreadable;
+ case 5:
+ return paletteRAM[address & 0x3ff];
+ case 6:
+ address = (address & 0x1ffff);
+ if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
+ return 0;
+ if ((address & 0x18000) == 0x18000)
+ address &= 0x17fff;
+ return vram[address];
+ case 7:
+ return oam[address & 0x3ff];
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ return rom[address & 0x1FFFFFF];
+ case 13:
+ if(cpuEEPROMEnabled)
+ return /*eepromRead(address)*/0;
+ goto unreadable;
+ case 14:
+ if(cpuSramEnabled | cpuFlashEnabled)
+ return /*flashRead(address)*/0;
+ if(cpuEEPROMSensorEnabled) {
+ switch(address & 0x00008f00) {
+ case 0x8200:
+ return /*systemGetSensorX() & 255*/0;
+ case 0x8300:
+ return /*(systemGetSensorX() >> 8)|0x80*/0;
+ case 0x8400:
+ return /*systemGetSensorY() & 255*/0;
+ case 0x8500:
+ return /*systemGetSensorY() >> 8*/0;
+ }
+ }
+ // default
+ default:
+unreadable:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_ILLEGAL_READ) {
+ log("Illegal byte read: %08x at %08x\n", address, armMode ?
+ armNextPC - 4 : armNextPC - 2);
+ }
+#endif
+ if(cpuDmaHack) {
+ return cpuDmaLast & 0xFF;
+ } else {
+ if(armState) {
+ return CPUReadByteQuick(reg[15].I+(address & 3));
+ } else {
+ return CPUReadByteQuick(reg[15].I+(address & 1));
+ }
+ }
+ break;
+ }
+}
+
+static inline void CPUWriteMemory(u32 address, u32 value)
+{
+
+#ifdef GBA_LOGGING
+ if(address & 3) {
+ if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
+ log("Unaligned word write: %08x to %08x from %08x\n",
+ value,
+ address,
+ armMode ? armNextPC - 4 : armNextPC - 2);
+ }
+ }
+#endif
+
+ switch(address >> 24) {
+ case 0x02:
+#ifdef BKPT_SUPPORT
+ if(*((u32 *)&freezeWorkRAM[address & 0x3FFFC]))
+ cheatsWriteMemory(address & 0x203FFFC,
+ value);
+ else
+#endif
+ WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value);
+ break;
+ case 0x03:
+#ifdef BKPT_SUPPORT
+ if(*((u32 *)&freezeInternalRAM[address & 0x7ffc]))
+ cheatsWriteMemory(address & 0x3007FFC,
+ value);
+ else
+#endif
+ WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value);
+ break;
+ case 0x04:
+ if(address < 0x4000400) {
+ CPUUpdateRegister((address & 0x3FC), value & 0xFFFF);
+ CPUUpdateRegister((address & 0x3FC) + 2, (value >> 16));
+ } else goto unwritable;
+ break;
+ case 0x05:
+#ifdef BKPT_SUPPORT
+ if(*((u32 *)&freezePRAM[address & 0x3fc]))
+ cheatsWriteMemory(address & 0x70003FC,
+ value);
+ else
+#endif
+ WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value);
+ break;
+ case 0x06:
+ address = (address & 0x1fffc);
+ if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
+ return;
+ if ((address & 0x18000) == 0x18000)
+ address &= 0x17fff;
+
+#ifdef BKPT_SUPPORT
+ if(*((u32 *)&freezeVRAM[address]))
+ cheatsWriteMemory(address + 0x06000000, value);
+ else
+#endif
+
+ WRITE32LE(((u32 *)&vram[address]), value);
+ break;
+ case 0x07:
+#ifdef BKPT_SUPPORT
+ if(*((u32 *)&freezeOAM[address & 0x3fc]))
+ cheatsWriteMemory(address & 0x70003FC,
+ value);
+ else
+#endif
+ WRITE32LE(((u32 *)&oam[address & 0x3fc]), value);
+ break;
+ case 0x0D:
+ if(cpuEEPROMEnabled) {
+ //eepromWrite(address, value);
+ break;
+ }
+ goto unwritable;
+ case 0x0E:
+ if(/*(!eepromInUse) | */cpuSramEnabled | cpuFlashEnabled) {
+ //(*cpuSaveGameFunc)(address, (u8)value);
+ break;
+ }
+ // default
+ default:
+unwritable:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
+ log("Illegal word write: %08x to %08x from %08x\n",
+ value,
+ address,
+ armMode ? armNextPC - 4 : armNextPC - 2);
+ }
+#endif
+ break;
+ }
+}
+
+static inline void CPUWriteHalfWord(u32 address, u16 value)
+{
+#ifdef GBA_LOGGING
+ if(address & 1) {
+ if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
+ log("Unaligned halfword write: %04x to %08x from %08x\n",
+ value,
+ address,
+ armMode ? armNextPC - 4 : armNextPC - 2);
+ }
+ }
+#endif
+
+ switch(address >> 24) {
+ case 2:
+#ifdef BKPT_SUPPORT
+ if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE]))
+ cheatsWriteHalfWord(address & 0x203FFFE,
+ value);
+ else
+#endif
+ WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value);
+ break;
+ case 3:
+#ifdef BKPT_SUPPORT
+ if(*((u16 *)&freezeInternalRAM[address & 0x7ffe]))
+ cheatsWriteHalfWord(address & 0x3007ffe,
+ value);
+ else
+#endif
+ WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value);
+ break;
+ case 4:
+ if(address < 0x4000400)
+ CPUUpdateRegister(address & 0x3fe, value);
+ else goto unwritable;
+ break;
+ case 5:
+#ifdef BKPT_SUPPORT
+ if(*((u16 *)&freezePRAM[address & 0x03fe]))
+ cheatsWriteHalfWord(address & 0x70003fe,
+ value);
+ else
+#endif
+ WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
+ break;
+ case 6:
+ address = (address & 0x1fffe);
+ if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
+ return;
+ if ((address & 0x18000) == 0x18000)
+ address &= 0x17fff;
+#ifdef BKPT_SUPPORT
+ if(*((u16 *)&freezeVRAM[address]))
+ cheatsWriteHalfWord(address + 0x06000000,
+ value);
+ else
+#endif
+ WRITE16LE(((u16 *)&vram[address]), value);
+ break;
+ case 7:
+#ifdef BKPT_SUPPORT
+ if(*((u16 *)&freezeOAM[address & 0x03fe]))
+ cheatsWriteHalfWord(address & 0x70003fe,
+ value);
+ else
+#endif
+ WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
+ break;
+ case 8:
+ case 9:
+ /* if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) {
+ if(!rtcWrite(address, value))
+ goto unwritable;
+ } else if(!agbPrintWrite(address, value)) goto unwritable;*/
+ break;
+ case 13:
+ if(cpuEEPROMEnabled) {
+ //eepromWrite(address, (u8)value);
+ break;
+ }
+ goto unwritable;
+ case 14:
+ if(/*(!eepromInUse) | */cpuSramEnabled | cpuFlashEnabled) {
+ //(*cpuSaveGameFunc)(address, (u8)value);
+ break;
+ }
+ goto unwritable;
+ default:
+unwritable:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
+ log("Illegal halfword write: %04x to %08x from %08x\n",
+ value,
+ address,
+ armMode ? armNextPC - 4 : armNextPC - 2);
+ }
+#endif
+ break;
+ }
+}
+
+static inline void CPUWriteByte(u32 address, u8 b)
+{
+ switch(address >> 24) {
+ case 2:
+#ifdef BKPT_SUPPORT
+ if(freezeWorkRAM[address & 0x3FFFF])
+ cheatsWriteByte(address & 0x203FFFF, b);
+ else
+#endif
+ workRAM[address & 0x3FFFF] = b;
+ break;
+ case 3:
+#ifdef BKPT_SUPPORT
+ if(freezeInternalRAM[address & 0x7fff])
+ cheatsWriteByte(address & 0x3007fff, b);
+ else
+#endif
+ internalRAM[address & 0x7fff] = b;
+ break;
+ case 4:
+ if(address < 0x4000400) {
+ switch(address & 0x3FF) {
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x68:
+ case 0x69:
+ case 0x6c:
+ case 0x6d:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x78:
+ case 0x79:
+ case 0x7c:
+ case 0x7d:
+ case 0x80:
+ case 0x81:
+ case 0x84:
+ case 0x85:
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+ soundEvent(address&0xFF, b);
+ break;
+ case 0x301: // HALTCNT, undocumented
+ if(b == 0x80)
+ stopState = true;
+ holdState = 1;
+ holdType = -1;
+ cpuNextEvent = cpuTotalTicks;
+ break;
+ default: // every other register
+ u32 lowerBits = address & 0x3fe;
+ if(address & 1) {
+ CPUUpdateRegister(lowerBits, (READ16LE(&ioMem[lowerBits]) & 0x00FF) | (b << 8));
+ } else {
+ CPUUpdateRegister(lowerBits, (READ16LE(&ioMem[lowerBits]) & 0xFF00) | b);
+ }
+ }
+ break;
+ } else goto unwritable;
+ break;
+ case 5:
+ // no need to switch
+ *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b;
+ break;
+ case 6:
+ address = (address & 0x1fffe);
+ if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
+ return;
+ if ((address & 0x18000) == 0x18000)
+ address &= 0x17fff;
+
+ // no need to switch
+ // byte writes to OBJ VRAM are ignored
+ if ((address) < objTilesAddress[((DISPCNT&7)+1)>>2])
+ {
+#ifdef BKPT_SUPPORT
+ if(freezeVRAM[address])
+ cheatsWriteByte(address + 0x06000000, b);
+ else
+#endif
+ *((u16 *)&vram[address]) = (b << 8) | b;
+ }
+ break;
+ case 7:
+ // no need to switch
+ // byte writes to OAM are ignored
+ // *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b;
+ break;
+ case 13:
+ if(cpuEEPROMEnabled) {
+ //eepromWrite(address, b);
+ break;
+ }
+ goto unwritable;
+ case 14:
+ if ((saveType != 5) && (/*(!eepromInUse) | */cpuSramEnabled | cpuFlashEnabled)) {
+
+ //if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) {
+
+ //(*cpuSaveGameFunc)(address, b);
+ break;
+ }
+ // default
+ default:
+unwritable:
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
+ log("Illegal byte write: %02x to %08x from %08x\n",
+ b,
+ address,
+ armMode ? armNextPC - 4 : armNextPC -2 );
+ }
+#endif
+ break;
+ }
+}
+
+#endif // GBAINLINE_H
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/Globals.cpp
@@ -1,1 +1,130 @@
+#include "GBA.h"
+#ifdef BKPT_SUPPORT
+int oldreg[18];
+char oldbuffer[10];
+#endif
+
+reg_pair reg[45];
+memoryMap map[256];
+bool ioReadable[0x400];
+bool N_FLAG = 0;
+bool C_FLAG = 0;
+bool Z_FLAG = 0;
+bool V_FLAG = 0;
+bool armState = true;
+bool armIrqEnable = true;
+u32 armNextPC = 0x00000000;
+int armMode = 0x1f;
+u32 stop = 0x08000568;
+int saveType = 0;
+bool useBios = false;
+bool skipBios = false;
+int frameSkip = 1;
+bool speedup = false;
+bool synchronize = true;
+bool cpuDisableSfx = false;
+bool cpuIsMultiBoot = false;
+bool parseDebug = true;
+int layerSettings = 0xff00;
+int layerEnable = 0xff00;
+bool speedHack = false;
+int cpuSaveType = 0;
+bool cheatsEnabled = true;
+bool mirroringEnable = false;
+bool skipSaveGameBattery = false;
+bool skipSaveGameCheats = false;
+
+// this is an optional hack to change the backdrop/background color:
+// -1: disabled
+// 0x0000 to 0x7FFF: set custom 15 bit color
+int customBackdropColor = -1;
+
+u8 *bios = 0;
+u8 *rom = 0;
+u8 *internalRAM = 0;
+u8 *workRAM = 0;
+u8 *paletteRAM = 0;
+u8 *vram = 0;
+u8 *pix = 0;
+u8 *oam = 0;
+u8 *ioMem = 0;
+
+u16 DISPCNT = 0x0080;
+u16 DISPSTAT = 0x0000;
+u16 VCOUNT = 0x0000;
+u16 BG0CNT = 0x0000;
+u16 BG1CNT = 0x0000;
+u16 BG2CNT = 0x0000;
+u16 BG3CNT = 0x0000;
+u16 BG0HOFS = 0x0000;
+u16 BG0VOFS = 0x0000;
+u16 BG1HOFS = 0x0000;
+u16 BG1VOFS = 0x0000;
+u16 BG2HOFS = 0x0000;
+u16 BG2VOFS = 0x0000;
+u16 BG3HOFS = 0x0000;
+u16 BG3VOFS = 0x0000;
+u16 BG2PA = 0x0100;
+u16 BG2PB = 0x0000;
+u16 BG2PC = 0x0000;
+u16 BG2PD = 0x0100;
+u16 BG2X_L = 0x0000;
+u16 BG2X_H = 0x0000;
+u16 BG2Y_L = 0x0000;
+u16 BG2Y_H = 0x0000;
+u16 BG3PA = 0x0100;
+u16 BG3PB = 0x0000;
+u16 BG3PC = 0x0000;
+u16 BG3PD = 0x0100;
+u16 BG3X_L = 0x0000;
+u16 BG3X_H = 0x0000;
+u16 BG3Y_L = 0x0000;
+u16 BG3Y_H = 0x0000;
+u16 WIN0H = 0x0000;
+u16 WIN1H = 0x0000;
+u16 WIN0V = 0x0000;
+u16 WIN1V = 0x0000;
+u16 WININ = 0x0000;
+u16 WINOUT = 0x0000;
+u16 MOSAIC = 0x0000;
+u16 BLDMOD = 0x0000;
+u16 COLEV = 0x0000;
+u16 COLY = 0x0000;
+u16 DM0SAD_L = 0x0000;
+u16 DM0SAD_H = 0x0000;
+u16 DM0DAD_L = 0x0000;
+u16 DM0DAD_H = 0x0000;
+u16 DM0CNT_L = 0x0000;
+u16 DM0CNT_H = 0x0000;
+u16 DM1SAD_L = 0x0000;
+u16 DM1SAD_H = 0x0000;
+u16 DM1DAD_L = 0x0000;
+u16 DM1DAD_H = 0x0000;
+u16 DM1CNT_L = 0x0000;
+u16 DM1CNT_H = 0x0000;
+u16 DM2SAD_L = 0x0000;
+u16 DM2SAD_H = 0x0000;
+u16 DM2DAD_L = 0x0000;
+u16 DM2DAD_H = 0x0000;
+u16 DM2CNT_L = 0x0000;
+u16 DM2CNT_H = 0x0000;
+u16 DM3SAD_L = 0x0000;
+u16 DM3SAD_H = 0x0000;
+u16 DM3DAD_L = 0x0000;
+u16 DM3DAD_H = 0x0000;
+u16 DM3CNT_L = 0x0000;
+u16 DM3CNT_H = 0x0000;
+u16 TM0D = 0x0000;
+u16 TM0CNT = 0x0000;
+u16 TM1D = 0x0000;
+u16 TM1CNT = 0x0000;
+u16 TM2D = 0x0000;
+u16 TM2CNT = 0x0000;
+u16 TM3D = 0x0000;
+u16 TM3CNT = 0x0000;
+u16 P1 = 0xFFFF;
+u16 IE = 0x0000;
+u16 IF = 0x0000;
+u16 IME = 0x0000;
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/Globals.h
@@ -1,1 +1,138 @@
+#ifndef GLOBALS_H
+#define GLOBALS_H
+#include "../common/Types.h"
+#include "GBA.h"
+
+#define VERBOSE_SWI 1
+#define VERBOSE_UNALIGNED_MEMORY 2
+#define VERBOSE_ILLEGAL_WRITE 4
+#define VERBOSE_ILLEGAL_READ 8
+#define VERBOSE_DMA0 16
+#define VERBOSE_DMA1 32
+#define VERBOSE_DMA2 64
+#define VERBOSE_DMA3 128
+#define VERBOSE_UNDEFINED 256
+#define VERBOSE_AGBPRINT 512
+#define VERBOSE_SOUNDOUTPUT 1024
+
+extern reg_pair reg[45];
+extern bool ioReadable[0x400];
+extern bool N_FLAG;
+extern bool C_FLAG;
+extern bool Z_FLAG;
+extern bool V_FLAG;
+extern bool armState;
+extern bool armIrqEnable;
+extern u32 armNextPC;
+extern int armMode;
+extern u32 stop;
+extern int saveType;
+extern bool useBios;
+extern bool skipBios;
+extern int frameSkip;
+extern bool speedup;
+extern bool synchronize;
+extern bool cpuDisableSfx;
+extern bool cpuIsMultiBoot;
+extern bool parseDebug;
+extern int layerSettings;
+extern int layerEnable;
+extern bool speedHack;
+extern int cpuSaveType;
+extern bool cheatsEnabled;
+extern bool mirroringEnable;
+extern bool skipSaveGameBattery; // skip battery data when reading save states
+extern bool skipSaveGameCheats; // skip cheat list data when reading save states
+extern int customBackdropColor;
+
+extern u8 *bios;
+extern u8 *rom;
+extern u8 *internalRAM;
+extern u8 *workRAM;
+extern u8 *paletteRAM;
+extern u8 *vram;
+extern u8 *pix;
+extern u8 *oam;
+extern u8 *ioMem;
+
+extern u16 DISPCNT;
+extern u16 DISPSTAT;
+extern u16 VCOUNT;
+extern u16 BG0CNT;
+extern u16 BG1CNT;
+extern u16 BG2CNT;
+extern u16 BG3CNT;
+extern u16 BG0HOFS;
+extern u16 BG0VOFS;
+extern u16 BG1HOFS;
+extern u16 BG1VOFS;
+extern u16 BG2HOFS;
+extern u16 BG2VOFS;
+extern u16 BG3HOFS;
+extern u16 BG3VOFS;
+extern u16 BG2PA;
+extern u16 BG2PB;
+extern u16 BG2PC;
+extern u16 BG2PD;
+extern u16 BG2X_L;
+extern u16 BG2X_H;
+extern u16 BG2Y_L;
+extern u16 BG2Y_H;
+extern u16 BG3PA;
+extern u16 BG3PB;
+extern u16 BG3PC;
+extern u16 BG3PD;
+extern u16 BG3X_L;
+extern u16 BG3X_H;
+extern u16 BG3Y_L;
+extern u16 BG3Y_H;
+extern u16 WIN0H;
+extern u16 WIN1H;
+extern u16 WIN0V;
+extern u16 WIN1V;
+extern u16 WININ;
+extern u16 WINOUT;
+extern u16 MOSAIC;
+extern u16 BLDMOD;
+extern u16 COLEV;
+extern u16 COLY;
+extern u16 DM0SAD_L;
+extern u16 DM0SAD_H;
+extern u16 DM0DAD_L;
+extern u16 DM0DAD_H;
+extern u16 DM0CNT_L;
+extern u16 DM0CNT_H;
+extern u16 DM1SAD_L;
+extern u16 DM1SAD_H;
+extern u16 DM1DAD_L;
+extern u16 DM1DAD_H;
+extern u16 DM1CNT_L;
+extern u16 DM1CNT_H;
+extern u16 DM2SAD_L;
+extern u16 DM2SAD_H;
+extern u16 DM2DAD_L;
+extern u16 DM2DAD_H;
+extern u16 DM2CNT_L;
+extern u16 DM2CNT_H;
+extern u16 DM3SAD_L;
+extern u16 DM3SAD_H;
+extern u16 DM3DAD_L;
+extern u16 DM3DAD_H;
+extern u16 DM3CNT_L;
+extern u16 DM3CNT_H;
+extern u16 TM0D;
+extern u16 TM0CNT;
+extern u16 TM1D;
+extern u16 TM1CNT;
+extern u16 TM2D;
+extern u16 TM2CNT;
+extern u16 TM3D;
+extern u16 TM3CNT;
+extern u16 P1;
+extern u16 IE;
+extern u16 IF;
+extern u16 IME;
+
+#endif // GLOBALS_H
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/Sound.cpp
@@ -1,1 +1,815 @@
-
+#include <string.h>
+
+#include "Sound.h"
+
+#include "GBA.h"
+#include "Globals.h"
+//#include "../Util.h"
+#include "../common/Port.h"
+
+#include "../apu/Gb_Apu.h"
+#include "../apu/Multi_Buffer.h"
+
+#include "../common/SoundDriver.h"
+
+extern SoundDriver *systemSoundInit();
+
+#define NR10 0x60
+#define NR11 0x62
+#define NR12 0x63
+#define NR13 0x64
+#define NR14 0x65
+#define NR21 0x68
+#define NR22 0x69
+#define NR23 0x6c
+#define NR24 0x6d
+#define NR30 0x70
+#define NR31 0x72
+#define NR32 0x73
+#define NR33 0x74
+#define NR34 0x75
+#define NR41 0x78
+#define NR42 0x79
+#define NR43 0x7c
+#define NR44 0x7d
+#define NR50 0x80
+#define NR51 0x81
+#define NR52 0x84
+
+SoundDriver * soundDriver = 0;
+
+extern bool stopState; // TODO: silence sound when true
+
+int const SOUND_CLOCK_TICKS_ = 167772; // 1/100 second
+
+static u16 soundFinalWave [1600];
+long soundSampleRate = 44100;
+bool soundInterpolation = true;
+bool soundPaused = true;
+float soundFiltering = 0.5f;
+int SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_;
+int soundTicks = SOUND_CLOCK_TICKS_;
+
+static float soundVolume = 1.0f;
+static int soundEnableFlag = 0x3ff; // emulator channels enabled
+static float soundFiltering_ = -1;
+static float soundVolume_ = -1;
+
+void interp_rate() { /* empty for now */ }
+
+class Gba_Pcm {
+public:
+ void init();
+ void apply_control( int idx );
+ void update( int dac );
+ void end_frame( blip_time_t );
+
+private:
+ Blip_Buffer* output;
+ blip_time_t last_time;
+ int last_amp;
+ int shift;
+};
+
+class Gba_Pcm_Fifo {
+public:
+ int which;
+ Gba_Pcm pcm;
+
+ void write_control( int data );
+ void write_fifo( int data );
+ void timer_overflowed( int which_timer );
+
+ // public only so save state routines can access it
+ int readIndex;
+ int count;
+ int writeIndex;
+ u8 fifo [32];
+ int dac;
+private:
+
+ int timer;
+ bool enabled;
+};
+
+static Gba_Pcm_Fifo pcm [2];
+static Gb_Apu* gb_apu;
+static Stereo_Buffer* stereo_buffer;
+
+static Blip_Synth<blip_best_quality,1> pcm_synth [3]; // 32 kHz, 16 kHz, 8 kHz
+
+static inline blip_time_t blip_time()
+{
+ return SOUND_CLOCK_TICKS - soundTicks;
+}
+
+void Gba_Pcm::init()
+{
+ output = 0;
+ last_time = 0;
+ last_amp = 0;
+ shift = 0;
+}
+
+void Gba_Pcm::apply_control( int idx )
+{
+ shift = ~ioMem [SGCNT0_H] >> (2 + idx) & 1;
+
+ int ch = 0;
+ if ( (soundEnableFlag >> idx & 0x100) && (ioMem [NR52] & 0x80) )
+ ch = ioMem [SGCNT0_H+1] >> (idx * 4) & 3;
+
+ Blip_Buffer* out = 0;
+ switch ( ch )
+ {
+ case 1: out = stereo_buffer->right(); break;
+ case 2: out = stereo_buffer->left(); break;
+ case 3: out = stereo_buffer->center(); break;
+ }
+
+ if ( output != out )
+ {
+ if ( output )
+ {
+ output->set_modified();
+ pcm_synth [0].offset( blip_time(), -last_amp, output );
+ }
+ last_amp = 0;
+ output = out;
+ }
+}
+
+void Gba_Pcm::end_frame( blip_time_t time )
+{
+ last_time -= time;
+ if ( last_time < -2048 )
+ last_time = -2048;
+
+ if ( output )
+ output->set_modified();
+}
+
+void Gba_Pcm::update( int dac )
+{
+ if ( output )
+ {
+ blip_time_t time = blip_time();
+
+ dac = (s8) dac >> shift;
+ int delta = dac - last_amp;
+ if ( delta )
+ {
+ last_amp = dac;
+
+ int filter = 0;
+ if ( soundInterpolation )
+ {
+ // base filtering on how long since last sample was output
+ int period = time - last_time;
+
+ int idx = (unsigned) period / 512;
+ if ( idx >= 3 )
+ idx = 3;
+
+ static int const filters [4] = { 0, 0, 1, 2 };
+ filter = filters [idx];
+ }
+
+ pcm_synth [filter].offset( time, delta, output );
+ }
+ last_time = time;
+ }
+}
+
+void Gba_Pcm_Fifo::timer_overflowed( int which_timer )
+{
+ if ( which_timer == timer && enabled )
+ {
+ if ( count <= 16 )
+ {
+ // Need to fill FIFO
+ CPUCheckDMA( 3, which ? 4 : 2 );
+ if ( count <= 16 )
+ {
+ // Not filled by DMA, so fill with 16 bytes of silence
+ int reg = which ? FIFOB_L : FIFOA_L;
+ for ( int n = 4; n--; )
+ {
+ soundEvent(reg , (u16)0);
+ soundEvent(reg+2, (u16)0);
+ }
+ }
+ }
+
+ // Read next sample from FIFO
+ count--;
+ dac = fifo [readIndex];
+ readIndex = (readIndex + 1) & 31;
+ pcm.update( dac );
+ }
+}
+
+void Gba_Pcm_Fifo::write_control( int data )
+{
+ enabled = (data & 0x0300) ? true : false;
+ timer = (data & 0x0400) ? 1 : 0;
+
+ if ( data & 0x0800 )
+ {
+ // Reset
+ writeIndex = 0;
+ readIndex = 0;
+ count = 0;
+ dac = 0;
+ memset( fifo, 0, sizeof fifo );
+ }
+
+ pcm.apply_control( which );
+ pcm.update( dac );
+}
+
+void Gba_Pcm_Fifo::write_fifo( int data )
+{
+ fifo [writeIndex ] = data & 0xFF;
+ fifo [writeIndex+1] = data >> 8;
+ count += 2;
+ writeIndex = (writeIndex + 2) & 31;
+}
+
+static void apply_control()
+{
+ pcm [0].pcm.apply_control( 0 );
+ pcm [1].pcm.apply_control( 1 );
+}
+
+static int gba_to_gb_sound( int addr )
+{
+ static const int table [0x40] =
+ {
+ 0xFF10, 0,0xFF11,0xFF12,0xFF13,0xFF14, 0, 0,
+ 0xFF16,0xFF17, 0, 0,0xFF18,0xFF19, 0, 0,
+ 0xFF1A, 0,0xFF1B,0xFF1C,0xFF1D,0xFF1E, 0, 0,
+ 0xFF20,0xFF21, 0, 0,0xFF22,0xFF23, 0, 0,
+ 0xFF24,0xFF25, 0, 0,0xFF26, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,
+ 0xFF38,0xFF39,0xFF3A,0xFF3B,0xFF3C,0xFF3D,0xFF3E,0xFF3F,
+ };
+ if ( addr >= 0x60 && addr < 0xA0 )
+ return table [addr - 0x60];
+ return 0;
+}
+
+void soundEvent(u32 address, u8 data)
+{
+ int gb_addr = gba_to_gb_sound( address );
+ if ( gb_addr )
+ {
+ ioMem[address] = data;
+ gb_apu->write_register( blip_time(), gb_addr, data );
+
+ if ( address == NR52 )
+ apply_control();
+ }
+
+ ioMem[NR52] = (ioMem[NR52] & 0x80) | (gb_apu->read_status() & 0x7f);
+
+ // TODO: what about byte writes to SGCNT0_H etc.?
+}
+
+static void apply_volume( bool apu_only = false )
+{
+ if ( !apu_only )
+ soundVolume_ = soundVolume;
+
+ if ( gb_apu )
+ {
+ static float const apu_vols [4] = { 0.25, 0.5, 1, 0.25 };
+ gb_apu->volume( soundVolume_ * apu_vols [ioMem [SGCNT0_H] & 3] );
+ }
+
+ if ( !apu_only )
+ {
+ for ( int i = 0; i < 3; i++ )
+ pcm_synth [i].volume( 0.66 / 256 * soundVolume_ );
+ }
+}
+
+static void write_SGCNT0_H( int data )
+{
+ WRITE16LE( &ioMem [SGCNT0_H], data & 0x770F );
+ pcm [0].write_control( data );
+ pcm [1].write_control( data >> 4 );
+ apply_volume( true );
+}
+
+void soundEvent(u32 address, u16 data)
+{
+ switch ( address )
+ {
+ case SGCNT0_H:
+ write_SGCNT0_H( data );
+ break;
+
+ case FIFOA_L:
+ case FIFOA_H:
+ pcm [0].write_fifo( data );
+ WRITE16LE( &ioMem[address], data );
+ break;
+
+ case FIFOB_L:
+ case FIFOB_H:
+ pcm [1].write_fifo( data );
+ WRITE16LE( &ioMem[address], data );
+ break;
+
+ case 0x88:
+ data &= 0xC3FF;
+ WRITE16LE( &ioMem[address], data );
+ break;
+
+ default:
+ soundEvent( address & ~1, (u8) (data ) ); // even
+ soundEvent( address | 1, (u8) (data >> 8) ); // odd
+ break;
+ }
+}
+
+void soundTimerOverflow(int timer)
+{
+ pcm [0].timer_overflowed( timer );
+ pcm [1].timer_overflowed( timer );
+}
+
+static void end_frame( blip_time_t time )
+{
+ pcm [0].pcm.end_frame( time );
+ pcm [1].pcm.end_frame( time );
+
+ gb_apu ->end_frame( time );
+ stereo_buffer->end_frame( time );
+}
+
+void flush_samples(Multi_Buffer * buffer)
+{
+ // We want to write the data frame by frame to support legacy audio drivers
+ // that don't use the length parameter of the write method.
+ // TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the
+ // samples at once to help reducing the audio delay on all platforms.
+ int soundBufferLen = ( soundSampleRate / 60 ) * 4;
+
+ // soundBufferLen should have a whole number of sample pairs
+ assert( soundBufferLen % (2 * sizeof *soundFinalWave) == 0 );
+
+ // number of samples in output buffer
+ int const out_buf_size = soundBufferLen / sizeof *soundFinalWave;
+
+ // Keep filling and writing soundFinalWave until it can't be fully filled
+ while ( buffer->samples_avail() >= out_buf_size )
+ {
+ buffer->read_samples( (blip_sample_t*) soundFinalWave, out_buf_size );
+ if(soundPaused)
+ soundResume();
+
+ soundDriver->write(soundFinalWave, soundBufferLen);
+ //systemOnWriteDataToSoundBuffer(soundFinalWave, soundBufferLen);
+ }
+}
+
+static void apply_filtering()
+{
+ soundFiltering_ = soundFiltering;
+
+ int const base_freq = (int) (32768 - soundFiltering_ * 16384);
+ int const nyquist = stereo_buffer->sample_rate() / 2;
+
+ for ( int i = 0; i < 3; i++ )
+ {
+ int cutoff = base_freq >> i;
+ if ( cutoff > nyquist )
+ cutoff = nyquist;
+ pcm_synth [i].treble_eq( blip_eq_t( 0, 0, stereo_buffer->sample_rate(), cutoff ) );
+ }
+}
+
+void psoundTickfn()
+{
+ if ( gb_apu && stereo_buffer )
+ {
+ // Run sound hardware to present
+ end_frame( SOUND_CLOCK_TICKS );
+
+ flush_samples(stereo_buffer);
+
+ if ( soundFiltering_ != soundFiltering )
+ apply_filtering();
+
+ if ( soundVolume_ != soundVolume )
+ apply_volume();
+ }
+
+ ioMem[NR52] = (ioMem[NR52] & 0x80) | (gb_apu->read_status() & 0x7f);
+}
+
+static void apply_muting()
+{
+ if ( !stereo_buffer || !ioMem )
+ return;
+
+ // PCM
+ apply_control();
+
+ if ( gb_apu )
+ {
+ // APU
+ for ( int i = 0; i < 4; i++ )
+ {
+ if ( soundEnableFlag >> i & 1 )
+ gb_apu->set_output( stereo_buffer->center(),
+ stereo_buffer->left(), stereo_buffer->right(), i );
+ else
+ gb_apu->set_output( 0, 0, 0, i );
+ }
+ }
+}
+
+static void reset_apu()
+{
+ gb_apu->reset( gb_apu->mode_agb, true );
+
+ if ( stereo_buffer )
+ stereo_buffer->clear();
+
+ soundTicks = SOUND_CLOCK_TICKS;
+}
+
+static void remake_stereo_buffer()
+{
+ if ( !ioMem )
+ return;
+
+ // Clears pointers kept to old stereo_buffer
+ pcm [0].pcm.init();
+ pcm [1].pcm.init();
+
+ // Stereo_Buffer
+ delete stereo_buffer;
+ stereo_buffer = 0;
+
+ stereo_buffer = new Stereo_Buffer; // TODO: handle out of memory
+ stereo_buffer->set_sample_rate( soundSampleRate ); // TODO: handle out of memory
+ stereo_buffer->clock_rate( gb_apu->clock_rate );
+
+ // PCM
+ pcm [0].which = 0;
+ pcm [1].which = 1;
+ apply_filtering();
+
+ // APU
+ if ( !gb_apu )
+ {
+ gb_apu = new Gb_Apu; // TODO: handle out of memory
+ reset_apu();
+ }
+
+ apply_muting();
+ apply_volume();
+}
+
+void soundShutdown()
+{
+ if (soundDriver)
+ {
+ delete soundDriver;
+ soundDriver = 0;
+ }
+
+ //systemOnSoundShutdown();
+}
+
+void soundPause()
+{
+ soundPaused = true;
+ if (soundDriver)
+ soundDriver->pause();
+}
+
+void soundResume()
+{
+ soundPaused = false;
+ if (soundDriver)
+ soundDriver->resume();
+}
+
+void soundSetVolume( float volume )
+{
+ soundVolume = volume;
+}
+
+float soundGetVolume()
+{
+ return soundVolume;
+}
+
+void soundSetEnable(int channels)
+{
+ soundEnableFlag = channels;
+ apply_muting();
+}
+
+int soundGetEnable()
+{
+ return (soundEnableFlag & 0x30f);
+}
+
+void soundReset()
+{
+ soundDriver->reset();
+
+ remake_stereo_buffer();
+ reset_apu();
+
+ soundPaused = true;
+ SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_;
+ soundTicks = SOUND_CLOCK_TICKS_;
+
+ soundEvent( NR52, (u8) 0x80 );
+}
+
+bool soundInit()
+{
+ soundDriver = systemSoundInit();
+ if ( !soundDriver )
+ return false;
+
+ if (!soundDriver->init(soundSampleRate))
+ return false;
+
+ soundPaused = true;
+ return true;
+}
+
+void soundSetThrottle(unsigned short throttle)
+{
+ if(!soundDriver)
+ return;
+ soundDriver->setThrottle(throttle);
+}
+
+long soundGetSampleRate()
+{
+ return soundSampleRate;
+}
+
+void soundSetSampleRate(long sampleRate)
+{
+ if ( soundSampleRate != sampleRate )
+ {
+ /*if ( systemCanChangeSoundQuality() )
+ {
+ soundShutdown();
+ soundSampleRate = sampleRate;
+ soundInit();
+ }
+ else*/
+ {
+ soundSampleRate = sampleRate;
+ }
+
+ remake_stereo_buffer();
+ }
+}
+
+/*static int dummy_state [16];
+
+#define SKIP( type, name ) { dummy_state, sizeof (type) }
+
+#define LOAD( type, name ) { &name, sizeof (type) }
+
+static struct {
+ gb_apu_state_t apu;
+
+ // old state
+ u8 soundDSAValue;
+ int soundDSBValue;
+} state;
+
+// Old GBA sound state format
+static variable_desc old_gba_state [] =
+{
+ SKIP( int, soundPaused ),
+ SKIP( int, soundPlay ),
+ SKIP( int, soundTicks ),
+ SKIP( int, SOUND_CLOCK_TICKS ),
+ SKIP( int, soundLevel1 ),
+ SKIP( int, soundLevel2 ),
+ SKIP( int, soundBalance ),
+ SKIP( int, soundMasterOn ),
+ SKIP( int, soundIndex ),
+ SKIP( int, sound1On ),
+ SKIP( int, sound1ATL ),
+ SKIP( int, sound1Skip ),
+ SKIP( int, sound1Index ),
+ SKIP( int, sound1Continue ),
+ SKIP( int, sound1EnvelopeVolume ),
+ SKIP( int, sound1EnvelopeATL ),
+ SKIP( int, sound1EnvelopeATLReload ),
+ SKIP( int, sound1EnvelopeUpDown ),
+ SKIP( int, sound1SweepATL ),
+ SKIP( int, sound1SweepATLReload ),
+ SKIP( int, sound1SweepSteps ),
+ SKIP( int, sound1SweepUpDown ),
+ SKIP( int, sound1SweepStep ),
+ SKIP( int, sound2On ),
+ SKIP( int, sound2ATL ),
+ SKIP( int, sound2Skip ),
+ SKIP( int, sound2Index ),
+ SKIP( int, sound2Continue ),
+ SKIP( int, sound2EnvelopeVolume ),
+ SKIP( int, sound2EnvelopeATL ),
+ SKIP( int, sound2EnvelopeATLReload ),
+ SKIP( int, sound2EnvelopeUpDown ),
+ SKIP( int, sound3On ),
+ SKIP( int, sound3ATL ),
+ SKIP( int, sound3Skip ),
+ SKIP( int, sound3Index ),
+ SKIP( int, sound3Continue ),
+ SKIP( int, sound3OutputLevel ),
+ SKIP( int, sound4On ),
+ SKIP( int, sound4ATL ),
+ SKIP( int, sound4Skip ),
+ SKIP( int, sound4Index ),
+ SKIP( int, sound4Clock ),
+ SKIP( int, sound4ShiftRight ),
+ SKIP( int, sound4ShiftSkip ),
+ SKIP( int, sound4ShiftIndex ),
+ SKIP( int, sound4NSteps ),
+ SKIP( int, sound4CountDown ),
+ SKIP( int, sound4Continue ),
+ SKIP( int, sound4EnvelopeVolume ),
+ SKIP( int, sound4EnvelopeATL ),
+ SKIP( int, sound4EnvelopeATLReload ),
+ SKIP( int, sound4EnvelopeUpDown ),
+ LOAD( int, soundEnableFlag ),
+ SKIP( int, soundControl ),
+ LOAD( int, pcm [0].readIndex ),
+ LOAD( int, pcm [0].count ),
+ LOAD( int, pcm [0].writeIndex ),
+ SKIP( u8, soundDSAEnabled ), // was bool, which was one byte on MS compiler
+ SKIP( int, soundDSATimer ),
+ LOAD( u8 [32], pcm [0].fifo ),
+ LOAD( u8, state.soundDSAValue ),
+ LOAD( int, pcm [1].readIndex ),
+ LOAD( int, pcm [1].count ),
+ LOAD( int, pcm [1].writeIndex ),
+ SKIP( int, soundDSBEnabled ),
+ SKIP( int, soundDSBTimer ),
+ LOAD( u8 [32], pcm [1].fifo ),
+ LOAD( int, state.soundDSBValue ),
+
+ // skipped manually
+ //LOAD( int, soundBuffer[0][0], 6*735 },
+ //LOAD( int, soundFinalWave[0], 2*735 },
+ { NULL, 0 }
+};
+
+variable_desc old_gba_state2 [] =
+{
+ LOAD( u8 [0x20], state.apu.regs [0x20] ),
+ SKIP( int, sound3Bank ),
+ SKIP( int, sound3DataSize ),
+ SKIP( int, sound3ForcedOutput ),
+ { NULL, 0 }
+};
+
+// New state format
+static variable_desc gba_state [] =
+{
+ // PCM
+ LOAD( int, pcm [0].readIndex ),
+ LOAD( int, pcm [0].count ),
+ LOAD( int, pcm [0].writeIndex ),
+ LOAD(u8[32],pcm[0].fifo ),
+ LOAD( int, pcm [0].dac ),
+
+ SKIP( int [4], room_for_expansion ),
+
+ LOAD( int, pcm [1].readIndex ),
+ LOAD( int, pcm [1].count ),
+ LOAD( int, pcm [1].writeIndex ),
+ LOAD(u8[32],pcm[1].fifo ),
+ LOAD( int, pcm [1].dac ),
+
+ SKIP( int [4], room_for_expansion ),
+
+ // APU
+ LOAD( u8 [0x40], state.apu.regs ), // last values written to registers and wave RAM (both banks)
+ LOAD( int, state.apu.frame_time ), // clocks until next frame sequencer action
+ LOAD( int, state.apu.frame_phase ), // next step frame sequencer will run
+
+ LOAD( int, state.apu.sweep_freq ), // sweep's internal frequency register
+ LOAD( int, state.apu.sweep_delay ), // clocks until next sweep action
+ LOAD( int, state.apu.sweep_enabled ),
+ LOAD( int, state.apu.sweep_neg ), // obscure internal flag
+ LOAD( int, state.apu.noise_divider ),
+ LOAD( int, state.apu.wave_buf ), // last read byte of wave RAM
+
+ LOAD( int [4], state.apu.delay ), // clocks until next channel action
+ LOAD( int [4], state.apu.length_ctr ),
+ LOAD( int [4], state.apu.phase ), // square/wave phase, noise LFSR
+ LOAD( int [4], state.apu.enabled ), // internal enabled flag
+
+ LOAD( int [3], state.apu.env_delay ), // clocks until next envelope action
+ LOAD( int [3], state.apu.env_volume ),
+ LOAD( int [3], state.apu.env_enabled ),
+
+ SKIP( int [13], room_for_expansion ),
+
+ // Emulator
+ LOAD( int, soundEnableFlag ),
+
+ SKIP( int [15], room_for_expansion ),
+
+ { NULL, 0 }
+};
+
+// Reads and discards count bytes from in
+static void skip_read( gzFile in, int count )
+{
+ char buf [512];
+
+ while ( count )
+ {
+ int n = sizeof buf;
+ if ( n > count )
+ n = count;
+
+ count -= n;
+ utilGzRead( in, buf, n );
+ }
+}
+
+void soundSaveGame( gzFile out )
+{
+ gb_apu->save_state( &state.apu );
+
+ // Be sure areas for expansion get written as zero
+ memset( dummy_state, 0, sizeof dummy_state );
+
+ utilWriteData( out, gba_state );
+}
+
+static void soundReadGameOld( gzFile in, int version )
+{
+ // Read main data
+ utilReadData( in, old_gba_state );
+ skip_read( in, 6*735 + 2*735 );
+
+ // Copy APU regs
+ static int const regs_to_copy [] = {
+ NR10, NR11, NR12, NR13, NR14,
+ NR21, NR22, NR23, NR24,
+ NR30, NR31, NR32, NR33, NR34,
+ NR41, NR42, NR43, NR44,
+ NR50, NR51, NR52, -1
+ };
+
+ ioMem [NR52] |= 0x80; // old sound played even when this wasn't set (power on)
+
+ for ( int i = 0; regs_to_copy [i] >= 0; i++ )
+ state.apu.regs [gba_to_gb_sound( regs_to_copy [i] ) - 0xFF10] = ioMem [regs_to_copy [i]];
+
+ // Copy wave RAM to both banks
+ memcpy( &state.apu.regs [0x20], &ioMem [0x90], 0x10 );
+ memcpy( &state.apu.regs [0x30], &ioMem [0x90], 0x10 );
+
+ // Read both banks of wave RAM if available
+ if ( version >= SAVE_GAME_VERSION_3 )
+ utilReadData( in, old_gba_state2 );
+
+ // Restore PCM
+ pcm [0].dac = state.soundDSAValue;
+ pcm [1].dac = state.soundDSBValue;
+
+ (void) utilReadInt( in ); // ignore quality
+}
+
+#include <stdio.h>
+
+void soundReadGame( gzFile in, int version )
+{
+ // Prepare APU and default state
+ reset_apu();
+ gb_apu->save_state( &state.apu );
+
+ if ( version > SAVE_GAME_VERSION_9 )
+ utilReadData( in, gba_state );
+ else
+ soundReadGameOld( in, version );
+
+ gb_apu->load_state( state.apu );
+ write_SGCNT0_H( READ16LE( &ioMem [SGCNT0_H] ) & 0x770F );
+
+ apply_muting();
+}*/
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/Sound.h
@@ -1,1 +1,86 @@
+#ifndef SOUND_H
+#define SOUND_H
+// Sound emulation setup/options and GBA sound emulation
+
+//#include "../System.h"
+#include "../common/Types.h"
+
+//// Setup/options (these affect GBA and GB sound)
+
+// Initializes sound and returns true if successful. Sets sound quality to
+// current value in soundQuality global.
+bool soundInit();
+
+// sets the Sound throttle
+void soundSetThrottle(unsigned short throttle);
+
+// Manages sound volume, where 1.0 is normal
+void soundSetVolume( float );
+float soundGetVolume();
+
+// Manages muting bitmask. The bits control the following channels:
+// 0x001 Pulse 1
+// 0x002 Pulse 2
+// 0x004 Wave
+// 0x008 Noise
+// 0x100 PCM 1
+// 0x200 PCM 2
+void soundSetEnable( int mask );
+int soundGetEnable();
+
+// Pauses/resumes system sound output
+void soundPause();
+void soundResume();
+extern bool soundPaused; // current paused state
+
+// Cleans up sound. Afterwards, soundInit() can be called again.
+void soundShutdown();
+
+//// GBA sound options
+
+long soundGetSampleRate();
+void soundSetSampleRate(long sampleRate);
+
+// Sound settings
+extern bool soundInterpolation; // 1 if PCM should have low-pass filtering
+extern float soundFiltering; // 0.0 = none, 1.0 = max
+
+
+//// GBA sound emulation
+
+// GBA sound registers
+#define SGCNT0_H 0x82
+#define FIFOA_L 0xa0
+#define FIFOA_H 0xa2
+#define FIFOB_L 0xa4
+#define FIFOB_H 0xa6
+
+// Resets emulated sound hardware
+void soundReset();
+
+// Emulates write to sound hardware
+void soundEvent( u32 addr, u8 data );
+void soundEvent( u32 addr, u16 data ); // TODO: error-prone to overload like this
+
+// Notifies emulator that a timer has overflowed
+void soundTimerOverflow( int which );
+
+// Notifies emulator that PCM rate may have changed
+void interp_rate();
+
+// Notifies emulator that SOUND_CLOCK_TICKS clocks have passed
+void psoundTickfn();
+extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to soundTick()
+extern int soundTicks; // Number of 16.8 MHz clocks until soundTick() will be called
+
+// Saves/loads emulator state
+//void soundSaveGame( gzFile );
+//void soundReadGame( gzFile, int version );
+
+class Multi_Buffer;
+
+void flush_samples(Multi_Buffer * buffer);
+
+#endif // SOUND_H
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/bios.cpp
@@ -1,1 +1,1148 @@
-
+#include <math.h>
+#include <memory.h>
+#include <stdlib.h>
+
+#include "GBA.h"
+#include "bios.h"
+#include "GBAinline.h"
+#include "Globals.h"
+
+s16 sineTable[256] = {
+ (s16)0x0000, (s16)0x0192, (s16)0x0323, (s16)0x04B5, (s16)0x0645, (s16)0x07D5, (s16)0x0964, (s16)0x0AF1,
+ (s16)0x0C7C, (s16)0x0E05, (s16)0x0F8C, (s16)0x1111, (s16)0x1294, (s16)0x1413, (s16)0x158F, (s16)0x1708,
+ (s16)0x187D, (s16)0x19EF, (s16)0x1B5D, (s16)0x1CC6, (s16)0x1E2B, (s16)0x1F8B, (s16)0x20E7, (s16)0x223D,
+ (s16)0x238E, (s16)0x24DA, (s16)0x261F, (s16)0x275F, (s16)0x2899, (s16)0x29CD, (s16)0x2AFA, (s16)0x2C21,
+ (s16)0x2D41, (s16)0x2E5A, (s16)0x2F6B, (s16)0x3076, (s16)0x3179, (s16)0x3274, (s16)0x3367, (s16)0x3453,
+ (s16)0x3536, (s16)0x3612, (s16)0x36E5, (s16)0x37AF, (s16)0x3871, (s16)0x392A, (s16)0x39DA, (s16)0x3A82,
+ (s16)0x3B20, (s16)0x3BB6, (s16)0x3C42, (s16)0x3CC5, (s16)0x3D3E, (s16)0x3DAE, (s16)0x3E14, (s16)0x3E71,
+ (s16)0x3EC5, (s16)0x3F0E, (s16)0x3F4E, (s16)0x3F84, (s16)0x3FB1, (s16)0x3FD3, (s16)0x3FEC, (s16)0x3FFB,
+ (s16)0x4000, (s16)0x3FFB, (s16)0x3FEC, (s16)0x3FD3, (s16)0x3FB1, (s16)0x3F84, (s16)0x3F4E, (s16)0x3F0E,
+ (s16)0x3EC5, (s16)0x3E71, (s16)0x3E14, (s16)0x3DAE, (s16)0x3D3E, (s16)0x3CC5, (s16)0x3C42, (s16)0x3BB6,
+ (s16)0x3B20, (s16)0x3A82, (s16)0x39DA, (s16)0x392A, (s16)0x3871, (s16)0x37AF, (s16)0x36E5, (s16)0x3612,
+ (s16)0x3536, (s16)0x3453, (s16)0x3367, (s16)0x3274, (s16)0x3179, (s16)0x3076, (s16)0x2F6B, (s16)0x2E5A,
+ (s16)0x2D41, (s16)0x2C21, (s16)0x2AFA, (s16)0x29CD, (s16)0x2899, (s16)0x275F, (s16)0x261F, (s16)0x24DA,
+ (s16)0x238E, (s16)0x223D, (s16)0x20E7, (s16)0x1F8B, (s16)0x1E2B, (s16)0x1CC6, (s16)0x1B5D, (s16)0x19EF,
+ (s16)0x187D, (s16)0x1708, (s16)0x158F, (s16)0x1413, (s16)0x1294, (s16)0x1111, (s16)0x0F8C, (s16)0x0E05,
+ (s16)0x0C7C, (s16)0x0AF1, (s16)0x0964, (s16)0x07D5, (s16)0x0645, (s16)0x04B5, (s16)0x0323, (s16)0x0192,
+ (s16)0x0000, (s16)0xFE6E, (s16)0xFCDD, (s16)0xFB4B, (s16)0xF9BB, (s16)0xF82B, (s16)0xF69C, (s16)0xF50F,
+ (s16)0xF384, (s16)0xF1FB, (s16)0xF074, (s16)0xEEEF, (s16)0xED6C, (s16)0xEBED, (s16)0xEA71, (s16)0xE8F8,
+ (s16)0xE783, (s16)0xE611, (s16)0xE4A3, (s16)0xE33A, (s16)0xE1D5, (s16)0xE075, (s16)0xDF19, (s16)0xDDC3,
+ (s16)0xDC72, (s16)0xDB26, (s16)0xD9E1, (s16)0xD8A1, (s16)0xD767, (s16)0xD633, (s16)0xD506, (s16)0xD3DF,
+ (s16)0xD2BF, (s16)0xD1A6, (s16)0xD095, (s16)0xCF8A, (s16)0xCE87, (s16)0xCD8C, (s16)0xCC99, (s16)0xCBAD,
+ (s16)0xCACA, (s16)0xC9EE, (s16)0xC91B, (s16)0xC851, (s16)0xC78F, (s16)0xC6D6, (s16)0xC626, (s16)0xC57E,
+ (s16)0xC4E0, (s16)0xC44A, (s16)0xC3BE, (s16)0xC33B, (s16)0xC2C2, (s16)0xC252, (s16)0xC1EC, (s16)0xC18F,
+ (s16)0xC13B, (s16)0xC0F2, (s16)0xC0B2, (s16)0xC07C, (s16)0xC04F, (s16)0xC02D, (s16)0xC014, (s16)0xC005,
+ (s16)0xC000, (s16)0xC005, (s16)0xC014, (s16)0xC02D, (s16)0xC04F, (s16)0xC07C, (s16)0xC0B2, (s16)0xC0F2,
+ (s16)0xC13B, (s16)0xC18F, (s16)0xC1EC, (s16)0xC252, (s16)0xC2C2, (s16)0xC33B, (s16)0xC3BE, (s16)0xC44A,
+ (s16)0xC4E0, (s16)0xC57E, (s16)0xC626, (s16)0xC6D6, (s16)0xC78F, (s16)0xC851, (s16)0xC91B, (s16)0xC9EE,
+ (s16)0xCACA, (s16)0xCBAD, (s16)0xCC99, (s16)0xCD8C, (s16)0xCE87, (s16)0xCF8A, (s16)0xD095, (s16)0xD1A6,
+ (s16)0xD2BF, (s16)0xD3DF, (s16)0xD506, (s16)0xD633, (s16)0xD767, (s16)0xD8A1, (s16)0xD9E1, (s16)0xDB26,
+ (s16)0xDC72, (s16)0xDDC3, (s16)0xDF19, (s16)0xE075, (s16)0xE1D5, (s16)0xE33A, (s16)0xE4A3, (s16)0xE611,
+ (s16)0xE783, (s16)0xE8F8, (s16)0xEA71, (s16)0xEBED, (s16)0xED6C, (s16)0xEEEF, (s16)0xF074, (s16)0xF1FB,
+ (s16)0xF384, (s16)0xF50F, (s16)0xF69C, (s16)0xF82B, (s16)0xF9BB, (s16)0xFB4B, (s16)0xFCDD, (s16)0xFE6E
+};
+
+void BIOS_ArcTan()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("ArcTan: %08x (VCOUNT=%2d)\n",
+ reg[0].I,
+ VCOUNT);
+ }
+#endif
+
+ s32 a = -(((s32)(reg[0].I*reg[0].I)) >> 14);
+ s32 b = ((0xA9 * a) >> 14) + 0x390;
+ b = ((b * a) >> 14) + 0x91C;
+ b = ((b * a) >> 14) + 0xFB6;
+ b = ((b * a) >> 14) + 0x16AA;
+ b = ((b * a) >> 14) + 0x2081;
+ b = ((b * a) >> 14) + 0x3651;
+ b = ((b * a) >> 14) + 0xA2F9;
+ a = ((s32)reg[0].I * b) >> 16;
+ reg[0].I = a;
+
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("ArcTan: return=%08x\n",
+ reg[0].I);
+ }
+#endif
+}
+
+void BIOS_ArcTan2()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("ArcTan2: %08x,%08x (VCOUNT=%2d)\n",
+ reg[0].I,
+ reg[1].I,
+ VCOUNT);
+ }
+#endif
+
+ s32 x = reg[0].I;
+ s32 y = reg[1].I;
+ u32 res = 0;
+ if (y == 0) {
+ res = ((x>>16) & 0x8000);
+ } else {
+ if (x == 0) {
+ res = ((y>>16) & 0x8000) + 0x4000;
+ } else {
+ if ((abs(x) > abs(y)) || ((abs(x) == abs(y)) && (!((x<0) && (y<0))))) {
+ reg[1].I = x;
+ reg[0].I = y << 14;
+ BIOS_Div();
+ BIOS_ArcTan();
+ if (x < 0)
+ res = 0x8000 + reg[0].I;
+ else
+ res = (((y>>16) & 0x8000)<<1) + reg[0].I;
+ } else {
+ reg[0].I = x << 14;
+ BIOS_Div();
+ BIOS_ArcTan();
+ res = (0x4000 + ((y>>16) & 0x8000)) - reg[0].I;
+ }
+ }
+ }
+ reg[0].I = res;
+
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("ArcTan2: return=%08x\n",
+ reg[0].I);
+ }
+#endif
+}
+
+void BIOS_BitUnPack()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("BitUnPack: %08x,%08x,%08x (VCOUNT=%2d)\n",
+ reg[0].I,
+ reg[1].I,
+ reg[2].I,
+ VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+ u32 header = reg[2].I;
+
+ int len = CPUReadHalfWord(header);
+ // check address
+ if(((source & 0xe000000) == 0) ||
+ ((source + len) & 0xe000000) == 0)
+ return;
+
+ int bits = CPUReadByte(header+2);
+ int revbits = 8 - bits;
+ // u32 value = 0;
+ u32 base = CPUReadMemory(header+4);
+ bool addBase = (base & 0x80000000) ? true : false;
+ base &= 0x7fffffff;
+ int dataSize = CPUReadByte(header+3);
+
+ int data = 0;
+ int bitwritecount = 0;
+ while(1) {
+ len -= 1;
+ if(len < 0)
+ break;
+ int mask = 0xff >> revbits;
+ u8 b = CPUReadByte(source);
+ source++;
+ int bitcount = 0;
+ while(1) {
+ if(bitcount >= 8)
+ break;
+ u32 d = b & mask;
+ u32 temp = d >> bitcount;
+ if(d || addBase) {
+ temp += base;
+ }
+ data |= temp << bitwritecount;
+ bitwritecount += dataSize;
+ if(bitwritecount >= 32) {
+ CPUWriteMemory(dest, data);
+ dest += 4;
+ data = 0;
+ bitwritecount = 0;
+ }
+ mask <<= bits;
+ bitcount += bits;
+ }
+ }
+}
+
+void BIOS_GetBiosChecksum()
+{
+ reg[0].I=0xBAAE187F;
+}
+
+void BIOS_BgAffineSet()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("BgAffineSet: %08x,%08x,%08x (VCOUNT=%2d)\n",
+ reg[0].I,
+ reg[1].I,
+ reg[2].I,
+ VCOUNT);
+ }
+#endif
+
+ u32 src = reg[0].I;
+ u32 dest = reg[1].I;
+ int num = reg[2].I;
+
+ for(int i = 0; i < num; i++) {
+ s32 cx = CPUReadMemory(src);
+ src+=4;
+ s32 cy = CPUReadMemory(src);
+ src+=4;
+ s16 dispx = CPUReadHalfWord(src);
+ src+=2;
+ s16 dispy = CPUReadHalfWord(src);
+ src+=2;
+ s16 rx = CPUReadHalfWord(src);
+ src+=2;
+ s16 ry = CPUReadHalfWord(src);
+ src+=2;
+ u16 theta = CPUReadHalfWord(src)>>8;
+ src+=4; // keep structure alignment
+ s32 a = sineTable[(theta+0x40)&255];
+ s32 b = sineTable[theta];
+
+ s16 dx = (rx * a)>>14;
+ s16 dmx = (rx * b)>>14;
+ s16 dy = (ry * b)>>14;
+ s16 dmy = (ry * a)>>14;
+
+ CPUWriteHalfWord(dest, dx);
+ dest += 2;
+ CPUWriteHalfWord(dest, -dmx);
+ dest += 2;
+ CPUWriteHalfWord(dest, dy);
+ dest += 2;
+ CPUWriteHalfWord(dest, dmy);
+ dest += 2;
+
+ s32 startx = cx - dx * dispx + dmx * dispy;
+ s32 starty = cy - dy * dispx - dmy * dispy;
+
+ CPUWriteMemory(dest, startx);
+ dest += 4;
+ CPUWriteMemory(dest, starty);
+ dest += 4;
+ }
+}
+
+void BIOS_CpuSet()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("CpuSet: 0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I,
+ reg[2].I, VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+ u32 cnt = reg[2].I;
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + (((cnt << 11)>>9) & 0x1fffff)) & 0xe000000) == 0)
+ return;
+
+ int count = cnt & 0x1FFFFF;
+
+ // 32-bit ?
+ if((cnt >> 26) & 1) {
+ // needed for 32-bit mode!
+ source &= 0xFFFFFFFC;
+ dest &= 0xFFFFFFFC;
+ // fill ?
+ if((cnt >> 24) & 1) {
+ u32 value = (source>0x0EFFFFFF ? 0x1CAD1CAD : CPUReadMemory(source));
+ while(count) {
+ CPUWriteMemory(dest, value);
+ dest += 4;
+ count--;
+ }
+ } else {
+ // copy
+ while(count) {
+ CPUWriteMemory(dest, (source>0x0EFFFFFF ? 0x1CAD1CAD : CPUReadMemory(source)));
+ source += 4;
+ dest += 4;
+ count--;
+ }
+ }
+ } else {
+ // 16-bit fill?
+ if((cnt >> 24) & 1) {
+ u16 value = (source>0x0EFFFFFF ? 0x1CAD : CPUReadHalfWord(source));
+ while(count) {
+ CPUWriteHalfWord(dest, value);
+ dest += 2;
+ count--;
+ }
+ } else {
+ // copy
+ while(count) {
+ CPUWriteHalfWord(dest, (source>0x0EFFFFFF ? 0x1CAD : CPUReadHalfWord(source)));
+ source += 2;
+ dest += 2;
+ count--;
+ }
+ }
+ }
+}
+
+void BIOS_CpuFastSet()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("CpuFastSet: 0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I,
+ reg[2].I, VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+ u32 cnt = reg[2].I;
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + (((cnt << 11)>>9) & 0x1fffff)) & 0xe000000) == 0)
+ return;
+
+ // needed for 32-bit mode!
+ source &= 0xFFFFFFFC;
+ dest &= 0xFFFFFFFC;
+
+ int count = cnt & 0x1FFFFF;
+
+ // fill?
+ if((cnt >> 24) & 1) {
+ while(count > 0) {
+ // BIOS always transfers 32 bytes at a time
+ u32 value = (source>0x0EFFFFFF ? 0xBAFFFFFB : CPUReadMemory(source));
+ for(int i = 0; i < 8; i++) {
+ CPUWriteMemory(dest, value);
+ dest += 4;
+ }
+ count -= 8;
+ }
+ } else {
+ // copy
+ while(count > 0) {
+ // BIOS always transfers 32 bytes at a time
+ for(int i = 0; i < 8; i++) {
+ CPUWriteMemory(dest, (source>0x0EFFFFFF ? 0xBAFFFFFB :CPUReadMemory(source)));
+ source += 4;
+ dest += 4;
+ }
+ count -= 8;
+ }
+ }
+}
+
+void BIOS_Diff8bitUnFilterWram()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("Diff8bitUnFilterWram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I,
+ reg[1].I, VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+
+ u32 header = CPUReadMemory(source);
+ source += 4;
+
+ if(((source & 0xe000000) == 0) ||
+ (((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0))
+ return;
+
+ int len = header >> 8;
+
+ u8 data = CPUReadByte(source++);
+ CPUWriteByte(dest++, data);
+ len--;
+
+ while(len > 0) {
+ u8 diff = CPUReadByte(source++);
+ data += diff;
+ CPUWriteByte(dest++, data);
+ len--;
+ }
+}
+
+void BIOS_Diff8bitUnFilterVram()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("Diff8bitUnFilterVram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I,
+ reg[1].I, VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+
+ u32 header = CPUReadMemory(source);
+ source += 4;
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return;
+
+ int len = header >> 8;
+
+ u8 data = CPUReadByte(source++);
+ u16 writeData = data;
+ int shift = 8;
+ int bytes = 1;
+
+ while(len >= 2) {
+ u8 diff = CPUReadByte(source++);
+ data += diff;
+ writeData |= (data << shift);
+ bytes++;
+ shift += 8;
+ if(bytes == 2) {
+ CPUWriteHalfWord(dest, writeData);
+ dest += 2;
+ len -= 2;
+ bytes = 0;
+ writeData = 0;
+ shift = 0;
+ }
+ }
+}
+
+void BIOS_Diff16bitUnFilter()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("Diff16bitUnFilter: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I,
+ reg[1].I, VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+
+ u32 header = CPUReadMemory(source);
+ source += 4;
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return;
+
+ int len = header >> 8;
+
+ u16 data = CPUReadHalfWord(source);
+ source += 2;
+ CPUWriteHalfWord(dest, data);
+ dest += 2;
+ len -= 2;
+
+ while(len >= 2) {
+ u16 diff = CPUReadHalfWord(source);
+ source += 2;
+ data += diff;
+ CPUWriteHalfWord(dest, data);
+ dest += 2;
+ len -= 2;
+ }
+}
+
+void BIOS_Div()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("Div: 0x%08x,0x%08x (VCOUNT=%d)\n",
+ reg[0].I,
+ reg[1].I,
+ VCOUNT);
+ }
+#endif
+
+ int number = reg[0].I;
+ int denom = reg[1].I;
+
+ if(denom != 0) {
+ reg[0].I = number / denom;
+ reg[1].I = number % denom;
+ s32 temp = (s32)reg[0].I;
+ reg[3].I = temp < 0 ? (u32)-temp : (u32)temp;
+ }
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("Div: return=0x%08x,0x%08x,0x%08x\n",
+ reg[0].I,
+ reg[1].I,
+ reg[3].I);
+ }
+#endif
+}
+
+void BIOS_DivARM()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("DivARM: 0x%08x, (VCOUNT=%d)\n",
+ reg[0].I,
+ VCOUNT);
+ }
+#endif
+
+ u32 temp = reg[0].I;
+ reg[0].I = reg[1].I;
+ reg[1].I = temp;
+ BIOS_Div();
+}
+
+void BIOS_HuffUnComp()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("HuffUnComp: 0x%08x,0x%08x (VCOUNT=%d)\n",
+ reg[0].I,
+ reg[1].I,
+ VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+
+ u32 header = CPUReadMemory(source);
+ source += 4;
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return;
+
+ u8 treeSize = CPUReadByte(source++);
+
+ u32 treeStart = source;
+
+ source += ((treeSize+1)<<1)-1; // minus because we already skipped one byte
+
+ int len = header >> 8;
+
+ u32 mask = 0x80000000;
+ u32 data = CPUReadMemory(source);
+ source += 4;
+
+ int pos = 0;
+ u8 rootNode = CPUReadByte(treeStart);
+ u8 currentNode = rootNode;
+ bool writeData = false;
+ int byteShift = 0;
+ int byteCount = 0;
+ u32 writeValue = 0;
+
+ if((header & 0x0F) == 8) {
+ while(len > 0) {
+ // take left
+ if(pos == 0)
+ pos++;
+ else
+ pos += (((currentNode & 0x3F)+1)<<1);
+
+ if(data & mask) {
+ // right
+ if(currentNode & 0x40)
+ writeData = true;
+ currentNode = CPUReadByte(treeStart+pos+1);
+ } else {
+ // left
+ if(currentNode & 0x80)
+ writeData = true;
+ currentNode = CPUReadByte(treeStart+pos);
+ }
+
+ if(writeData) {
+ writeValue |= (currentNode << byteShift);
+ byteCount++;
+ byteShift += 8;
+
+ pos = 0;
+ currentNode = rootNode;
+ writeData = false;
+
+ if(byteCount == 4) {
+ byteCount = 0;
+ byteShift = 0;
+ CPUWriteMemory(dest, writeValue);
+ writeValue = 0;
+ dest += 4;
+ len -= 4;
+ }
+ }
+ mask >>= 1;
+ if(mask == 0) {
+ mask = 0x80000000;
+ data = CPUReadMemory(source);
+ source += 4;
+ }
+ }
+ } else {
+ int halfLen = 0;
+ int value = 0;
+ while(len > 0) {
+ // take left
+ if(pos == 0)
+ pos++;
+ else
+ pos += (((currentNode & 0x3F)+1)<<1);
+
+ if((data & mask)) {
+ // right
+ if(currentNode & 0x40)
+ writeData = true;
+ currentNode = CPUReadByte(treeStart+pos+1);
+ } else {
+ // left
+ if(currentNode & 0x80)
+ writeData = true;
+ currentNode = CPUReadByte(treeStart+pos);
+ }
+
+ if(writeData) {
+ if(halfLen == 0)
+ value |= currentNode;
+ else
+ value |= (currentNode<<4);
+
+ halfLen += 4;
+ if(halfLen == 8) {
+ writeValue |= (value << byteShift);
+ byteCount++;
+ byteShift += 8;
+
+ halfLen = 0;
+ value = 0;
+
+ if(byteCount == 4) {
+ byteCount = 0;
+ byteShift = 0;
+ CPUWriteMemory(dest, writeValue);
+ dest += 4;
+ writeValue = 0;
+ len -= 4;
+ }
+ }
+ pos = 0;
+ currentNode = rootNode;
+ writeData = false;
+ }
+ mask >>= 1;
+ if(mask == 0) {
+ mask = 0x80000000;
+ data = CPUReadMemory(source);
+ source += 4;
+ }
+ }
+ }
+}
+
+void BIOS_LZ77UnCompVram()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("LZ77UnCompVram: 0x%08x,0x%08x (VCOUNT=%d)\n",
+ reg[0].I,
+ reg[1].I,
+ VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+
+ u32 header = CPUReadMemory(source);
+ source += 4;
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return;
+
+ int byteCount = 0;
+ int byteShift = 0;
+ u32 writeValue = 0;
+
+ int len = header >> 8;
+
+ while(len > 0) {
+ u8 d = CPUReadByte(source++);
+
+ if(d) {
+ for(int i = 0; i < 8; i++) {
+ if(d & 0x80) {
+ u16 data = CPUReadByte(source++) << 8;
+ data |= CPUReadByte(source++);
+ int length = (data >> 12) + 3;
+ int offset = (data & 0x0FFF);
+ u32 windowOffset = dest + byteCount - offset - 1;
+ for(int i2 = 0; i2 < length; i2++) {
+ writeValue |= (CPUReadByte(windowOffset++) << byteShift);
+ byteShift += 8;
+ byteCount++;
+
+ if(byteCount == 2) {
+ CPUWriteHalfWord(dest, writeValue);
+ dest += 2;
+ byteCount = 0;
+ byteShift = 0;
+ writeValue = 0;
+ }
+ len--;
+ if(len == 0)
+ return;
+ }
+ } else {
+ writeValue |= (CPUReadByte(source++) << byteShift);
+ byteShift += 8;
+ byteCount++;
+ if(byteCount == 2) {
+ CPUWriteHalfWord(dest, writeValue);
+ dest += 2;
+ byteCount = 0;
+ byteShift = 0;
+ writeValue = 0;
+ }
+ len--;
+ if(len == 0)
+ return;
+ }
+ d <<= 1;
+ }
+ } else {
+ for(int i = 0; i < 8; i++) {
+ writeValue |= (CPUReadByte(source++) << byteShift);
+ byteShift += 8;
+ byteCount++;
+ if(byteCount == 2) {
+ CPUWriteHalfWord(dest, writeValue);
+ dest += 2;
+ byteShift = 0;
+ byteCount = 0;
+ writeValue = 0;
+ }
+ len--;
+ if(len == 0)
+ return;
+ }
+ }
+ }
+}
+
+void BIOS_LZ77UnCompWram()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("LZ77UnCompWram: 0x%08x,0x%08x (VCOUNT=%d)\n", reg[0].I, reg[1].I,
+ VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+
+ u32 header = CPUReadMemory(source);
+ source += 4;
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return;
+
+ int len = header >> 8;
+
+ while(len > 0) {
+ u8 d = CPUReadByte(source++);
+
+ if(d) {
+ for(int i = 0; i < 8; i++) {
+ if(d & 0x80) {
+ u16 data = CPUReadByte(source++) << 8;
+ data |= CPUReadByte(source++);
+ int length = (data >> 12) + 3;
+ int offset = (data & 0x0FFF);
+ u32 windowOffset = dest - offset - 1;
+ for(int i2 = 0; i2 < length; i2++) {
+ CPUWriteByte(dest++, CPUReadByte(windowOffset++));
+ len--;
+ if(len == 0)
+ return;
+ }
+ } else {
+ CPUWriteByte(dest++, CPUReadByte(source++));
+ len--;
+ if(len == 0)
+ return;
+ }
+ d <<= 1;
+ }
+ } else {
+ for(int i = 0; i < 8; i++) {
+ CPUWriteByte(dest++, CPUReadByte(source++));
+ len--;
+ if(len == 0)
+ return;
+ }
+ }
+ }
+}
+
+void BIOS_ObjAffineSet()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("ObjAffineSet: 0x%08x,0x%08x,0x%08x,0x%08x (VCOUNT=%d)\n",
+ reg[0].I,
+ reg[1].I,
+ reg[2].I,
+ reg[3].I,
+ VCOUNT);
+ }
+#endif
+
+ u32 src = reg[0].I;
+ u32 dest = reg[1].I;
+ int num = reg[2].I;
+ int offset = reg[3].I;
+
+ for(int i = 0; i < num; i++) {
+ s16 rx = CPUReadHalfWord(src);
+ src+=2;
+ s16 ry = CPUReadHalfWord(src);
+ src+=2;
+ u16 theta = CPUReadHalfWord(src)>>8;
+ src+=4; // keep structure alignment
+
+ s32 a = (s32)sineTable[(theta+0x40)&255];
+ s32 b = (s32)sineTable[theta];
+
+ s16 dx = ((s32)rx * a)>>14;
+ s16 dmx = ((s32)rx * b)>>14;
+ s16 dy = ((s32)ry * b)>>14;
+ s16 dmy = ((s32)ry * a)>>14;
+
+ CPUWriteHalfWord(dest, dx);
+ dest += offset;
+ CPUWriteHalfWord(dest, -dmx);
+ dest += offset;
+ CPUWriteHalfWord(dest, dy);
+ dest += offset;
+ CPUWriteHalfWord(dest, dmy);
+ dest += offset;
+ }
+}
+
+void BIOS_RegisterRamReset(u32 flags)
+{
+ // no need to trace here. this is only called directly from GBA.cpp
+ // to emulate bios initialization
+
+ CPUUpdateRegister(0x0, 0x80);
+
+ if(flags) {
+ if(flags & 0x01) {
+ // clear work RAM
+ memset(workRAM, 0, 0x40000);
+ }
+ if(flags & 0x02) {
+ // clear internal RAM
+ memset(internalRAM, 0, 0x7e00); // don't clear 0x7e00-0x7fff
+ }
+ if(flags & 0x04) {
+ // clear palette RAM
+ memset(paletteRAM, 0, 0x400);
+ }
+ if(flags & 0x08) {
+ // clear VRAM
+ memset(vram, 0, 0x18000);
+ }
+ if(flags & 0x10) {
+ // clean OAM
+ memset(oam, 0, 0x400);
+ }
+
+ if(flags & 0x80) {
+ int i;
+ for(i = 0; i < 0x10; i++)
+ CPUUpdateRegister(0x200+i*2, 0);
+
+ for(i = 0; i < 0xF; i++)
+ CPUUpdateRegister(0x4+i*2, 0);
+
+ for(i = 0; i < 0x20; i++)
+ CPUUpdateRegister(0x20+i*2, 0);
+
+ for(i = 0; i < 0x18; i++)
+ CPUUpdateRegister(0xb0+i*2, 0);
+
+ CPUUpdateRegister(0x130, 0);
+ CPUUpdateRegister(0x20, 0x100);
+ CPUUpdateRegister(0x30, 0x100);
+ CPUUpdateRegister(0x26, 0x100);
+ CPUUpdateRegister(0x36, 0x100);
+ }
+
+ if(flags & 0x20) {
+ int i;
+ for(i = 0; i < 8; i++)
+ CPUUpdateRegister(0x110+i*2, 0);
+ CPUUpdateRegister(0x134, 0x8000);
+ for(i = 0; i < 7; i++)
+ CPUUpdateRegister(0x140+i*2, 0);
+ }
+
+ if(flags & 0x40) {
+ int i;
+ CPUWriteByte(0x4000084, 0);
+ CPUWriteByte(0x4000084, 0x80);
+ CPUWriteMemory(0x4000080, 0x880e0000);
+ CPUUpdateRegister(0x88, CPUReadHalfWord(0x4000088)&0x3ff);
+ CPUWriteByte(0x4000070, 0x70);
+ for(i = 0; i < 8; i++)
+ CPUUpdateRegister(0x90+i*2, 0);
+ CPUWriteByte(0x4000070, 0);
+ for(i = 0; i < 8; i++)
+ CPUUpdateRegister(0x90+i*2, 0);
+ CPUWriteByte(0x4000084, 0);
+ }
+ }
+}
+
+void BIOS_RegisterRamReset()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("RegisterRamReset: 0x%08x (VCOUNT=%d)\n",
+ reg[0].I,
+ VCOUNT);
+ }
+#endif
+
+ BIOS_RegisterRamReset(reg[0].I);
+}
+
+void BIOS_RLUnCompVram()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("RLUnCompVram: 0x%08x,0x%08x (VCOUNT=%d)\n",
+ reg[0].I,
+ reg[1].I,
+ VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+
+ u32 header = CPUReadMemory(source & 0xFFFFFFFC);
+ source += 4;
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return;
+
+ int len = header >> 8;
+ int byteCount = 0;
+ int byteShift = 0;
+ u32 writeValue = 0;
+
+ while(len > 0) {
+ u8 d = CPUReadByte(source++);
+ int l = d & 0x7F;
+ if(d & 0x80) {
+ u8 data = CPUReadByte(source++);
+ l += 3;
+ for(int i = 0;i < l; i++) {
+ writeValue |= (data << byteShift);
+ byteShift += 8;
+ byteCount++;
+
+ if(byteCount == 2) {
+ CPUWriteHalfWord(dest, writeValue);
+ dest += 2;
+ byteCount = 0;
+ byteShift = 0;
+ writeValue = 0;
+ }
+ len--;
+ if(len == 0)
+ return;
+ }
+ } else {
+ l++;
+ for(int i = 0; i < l; i++) {
+ writeValue |= (CPUReadByte(source++) << byteShift);
+ byteShift += 8;
+ byteCount++;
+ if(byteCount == 2) {
+ CPUWriteHalfWord(dest, writeValue);
+ dest += 2;
+ byteCount = 0;
+ byteShift = 0;
+ writeValue = 0;
+ }
+ len--;
+ if(len == 0)
+ return;
+ }
+ }
+ }
+}
+
+void BIOS_RLUnCompWram()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("RLUnCompWram: 0x%08x,0x%08x (VCOUNT=%d)\n",
+ reg[0].I,
+ reg[1].I,
+ VCOUNT);
+ }
+#endif
+
+ u32 source = reg[0].I;
+ u32 dest = reg[1].I;
+
+ u32 header = CPUReadMemory(source & 0xFFFFFFFC);
+ source += 4;
+
+ if(((source & 0xe000000) == 0) ||
+ ((source + ((header >> 8) & 0x1fffff)) & 0xe000000) == 0)
+ return;
+
+ int len = header >> 8;
+
+ while(len > 0) {
+ u8 d = CPUReadByte(source++);
+ int l = d & 0x7F;
+ if(d & 0x80) {
+ u8 data = CPUReadByte(source++);
+ l += 3;
+ for(int i = 0;i < l; i++) {
+ CPUWriteByte(dest++, data);
+ len--;
+ if(len == 0)
+ return;
+ }
+ } else {
+ l++;
+ for(int i = 0; i < l; i++) {
+ CPUWriteByte(dest++, CPUReadByte(source++));
+ len--;
+ if(len == 0)
+ return;
+ }
+ }
+ }
+}
+
+void BIOS_SoftReset()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("SoftReset: (VCOUNT=%d)\n", VCOUNT);
+ }
+#endif
+
+ armState = true;
+ armMode = 0x1F;
+ armIrqEnable = false;
+ C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false;
+ reg[13].I = 0x03007F00;
+ reg[14].I = 0x00000000;
+ reg[16].I = 0x00000000;
+ reg[R13_IRQ].I = 0x03007FA0;
+ reg[R14_IRQ].I = 0x00000000;
+ reg[SPSR_IRQ].I = 0x00000000;
+ reg[R13_SVC].I = 0x03007FE0;
+ reg[R14_SVC].I = 0x00000000;
+ reg[SPSR_SVC].I = 0x00000000;
+ u8 b = internalRAM[0x7ffa];
+
+ memset(&internalRAM[0x7e00], 0, 0x200);
+
+ if(b) {
+ armNextPC = 0x02000000;
+ reg[15].I = 0x02000004;
+ } else {
+ armNextPC = 0x08000000;
+ reg[15].I = 0x08000004;
+ }
+}
+
+void BIOS_Sqrt()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("Sqrt: %08x (VCOUNT=%2d)\n",
+ reg[0].I,
+ VCOUNT);
+ }
+#endif
+ reg[0].I = (u32)sqrt((double)reg[0].I);
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("Sqrt: return=%08x\n",
+ reg[0].I);
+ }
+#endif
+}
+
+void BIOS_MidiKey2Freq()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("MidiKey2Freq: WaveData=%08x mk=%08x fp=%08x\n",
+ reg[0].I,
+ reg[1].I,
+ reg[2].I);
+ }
+#endif
+ int freq = CPUReadMemory(reg[0].I+4);
+ double tmp;
+ tmp = ((double)(180 - reg[1].I)) - ((double)reg[2].I / 256.f);
+ tmp = pow((double)2.f, tmp / 12.f);
+ reg[0].I = (int)((double)freq / tmp);
+
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("MidiKey2Freq: return %08x\n",
+ reg[0].I);
+ }
+#endif
+}
+
+void BIOS_SndDriverJmpTableCopy()
+{
+#ifdef GBA_LOGGING
+ if(systemVerbose & VERBOSE_SWI) {
+ log("SndDriverJmpTableCopy: dest=%08x\n",
+ reg[0].I);
+ }
+#endif
+ for(int i = 0; i < 0x24; i++) {
+ CPUWriteMemory(reg[0].I, 0x9c);
+ reg[0].I += 4;
+ }
+}
+
--- /dev/null
+++ b/src/in_gsf/vbam/gba/bios.h
@@ -1,1 +1,30 @@
+#ifndef BIOS_H
+#define BIOS_H
+extern void BIOS_ArcTan();
+extern void BIOS_ArcTan2();
+extern void BIOS_BitUnPack();
+extern void BIOS_GetBiosChecksum();
+extern void BIOS_BgAffineSet();
+extern void BIOS_CpuSet();
+extern void BIOS_CpuFastSet();
+extern void BIOS_Diff8bitUnFilterWram();
+extern void BIOS_Diff8bitUnFilterVram();
+extern void BIOS_Diff16bitUnFilter();
+extern void BIOS_Div();
+extern void BIOS_DivARM();
+extern void BIOS_HuffUnComp();
+extern void BIOS_LZ77UnCompVram();
+extern void BIOS_LZ77UnCompWram();
+extern void BIOS_ObjAffineSet();
+extern void BIOS_RegisterRamReset();
+extern void BIOS_RegisterRamReset(u32);
+extern void BIOS_RLUnCompVram();
+extern void BIOS_RLUnCompWram();
+extern void BIOS_SoftReset();
+extern void BIOS_Sqrt();
+extern void BIOS_MidiKey2Freq();
+extern void BIOS_SndDriverJmpTableCopy();
+
+#endif // BIOS_H
+
--- /dev/null
+++ b/src/in_gsf/vbam/gpl.txt
@@ -1,1 +1,340 @@
-
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+++ b/src/in_gsf/vbam/revision.txt
@@ -1,1 +1,1 @@
-
+1102
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/Channel.cpp
@@ -1,1 +1,660 @@
-
+/*
+ * SSEQ Player - Channel structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Adapted from source code of FeOS Sound System
+ * By fincs
+ * https://github.com/fincs/FSS
+ *
+ * Some code/concepts from DeSmuME
+ * http://desmume.org/
+ */
+
+#define _USE_MATH_DEFINES
+#include <cmath>
+#include "Channel.h"
+#include "Player.h"
+#include "common.h"
+
+NDSSoundRegister::NDSSoundRegister() : volumeMul(0), volumeDiv(0), panning(0), waveDuty(0), repeatMode(0), format(0), enable(false),
+ source(NULL), timer(0), psgX(0), psgLast(0), psgLastCount(0), samplePosition(0), sampleIncrease(0), loopStart(0), length(0)
+{
+}
+
+void NDSSoundRegister::ClearControlRegister()
+{
+ this->volumeMul = this->volumeDiv = this->panning = this->waveDuty = this->repeatMode = this->format = 0;
+ this->enable = false;
+}
+
+void NDSSoundRegister::SetControlRegister(uint32_t reg)
+{
+ this->volumeMul = reg & 0x7F;
+ this->volumeDiv = (reg >> 8) & 0x03;
+ this->panning = (reg >> 16) & 0x7F;
+ this->waveDuty = (reg >> 24) & 0x07;
+ this->repeatMode = (reg >> 27) & 0x03;
+ this->format = (reg >> 29) & 0x03;
+ this->enable = (reg >> 31) & 0x01;
+}
+
+TempSndReg::TempSndReg() : CR(0), SOURCE(NULL), TIMER(0), REPEAT_POINT(0), LENGTH(0)
+{
+}
+
+Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), manualSweep(false), flags(), pan(0), extAmpl(0), velocity(0), extPan(0),
+ key(0), ampl(0), extTune(0), orgKey(0), modType(0), modSpeed(0), modDepth(0), modRange(0), modDelay(0), modDelayCnt(0), modCounter(0),
+ sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(NULL), reg()
+{
+}
+
+void Channel::UpdateVol(const Track &trk)
+{
+ int finalVol = trk.ply->masterVol;
+ finalVol += Cnv_Sust(trk.vol);
+ finalVol += Cnv_Sust(trk.expr);
+ if (finalVol < -AMPL_K)
+ finalVol = -AMPL_K;
+ this->extAmpl = finalVol;
+}
+
+void Channel::UpdatePan(const Track &trk)
+{
+ this->extPan = trk.pan;
+}
+
+void Channel::UpdateTune(const Track &trk)
+{
+ int tune = (static_cast<int>(this->key) - static_cast<int>(this->orgKey)) * 64;
+ tune += (static_cast<int>(trk.pitchBend) * static_cast<int>(trk.pitchBendRange)) >> 1;
+ this->extTune = tune;
+}
+
+void Channel::UpdateMod(const Track &trk)
+{
+ this->modType = trk.modType;
+ this->modSpeed = trk.modSpeed;
+ this->modDepth = trk.modDepth;
+ this->modRange = trk.modRange;
+ this->modDelay = trk.modDelay;
+}
+
+void Channel::UpdatePorta(const Track &trk)
+{
+ this->manualSweep = false;
+ this->sweepPitch = trk.sweepPitch;
+ this->sweepCnt = 0;
+ if (!trk.state[TS_PORTABIT])
+ {
+ this->sweepLen = 0;
+ return;
+ }
+
+ int diff = (static_cast<int>(trk.portaKey) - static_cast<int>(this->key)) << 22;
+ this->sweepPitch += diff >> 16;
+
+ if (!trk.portaTime)
+ {
+ this->sweepLen = this->noteLength;
+ this->manualSweep = true;
+ }
+ else
+ {
+ int sq_time = static_cast<uint32_t>(trk.portaTime) * static_cast<uint32_t>(trk.portaTime);
+ int abs_sp = std::abs(this->sweepPitch);
+ this->sweepLen = (abs_sp * sq_time) >> 11;
+ }
+}
+
+void Channel::Release()
+{
+ this->noteLength = -1;
+ this->prio = 1;
+ this->state = CS_RELEASE;
+}
+
+void Channel::Kill()
+{
+ this->state = CS_NONE;
+ this->trackId = -1;
+ this->prio = 0;
+ this->reg.ClearControlRegister();
+ this->vol = 0;
+ this->noteLength = -1;
+}
+
+static inline int getModFlag(int type)
+{
+ switch (type)
+ {
+ case 0:
+ return CF_UPDTMR;
+ case 1:
+ return CF_UPDVOL;
+ case 2:
+ return CF_UPDPAN;
+ default:
+ return 0;
+ }
+}
+
+void Channel::UpdateTrack()
+{
+ if (!this->ply)
+ return;
+
+ int trkn = this->trackId;
+ if (trkn == -1)
+ return;
+
+ auto &trackFlags = this->ply->tracks[trkn].updateFlags;
+ if (trackFlags.none())
+ return;
+
+ auto &trk = this->ply->tracks[trkn];
+ if (trackFlags[TUF_LEN])
+ {
+ int st = this->state;
+ if (st > CS_START)
+ {
+ if (st < CS_RELEASE && !--this->noteLength)
+ this->Release();
+ if (this->manualSweep && this->sweepCnt < this->sweepLen)
+ ++this->sweepCnt;
+ }
+ }
+ if (trackFlags[TUF_VOL])
+ {
+ this->UpdateVol(trk);
+ this->flags.set(CF_UPDVOL);
+ }
+ if (trackFlags[TUF_PAN])
+ {
+ this->UpdatePan(trk);
+ this->flags.set(CF_UPDPAN);
+ }
+ if (trackFlags[TUF_TIMER])
+ {
+ this->UpdateTune(trk);
+ this->flags.set(CF_UPDTMR);
+ }
+ if (trackFlags[TUF_MOD])
+ {
+ int oldType = this->modType;
+ int newType = trk.modType;
+ this->UpdateMod(trk);
+ if (oldType != newType)
+ {
+ this->flags.set(getModFlag(oldType));
+ this->flags.set(getModFlag(newType));
+ }
+ }
+}
+
+static const uint16_t getpitchtbl[] =
+{
+ 0x0000, 0x003B, 0x0076, 0x00B2, 0x00ED, 0x0128, 0x0164, 0x019F,
+ 0x01DB, 0x0217, 0x0252, 0x028E, 0x02CA, 0x0305, 0x0341, 0x037D,
+ 0x03B9, 0x03F5, 0x0431, 0x046E, 0x04AA, 0x04E6, 0x0522, 0x055F,
+ 0x059B, 0x05D8, 0x0614, 0x0651, 0x068D, 0x06CA, 0x0707, 0x0743,
+ 0x0780, 0x07BD, 0x07FA, 0x0837, 0x0874, 0x08B1, 0x08EF, 0x092C,
+ 0x0969, 0x09A7, 0x09E4, 0x0A21, 0x0A5F, 0x0A9C, 0x0ADA, 0x0B18,
+ 0x0B56, 0x0B93, 0x0BD1, 0x0C0F, 0x0C4D, 0x0C8B, 0x0CC9, 0x0D07,
+ 0x0D45, 0x0D84, 0x0DC2, 0x0E00, 0x0E3F, 0x0E7D, 0x0EBC, 0x0EFA,
+ 0x0F39, 0x0F78, 0x0FB6, 0x0FF5, 0x1034, 0x1073, 0x10B2, 0x10F1,
+ 0x1130, 0x116F, 0x11AE, 0x11EE, 0x122D, 0x126C, 0x12AC, 0x12EB,
+ 0x132B, 0x136B, 0x13AA, 0x13EA, 0x142A, 0x146A, 0x14A9, 0x14E9,
+ 0x1529, 0x1569, 0x15AA, 0x15EA, 0x162A, 0x166A, 0x16AB, 0x16EB,
+ 0x172C, 0x176C, 0x17AD, 0x17ED, 0x182E, 0x186F, 0x18B0, 0x18F0,
+ 0x1931, 0x1972, 0x19B3, 0x19F5, 0x1A36, 0x1A77, 0x1AB8, 0x1AFA,
+ 0x1B3B, 0x1B7D, 0x1BBE, 0x1C00, 0x1C41, 0x1C83, 0x1CC5, 0x1D07,
+ 0x1D48, 0x1D8A, 0x1DCC, 0x1E0E, 0x1E51, 0x1E93, 0x1ED5, 0x1F17,
+ 0x1F5A, 0x1F9C, 0x1FDF, 0x2021, 0x2064, 0x20A6, 0x20E9, 0x212C,
+ 0x216F, 0x21B2, 0x21F5, 0x2238, 0x227B, 0x22BE, 0x2301, 0x2344,
+ 0x2388, 0x23CB, 0x240E, 0x2452, 0x2496, 0x24D9, 0x251D, 0x2561,
+ 0x25A4, 0x25E8, 0x262C, 0x2670, 0x26B4, 0x26F8, 0x273D, 0x2781,
+ 0x27C5, 0x280A, 0x284E, 0x2892, 0x28D7, 0x291C, 0x2960, 0x29A5,
+ 0x29EA, 0x2A2F, 0x2A74, 0x2AB9, 0x2AFE, 0x2B43, 0x2B88, 0x2BCD,
+ 0x2C13, 0x2C58, 0x2C9D, 0x2CE3, 0x2D28, 0x2D6E, 0x2DB4, 0x2DF9,
+ 0x2E3F, 0x2E85, 0x2ECB, 0x2F11, 0x2F57, 0x2F9D, 0x2FE3, 0x302A,
+ 0x3070, 0x30B6, 0x30FD, 0x3143, 0x318A, 0x31D0, 0x3217, 0x325E,
+ 0x32A5, 0x32EC, 0x3332, 0x3379, 0x33C1, 0x3408, 0x344F, 0x3496,
+ 0x34DD, 0x3525, 0x356C, 0x35B4, 0x35FB, 0x3643, 0x368B, 0x36D3,
+ 0x371A, 0x3762, 0x37AA, 0x37F2, 0x383A, 0x3883, 0x38CB, 0x3913,
+ 0x395C, 0x39A4, 0x39ED, 0x3A35, 0x3A7E, 0x3AC6, 0x3B0F, 0x3B58,
+ 0x3BA1, 0x3BEA, 0x3C33, 0x3C7C, 0x3CC5, 0x3D0E, 0x3D58, 0x3DA1,
+ 0x3DEA, 0x3E34, 0x3E7D, 0x3EC7, 0x3F11, 0x3F5A, 0x3FA4, 0x3FEE,
+ 0x4038, 0x4082, 0x40CC, 0x4116, 0x4161, 0x41AB, 0x41F5, 0x4240,
+ 0x428A, 0x42D5, 0x431F, 0x436A, 0x43B5, 0x4400, 0x444B, 0x4495,
+ 0x44E1, 0x452C, 0x4577, 0x45C2, 0x460D, 0x4659, 0x46A4, 0x46F0,
+ 0x473B, 0x4787, 0x47D3, 0x481E, 0x486A, 0x48B6, 0x4902, 0x494E,
+ 0x499A, 0x49E6, 0x4A33, 0x4A7F, 0x4ACB, 0x4B18, 0x4B64, 0x4BB1,
+ 0x4BFE, 0x4C4A, 0x4C97, 0x4CE4, 0x4D31, 0x4D7E, 0x4DCB, 0x4E18,
+ 0x4E66, 0x4EB3, 0x4F00, 0x4F4E, 0x4F9B, 0x4FE9, 0x5036, 0x5084,
+ 0x50D2, 0x5120, 0x516E, 0x51BC, 0x520A, 0x5258, 0x52A6, 0x52F4,
+ 0x5343, 0x5391, 0x53E0, 0x542E, 0x547D, 0x54CC, 0x551A, 0x5569,
+ 0x55B8, 0x5607, 0x5656, 0x56A5, 0x56F4, 0x5744, 0x5793, 0x57E2,
+ 0x5832, 0x5882, 0x58D1, 0x5921, 0x5971, 0x59C1, 0x5A10, 0x5A60,
+ 0x5AB0, 0x5B01, 0x5B51, 0x5BA1, 0x5BF1, 0x5C42, 0x5C92, 0x5CE3,
+ 0x5D34, 0x5D84, 0x5DD5, 0x5E26, 0x5E77, 0x5EC8, 0x5F19, 0x5F6A,
+ 0x5FBB, 0x600D, 0x605E, 0x60B0, 0x6101, 0x6153, 0x61A4, 0x61F6,
+ 0x6248, 0x629A, 0x62EC, 0x633E, 0x6390, 0x63E2, 0x6434, 0x6487,
+ 0x64D9, 0x652C, 0x657E, 0x65D1, 0x6624, 0x6676, 0x66C9, 0x671C,
+ 0x676F, 0x67C2, 0x6815, 0x6869, 0x68BC, 0x690F, 0x6963, 0x69B6,
+ 0x6A0A, 0x6A5E, 0x6AB1, 0x6B05, 0x6B59, 0x6BAD, 0x6C01, 0x6C55,
+ 0x6CAA, 0x6CFE, 0x6D52, 0x6DA7, 0x6DFB, 0x6E50, 0x6EA4, 0x6EF9,
+ 0x6F4E, 0x6FA3, 0x6FF8, 0x704D, 0x70A2, 0x70F7, 0x714D, 0x71A2,
+ 0x71F7, 0x724D, 0x72A2, 0x72F8, 0x734E, 0x73A4, 0x73FA, 0x7450,
+ 0x74A6, 0x74FC, 0x7552, 0x75A8, 0x75FF, 0x7655, 0x76AC, 0x7702,
+ 0x7759, 0x77B0, 0x7807, 0x785E, 0x78B4, 0x790C, 0x7963, 0x79BA,
+ 0x7A11, 0x7A69, 0x7AC0, 0x7B18, 0x7B6F, 0x7BC7, 0x7C1F, 0x7C77,
+ 0x7CCF, 0x7D27, 0x7D7F, 0x7DD7, 0x7E2F, 0x7E88, 0x7EE0, 0x7F38,
+ 0x7F91, 0x7FEA, 0x8042, 0x809B, 0x80F4, 0x814D, 0x81A6, 0x81FF,
+ 0x8259, 0x82B2, 0x830B, 0x8365, 0x83BE, 0x8418, 0x8472, 0x84CB,
+ 0x8525, 0x857F, 0x85D9, 0x8633, 0x868E, 0x86E8, 0x8742, 0x879D,
+ 0x87F7, 0x8852, 0x88AC, 0x8907, 0x8962, 0x89BD, 0x8A18, 0x8A73,
+ 0x8ACE, 0x8B2A, 0x8B85, 0x8BE0, 0x8C3C, 0x8C97, 0x8CF3, 0x8D4F,
+ 0x8DAB, 0x8E07, 0x8E63, 0x8EBF, 0x8F1B, 0x8F77, 0x8FD4, 0x9030,
+ 0x908C, 0x90E9, 0x9146, 0x91A2, 0x91FF, 0x925C, 0x92B9, 0x9316,
+ 0x9373, 0x93D1, 0x942E, 0x948C, 0x94E9, 0x9547, 0x95A4, 0x9602,
+ 0x9660, 0x96BE, 0x971C, 0x977A, 0x97D8, 0x9836, 0x9895, 0x98F3,
+ 0x9952, 0x99B0, 0x9A0F, 0x9A6E, 0x9ACD, 0x9B2C, 0x9B8B, 0x9BEA,
+ 0x9C49, 0x9CA8, 0x9D08, 0x9D67, 0x9DC7, 0x9E26, 0x9E86, 0x9EE6,
+ 0x9F46, 0x9FA6, 0xA006, 0xA066, 0xA0C6, 0xA127, 0xA187, 0xA1E8,
+ 0xA248, 0xA2A9, 0xA30A, 0xA36B, 0xA3CC, 0xA42D, 0xA48E, 0xA4EF,
+ 0xA550, 0xA5B2, 0xA613, 0xA675, 0xA6D6, 0xA738, 0xA79A, 0xA7FC,
+ 0xA85E, 0xA8C0, 0xA922, 0xA984, 0xA9E7, 0xAA49, 0xAAAC, 0xAB0E,
+ 0xAB71, 0xABD4, 0xAC37, 0xAC9A, 0xACFD, 0xAD60, 0xADC3, 0xAE27,
+ 0xAE8A, 0xAEED, 0xAF51, 0xAFB5, 0xB019, 0xB07C, 0xB0E0, 0xB145,
+ 0xB1A9, 0xB20D, 0xB271, 0xB2D6, 0xB33A, 0xB39F, 0xB403, 0xB468,
+ 0xB4CD, 0xB532, 0xB597, 0xB5FC, 0xB662, 0xB6C7, 0xB72C, 0xB792,
+ 0xB7F7, 0xB85D, 0xB8C3, 0xB929, 0xB98F, 0xB9F5, 0xBA5B, 0xBAC1,
+ 0xBB28, 0xBB8E, 0xBBF5, 0xBC5B, 0xBCC2, 0xBD29, 0xBD90, 0xBDF7,
+ 0xBE5E, 0xBEC5, 0xBF2C, 0xBF94, 0xBFFB, 0xC063, 0xC0CA, 0xC132,
+ 0xC19A, 0xC202, 0xC26A, 0xC2D2, 0xC33A, 0xC3A2, 0xC40B, 0xC473,
+ 0xC4DC, 0xC544, 0xC5AD, 0xC616, 0xC67F, 0xC6E8, 0xC751, 0xC7BB,
+ 0xC824, 0xC88D, 0xC8F7, 0xC960, 0xC9CA, 0xCA34, 0xCA9E, 0xCB08,
+ 0xCB72, 0xCBDC, 0xCC47, 0xCCB1, 0xCD1B, 0xCD86, 0xCDF1, 0xCE5B,
+ 0xCEC6, 0xCF31, 0xCF9C, 0xD008, 0xD073, 0xD0DE, 0xD14A, 0xD1B5,
+ 0xD221, 0xD28D, 0xD2F8, 0xD364, 0xD3D0, 0xD43D, 0xD4A9, 0xD515,
+ 0xD582, 0xD5EE, 0xD65B, 0xD6C7, 0xD734, 0xD7A1, 0xD80E, 0xD87B,
+ 0xD8E9, 0xD956, 0xD9C3, 0xDA31, 0xDA9E, 0xDB0C, 0xDB7A, 0xDBE8,
+ 0xDC56, 0xDCC4, 0xDD32, 0xDDA0, 0xDE0F, 0xDE7D, 0xDEEC, 0xDF5B,
+ 0xDFC9, 0xE038, 0xE0A7, 0xE116, 0xE186, 0xE1F5, 0xE264, 0xE2D4,
+ 0xE343, 0xE3B3, 0xE423, 0xE493, 0xE503, 0xE573, 0xE5E3, 0xE654,
+ 0xE6C4, 0xE735, 0xE7A5, 0xE816, 0xE887, 0xE8F8, 0xE969, 0xE9DA,
+ 0xEA4B, 0xEABC, 0xEB2E, 0xEB9F, 0xEC11, 0xEC83, 0xECF5, 0xED66,
+ 0xEDD9, 0xEE4B, 0xEEBD, 0xEF2F, 0xEFA2, 0xF014, 0xF087, 0xF0FA,
+ 0xF16D, 0xF1E0, 0xF253, 0xF2C6, 0xF339, 0xF3AD, 0xF420, 0xF494,
+ 0xF507, 0xF57B, 0xF5EF, 0xF663, 0xF6D7, 0xF74C, 0xF7C0, 0xF834,
+ 0xF8A9, 0xF91E, 0xF992, 0xFA07, 0xFA7C, 0xFAF1, 0xFB66, 0xFBDC,
+ 0xFC51, 0xFCC7, 0xFD3C, 0xFDB2, 0xFE28, 0xFE9E, 0xFF14, 0xFF8A
+};
+
+static const uint8_t getvoltbl[] =
+{
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+ 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
+ 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E,
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14,
+ 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x18,
+ 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C,
+ 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
+ 0x22, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x29,
+ 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x31, 0x31,
+ 0x32, 0x32, 0x33, 0x33, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3A, 0x3A, 0x3B,
+ 0x3C, 0x3C, 0x3D, 0x3E, 0x3F, 0x3F, 0x40, 0x41, 0x42, 0x42, 0x43, 0x44, 0x45, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x52, 0x53, 0x54, 0x55,
+ 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6D, 0x6E, 0x6F, 0x71, 0x72, 0x73, 0x75, 0x76, 0x77, 0x79, 0x7A, 0x7B,
+ 0x7D, 0x7E, 0x7F, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25,
+ 0x26, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D,
+ 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x31, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x36,
+ 0x36, 0x37, 0x37, 0x38, 0x39, 0x39, 0x3A, 0x3B, 0x3B, 0x3C, 0x3D, 0x3E, 0x3E, 0x3F, 0x40, 0x40,
+ 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4D,
+ 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D,
+ 0x5E, 0x5F, 0x60, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6F, 0x70,
+ 0x71, 0x73, 0x74, 0x75, 0x77, 0x78, 0x79, 0x7B, 0x7C, 0x7E, 0x7E, 0x40, 0x41, 0x42, 0x43, 0x43,
+ 0x44, 0x45, 0x46, 0x47, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
+ 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
+ 0x62, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x71, 0x72, 0x74, 0x75,
+ 0x76, 0x78, 0x79, 0x7B, 0x7C, 0x7D, 0x7E, 0x40, 0x41, 0x42, 0x42, 0x43, 0x44, 0x45, 0x46, 0x46,
+ 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55,
+ 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6A, 0x6C, 0x6D, 0x6E, 0x6F, 0x71, 0x72, 0x73, 0x75, 0x76, 0x77, 0x79, 0x7A,
+ 0x7C, 0x7D, 0x7E, 0x7F
+};
+
+// This function was obtained through disassembly of Ninty's sound driver
+static inline uint16_t Timer_Adjust(uint16_t basetmr, int pitch)
+{
+ int shift = 0;
+ pitch = -pitch;
+
+ while (pitch < 0)
+ {
+ --shift;
+ pitch += 0x300;
+ }
+
+ while (pitch >= 0x300)
+ {
+ ++shift;
+ pitch -= 0x300;
+ }
+
+ uint64_t tmr = static_cast<uint64_t>(basetmr) * (static_cast<uint32_t>(getpitchtbl[pitch]) + 0x10000);
+ shift -= 16;
+ if (shift <= 0)
+ tmr >>= -shift;
+ else if (shift < 32)
+ {
+ if (tmr & ((~0ULL) << (32 - shift)))
+ return 0xFFFF;
+ tmr <<= shift;
+ }
+ else
+ return 0x10;
+
+ if (tmr < 0x10)
+ return 0x10;
+ if (tmr > 0xFFFF)
+ return 0xFFFF;
+ return static_cast<uint16_t>(tmr);
+}
+
+static inline int calcVolDivShift(int x)
+{
+ // VOLDIV(0) /1 >>0
+ // VOLDIV(1) /2 >>1
+ // VOLDIV(2) /4 >>2
+ // VOLDIV(3) /16 >>4
+ if (x < 3)
+ return x;
+ return 4;
+}
+
+void Channel::Update()
+{
+ // Kill active channels that aren't physically active
+ if (this->state > CS_START && !this->reg.enable)
+ {
+ this->Kill();
+ return;
+ }
+
+ bool bNotInSustain = this->state != CS_SUSTAIN;
+ bool bInStart = this->state == CS_START;
+ bool bPitchSweep = this->sweepPitch && this->sweepLen && this->sweepCnt <= this->sweepLen;
+ bool bModulation = !!this->modDepth;
+ bool bVolNeedUpdate = this->flags[CF_UPDVOL] || bNotInSustain;
+ bool bPanNeedUpdate = this->flags[CF_UPDPAN] || bInStart;
+ bool bTmrNeedUpdate = this->flags[CF_UPDTMR] || bInStart || bPitchSweep;
+ int modParam = 0;
+
+ switch (this->state)
+ {
+ case CS_NONE:
+ return;
+ case CS_START:
+ this->reg.ClearControlRegister();
+ this->reg.source = this->tempReg.SOURCE;
+ this->reg.loopStart = this->tempReg.REPEAT_POINT;
+ this->reg.length = this->tempReg.LENGTH;
+ this->ampl = AMPL_THRESHOLD;
+ this->state = CS_ATTACK;
+ // Fall down
+ case CS_ATTACK:
+ this->ampl = (static_cast<int>(this->ampl) * static_cast<int>(this->attackLvl)) / 255;
+ if (!this->ampl)
+ this->state = CS_DECAY;
+ break;
+ case CS_DECAY:
+ {
+ this->ampl -= static_cast<int>(this->decayRate);
+ int sustLvl = Cnv_Sust(this->sustainLvl) << 7;
+ if (this->ampl <= sustLvl)
+ {
+ this->ampl = sustLvl;
+ this->state = CS_SUSTAIN;
+ }
+ break;
+ }
+ case CS_RELEASE:
+ this->ampl -= static_cast<int>(this->releaseRate);
+ if (this->ampl > AMPL_THRESHOLD)
+ break;
+ this->Kill();
+ return;
+ }
+
+ if (bModulation && this->modDelayCnt < this->modDelay)
+ {
+ ++this->modDelayCnt;
+ bModulation = false;
+ }
+
+ if (bModulation)
+ {
+ switch (this->modType)
+ {
+ case 0:
+ bTmrNeedUpdate = true;
+ break;
+ case 1:
+ bVolNeedUpdate = true;
+ break;
+ case 2:
+ bPanNeedUpdate = true;
+ }
+
+ // Get the current modulation parameter
+ modParam = Cnv_Sine(this->modCounter >> 8) * this->modRange * this->modDepth;
+
+ if (!this->modType)
+ modParam = static_cast<int64_t>(modParam * 60) >> 14;
+ else
+ // This ugly formula whose exact meaning and workings I cannot figure out is used for volume/pan modulation.
+ modParam = ((modParam & ~0xFC000000) >> 8) | ((((modParam < 0 ? -1 : 0) << 6) | (static_cast<uint32_t>(modParam) >> 26)) << 18);
+
+ // Update the modulation variables
+
+ uint16_t speed = static_cast<uint16_t>(this->modSpeed) << 6;
+ uint16_t counter = (this->modCounter + speed) >> 8;
+
+ while (counter >= 0x80)
+ counter -= 0x80;
+
+ this->modCounter += speed;
+ this->modCounter &= 0xFF;
+ this->modCounter |= counter << 8;
+ }
+
+ if (bTmrNeedUpdate)
+ {
+ int totalAdj = this->extTune;
+ if (bModulation && !this->modType)
+ totalAdj += modParam;
+ if (bPitchSweep)
+ {
+ int len = this->sweepLen;
+ int cnt = this->sweepCnt;
+ totalAdj += (static_cast<int64_t>(this->sweepPitch) * (len - cnt)) / len;
+ if (!this->manualSweep)
+ ++this->sweepCnt;
+ }
+ uint16_t tmr = this->tempReg.TIMER;
+
+ if (totalAdj)
+ tmr = Timer_Adjust(tmr, totalAdj);
+ this->reg.timer = -tmr;
+ this->reg.sampleIncrease = (ARM7_CLOCK / static_cast<double>(this->ply->sampleRate * 2)) / (0x10000 - this->reg.timer);
+ this->flags.reset(CF_UPDTMR);
+ }
+
+ if (bVolNeedUpdate || bPanNeedUpdate)
+ {
+ uint32_t cr = this->tempReg.CR;
+ if (bVolNeedUpdate)
+ {
+ int totalVol = this->ampl >> 7;
+ totalVol += this->extAmpl;
+ totalVol += this->velocity;
+ if (bModulation && this->modType == 1)
+ totalVol += modParam;
+ totalVol += AMPL_K;
+ if (totalVol < 0)
+ totalVol = 0;
+
+ cr &= ~(SOUND_VOL(0x7F) | SOUND_VOLDIV(3));
+ cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol]));
+
+ if (totalVol < AMPL_K - 240)
+ cr |= SOUND_VOLDIV(3);
+ else if (totalVol < AMPL_K - 120)
+ cr |= SOUND_VOLDIV(2);
+ else if (totalVol < AMPL_K - 60)
+ cr |= SOUND_VOLDIV(1);
+
+ this->vol = ((cr & SOUND_VOL(0x7F)) << 4) >> calcVolDivShift((cr & SOUND_VOLDIV(3)) >> 8);
+
+ this->flags.reset(CF_UPDVOL);
+ }
+
+ if (bPanNeedUpdate)
+ {
+ int realPan = this->pan;
+ realPan += this->extPan;
+ if (bModulation && this->modType == 2)
+ realPan += modParam;
+ realPan += 64;
+ if (realPan < 0)
+ realPan = 0;
+ else if (realPan > 127)
+ realPan = 127;
+
+ cr &= ~SOUND_PAN(0x7F);
+ cr |= SOUND_PAN(realPan);
+ this->flags.reset(CF_UPDPAN);
+ }
+
+ this->tempReg.CR = cr;
+ this->reg.SetControlRegister(cr);
+ }
+}
+
+static const int16_t wavedutytbl[8][8] =
+{
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF }
+};
+
+#ifndef M_PI
+static const double M_PI = 3.14159265358979323846;
+#endif
+
+int32_t Channel::Interpolate(int32_t a, int32_t b, double ratio)
+{
+ float ratiof = static_cast<float>(ratio);
+ ratiof -= static_cast<int32_t>(ratiof);
+ if (this->ply->interpolation == INTERPOLATION_COSINE)
+ {
+ double ratio2 = (1.0 - std::cos(ratiof * M_PI)) * 0.5;
+ return static_cast<int32_t>((1 - ratio2) * a + ratio2 * b);
+ }
+ else
+ return static_cast<int32_t>((1 - ratiof) * a + ratiof * b);
+}
+
+int32_t Channel::GenerateSample()
+{
+ if (this->reg.samplePosition < 0)
+ return 0;
+
+ if (this->reg.format != 3)
+ {
+ if (this->ply->interpolation == INTERPOLATION_NONE)
+ return this->reg.source->data[static_cast<uint32_t>(this->reg.samplePosition)];
+ else
+ {
+ uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition);
+ int32_t a = this->reg.source->data[loc], b;
+ if (loc < static_cast<uint32_t>(this->reg.loopStart + this->reg.length - 1))
+ {
+ b = this->reg.source->data[loc + 1];
+ a = this->Interpolate(a, b, this->reg.samplePosition);
+ }
+ return a;
+ }
+ }
+ else
+ {
+ if (this->chnId < 8)
+ return 0;
+ else if (this->chnId < 14)
+ return wavedutytbl[this->reg.waveDuty][static_cast<uint32_t>(this->reg.samplePosition) & 0x7];
+ else
+ {
+ if (this->reg.psgLastCount != static_cast<uint32_t>(this->reg.samplePosition))
+ {
+ uint32_t max = static_cast<uint32_t>(this->reg.samplePosition);
+ for (uint32_t i = this->reg.psgLastCount; i < max; ++i)
+ {
+ if (this->reg.psgX & 0x1)
+ {
+ this->reg.psgX = (this->reg.psgX >> 1) ^ 0x6000;
+ this->reg.psgLast = -0x7FFF;
+ }
+ else
+ {
+ this->reg.psgX >>= 1;
+ this->reg.psgLast = 0x7FFF;
+ }
+ }
+
+ this->reg.psgLastCount = static_cast<uint32_t>(this->reg.samplePosition);
+ }
+
+ return this->reg.psgLast;
+ }
+ }
+}
+
+void Channel::IncrementSample()
+{
+ this->reg.samplePosition += this->reg.sampleIncrease;
+ if (this->reg.format != 3 && this->reg.samplePosition >= (this->reg.loopStart + this->reg.length))
+ {
+ if (this->reg.repeatMode == 1)
+ {
+ while (this->reg.samplePosition >= (this->reg.loopStart + this->reg.length))
+ this->reg.samplePosition -= this->reg.length;
+ }
+ else
+ this->Kill();
+ }
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/Channel.h
@@ -1,1 +1,144 @@
+/*
+ * SSEQ Player - Channel structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Adapted from source code of FeOS Sound System
+ * By fincs
+ * https://github.com/fincs/FSS
+ *
+ * Some code/concepts from DeSmuME
+ * http://desmume.org/
+ */
+#ifndef SSEQPLAYER_CHANNEL_H
+#define SSEQPLAYER_CHANNEL_H
+
+#include <bitset>
+#include "SWAV.h"
+#include "Track.h"
+#include "pstdint.h"
+
+/*
+ * This structure is meant to be similar to what is stored in the actual
+ * Nintendo DS's sound registers. Items that were not being used by this
+ * player have been removed, and items which help the simulated registers
+ * have been added.
+ */
+struct NDSSoundRegister
+{
+ // Control Register
+ uint8_t volumeMul;
+ uint8_t volumeDiv;
+ uint8_t panning;
+ uint8_t waveDuty;
+ uint8_t repeatMode;
+ uint8_t format;
+ bool enable;
+
+ // Data Source Register
+ const SWAV *source;
+
+ // Timer Register
+ uint16_t timer;
+
+ // PSG Handling, not a DS register
+ uint16_t psgX;
+ int16_t psgLast;
+ uint32_t psgLastCount;
+
+ // The following are taken from DeSmuME
+ double samplePosition;
+ double sampleIncrease;
+
+ // Loopstart Register
+ uint32_t loopStart;
+
+ // Length Register
+ uint32_t length;
+
+ NDSSoundRegister();
+
+ void ClearControlRegister();
+ void SetControlRegister(uint32_t reg);
+};
+
+/*
+ * From FeOS Sound System, this is temporary storage of what will go into
+ * the Nintendo DS sound registers. It is kept separate as the original code
+ * from FeOS Sound System utilized this to hold data prior to passing it into
+ * the DS's registers.
+ */
+struct TempSndReg
+{
+ uint32_t CR;
+ const SWAV *SOURCE;
+ uint16_t TIMER;
+ uint32_t REPEAT_POINT, LENGTH;
+
+ TempSndReg();
+};
+
+struct Player;
+
+struct Channel
+{
+ int8_t chnId;
+
+ TempSndReg tempReg;
+ uint8_t state;
+ int8_t trackId; // -1 = none
+ uint8_t prio;
+ bool manualSweep;
+
+ std::bitset<CF_BITS> flags;
+ int8_t pan; // -64 .. 63
+ int16_t extAmpl;
+
+ int16_t velocity;
+ int8_t extPan;
+ uint8_t key;
+
+ int ampl; // 7 fractionary bits
+ int extTune; // in 64ths of a semitone
+
+ uint8_t orgKey;
+
+ uint8_t modType, modSpeed, modDepth, modRange;
+ uint16_t modDelay, modDelayCnt, modCounter;
+
+ uint32_t sweepLen, sweepCnt;
+ int16_t sweepPitch;
+
+ uint8_t attackLvl, sustainLvl;
+ uint16_t decayRate, releaseRate;
+
+ /*
+ * These were originally global variables in FeOS Sound System, but
+ * since they were linked to a certain channel anyways, I moved them
+ * into this class.
+ */
+ int noteLength;
+ uint16_t vol;
+
+ const Player *ply;
+ NDSSoundRegister reg;
+
+ Channel();
+
+ void UpdateVol(const Track &trk);
+ void UpdatePan(const Track &trk);
+ void UpdateTune(const Track &trk);
+ void UpdateMod(const Track &trk);
+ void UpdatePorta(const Track &trk);
+ void Release();
+ void Kill();
+ void UpdateTrack();
+ void Update();
+ int32_t Interpolate(int32_t a, int32_t b, double ratio);
+ int32_t GenerateSample();
+ void IncrementSample();
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/FATSection.cpp
@@ -1,1 +1,40 @@
+/*
+ * SSEQ Player - SDAT FAT (File Allocation Table) Section structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#include "FATSection.h"
+
+FATRecord::FATRecord() : offset(0)
+{
+}
+
+void FATRecord::Read(PseudoFile &file)
+{
+ this->offset = file.ReadLE<uint32_t>();
+ file.ReadLE<uint32_t>(); // size
+ uint32_t reserved[2];
+ file.ReadLE(reserved);
+}
+
+FATSection::FATSection() : records()
+{
+}
+
+void FATSection::Read(PseudoFile &file)
+{
+ int8_t type[4];
+ file.ReadLE(type);
+ if (!VerifyHeader(type, "FAT "))
+ throw std::runtime_error("SDAT FAT Section invalid");
+ file.ReadLE<uint32_t>(); // size
+ uint32_t count = file.ReadLE<uint32_t>();
+ this->records.resize(count);
+ for (uint32_t i = 0; i < count; ++i)
+ this->records[i].Read(file);
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/FATSection.h
@@ -1,1 +1,34 @@
+/*
+ * SSEQ Player - SDAT FAT (File Allocation Table) Section structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#ifndef SSEQPLAYER_FATSECTION_H
+#define SSEQPLAYER_FATSECTION_H
+
+#include "common.h"
+
+struct FATRecord
+{
+ uint32_t offset;
+
+ FATRecord();
+
+ void Read(PseudoFile &file);
+};
+
+struct FATSection
+{
+ std::vector<FATRecord> records;
+
+ FATSection();
+
+ void Read(PseudoFile &file);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/INFOEntry.cpp
@@ -1,1 +1,47 @@
+/*
+ * SSEQ Player - SDAT INFO Entry structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#include "INFOEntry.h"
+
+INFOEntrySEQ::INFOEntrySEQ() : fileID(0), bank(0)
+{
+}
+
+void INFOEntrySEQ::Read(PseudoFile &file)
+{
+ this->fileID = file.ReadLE<uint16_t>();
+ file.ReadLE<uint16_t>(); // unknown
+ this->bank = file.ReadLE<uint16_t>();
+ file.ReadLE<uint8_t>(); // vol
+ file.ReadLE<uint8_t>(); // cpr
+ file.ReadLE<uint8_t>(); // ppr
+ file.ReadLE<uint8_t>(); // ply
+}
+
+INFOEntryBANK::INFOEntryBANK() : fileID(0)
+{
+ memset(this->waveArc, 0, sizeof(this->waveArc));
+}
+
+void INFOEntryBANK::Read(PseudoFile &file)
+{
+ this->fileID = file.ReadLE<uint16_t>();
+ file.ReadLE<uint16_t>(); // unknown
+ file.ReadLE(this->waveArc);
+}
+
+INFOEntryWAVEARC::INFOEntryWAVEARC() : fileID(0)
+{
+}
+
+void INFOEntryWAVEARC::Read(PseudoFile &file)
+{
+ this->fileID = file.ReadLE<uint16_t>();
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/INFOEntry.h
@@ -1,1 +1,54 @@
+/*
+ * SSEQ Player - SDAT INFO Entry structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#ifndef SSEQPLAYER_INFOENTRY_H
+#define SSEQPLAYER_INFOENTRY_H
+
+#include "common.h"
+
+struct INFOEntry
+{
+ virtual ~INFOEntry()
+ {
+ }
+
+ virtual void Read(PseudoFile &file) = 0;
+};
+
+struct INFOEntrySEQ : INFOEntry
+{
+ uint16_t fileID;
+ uint16_t bank;
+
+ INFOEntrySEQ();
+
+ void Read(PseudoFile &file);
+};
+
+struct INFOEntryBANK : INFOEntry
+{
+ uint16_t fileID;
+ uint16_t waveArc[4];
+
+ INFOEntryBANK();
+
+ void Read(PseudoFile &file);
+};
+
+struct INFOEntryWAVEARC : INFOEntry
+{
+ uint16_t fileID;
+
+ INFOEntryWAVEARC();
+
+ void Read(PseudoFile &file);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/INFOSection.cpp
@@ -1,1 +1,61 @@
+/*
+ * SSEQ Player - SDAT INFO Section structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#include <vector>
+#include "INFOSection.h"
+
+template<typename T> INFORecord<T>::INFORecord() : entries()
+{
+}
+
+template<typename T> void INFORecord<T>::Read(PseudoFile &file, uint32_t startOffset)
+{
+ uint32_t count = file.ReadLE<uint32_t>();
+ auto entryOffsets = std::vector<uint32_t>(count);
+ file.ReadLE(entryOffsets);
+ for (uint32_t i = 0; i < count; ++i)
+ if (entryOffsets[i])
+ {
+ file.pos = startOffset + entryOffsets[i];
+ this->entries[i] = T();
+ this->entries[i].Read(file);
+ }
+}
+
+INFOSection::INFOSection() : SEQrecord(), BANKrecord(), WAVEARCrecord()
+{
+}
+
+void INFOSection::Read(PseudoFile &file)
+{
+ uint32_t startOfINFO = file.pos;
+ int8_t type[4];
+ file.ReadLE(type);
+ if (!VerifyHeader(type, "INFO"))
+ throw std::runtime_error("SDAT INFO Section invalid");
+ file.ReadLE<uint32_t>(); // size
+ uint32_t recordOffsets[8];
+ file.ReadLE(recordOffsets);
+ if (recordOffsets[REC_SEQ])
+ {
+ file.pos = startOfINFO + recordOffsets[REC_SEQ];
+ this->SEQrecord.Read(file, startOfINFO);
+ }
+ if (recordOffsets[REC_BANK])
+ {
+ file.pos = startOfINFO + recordOffsets[REC_BANK];
+ this->BANKrecord.Read(file, startOfINFO);
+ }
+ if (recordOffsets[REC_WAVEARC])
+ {
+ file.pos = startOfINFO + recordOffsets[REC_WAVEARC];
+ this->WAVEARCrecord.Read(file, startOfINFO);
+ }
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/INFOSection.h
@@ -1,1 +1,38 @@
+/*
+ * SSEQ Player - SDAT INFO Section structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#ifndef SSEQPLAYER_INFOSECTION_H
+#define SSEQPLAYER_INFOSECTION_H
+
+#include <map>
+#include "INFOEntry.h"
+#include "common.h"
+
+template<typename T> struct INFORecord
+{
+ std::map<uint32_t, T> entries;
+
+ INFORecord();
+
+ void Read(PseudoFile &file, uint32_t startOffset);
+};
+
+struct INFOSection
+{
+ INFORecord<INFOEntrySEQ> SEQrecord;
+ INFORecord<INFOEntryBANK> BANKrecord;
+ INFORecord<INFOEntryWAVEARC> WAVEARCrecord;
+
+ INFOSection();
+
+ void Read(PseudoFile &file);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/NDSStdHeader.cpp
@@ -1,1 +1,31 @@
+/*
+ * SSEQ Player - Nintendo DS Standard Header structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#include "NDSStdHeader.h"
+
+NDSStdHeader::NDSStdHeader() : magic(0)
+{
+ memset(this->type, 0, sizeof(this->type));
+}
+
+void NDSStdHeader::Read(PseudoFile &file)
+{
+ file.ReadLE(this->type);
+ this->magic = file.ReadLE<uint32_t>();
+ file.ReadLE<uint32_t>(); // file size
+ file.ReadLE<uint16_t>(); // structure size
+ file.ReadLE<uint16_t>(); // # of blocks
+}
+
+void NDSStdHeader::Verify(const std::string &typeToCheck, uint32_t magicToCheck)
+{
+ if (!VerifyHeader(this->type, typeToCheck) || this->magic != magicToCheck)
+ throw std::runtime_error("NDS Standard Header for " + typeToCheck + " invalid");
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/NDSStdHeader.h
@@ -1,1 +1,27 @@
+/*
+ * SSEQ Player - Nintendo DS Standard Header structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#ifndef SSEQPLAYER_NDSSTDHEADER_H
+#define SSEQPLAYER_NDSSTDHEADER_H
+
+#include "common.h"
+
+struct NDSStdHeader
+{
+ int8_t type[4];
+ uint32_t magic;
+
+ NDSStdHeader();
+
+ void Read(PseudoFile &file);
+ void Verify(const std::string &typeToCheck, uint32_t magicToCheck);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/Player.cpp
@@ -1,1 +1,141 @@
+/*
+ * SSEQ Player - Player structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Adapted from source code of FeOS Sound System
+ * By fincs
+ * https://github.com/fincs/FSS
+ */
+#include "Player.h"
+#include "common.h"
+
+Player::Player() : prio(0), nTracks(0), tempo(0), tempoCount(0), tempoRate(0), masterVol(0), sseq(NULL), sampleRate(0), interpolation(INTERPOLATION_NONE)
+{
+ memset(this->trackIds, 0, sizeof(this->trackIds));
+ for (size_t i = 0; i < 16; ++i)
+ this->channels[i].chnId = i;
+}
+
+bool Player::Setup(const SSEQ *sseqToPlay)
+{
+ this->sseq = sseqToPlay;
+
+ int firstTrack = this->TrackAlloc();
+ if (firstTrack == -1)
+ return false;
+ this->tracks[firstTrack].Init(firstTrack, this, NULL, 0);
+
+ this->nTracks = 1;
+ this->trackIds[0] = firstTrack;
+
+ auto pData = &this->sseq->data[0];
+ if (*pData == 0xFE)
+ for (pData += 3; *pData == 0x93; ) // Prepare extra tracks
+ {
+ ++pData;
+ int tNum = read8(&pData);
+ auto pos = &this->sseq->data[read24(&pData)];
+ int newTrack = this->TrackAlloc();
+ if (newTrack == -1)
+ continue;
+ this->tracks[newTrack].Init(newTrack, this, pos, tNum);
+ this->trackIds[this->nTracks++] = newTrack;
+ }
+
+ this->tracks[firstTrack].startPos = this->tracks[firstTrack].pos = pData;
+
+ this->ClearState();
+
+ return true;
+}
+
+void Player::ClearState()
+{
+ this->tempo = 120;
+ this->tempoCount = 0;
+ this->tempoRate = 0x100;
+ this->masterVol = 0; // this is actually the highest level
+}
+
+int Player::ChannelAlloc(int type, int priority)
+{
+ static const uint8_t pcmChnArray[] = { 4, 5, 6, 7, 2, 0, 3, 1, 8, 9, 10, 11, 14, 12, 15, 13 };
+ static const uint8_t psgChnArray[] = { 13, 12, 11, 10, 9, 8 };
+ static const uint8_t noiseChnArray[] = { 15, 14 };
+ static const uint8_t arraySizes[] = { sizeof(pcmChnArray), sizeof(psgChnArray), sizeof(noiseChnArray) };
+ static const uint8_t *const arrayArray[] = { pcmChnArray, psgChnArray, noiseChnArray };
+
+ auto chnArray = arrayArray[type];
+ int arraySize = arraySizes[type];
+
+ int curChnNo = -1;
+ for (int i = 0; i < arraySize; ++i)
+ {
+ int thisChnNo = chnArray[i];
+ Channel &thisChn = this->channels[thisChnNo];
+ Channel &curChn = this->channels[curChnNo];
+ if (curChnNo != -1 && thisChn.prio >= curChn.prio)
+ {
+ if (thisChn.prio != curChn.prio)
+ continue;
+ if (curChn.vol <= thisChn.vol)
+ continue;
+ }
+ curChnNo = thisChnNo;
+ }
+
+ if (curChnNo == -1 || priority < this->channels[curChnNo].prio)
+ return -1;
+ this->channels[curChnNo].ply = this;
+ this->channels[curChnNo].noteLength = -1;
+ this->channels[curChnNo].vol = 0;
+ return curChnNo;
+}
+
+int Player::TrackAlloc()
+{
+ for (int i = 0; i < FSS_MAXTRACKS; ++i)
+ {
+ Track &thisTrk = this->tracks[i];
+ if (!thisTrk.state[TS_ALLOCBIT])
+ {
+ thisTrk.Zero();
+ thisTrk.state.set(TS_ALLOCBIT);
+ thisTrk.updateFlags.reset();
+ return i;
+ }
+ }
+ return -1;
+}
+
+void Player::Run()
+{
+ while (this->tempoCount > 240)
+ {
+ this->tempoCount -= 240;
+ for (uint8_t i = 0; i < this->nTracks; ++i)
+ this->tracks[this->trackIds[i]].Run();
+ }
+ this->tempoCount += (static_cast<int>(this->tempo) * static_cast<int>(this->tempoRate)) >> 8;
+}
+
+void Player::UpdateTracks()
+{
+ for (int i = 0; i < 16; ++i)
+ this->channels[i].UpdateTrack();
+ for (int i = 0; i < FSS_MAXTRACKS; ++i)
+ this->tracks[i].updateFlags.reset();
+}
+
+void Player::Timer()
+{
+ this->UpdateTracks();
+
+ for (int i = 0; i < 16; ++i)
+ this->channels[i].Update();
+
+ this->Run();
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/Player.h
@@ -1,1 +1,46 @@
+/*
+ * SSEQ Player - Player structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Adapted from source code of FeOS Sound System
+ * By fincs
+ * https://github.com/fincs/FSS
+ */
+#ifndef SSEQPLAYER_PLAYER_H
+#define SSEQPLAYER_PLAYER_H
+
+#include "SSEQ.h"
+#include "Track.h"
+#include "Channel.h"
+#include "consts.h"
+
+struct Player
+{
+ uint8_t prio, nTracks;
+ uint16_t tempo, tempoCount, tempoRate /* 8.8 fixed point */;
+ int16_t masterVol;
+
+ const SSEQ *sseq;
+
+ uint8_t trackIds[FSS_TRACKCOUNT];
+ Track tracks[FSS_MAXTRACKS];
+ Channel channels[16];
+
+ uint32_t sampleRate;
+ Interpolation interpolation;
+
+ Player();
+
+ bool Setup(const SSEQ *sseq);
+ void ClearState();
+ int ChannelAlloc(int type, int prio);
+ int TrackAlloc();
+ void Run();
+ void UpdateTracks();
+ void Timer();
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SBNK.cpp
@@ -1,1 +1,123 @@
+/*
+ * SSEQ Player - SDAT SBNK (Sound Bank) structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#include "SBNK.h"
+#include "NDSStdHeader.h"
+
+SBNKInstrumentRange::SBNKInstrumentRange(uint8_t lowerNote, uint8_t upperNote, int recordType) : lowNote(lowerNote), highNote(upperNote),
+ record(recordType), swav(0), swar(0), noteNumber(0), attackRate(0), decayRate(0), sustainLevel(0), releaseRate(0), pan(0)
+{
+}
+
+void SBNKInstrumentRange::Read(PseudoFile &file)
+{
+ this->swav = file.ReadLE<uint16_t>();
+ this->swar = file.ReadLE<uint16_t>();
+ this->noteNumber = file.ReadLE<uint8_t>();
+ this->attackRate = file.ReadLE<uint8_t>();
+ this->decayRate = file.ReadLE<uint8_t>();
+ this->sustainLevel = file.ReadLE<uint8_t>();
+ this->releaseRate = file.ReadLE<uint8_t>();
+ this->pan = file.ReadLE<uint8_t>();
+}
+
+SBNKInstrument::SBNKInstrument() : record(0), ranges()
+{
+}
+
+void SBNKInstrument::Read(PseudoFile &file, uint32_t startOffset)
+{
+ this->record = file.ReadLE<uint8_t>();
+ uint16_t offset = file.ReadLE<uint16_t>();
+ file.ReadLE<uint8_t>();
+ uint32_t endOfInst = file.pos;
+ file.pos = startOffset + offset;
+ if (this->record)
+ {
+ if (this->record == 16)
+ {
+ uint8_t lowNote = file.ReadLE<uint8_t>();
+ uint8_t highNote = file.ReadLE<uint8_t>();
+ uint8_t num = highNote - lowNote + 1;
+ for (uint8_t i = 0; i < num; ++i)
+ {
+ uint16_t thisRecord = file.ReadLE<uint16_t>();
+ auto range = SBNKInstrumentRange(lowNote + i, lowNote + i, thisRecord);
+ range.Read(file);
+ this->ranges.push_back(range);
+ }
+ }
+ else if (this->record == 17)
+ {
+ uint8_t thisRanges[8];
+ file.ReadLE(thisRanges);
+ uint8_t i = 0;
+ while (i < 8 && thisRanges[i])
+ {
+ uint16_t thisRecord = file.ReadLE<uint16_t>();
+ uint8_t lowNote = i ? thisRanges[i - 1] + 1 : 0;
+ uint8_t highNote = thisRanges[i];
+ auto range = SBNKInstrumentRange(lowNote, highNote, thisRecord);
+ range.Read(file);
+ this->ranges.push_back(range);
+ ++i;
+ }
+ }
+ else
+ {
+ auto range = SBNKInstrumentRange(0, 127, this->record);
+ range.Read(file);
+ this->ranges.push_back(range);
+ }
+ }
+ file.pos = endOfInst;
+}
+
+SBNK::SBNK(const std::string &fn) : filename(fn), instruments(), info()
+{
+ memset(this->waveArc, 0, sizeof(this->waveArc));
+}
+
+SBNK::SBNK(const SBNK &sbnk) : filename(sbnk.filename), instruments(sbnk.instruments), info(sbnk.info)
+{
+ memcpy(this->waveArc, sbnk.waveArc, sizeof(this->waveArc));
+}
+
+SBNK &SBNK::operator=(const SBNK &sbnk)
+{
+ if (this != &sbnk)
+ {
+ this->filename = sbnk.filename;
+ this->instruments = sbnk.instruments;
+
+ memcpy(this->waveArc, sbnk.waveArc, sizeof(this->waveArc));
+ this->info = sbnk.info;
+ }
+ return *this;
+}
+
+void SBNK::Read(PseudoFile &file)
+{
+ uint32_t startOfSBNK = file.pos;
+ NDSStdHeader header;
+ header.Read(file);
+ header.Verify("SBNK", 0x0100FEFF);
+ int8_t type[4];
+ file.ReadLE(type);
+ if (!VerifyHeader(type, "DATA"))
+ throw std::runtime_error("SBNK DATA structure invalid");
+ file.ReadLE<uint32_t>(); // size
+ uint32_t reserved[8];
+ file.ReadLE(reserved);
+ uint32_t count = file.ReadLE<uint32_t>();
+ this->instruments.resize(count);
+ for (uint32_t i = 0; i < count; ++i)
+ this->instruments[i].Read(file, startOfSBNK);
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SBNK.h
@@ -1,1 +1,62 @@
+/*
+ * SSEQ Player - SDAT SBNK (Sound Bank) structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#ifndef SSEQPLAYER_SBNK_H
+#define SSEQPLAYER_SBNK_H
+
+#include "SWAR.h"
+#include "INFOEntry.h"
+#include "common.h"
+
+struct SBNKInstrumentRange
+{
+ uint8_t lowNote;
+ uint8_t highNote;
+ uint16_t record;
+ uint16_t swav;
+ uint16_t swar;
+ uint8_t noteNumber;
+ uint8_t attackRate;
+ uint8_t decayRate;
+ uint8_t sustainLevel;
+ uint8_t releaseRate;
+ uint8_t pan;
+
+ SBNKInstrumentRange(uint8_t lowerNote, uint8_t upperNote, int recordType);
+
+ void Read(PseudoFile &file);
+};
+
+struct SBNKInstrument
+{
+ uint8_t record;
+ std::vector<SBNKInstrumentRange> ranges;
+
+ SBNKInstrument();
+
+ void Read(PseudoFile &file, uint32_t startOffset);
+};
+
+struct SBNK
+{
+ std::string filename;
+ std::vector<SBNKInstrument> instruments;
+
+ const SWAR *waveArc[4];
+ INFOEntryBANK info;
+
+ SBNK(const std::string &fn = "");
+ SBNK(const SBNK &sbnk);
+ SBNK &operator=(const SBNK &sbnk);
+
+ void Read(PseudoFile &file);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SDAT.cpp
@@ -1,1 +1,94 @@
+/*
+ * SSEQ Player - SDAT structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#include "SDAT.h"
+#include "NDSStdHeader.h"
+#include "SYMBSection.h"
+#include "INFOSection.h"
+#include "FATSection.h"
+#include "convert.h"
+
+SDAT::SDAT(PseudoFile &file, uint32_t sseqToLoad) : sseq(), sbnk()
+{
+ // Read sections
+ NDSStdHeader header;
+ header.Read(file);
+ header.Verify("SDAT", 0x0100FEFF);
+ uint32_t SYMBOffset = file.ReadLE<uint32_t>();
+ file.ReadLE<uint32_t>(); // SYMB size
+ uint32_t INFOOffset = file.ReadLE<uint32_t>();
+ file.ReadLE<uint32_t>(); // INFO size
+ uint32_t FATOffset = file.ReadLE<uint32_t>();
+ file.ReadLE<uint32_t>(); // FAT Size
+ SYMBSection symbSection;
+ if (SYMBOffset)
+ {
+ file.pos = SYMBOffset;
+ symbSection.Read(file);
+ }
+ file.pos = INFOOffset;
+ INFOSection infoSection;
+ infoSection.Read(file);
+ file.pos = FATOffset;
+ FATSection fatSection;
+ fatSection.Read(file);
+
+ if (infoSection.SEQrecord.entries.empty())
+ throw std::logic_error("No SSEQ records found in SDAT");
+
+ if (!infoSection.SEQrecord.entries.count(sseqToLoad))
+ throw std::range_error("SSEQ of " + stringify(sseqToLoad) + " is not found");
+
+ // Read SSEQ
+ if (infoSection.SEQrecord.entries.count(sseqToLoad))
+ {
+ uint16_t fileID = infoSection.SEQrecord.entries[sseqToLoad].fileID;
+ std::string name = "SSEQ" + NumToHexString(fileID).substr(2);
+ if (SYMBOffset)
+ name = NumToHexString(sseqToLoad).substr(6) + " - " + symbSection.SEQrecord.entries[sseqToLoad];
+ file.pos = fatSection.records[fileID].offset;
+ SSEQ *newSSEQ = new SSEQ(name);
+ newSSEQ->info = infoSection.SEQrecord.entries[sseqToLoad];
+ newSSEQ->Read(file);
+ this->sseq.reset(newSSEQ);
+
+ // Read SBNK for this SSEQ
+ uint16_t bank = newSSEQ->info.bank;
+ fileID = infoSection.BANKrecord.entries[bank].fileID;
+ name = "SBNK" + NumToHexString(fileID).substr(2);
+ if (SYMBOffset)
+ name = NumToHexString(bank).substr(2) + " - " + symbSection.BANKrecord.entries[bank];
+ file.pos = fatSection.records[fileID].offset;
+ SBNK *newSBNK = new SBNK(name);
+ newSSEQ->bank = newSBNK;
+ newSBNK->info = infoSection.BANKrecord.entries[bank];
+ newSBNK->Read(file);
+ this->sbnk.reset(newSBNK);
+
+ // Read SWARs for this SBNK
+ for (int i = 0; i < 4; ++i)
+ if (newSBNK->info.waveArc[i] != 0xFFFF)
+ {
+ uint16_t waveArc = newSBNK->info.waveArc[i];
+ fileID = infoSection.WAVEARCrecord.entries[waveArc].fileID;
+ name = "SWAR" + NumToHexString(fileID).substr(2);
+ if (SYMBOffset)
+ name = NumToHexString(waveArc).substr(2) + " - " + symbSection.WAVEARCrecord.entries[waveArc];
+ file.pos = fatSection.records[fileID].offset;
+ SWAR *newSWAR = new SWAR(name);
+ newSBNK->waveArc[i] = newSWAR;
+ newSWAR->info = infoSection.WAVEARCrecord.entries[waveArc];
+ newSWAR->Read(file);
+ this->swar[i].reset(newSWAR);
+ }
+ else
+ this->swar[i].release();
+ }
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SDAT.h
@@ -1,1 +1,32 @@
+/*
+ * SSEQ Player - SDAT structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#ifndef SSEQPLAYER_SDAT_H
+#define SSEQPLAYER_SDAT_H
+
+#include <memory>
+#include "SSEQ.h"
+#include "SBNK.h"
+#include "SWAR.h"
+#include "common.h"
+
+struct SDAT
+{
+ std::auto_ptr<SSEQ> sseq;
+ std::auto_ptr<SBNK> sbnk;
+ std::auto_ptr<SWAR> swar[4];
+
+ SDAT(PseudoFile &file, uint32_t sseqToLoad);
+private:
+ SDAT(const SDAT &);
+ SDAT &operator=(const SDAT &);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SSEQ.cpp
@@ -1,1 +1,50 @@
+/*
+ * SSEQ Player - SDAT SSEQ (Sequence) structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#include "SSEQ.h"
+#include "NDSStdHeader.h"
+
+SSEQ::SSEQ(const std::string &fn) : filename(fn), data(), bank(NULL), info()
+{
+}
+
+SSEQ::SSEQ(const SSEQ &sseq) : filename(sseq.filename), data(sseq.data), bank(sseq.bank), info(sseq.info)
+{
+}
+
+SSEQ &SSEQ::operator=(const SSEQ &sseq)
+{
+ if (this != &sseq)
+ {
+ this->filename = sseq.filename;
+ this->data = sseq.data;
+
+ this->bank = sseq.bank;
+ this->info = sseq.info;
+ }
+ return *this;
+}
+
+void SSEQ::Read(PseudoFile &file)
+{
+ uint32_t startOfSSEQ = file.pos;
+ NDSStdHeader header;
+ header.Read(file);
+ header.Verify("SSEQ", 0x0100FEFF);
+ int8_t type[4];
+ file.ReadLE(type);
+ if (!VerifyHeader(type, "DATA"))
+ throw std::runtime_error("SSEQ DATA structure invalid");
+ uint32_t size = file.ReadLE<uint32_t>();
+ uint32_t dataOffset = file.ReadLE<uint32_t>();
+ this->data.resize(size, 0);
+ file.pos = startOfSSEQ + dataOffset;
+ file.ReadLE(this->data);
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SSEQ.h
@@ -1,1 +1,33 @@
+/*
+ * SSEQ Player - SDAT SSEQ (Sequence) structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#ifndef SSEQPLAYER_SSEQ_H
+#define SSEQPLAYER_SSEQ_H
+
+#include "SBNK.h"
+#include "INFOEntry.h"
+#include "common.h"
+
+struct SSEQ
+{
+ std::string filename;
+ std::vector<uint8_t> data;
+
+ const SBNK *bank;
+ INFOEntrySEQ info;
+
+ SSEQ(const std::string &fn = "");
+ SSEQ(const SSEQ &sseq);
+ SSEQ &operator=(const SSEQ &sseq);
+
+ void Read(PseudoFile &file);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SWAR.cpp
@@ -1,1 +1,42 @@
+/*
+ * SSEQ Player - SDAT SWAR (Wave Archive) structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#include <vector>
+#include "SWAR.h"
+#include "NDSStdHeader.h"
+
+SWAR::SWAR(const std::string &fn) : filename(fn), swavs(), info()
+{
+}
+
+void SWAR::Read(PseudoFile &file)
+{
+ uint32_t startOfSWAR = file.pos;
+ NDSStdHeader header;
+ header.Read(file);
+ header.Verify("SWAR", 0x0100FEFF);
+ int8_t type[4];
+ file.ReadLE(type);
+ if (!VerifyHeader(type, "DATA"))
+ throw std::runtime_error("SWAR DATA structure invalid");
+ file.ReadLE<uint32_t>(); // size
+ uint32_t reserved[8];
+ file.ReadLE(reserved);
+ uint32_t count = file.ReadLE<uint32_t>();
+ auto offsets = std::vector<uint32_t>(count);
+ file.ReadLE(offsets);
+ for (uint32_t i = 0; i < count; ++i)
+ if (offsets[i])
+ {
+ file.pos = startOfSWAR + offsets[i];
+ this->swavs[i] = SWAV();
+ this->swavs[i].Read(file);
+ }
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SWAR.h
@@ -1,1 +1,34 @@
+/*
+ * SSEQ Player - SDAT SWAR (Wave Archive) structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#ifndef SSEQPLAYER_SWAR_H
+#define SSEQPLAYER_SWAR_H
+
+#include <map>
+#include "SWAV.h"
+#include "INFOEntry.h"
+#include "common.h"
+
+/*
+ * The size has been left out of this structure as it is unused by this player.
+ */
+struct SWAR
+{
+ std::string filename;
+ std::map<uint32_t, SWAV> swavs;
+
+ INFOEntryWAVEARC info;
+
+ SWAR(const std::string &fn = "");
+
+ void Read(PseudoFile &file);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SWAV.cpp
@@ -1,1 +1,123 @@
+/*
+ * SSEQ Player - SDAT SWAV (Waveform/Sample) structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#include "SWAV.h"
+
+static int ima_index_table[] =
+{
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+};
+
+static int ima_step_table[] =
+{
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+SWAV::SWAV() : waveType(0), loop(0), sampleRate(0), time(0), loopOffset(0), nonLoopLength(0), data()
+{
+}
+
+static inline void DecodeADPCMNibble(int32_t nibble, int32_t &stepIndex, int32_t &predictedValue)
+{
+ int32_t step = ima_step_table[stepIndex];
+
+ stepIndex += ima_index_table[nibble];
+
+ if (stepIndex < 0)
+ stepIndex = 0;
+ else if (stepIndex > 88)
+ stepIndex = 88;
+
+ int32_t diff = step >> 3;
+
+ if (nibble & 4)
+ diff += step;
+ if (nibble & 2)
+ diff += step >> 1;
+ if (nibble & 1)
+ diff += step >> 2;
+ if (nibble & 8)
+ predictedValue -= diff;
+ else
+ predictedValue += diff;
+
+ if (predictedValue < -0x8000)
+ predictedValue = -0x8000;
+ else if (predictedValue > 0x7FFF)
+ predictedValue = 0x7FFF;
+}
+
+void SWAV::DecodeADPCM(const std::vector<uint8_t> &origData)
+{
+ int32_t predictedValue = origData[0] | (origData[1] << 8);
+ int32_t stepIndex = origData[2] | (origData[3] << 8);
+
+ for (int i = 0, len = origData.size() - 4; i < len; ++i)
+ {
+ int32_t nibble = origData[i + 4] & 0x0F;
+ DecodeADPCMNibble(nibble, stepIndex, predictedValue);
+ this->data[2 * i] = predictedValue;
+
+ nibble = (origData[i + 4] >> 4) & 0x0F;
+ DecodeADPCMNibble(nibble, stepIndex, predictedValue);
+ this->data[2 * i + 1] = predictedValue;
+ }
+}
+
+void SWAV::Read(PseudoFile &file)
+{
+ this->waveType = file.ReadLE<uint8_t>();
+ this->loop = file.ReadLE<uint8_t>();
+ this->sampleRate = file.ReadLE<uint16_t>();
+ this->time = file.ReadLE<uint16_t>();
+ this->loopOffset = file.ReadLE<uint16_t>();
+ this->nonLoopLength = file.ReadLE<uint32_t>();
+ uint32_t size = (this->loopOffset + this->nonLoopLength) * 4;
+ auto origData = std::vector<uint8_t>(size);
+ file.ReadLE(origData);
+
+ // Convert data accordingly
+ if (!this->waveType)
+ {
+ // PCM 8-bit -> PCM signed 16-bit
+ this->data.resize(origData.size(), 0);
+ for (size_t i = 0, len = origData.size(); i < len; ++i)
+ this->data[i] = origData[i] << 8;
+ this->loopOffset *= 4;
+ this->nonLoopLength *= 4;
+ }
+ else if (this->waveType == 1)
+ {
+ // PCM signed 16-bit, no conversion
+ this->data.resize(origData.size() / 2, 0);
+ for (size_t i = 0, len = origData.size() / 2; i < len; ++i)
+ this->data[i] = ReadLE<int16_t>(&origData[2 * i]);
+ this->loopOffset *= 2;
+ this->nonLoopLength *= 2;
+ }
+ else if (this->waveType == 2)
+ {
+ // IMA ADPCM -> PCM signed 16-bit
+ this->data.resize((origData.size() - 4) * 2, 0);
+ this->DecodeADPCM(origData);
+ --this->loopOffset;
+ this->loopOffset *= 8;
+ this->nonLoopLength *= 8;
+ }
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SWAV.h
@@ -1,1 +1,32 @@
+/*
+ * SSEQ Player - SDAT SWAV (Waveform/Sample) structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#ifndef SSEQPLAYER_SWAV_H
+#define SSEQPLAYER_SWAV_H
+
+#include "common.h"
+
+struct SWAV
+{
+ uint8_t waveType;
+ uint8_t loop;
+ uint16_t sampleRate;
+ uint16_t time;
+ uint32_t loopOffset;
+ uint32_t nonLoopLength;
+ std::vector<int16_t> data;
+
+ SWAV();
+
+ void Read(PseudoFile &file);
+ void DecodeADPCM(const std::vector<uint8_t> &data);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SYMBSection.cpp
@@ -1,1 +1,60 @@
+/*
+ * SSEQ Player - SDAT SYMB (Symbol/Filename) Section structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#include <vector>
+#include "SYMBSection.h"
+
+SYMBRecord::SYMBRecord() : entries()
+{
+}
+
+void SYMBRecord::Read(PseudoFile &file, uint32_t startOffset)
+{
+ uint32_t count = file.ReadLE<uint32_t>();
+ auto entryOffsets = std::vector<uint32_t>(count);
+ file.ReadLE(entryOffsets);
+ for (uint32_t i = 0; i < count; ++i)
+ if (entryOffsets[i])
+ {
+ file.pos = startOffset + entryOffsets[i];
+ this->entries[i] = file.ReadNullTerminatedString();
+ }
+}
+
+SYMBSection::SYMBSection() : SEQrecord(), BANKrecord(), WAVEARCrecord()
+{
+}
+
+void SYMBSection::Read(PseudoFile &file)
+{
+ uint32_t startOfSYMB = file.pos;
+ int8_t type[4];
+ file.ReadLE(type);
+ if (!VerifyHeader(type, "SYMB"))
+ throw std::runtime_error("SDAT SYMB Section invalid");
+ file.ReadLE<uint32_t>(); // size
+ uint32_t recordOffsets[8];
+ file.ReadLE(recordOffsets);
+ if (recordOffsets[REC_SEQ])
+ {
+ file.pos = startOfSYMB + recordOffsets[REC_SEQ];
+ this->SEQrecord.Read(file, startOfSYMB);
+ }
+ if (recordOffsets[REC_BANK])
+ {
+ file.pos = startOfSYMB + recordOffsets[REC_BANK];
+ this->BANKrecord.Read(file, startOfSYMB);
+ }
+ if (recordOffsets[REC_WAVEARC])
+ {
+ file.pos = startOfSYMB + recordOffsets[REC_WAVEARC];
+ this->WAVEARCrecord.Read(file, startOfSYMB);
+ }
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/SYMBSection.h
@@ -1,1 +1,40 @@
+/*
+ * SSEQ Player - SDAT SYMB (Symbol/Filename) Section structures
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Nintendo DS Nitro Composer (SDAT) Specification document found at
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+#ifndef SSEQPLAYER_SYMBSECTION_H
+#define SSEQPLAYER_SYMBSECTION_H
+
+#include <map>
+#include "common.h"
+
+struct SYMBRecord
+{
+ std::map<uint32_t, std::string> entries;
+
+ SYMBRecord();
+
+ void Read(PseudoFile &file, uint32_t startOffset);
+};
+
+/*
+ * The size has been left out of this structure as it is unused by this player.
+ */
+struct SYMBSection
+{
+ SYMBRecord SEQrecord;
+ SYMBRecord BANKrecord;
+ SYMBRecord WAVEARCrecord;
+
+ SYMBSection();
+
+ void Read(PseudoFile &file);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/Track.cpp
@@ -1,1 +1,547 @@
-
+/*
+ * SSEQ Player - Track structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Adapted from source code of FeOS Sound System
+ * By fincs
+ * https://github.com/fincs/FSS
+ */
+
+#include "Track.h"
+#include "Player.h"
+#include "common.h"
+
+Track::Track()
+{
+ this->Zero();
+}
+
+void Track::Init(uint8_t handle, Player *player, const uint8_t *dataPos, int n)
+{
+ this->trackId = handle;
+ this->num = n;
+ this->ply = player;
+ this->startPos = dataPos;
+ this->ClearState();
+}
+
+void Track::Zero()
+{
+ this->trackId = -1;
+
+ this->state.reset();
+ this->num = this->prio = 0;
+ this->ply = NULL;
+
+ this->startPos = this->pos = NULL;
+ memset(this->stack, 0, sizeof(this->stack));
+ this->stackPos = 0;
+ memset(this->loopCount, 0, sizeof(this->loopCount));
+
+ this->wait = 0;
+ this->patch = 0;
+ this->portaKey = this->portaTime = 0;
+ this->sweepPitch = 0;
+ this->vol = this->expr = 0;
+ this->pan = 0;
+ this->pitchBendRange = 0;
+ this->pitchBend = this->transpose = 0;
+
+ this->a = this->d = this->s = this->r = 0;
+
+ this->modType = this->modSpeed = this->modDepth = this->modRange = 0;
+ this->modDelay = 0;
+
+ this->updateFlags.reset();
+}
+
+void Track::ClearState()
+{
+ this->state.reset();
+ this->state.set(TS_ALLOCBIT);
+ this->state.set(TS_NOTEWAIT);
+ this->prio = this->ply->prio + 64;
+
+ this->pos = this->startPos;
+ this->stackPos = 0;
+
+ this->wait = 0;
+ this->patch = 0;
+ this->portaKey = 60;
+ this->portaTime = 0;
+ this->sweepPitch = 0;
+ this->vol = 64;
+ this->expr = 127;
+ this->pan = 0;
+ this->pitchBendRange = 2;
+ this->pitchBend = this->transpose = 0;
+
+ this->a = this->d = this->s = this->r = 0xFF;
+
+ this->modType = 0;
+ this->modRange = 1;
+ this->modSpeed = 16;
+ this->modDelay = 10;
+ this->modDepth = 0;
+}
+
+int Track::NoteOn(int key, int vel, int len)
+{
+ auto sbnk = this->ply->sseq->bank;
+
+ if (this->patch >= sbnk->instruments.size())
+ return -1;
+
+ bool bIsPCM = true;
+ Channel *chn;
+ int nCh;
+
+ auto &instrument = sbnk->instruments[this->patch];
+ const SBNKInstrumentRange *noteDef = NULL;
+ int fRecord = instrument.record;
+
+ if (fRecord == 16)
+ {
+ if (!(instrument.ranges[0].lowNote <= key && key <= instrument.ranges[instrument.ranges.size() - 1].highNote))
+ return -1;
+ int rn = key - instrument.ranges[0].lowNote;
+ noteDef = &instrument.ranges[rn];
+ fRecord = noteDef->record;
+ }
+ else if (fRecord == 17)
+ {
+ size_t reg, ranges;
+ for (reg = 0, ranges = instrument.ranges.size(); reg < ranges; ++reg)
+ if (key <= instrument.ranges[reg].highNote)
+ break;
+ if (reg == ranges)
+ return -1;
+
+ noteDef = &instrument.ranges[reg];
+ fRecord = noteDef->record;
+ }
+
+ if (!fRecord)
+ return -1;
+ else if (fRecord == 1)
+ {
+ if (!noteDef)
+ noteDef = &instrument.ranges[0];
+ }
+ else if (fRecord < 4)
+ {
+ // PSG
+ // fRecord = 2 -> PSG tone, pNoteDef->wavid -> PSG duty
+ // fRecord = 3 -> PSG noise
+ bIsPCM = false;
+ if (!noteDef)
+ noteDef = &instrument.ranges[0];
+ if (fRecord == 3)
+ {
+ nCh = this->ply->ChannelAlloc(TYPE_NOISE, this->prio);
+ if (nCh < 0)
+ return -1;
+ chn = &this->ply->channels[nCh];
+ chn->tempReg.CR = SOUND_FORMAT_PSG | SCHANNEL_ENABLE;
+ }
+ else
+ {
+ nCh = this->ply->ChannelAlloc(TYPE_PSG, this->prio);
+ if (nCh < 0)
+ return -1;
+ chn = &this->ply->channels[nCh];
+ chn->tempReg.CR = SOUND_FORMAT_PSG | SCHANNEL_ENABLE | SOUND_DUTY(noteDef->swav & 0x7);
+ }
+ // TODO: figure out what pNoteDef->tnote means for PSG channels
+ chn->tempReg.TIMER = -SOUND_FREQ(440 * 8); // key #69 (A4)
+ chn->reg.samplePosition = -1;
+ chn->reg.psgX = 0x7FFF;
+ }
+
+ if (bIsPCM)
+ {
+ nCh = this->ply->ChannelAlloc(TYPE_PCM, this->prio);
+ if (nCh < 0)
+ return -1;
+ chn = &this->ply->channels[nCh];
+
+ auto swav = &sbnk->waveArc[noteDef->swar]->swavs.find(noteDef->swav)->second;
+ chn->tempReg.CR = SOUND_FORMAT(swav->waveType & 3) | SOUND_LOOP(!!swav->loop) | SCHANNEL_ENABLE;
+ chn->tempReg.SOURCE = swav;
+ chn->tempReg.TIMER = swav->time;
+ chn->tempReg.REPEAT_POINT = swav->loopOffset;
+ chn->tempReg.LENGTH = swav->nonLoopLength;
+ chn->reg.samplePosition = -3;
+ }
+
+ chn->state = CS_START;
+ chn->trackId = this->trackId;
+ chn->flags.reset();
+ chn->prio = this->prio;
+ chn->key = key;
+ chn->orgKey = bIsPCM ? noteDef->noteNumber : 69;
+ chn->velocity = Cnv_Sust(vel);
+ chn->pan = static_cast<int>(noteDef->pan) - 64;
+ chn->modDelayCnt = 0;
+ chn->modCounter = 0;
+ chn->noteLength = len;
+ chn->reg.sampleIncrease = 0;
+
+ chn->attackLvl = Cnv_Attack(this->a == 0xFF ? noteDef->attackRate : this->a);
+ chn->decayRate = Cnv_Fall(this->d == 0xFF ? noteDef->decayRate : this->d);
+ chn->sustainLvl = this->s == 0xFF ? noteDef->sustainLevel : this->s;
+ chn->releaseRate = Cnv_Fall(this->r == 0xFF ? noteDef->releaseRate : this->r);
+
+ chn->UpdateVol(*this);
+ chn->UpdatePan(*this);
+ chn->UpdateTune(*this);
+ chn->UpdateMod(*this);
+ chn->UpdatePorta(*this);
+
+ this->portaKey = key;
+
+ return nCh;
+}
+
+int Track::NoteOnTie(int key, int vel)
+{
+ // Find an existing note
+ int i;
+ Channel *chn;
+ for (i = 0; i < 16; ++i)
+ {
+ chn = &this->ply->channels[i];
+ if (chn->state > CS_NONE && chn->trackId == this->trackId && chn->state != CS_RELEASE)
+ break;
+ }
+
+ if (i == 16)
+ // Can't find note -> create an endless one
+ return this->NoteOn(key, vel, -1);
+
+ chn->flags.reset();
+ chn->prio = this->prio;
+ chn->key = key;
+ chn->velocity = Cnv_Sust(vel);
+ chn->modDelayCnt = 0;
+ chn->modCounter = 0;
+
+ chn->UpdateVol(*this);
+ //chn->UpdatePan(*this);
+ chn->UpdateTune(*this);
+ chn->UpdateMod(*this);
+ chn->UpdatePorta(*this);
+
+ this->portaKey = key;
+ chn->flags.set(CF_UPDTMR);
+
+ return i;
+}
+
+void Track::ReleaseAllNotes()
+{
+ for (int i = 0; i < 16; ++i)
+ {
+ Channel &chn = this->ply->channels[i];
+ if (chn.state > CS_NONE && chn.trackId == this->trackId && chn.state != CS_RELEASE)
+ chn.Release();
+ }
+}
+
+enum SseqCommand
+{
+ SSEQ_CMD_REST = 0x80,
+ SSEQ_CMD_PATCH = 0x81,
+ SSEQ_CMD_PAN = 0xC0,
+ SSEQ_CMD_VOL = 0xC1,
+ SSEQ_CMD_MASTERVOL = 0xC2,
+ SSEQ_CMD_PRIO = 0xC6,
+ SSEQ_CMD_NOTEWAIT = 0xC7,
+ SSEQ_CMD_TIE = 0xC8,
+ SSEQ_CMD_EXPR = 0xD5,
+ SSEQ_CMD_TEMPO = 0xE1,
+ SSEQ_CMD_END = 0xFF,
+
+ SSEQ_CMD_GOTO = 0x94,
+ SSEQ_CMD_CALL = 0x95,
+ SSEQ_CMD_RET = 0xFD,
+ SSEQ_CMD_LOOPSTART = 0xD4,
+ SSEQ_CMD_LOOPEND = 0xFC,
+
+ SSEQ_CMD_TRANSPOSE = 0xC3,
+ SSEQ_CMD_PITCHBEND = 0xC4,
+ SSEQ_CMD_PITCHBENDRANGE = 0xC5,
+
+ SSEQ_CMD_ATTACK = 0xD0,
+ SSEQ_CMD_DECAY = 0xD1,
+ SSEQ_CMD_SUSTAIN = 0xD2,
+ SSEQ_CMD_RELEASE = 0xD3,
+
+ SSEQ_CMD_PORTAKEY = 0xC9,
+ SSEQ_CMD_PORTAFLAG = 0xCE,
+ SSEQ_CMD_PORTATIME = 0xCF,
+ SSEQ_CMD_SWEEPPITCH = 0xE3,
+
+ SSEQ_CMD_MODDEPTH = 0xCA,
+ SSEQ_CMD_MODSPEED = 0xCB,
+ SSEQ_CMD_MODTYPE = 0xCC,
+ SSEQ_CMD_MODRANGE = 0xCD,
+ SSEQ_CMD_MODDELAY = 0xE0,
+
+ SSEQ_CMD_RANDOM = 0xA0,
+ SSEQ_CMD_PRINTVAR = 0xD6,
+ SSEQ_CMD_IF = 0xA2,
+ SSEQ_CMD_UNSUP1 = 0xA1,
+ SSEQ_CMD_UNSUP2_LO = 0xB0,
+ SSEQ_CMD_UNSUP2_HI = 0xBD
+};
+
+void Track::Run()
+{
+ // Indicate "heartbeat" for this track
+ this->updateFlags.set(TUF_LEN);
+
+ // Exit if the track has already ended
+ if (this->state[TS_END])
+ return;
+
+ if (this->wait)
+ {
+ --this->wait;
+ if (this->wait)
+ return;
+ }
+
+ auto pData = &this->pos;
+
+ while (!this->wait)
+ {
+ int cmd = read8(pData);
+ if (cmd < 0x80)
+ {
+ // Note on
+ int key = cmd + this->transpose;
+ int vel = read8(pData);
+ int len = readvl(pData);
+ if (this->state[TS_NOTEWAIT])
+ this->wait = len;
+ if (this->state[TS_TIEBIT])
+ this->NoteOnTie(key, vel);
+ else
+ this->NoteOn(key, vel, len);
+ }
+ else
+ switch (cmd)
+ {
+ //-----------------------------------------------------------------
+ // Main commands
+ //-----------------------------------------------------------------
+
+ case SSEQ_CMD_REST:
+ this->wait = readvl(pData);
+ break;
+
+ case SSEQ_CMD_PATCH:
+ this->patch = readvl(pData);
+ break;
+
+ case SSEQ_CMD_GOTO:
+ *pData = &this->ply->sseq->data[read24(pData)];
+ break;
+
+ case SSEQ_CMD_CALL:
+ {
+ const uint8_t *dest = &this->ply->sseq->data[read24(pData)];
+ this->stack[this->stackPos++] = *pData;
+ *pData = dest;
+ break;
+ }
+
+ case SSEQ_CMD_RET:
+ *pData = this->stack[--this->stackPos];
+ break;
+
+ case SSEQ_CMD_PAN:
+ this->pan = read8(pData) - 64;
+ this->updateFlags.set(TUF_PAN);
+ break;
+
+ case SSEQ_CMD_VOL:
+ this->vol = read8(pData);
+ this->updateFlags.set(TUF_VOL);
+ break;
+
+ case SSEQ_CMD_MASTERVOL:
+ this->ply->masterVol = Cnv_Sust(read8(pData));
+ for (uint8_t i = 0; i < this->ply->nTracks; ++i)
+ this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
+ break;
+
+ case SSEQ_CMD_PRIO:
+ this->prio = this->ply->prio + read8(pData);
+ // Update here?
+ break;
+
+ case SSEQ_CMD_NOTEWAIT:
+ this->state.set(TS_NOTEWAIT, !!read8(pData));
+ break;
+
+ case SSEQ_CMD_TIE:
+ this->state.set(TS_TIEBIT, !!read8(pData));
+ this->ReleaseAllNotes();
+ break;
+
+ case SSEQ_CMD_EXPR:
+ this->expr = read8(pData);
+ this->updateFlags.set(TUF_VOL);
+ break;
+
+ case SSEQ_CMD_TEMPO:
+ this->ply->tempo = read16(pData);
+ break;
+
+ case SSEQ_CMD_END:
+ this->state.set(TS_END);
+ return;
+
+ case SSEQ_CMD_LOOPSTART:
+ this->loopCount[this->stackPos] = read8(pData);
+ this->stack[this->stackPos++] = *pData;
+ break;
+
+ case SSEQ_CMD_LOOPEND:
+ if (this->stackPos)
+ {
+ const uint8_t *rPos = this->stack[this->stackPos - 1];
+ uint8_t &nR = this->loopCount[this->stackPos - 1];
+ uint8_t prevR = nR;
+ if (prevR && !--nR)
+ --this->stackPos;
+ *pData = rPos;
+ }
+ break;
+
+ //-----------------------------------------------------------------
+ // Tuning commands
+ //-----------------------------------------------------------------
+
+ case SSEQ_CMD_TRANSPOSE:
+ this->transpose = read8(pData);
+ break;
+
+ case SSEQ_CMD_PITCHBEND:
+ this->pitchBend = read8(pData);
+ this->updateFlags.set(TUF_TIMER);
+ break;
+
+ case SSEQ_CMD_PITCHBENDRANGE:
+ this->pitchBendRange = read8(pData);
+ this->updateFlags.set(TUF_TIMER);
+ break;
+
+ //-----------------------------------------------------------------
+ // Envelope-related commands
+ //-----------------------------------------------------------------
+
+ case SSEQ_CMD_ATTACK:
+ this->a = read8(pData);
+ break;
+
+ case SSEQ_CMD_DECAY:
+ this->d = read8(pData);
+ break;
+
+ case SSEQ_CMD_SUSTAIN:
+ this->s = read8(pData);
+ break;
+
+ case SSEQ_CMD_RELEASE:
+ this->r = read8(pData);
+ break;
+
+ //-----------------------------------------------------------------
+ // Portamento-related commands
+ //-----------------------------------------------------------------
+
+ case SSEQ_CMD_PORTAKEY:
+ this->portaKey = read8(pData) + this->transpose;
+ this->state.set(TS_PORTABIT);
+ // Update here?
+ break;
+
+ case SSEQ_CMD_PORTAFLAG:
+ this->state.set(TS_PORTABIT, !!read8(pData));
+ // Update here?
+ break;
+
+ case SSEQ_CMD_PORTATIME:
+ this->portaTime = read8(pData);
+ // Update here?
+ break;
+
+ case SSEQ_CMD_SWEEPPITCH:
+ this->sweepPitch = read16(pData);
+ // Update here?
+ break;
+
+ //-----------------------------------------------------------------
+ // Modulation-related commands
+ //-----------------------------------------------------------------
+
+ case SSEQ_CMD_MODDEPTH:
+ this->modDepth = read8(pData);
+ this->updateFlags.set(TUF_MOD);
+ break;
+
+ case SSEQ_CMD_MODSPEED:
+ this->modSpeed = read8(pData);
+ this->updateFlags.set(TUF_MOD);
+ break;
+
+ case SSEQ_CMD_MODTYPE:
+ this->modType = read8(pData);
+ this->updateFlags.set(TUF_MOD);
+ break;
+
+ case SSEQ_CMD_MODRANGE:
+ this->modRange = read8(pData);
+ this->updateFlags.set(TUF_MOD);
+ break;
+
+ case SSEQ_CMD_MODDELAY:
+ this->modDelay = read16(pData);
+ this->updateFlags.set(TUF_MOD);
+ break;
+
+ //-----------------------------------------------------------------
+ // Variable-related commands
+ //-----------------------------------------------------------------
+
+ case SSEQ_CMD_RANDOM: // TODO
+ *pData += 5;
+ break;
+
+ case SSEQ_CMD_PRINTVAR: // TODO
+ *pData += 1;
+ break;
+
+ case SSEQ_CMD_UNSUP1: // TODO
+ {
+ int t = read8(pData);
+ if (t >= SSEQ_CMD_UNSUP2_LO && t <= SSEQ_CMD_UNSUP2_HI)
+ *pData += 1;
+ *pData += 1;
+ break;
+ }
+
+ case SSEQ_CMD_IF: // TODO
+ break;
+
+ default:
+ if (cmd >= SSEQ_CMD_UNSUP2_LO && cmd <= SSEQ_CMD_UNSUP2_HI) // TODO
+ *pData += 3;
+ }
+ }
+}
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/Track.h
@@ -1,1 +1,62 @@
+/*
+ * SSEQ Player - Track structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Adapted from source code of FeOS Sound System
+ * By fincs
+ * https://github.com/fincs/FSS
+ */
+#ifndef SSEQPLAYER_TRACK_H
+#define SSEQPLAYER_TRACK_H
+
+#include <bitset>
+#include "consts.h"
+
+struct Player;
+
+struct Track
+{
+ int8_t trackId;
+
+ std::bitset<TS_BITS> state;
+ uint8_t num, prio;
+ Player *ply;
+
+ const uint8_t *startPos;
+ const uint8_t *pos;
+ const uint8_t *stack[FSS_TRACKSTACKSIZE];
+ uint8_t stackPos;
+ uint8_t loopCount[FSS_TRACKSTACKSIZE];
+
+ int wait;
+ uint16_t patch;
+ uint8_t portaKey, portaTime;
+ int16_t sweepPitch;
+ uint8_t vol, expr;
+ int8_t pan; // -64..63
+ uint8_t pitchBendRange;
+ int8_t pitchBend;
+ int8_t transpose;
+
+ uint8_t a, d, s, r;
+
+ uint8_t modType, modSpeed, modDepth, modRange;
+ uint16_t modDelay;
+
+ std::bitset<TUF_BITS> updateFlags;
+
+ Track();
+
+ void Init(uint8_t handle, Player *ply, const uint8_t *pos, int n);
+ void Zero();
+ void ClearState();
+ int NoteOn(int key, int vel, int len);
+ int NoteOnTie(int key, int vel);
+ void ReleaseAllNotes();
+ void Run();
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/common.h
@@ -1,1 +1,242 @@
-
+/*
+ * SSEQ Player - Common functions
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Some code from FeOS Sound System
+ * By fincs
+ * https://github.com/fincs/FSS
+ */
+
+#ifndef SSEQPLAYER_COMMON_H
+#define SSEQPLAYER_COMMON_H
+
+#include <string>
+#include <vector>
+#include <cstring>
+#include "pstdint.h"
+
+/*
+ * Pseudo-file data structure
+ */
+
+struct PseudoFile
+{
+ std::vector<uint8_t> *data;
+ uint32_t pos;
+
+ PseudoFile() : data(NULL), pos(0)
+ {
+ }
+
+ template<typename T> T ReadLE()
+ {
+ T finalVal = 0;
+ for (size_t i = 0; i < sizeof(T); ++i)
+ finalVal |= (*this->data)[this->pos++] << (i * 8);
+ return finalVal;
+ }
+
+ template<typename T, size_t N> void ReadLE(T (&arr)[N])
+ {
+ for (size_t i = 0; i < N; ++i)
+ arr[i] = this->ReadLE<T>();
+ }
+
+ template<size_t N> void ReadLE( uint8_t arr[N])
+ {
+ memcpy(&arr[0], &(*this->data)[this->pos], N);
+ this->pos += N;
+ }
+
+ template<typename T> void ReadLE(std::vector<T> &arr)
+ {
+ for (size_t i = 0, len = arr.size(); i < len; ++i)
+ arr[i] = this->ReadLE<T>();
+ }
+
+ void ReadLE(std::vector<uint8_t> &arr)
+ {
+ memcpy(&arr[0], &(*this->data)[this->pos], arr.size());
+ this->pos += arr.size();
+ }
+
+ std::string ReadNullTerminatedString()
+ {
+ char chr;
+ std::string str;
+ do
+ {
+ chr = static_cast<char>(this->ReadLE<uint8_t>());
+ if (chr)
+ str += chr;
+ } while (chr);
+ return str;
+ }
+};
+
+/*
+ * Data Reading
+ *
+ * The following ReadLE functions will either read from a file or from an
+ * array (sent in as a pointer), while making sure that the data is read in
+ * as little-endian formating.
+ */
+
+template<typename T> inline T ReadLE(const uint8_t *arr)
+{
+ T finalVal = 0;
+ for (size_t i = 0; i < sizeof(T); ++i)
+ finalVal |= arr[i] << (i * 8);
+ return finalVal;
+}
+
+/*
+ * The following function is used to convert an integer into a hexidecimal
+ * string, the length being determined by the size of the integer. 8-bit
+ * integers are in the format of 0x00, 16-bit integers are in the format of
+ * 0x0000, and so on.
+ */
+template<typename T> inline std::string NumToHexString(const T &num)
+{
+ std::string hex;
+ uint8_t len = sizeof(T) * 2;
+ for (uint8_t i = 0; i < len; ++i)
+ {
+ uint8_t tmp = (num >> (i * 4)) & 0xF;
+ hex = static_cast<char>(tmp < 10 ? tmp + '0' : tmp - 10 + 'a') + hex;
+ }
+ return "0x" + hex;
+}
+
+/*
+ * SDAT Record types
+ * List of types taken from the Nitro Composer Specification
+ * http://www.feshrine.net/hacking/doc/nds-sdat.html
+ */
+enum RecordName
+{
+ REC_SEQ,
+ REC_SEQARC,
+ REC_BANK,
+ REC_WAVEARC,
+ REC_PLAYER,
+ REC_GROUP,
+ REC_PLAYER2,
+ REC_STRM
+};
+
+template<size_t N> inline bool VerifyHeader(int8_t (&arr)[N], const std::string &header)
+{
+ std::string arrHeader = std::string(&arr[0], &arr[N]);
+ return arrHeader == header;
+}
+
+/*
+ * The remaining functions in this file come from the FeOS Sound System source code.
+ */
+inline int Cnv_Attack(int attk)
+{
+ static const uint8_t lut[] =
+ {
+ 0x00, 0x01, 0x05, 0x0E, 0x1A, 0x26, 0x33, 0x3F, 0x49, 0x54,
+ 0x5C, 0x64, 0x6D, 0x74, 0x7B, 0x7F, 0x84, 0x89, 0x8F
+ };
+
+ return attk >= 0x6D ? lut[0x7F - attk] : 0xFF - attk;
+}
+
+inline int Cnv_Fall(int fall)
+{
+ if (fall == 0x7F)
+ return 0xFFFF;
+ else if (fall == 0x7E)
+ return 0x3C00;
+ else if (fall < 0x32)
+ return ((fall << 1) + 1) & 0xFFFF;
+ else
+ return (0x1E00 / (0x7E - fall)) & 0xFFFF;
+}
+
+inline int Cnv_Sust(int sust)
+{
+ static const int16_t lut[] =
+ {
+ -32768, -722, -721, -651, -601, -562, -530, -503,
+ -480, -460, -442, -425, -410, -396, -383, -371,
+ -360, -349, -339, -330, -321, -313, -305, -297,
+ -289, -282, -276, -269, -263, -257, -251, -245,
+ -239, -234, -229, -224, -219, -214, -210, -205,
+ -201, -196, -192, -188, -184, -180, -176, -173,
+ -169, -165, -162, -158, -155, -152, -149, -145,
+ -142, -139, -136, -133, -130, -127, -125, -122,
+ -119, -116, -114, -111, -109, -106, -103, -101,
+ -99, -96, -94, -91, -89, -87, -85, -82,
+ -80, -78, -76, -74, -72, -70, -68, -66,
+ -64, -62, -60, -58, -56, -54, -52, -50,
+ -49, -47, -45, -43, -42, -40, -38, -36,
+ -35, -33, -31, -30, -28, -27, -25, -23,
+ -22, -20, -19, -17, -16, -14, -13, -11,
+ -10, -8, -7, -6, -4, -3, -1, 0
+ };
+
+ return lut[sust];
+}
+
+inline int Cnv_Sine(int arg)
+{
+ static const int lut_size = 32;
+ static const int8_t lut[] =
+ {
+ 0, 6, 12, 19, 25, 31, 37, 43, 49, 54, 60, 65, 71, 76, 81, 85, 90, 94,
+ 98, 102, 106, 109, 112, 115, 117, 120, 122, 123, 125, 126, 126, 127, 127
+ };
+
+ if (arg < lut_size)
+ return lut[arg];
+ if (arg < 2 * lut_size)
+ return lut[2 * lut_size - arg];
+ if (arg < 3 * lut_size)
+ return -lut[arg - 2 * lut_size];
+ /*else*/
+ return -lut[4 * lut_size - arg];
+}
+
+inline int read8(const uint8_t **ppData)
+{
+ auto pData = *ppData;
+ int x = *pData;
+ *ppData = pData + 1;
+ return x;
+}
+
+inline int read16(const uint8_t **ppData)
+{
+ int x = read8(ppData);
+ x |= read8(ppData) << 8;
+ return x;
+}
+
+inline int read24(const uint8_t **ppData)
+{
+ int x = read8(ppData);
+ x |= read8(ppData) << 8;
+ x |= read8(ppData) << 16;
+ return x;
+}
+
+inline int readvl(const uint8_t **ppData)
+{
+ int x = 0;
+ for (;;)
+ {
+ int data = read8(ppData);
+ x = (x << 7) | (data & 0x7F);
+ if (!(data & 0x80))
+ break;
+ }
+ return x;
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/SSEQPlayer/consts.h
@@ -1,1 +1,57 @@
+/*
+ * SSEQ Player - Constants/Macros
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Adapted from source code of FeOS Sound System
+ * By fincs
+ * https://github.com/fincs/FSS
+ *
+ * Some constants/macros also taken from libdns, part of the devkitARM portion of devkitPro
+ * http://devkitpro.org/
+ */
+#ifndef SSEQPLAYER_CONSTS_H
+#define SSEQPLAYER_CONSTS_H
+
+#include "pstdint.h"
+
+const uint32_t ARM7_CLOCK = 33513982;
+const double SecondsPerClockCycle = 64.0 * 2728.0 / ARM7_CLOCK;
+
+inline uint32_t BIT(uint32_t n) { return 1 << n; }
+
+enum { TS_ALLOCBIT, TS_NOTEWAIT, TS_PORTABIT, TS_TIEBIT, TS_END, TS_BITS };
+
+enum { TUF_VOL, TUF_PAN, TUF_TIMER, TUF_MOD, TUF_LEN, TUF_BITS };
+
+enum { CS_NONE, CS_START, CS_ATTACK, CS_DECAY, CS_SUSTAIN, CS_RELEASE };
+
+enum { CF_UPDVOL, CF_UPDPAN, CF_UPDTMR, CF_BITS };
+
+enum { TYPE_PCM, TYPE_PSG, TYPE_NOISE };
+
+const int FSS_TRACKCOUNT = 16;
+const int FSS_MAXTRACKS = 32;
+const int FSS_TRACKSTACKSIZE = 3;
+const int AMPL_K = 723;
+const int AMPL_MIN = -AMPL_K;
+const int AMPL_THRESHOLD = AMPL_MIN << 7;
+
+inline int SOUND_FREQ(int n) { return -0x1000000 / n; }
+
+inline uint32_t SOUND_VOL(int n) { return n; }
+inline uint32_t SOUND_VOLDIV(int n) { return n << 8; }
+inline uint32_t SOUND_PAN(int n) { return n << 16; }
+inline uint32_t SOUND_DUTY(int n) { return n << 24; }
+const uint32_t SOUND_REPEAT = BIT(27);
+const uint32_t SOUND_ONE_SHOT = BIT(28);
+inline uint32_t SOUND_LOOP(bool a) { return a ? SOUND_REPEAT : SOUND_ONE_SHOT; }
+const uint32_t SOUND_FORMAT_PSG = 3 << 29;
+inline uint32_t SOUND_FORMAT(int n) { return n << 29; }
+const uint32_t SCHANNEL_ENABLE = BIT(31);
+
+enum Interpolation { INTERPOLATION_NONE, INTERPOLATION_LINEAR, INTERPOLATION_COSINE };
+
+#endif
+
--- /dev/null
+++ b/src/in_ncsf/XSFConfig_NCSF.cpp
@@ -1,1 +1,145 @@
+/*
+ * xSF - NCSF configuration
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Partially based on the vio*sf framework
+ */
+#include <bitset>
+#include "XSFPlayer_NCSF.h"
+#include "XSFConfig.h"
+#include "convert.h"
+#include "BigSString.h"
+
+enum
+{
+ idInterpolation = 1000,
+ idMutes
+};
+
+class XSFConfig_NCSF : public XSFConfig
+{
+protected:
+ static unsigned initInterpolation;
+ static std::wstring initMutes;
+
+ friend class XSFConfig;
+ unsigned interpolation;
+ std::bitset<16> mutes;
+
+ XSFConfig_NCSF();
+ void LoadSpecificConfig();
+ void SaveSpecificConfig();
+ void GenerateSpecificDialogs();
+ INT_PTR CALLBACK ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void ResetSpecificConfigDefaults(HWND hwndDlg);
+ void SaveSpecificConfigDialog(HWND hwndDlg);
+ void CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
+public:
+ void About(HWND parent);
+};
+
+unsigned XSFConfig::initSampleRate = 44100;
+std::wstring XSFConfig::commonName = L"NCSF Decoder";
+std::wstring XSFConfig::versionNumber = L"1.0";
+unsigned XSFConfig_NCSF::initInterpolation = 2;
+std::wstring XSFConfig_NCSF::initMutes = L"0000000000000000";
+
+XSFConfig *XSFConfig::Create()
+{
+ return new XSFConfig_NCSF();
+}
+
+XSFConfig_NCSF::XSFConfig_NCSF() : XSFConfig(), interpolation(0), mutes()
+{
+ this->supportedSampleRates.push_back(8000);
+ this->supportedSampleRates.push_back(11025);
+ this->supportedSampleRates.push_back(16000);
+ this->supportedSampleRates.push_back(22050);
+ this->supportedSampleRates.push_back(32000);
+ this->supportedSampleRates.push_back(44100);
+ this->supportedSampleRates.push_back(48000);
+ this->supportedSampleRates.push_back(88200);
+ this->supportedSampleRates.push_back(96000);
+ this->supportedSampleRates.push_back(176400);
+ this->supportedSampleRates.push_back(192000);
+}
+
+void XSFConfig_NCSF::LoadSpecificConfig()
+{
+ this->interpolation = this->configIO->GetValue(L"Interpolation", XSFConfig_NCSF::initInterpolation);
+ std::wstringstream mutesSS = std::wstringstream(this->configIO->GetValue(L"Mutes", XSFConfig_NCSF::initMutes));
+ mutesSS >> this->mutes;
+}
+
+void XSFConfig_NCSF::SaveSpecificConfig()
+{
+ this->configIO->SetValue(L"Interpolation", this->interpolation);
+ this->configIO->SetValue(L"Mutes", this->mutes.to_string<wchar_t>());
+}
+
+void XSFConfig_NCSF::GenerateSpecificDialogs()
+{
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Interpolation").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
+ this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(78, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idInterpolation).
+ IsDropDownList().WithTabStop());
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Mute").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
+ this->configDialog.AddListBoxControl(DialogListBoxBuilder().WithSize(78, 45).WithExactHeight().InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idMutes).
+ WithBorder().WithVerticalScrollbar().WithMultipleSelect().WithTabStop());
+}
+
+INT_PTR CALLBACK XSFConfig_NCSF::ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // Interpolation
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"No Interpolation"));
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Linear Interpolation"));
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Cosine Interpolation"));
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_SETCURSEL, this->interpolation, 0);
+ // Mutes
+ for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
+ {
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>((L"SPU " + wstringify(x + 1)).c_str()));
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, this->mutes[x], x);
+ }
+ break;
+ case WM_COMMAND:
+ break;
+ }
+
+ return XSFConfig::ConfigDialogProc(hwndDlg, uMsg, wParam, lParam);
+}
+
+void XSFConfig_NCSF::ResetSpecificConfigDefaults(HWND hwndDlg)
+{
+ SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_SETCURSEL, XSFConfig_NCSF::initInterpolation, 0);
+ auto tmpMutes = std::bitset<16>(XSFConfig_NCSF::initMutes);
+ for (int x = 0, numMutes = tmpMutes.size(); x < numMutes; ++x)
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, tmpMutes[x], x);
+}
+
+void XSFConfig_NCSF::SaveSpecificConfigDialog(HWND hwndDlg)
+{
+ this->interpolation = static_cast<unsigned>(SendMessageW(GetDlgItem(hwndDlg, idInterpolation), CB_GETCURSEL, 0, 0));
+ for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
+ this->mutes[x] = !!SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_GETSEL, x, 0);
+}
+
+void XSFConfig_NCSF::CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad)
+{
+ XSFPlayer_NCSF *NCSFPlayer = static_cast<XSFPlayer_NCSF *>(xSFPlayer);
+ if (preLoad)
+ NCSFPlayer->SetInterpolation(this->interpolation);
+ else
+ NCSFPlayer->SetMutes(this->mutes);
+}
+
+void XSFConfig_NCSF::About(HWND parent)
+{
+ MessageBox(parent, (XSFConfig::commonName + L" v" + XSFConfig::versionNumber + L", using xSF Winamp plugin framework (based on the vio*sf plugins) by Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]\n\n"
+ L"Utilizes code adapted from the FeOS Sound System library by fincs, git revision 9cb9820 on GitHub, for audio playback.").c_str(), (XSFConfig::commonName + L" v" + XSFConfig::versionNumber).c_str(), MB_OK);
+}
+
--- /dev/null
+++ b/src/in_ncsf/XSFPlayer_NCSF.cpp
@@ -1,1 +1,206 @@
-
+/*
+ * xSF - NCSF Player
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Partially based on the vio*sf framework
+ *
+ * Utilizes a modified FeOS Sound System for playback
+ * https://github.com/fincs/FSS
+ */
+
+#include <memory>
+#include <zlib.h>
+#include "convert.h"
+#include "XSFPlayer_NCSF.h"
+#include "XSFCommon.h"
+#include "SSEQPlayer/SDAT.h"
+#include "SSEQPlayer/Player.h"
+
+const char *XSFPlayer::WinampDescription = "NCSF Decoder";
+const char *XSFPlayer::WinampExts = "ncsf;minincsf\0DS Nitro Composer Sound Format files (*.ncsf;*.minincsf)\0";
+
+XSFPlayer *XSFPlayer::Create(const std::string &fn)
+{
+ return new XSFPlayer_NCSF(fn);
+}
+
+XSFPlayer *XSFPlayer::Create(const std::wstring &fn)
+{
+ return new XSFPlayer_NCSF(fn);
+}
+
+void XSFPlayer_NCSF::MapNCSFSection(const std::vector<uint8_t> §ion)
+{
+ uint32_t size = Get32BitsLE(§ion[8]), finalSize = size;
+ if (this->sdatData.empty())
+ this->sdatData.resize(finalSize, 0);
+ else if (this->sdatData.size() < size)
+ this->sdatData.resize(finalSize);
+ memcpy(&this->sdatData[0], §ion[0], size);
+}
+
+bool XSFPlayer_NCSF::MapNCSF(XSFFile *xSFToLoad)
+{
+ if (!xSFToLoad->IsValidType(0x25))
+ return false;
+
+ auto &reservedSection = xSFToLoad->GetReservedSection(), &programSection = xSFToLoad->GetProgramSection();
+
+ if (!reservedSection.empty())
+ this->sseq = Get32BitsLE(&reservedSection[0]);
+
+ if (!programSection.empty())
+ this->MapNCSFSection(programSection);
+
+ return true;
+}
+
+bool XSFPlayer_NCSF::RecursiveLoadNCSF(XSFFile *xSFToLoad, int level)
+{
+ if (level <= 10 && xSFToLoad->GetTagExists("_lib"))
+ {
+#ifdef _WIN32
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSFToLoad->GetFilename().GetWStr()) + xSFToLoad->GetTagValue("_lib").GetWStr(), 8, 12));
+#else
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSFToLoad->GetFilename().GetAnsi()) + xSFToLoad->GetTagValue("_lib").GetAnsi(), 8, 12));
+#endif
+ if (!this->RecursiveLoadNCSF(libxSF.get(), level + 1))
+ return false;
+ }
+
+ if (!this->MapNCSF(xSFToLoad))
+ return false;
+
+ unsigned n = 2;
+ bool found;
+ do
+ {
+ found = false;
+ std::string libTag = "_lib" + stringify(n++);
+ if (xSFToLoad->GetTagExists(libTag))
+ {
+ found = true;
+#ifdef _WIN32
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSFToLoad->GetFilename().GetWStr()) + xSFToLoad->GetTagValue(libTag).GetWStr(), 8, 12));
+#else
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSFToLoad->GetFilename().GetAnsi()) + xSFToLoad->GetTagValue(libTag).GetAnsi(), 8, 12));
+#endif
+ if (!this->RecursiveLoadNCSF(libxSF.get(), level + 1))
+ return false;
+ }
+ } while (found);
+
+ return true;
+}
+
+bool XSFPlayer_NCSF::LoadNCSF()
+{
+ return this->RecursiveLoadNCSF(this->xSF, 1);
+}
+
+XSFPlayer_NCSF::XSFPlayer_NCSF(const std::string &filename) : XSFPlayer()
+{
+ this->xSF = new XSFFile(filename, 8, 12);
+}
+
+XSFPlayer_NCSF::XSFPlayer_NCSF(const std::wstring &filename) : XSFPlayer()
+{
+ this->xSF = new XSFFile(filename, 8, 12);
+}
+
+bool XSFPlayer_NCSF::Load()
+{
+ if (!this->LoadNCSF())
+ return false;
+
+ PseudoFile file;
+ file.data = &this->sdatData;
+ this->sdat.reset(new SDAT(file, this->sseq));
+ auto *sseqToPlay = this->sdat->sseq.get();
+ this->player.sampleRate = this->sampleRate;
+ this->player.Setup(sseqToPlay);
+ //this->player.masterVol = sseq->info.vol;
+ this->player.Timer();
+ this->secondsPerSample = 1.0 / this->sampleRate;
+ this->secondsIntoPlayback = 0;
+ this->secondsUntilNextClock = SecondsPerClockCycle;
+
+ return XSFPlayer::Load();
+}
+
+template<typename T1, typename T2> static inline void clamp(T1 &valueToClamp, const T2 &minValue, const T2 &maxValue)
+{
+ if (valueToClamp < minValue)
+ valueToClamp = minValue;
+ else if (valueToClamp > maxValue)
+ valueToClamp = maxValue;
+}
+
+static inline int32_t muldiv7(int32_t val, uint8_t mul)
+{
+ return mul == 127 ? val : ((val * mul) >> 7);
+}
+
+void XSFPlayer_NCSF::GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples)
+{
+ unsigned long mute = this->mutes.to_ulong();
+
+ for (unsigned smpl = 0; smpl < samples; ++smpl)
+ {
+ this->secondsIntoPlayback += this->secondsPerSample;
+
+ int32_t leftChannel = 0, rightChannel = 0;
+
+ // I need to advance the sound channels here
+ for (int i = 0; i < 16; ++i)
+ {
+ Channel &chn = this->player.channels[i];
+
+ if (chn.state > CS_NONE)
+ {
+ int32_t sample = chn.GenerateSample();
+ chn.IncrementSample();
+
+ if (mute & BIT(i))
+ continue;
+
+ uint8_t datashift = chn.reg.volumeDiv;
+ if (datashift == 3)
+ datashift = 4;
+ sample = muldiv7(sample, chn.reg.volumeMul) >> datashift;
+
+ leftChannel += muldiv7(sample, 127 - chn.reg.panning);
+ rightChannel += muldiv7(sample, chn.reg.panning);
+ }
+ }
+
+ leftChannel = muldiv7(leftChannel, 127 - this->player.masterVol);
+ rightChannel = muldiv7(rightChannel, 127 - this->player.masterVol);
+
+ clamp(leftChannel, -0x8000, 0x7FFF);
+ clamp(rightChannel, -0x8000, 0x7FFF);
+
+ buf[offset++] = leftChannel & 0xFF;
+ buf[offset++] = (leftChannel >> 8) & 0xFF;
+ buf[offset++] = rightChannel & 0xFF;
+ buf[offset++] = (rightChannel >> 8) & 0xFF;
+
+ if (this->secondsIntoPlayback > this->secondsUntilNextClock)
+ {
+ this->player.Timer();
+ this->secondsUntilNextClock += SecondsPerClockCycle;
+ }
+ }
+}
+
+void XSFPlayer_NCSF::SetInterpolation(unsigned interpolation)
+{
+ this->player.interpolation = static_cast<Interpolation>(interpolation);
+}
+
+void XSFPlayer_NCSF::SetMutes(const std::bitset<16> &newMutes)
+{
+ this->mutes = newMutes;
+}
+
--- /dev/null
+++ b/src/in_ncsf/XSFPlayer_NCSF.h
@@ -1,1 +1,46 @@
+/*
+ * xSF - NCSF Player
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Partially based on the vio*sf framework
+ *
+ * Utilizes a modified FeOS Sound System for playback
+ * https://github.com/fincs/FSS
+ */
+#ifndef XSFPLAYER_NCSF_H
+#define XSFPLAYER_NCSF_H
+
+#include <memory>
+#include <bitset>
+#include "XSFPlayer.h"
+#include "SSEQPlayer/SDAT.h"
+#include "SSEQPlayer/Player.h"
+
+class XSFPlayer_NCSF : public XSFPlayer
+{
+ uint32_t sseq;
+ std::vector<uint8_t> sdatData;
+ std::auto_ptr<SDAT> sdat;
+ Player player;
+ double secondsPerSample, secondsIntoPlayback, secondsUntilNextClock;
+ std::bitset<16> mutes;
+
+ void MapNCSFSection(const std::vector<uint8_t> §ion);
+ bool MapNCSF(XSFFile *xSFToLoad);
+ bool RecursiveLoadNCSF(XSFFile *xSFToLoad, int level);
+ bool LoadNCSF();
+public:
+ XSFPlayer_NCSF(const std::string &filename);
+ XSFPlayer_NCSF(const std::wstring &filename);
+ bool Load();
+ void GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples);
+ void Terminate() { }
+
+ void SetInterpolation(unsigned interpolation);
+ void SetMutes(const std::bitset<16> &newMutes);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/XSFConfig_SNSF.cpp
@@ -1,1 +1,150 @@
+/*
+ * xSF - SNSF configuration
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * 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 "XSFConfig_SNSF.h"
+#include "convert.h"
+#include "BigSString.h"
+#include "snes9x/apu/apu.h"
+
+enum
+{
+ idSixteenBitSound = 1000,
+ idReverseStereo,
+ idResampler,
+ idMutes
+};
+
+unsigned XSFConfig::initSampleRate = 44100;
+std::wstring XSFConfig::commonName = L"SNSF Decoder";
+std::wstring XSFConfig::versionNumber = L"0.9b";
+//bool XSFConfig_SNSF::initSixteenBitSound = true;
+bool XSFConfig_SNSF::initReverseStereo = false;
+unsigned XSFConfig_SNSF::initResampler = 1;
+std::wstring XSFConfig_SNSF::initMutes = L"00000000";
+
+XSFConfig *XSFConfig::Create()
+{
+ return new XSFConfig_SNSF();
+}
+
+XSFConfig_SNSF::XSFConfig_SNSF() : XSFConfig(), /*sixteenBitSound(false), */reverseStereo(false), mutes(), resampler(0)
+{
+ this->supportedSampleRates.push_back(8000);
+ this->supportedSampleRates.push_back(11025);
+ this->supportedSampleRates.push_back(16000);
+ this->supportedSampleRates.push_back(22050);
+ this->supportedSampleRates.push_back(32000);
+ this->supportedSampleRates.push_back(44100);
+ this->supportedSampleRates.push_back(48000);
+ this->supportedSampleRates.push_back(88200);
+ this->supportedSampleRates.push_back(96000);
+ this->supportedSampleRates.push_back(176400);
+ this->supportedSampleRates.push_back(192000);
+}
+
+void XSFConfig_SNSF::LoadSpecificConfig()
+{
+ //this->sixteenBitSound = this->configIO->GetValue(L"SixteenBitSound", XSFConfig_SNSF::initSixteenBitSound);
+ this->reverseStereo = this->configIO->GetValue(L"ReverseStereo", XSFConfig_SNSF::initReverseStereo);
+ this->resampler = this->configIO->GetValue(L"Resampler", XSFConfig_SNSF::initResampler);
+ std::wstringstream mutesSS(this->configIO->GetValue(L"Mutes", XSFConfig_SNSF::initMutes));
+ mutesSS >> this->mutes;
+}
+
+void XSFConfig_SNSF::SaveSpecificConfig()
+{
+ //this->configIO->SetValue(L"SixteenBitSound", this->sixteenBitSound);
+ this->configIO->SetValue(L"ReverseStereo", this->reverseStereo);
+ this->configIO->SetValue(L"Resampler", this->resampler);
+ this->configIO->SetValue(L"Mutes", this->mutes.to_string<wchar_t>());
+}
+
+void XSFConfig_SNSF::GenerateSpecificDialogs()
+{
+ /*this->configDialog.AddCheckBoxControl(DialogCheckBoxBuilder(L"Sixteen-Bit Sound").WithSize(80, 10).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 7), 2).WithTabStop().
+ WithID(idSixteenBitSound));*/
+ this->configDialog.AddCheckBoxControl(DialogCheckBoxBuilder(L"Reverse Stereo").WithSize(80, 10).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 7), 2).WithTabStop().
+ WithID(idReverseStereo));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Resampler").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10)).IsLeftJustified());
+ this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(78, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithTabStop().IsDropDownList().
+ WithID(idResampler));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Mute").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
+ this->configDialog.AddListBoxControl(DialogListBoxBuilder().WithSize(78, 45).WithExactHeight().InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idMutes).WithBorder().
+ WithVerticalScrollbar().WithMultipleSelect().WithTabStop());
+}
+
+INT_PTR CALLBACK XSFConfig_SNSF::ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // Sixteen-Bit Sound
+ /*if (this->sixteenBitSound)
+ SendMessageW(GetDlgItem(hwndDlg, idSixteenBitSound), BM_SETCHECK, BST_CHECKED, 0);*/
+ // Reverse Stereo
+ if (this->reverseStereo)
+ SendMessageW(GetDlgItem(hwndDlg, idReverseStereo), BM_SETCHECK, BST_CHECKED, 0);
+ // Resampler
+ SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Linear Resampler"));
+ SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Hermite Resampler"));
+ SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_SETCURSEL, this->resampler, 0);
+ // Mutes
+ for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
+ {
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_ADDSTRING, 0, reinterpret_cast<LPARAM>((L"BRRPCM " + wstringify(x + 1)).c_str()));
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, this->mutes[x], x);
+ }
+ break;
+ case WM_COMMAND:
+ break;
+ }
+
+ return XSFConfig::ConfigDialogProc(hwndDlg, uMsg, wParam, lParam);
+}
+
+void XSFConfig_SNSF::ResetSpecificConfigDefaults(HWND hwndDlg)
+{
+ //SendMessageW(GetDlgItem(hwndDlg, idSixteenBitSound), BM_SETCHECK, XSFConfig_SNSF::initSixteenBitSound ? BST_CHECKED : BST_UNCHECKED, 0);
+ SendMessageW(GetDlgItem(hwndDlg, idReverseStereo), BM_SETCHECK, XSFConfig_SNSF::initReverseStereo ? BST_CHECKED : BST_UNCHECKED, 0);
+ SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_SETCURSEL, XSFConfig_SNSF::initResampler, 0);
+ auto tmpMutes = std::bitset<8>(XSFConfig_SNSF::initMutes);
+ for (int x = 0, numMutes = tmpMutes.size(); x < numMutes; ++x)
+ SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_SETSEL, tmpMutes[x], x);
+}
+
+void XSFConfig_SNSF::SaveSpecificConfigDialog(HWND hwndDlg)
+{
+ //this->sixteenBitSound = SendMessageW(GetDlgItem(hwndDlg, idSixteenBitSound), BM_GETCHECK, 0, 0) == BST_CHECKED;
+ this->reverseStereo = SendMessageW(GetDlgItem(hwndDlg, idReverseStereo), BM_GETCHECK, 0, 0) == BST_CHECKED;
+ this->resampler = static_cast<unsigned>(SendMessageW(GetDlgItem(hwndDlg, idResampler), CB_GETCURSEL, 0, 0));
+ for (int x = 0, numMutes = this->mutes.size(); x < numMutes; ++x)
+ this->mutes[x] = !!SendMessageW(GetDlgItem(hwndDlg, idMutes), LB_GETSEL, x, 0);
+}
+
+void XSFConfig_SNSF::CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad)
+{
+ if (preLoad)
+ {
+ memset(&Settings, 0, sizeof(Settings));
+ //Settings.SixteenBitSound = this->sixteenBitSound;
+ Settings.ReverseStereo = this->reverseStereo;
+ }
+ else
+ S9xSetSoundControl(static_cast<uint8_t>(this->mutes.to_ulong()) ^ 0xFF);
+}
+
+void XSFConfig_SNSF::About(HWND parent)
+{
+ MessageBox(parent, (XSFConfig::commonName + L" v" + XSFConfig::versionNumber + L", using xSF Winamp plugin framework (based on the vio*sf plugins) by Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]\n\n"
+ L"Utilizes modified snes9x v1.53 for audio playback.").c_str(), (XSFConfig::commonName + L" v" + XSFConfig::versionNumber).c_str(), MB_OK);
+}
+
--- /dev/null
+++ b/src/in_snsf/XSFConfig_SNSF.h
@@ -1,1 +1,46 @@
+/*
+ * xSF - SNSF configuration
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * 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.
+ */
+#ifndef XSFCONFIG_SNSF_H
+#define XSFCONFIG_SNSF_H
+
+#include <bitset>
+#include "XSFPlayer.h"
+#include "XSFConfig.h"
+
+class XSFConfig_SNSF : public XSFConfig
+{
+protected:
+ static bool /*initSixteenBitSound, */initReverseStereo;
+ static unsigned initResampler;
+ static std::wstring initMutes;
+
+ friend class XSFConfig;
+ bool /*sixteenBitSound, */reverseStereo;
+ std::bitset<8> mutes;
+
+ XSFConfig_SNSF();
+ void LoadSpecificConfig();
+ void SaveSpecificConfig();
+ void GenerateSpecificDialogs();
+ INT_PTR CALLBACK ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void ResetSpecificConfigDefaults(HWND hwndDlg);
+ void SaveSpecificConfigDialog(HWND hwndDlg);
+ void CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
+public:
+ unsigned resampler;
+
+ void About(HWND parent);
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/XSFPlayer_SNSF.cpp
@@ -1,1 +1,285 @@
-
+/*
+ * xSF - SNSF Player
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Based on a modified in_snsf by Caitsith2
+ * http://snsf.caitsith2.net/
+ *
+ * Partially based on the vio*sf framework
+ *
+ * Utilizes a modified snes9x v1.53 for playback
+ * http://www.snes9x.com/
+ */
+
+#include <zlib.h>
+#include "convert.h"
+#include "XSFPlayer.h"
+#include "XSFConfig_SNSF.h"
+#include "XSFCommon.h"
+
+#undef min
+#undef max
+
+#include "snes9x/apu/apu.h"
+#include "snes9x/apu/linear_resampler.h"
+#include "snes9x/apu/hermite_resampler.h"
+#include "snes9x/memmap.h"
+
+class XSFPlayer_SNSF : public XSFPlayer
+{
+public:
+ XSFPlayer_SNSF(const std::string &filename);
+ XSFPlayer_SNSF(const std::wstring &filename);
+ ~XSFPlayer_SNSF() { this->Terminate(); }
+ bool Load();
+ void GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples);
+ void Terminate();
+};
+
+const char *XSFPlayer::WinampDescription = "SNSF Decoder";
+const char *XSFPlayer::WinampExts = "snsf;minisnsf\0SNES Sound Format files (*.snsf;*.minisnsf)\0";
+
+extern XSFConfig *xSFConfig;
+
+XSFPlayer *XSFPlayer::Create(const std::string &fn)
+{
+ return new XSFPlayer_SNSF(fn);
+}
+
+XSFPlayer *XSFPlayer::Create(const std::wstring &fn)
+{
+ return new XSFPlayer_SNSF(fn);
+}
+
+volatile bool execute = false;
+
+static struct
+{
+ std::vector<uint8_t> rom, sram;
+ bool first;
+ unsigned base;
+} loaderwork;
+
+class BUFFER
+{
+public:
+ std::vector<uint8_t> buf;
+ unsigned fil, cur, len;
+ BUFFER() : buf(), fil(0), cur(0), len(0) { }
+ bool Init()
+ {
+ this->len = 2 * 2 * 48000 / 5;
+ buf.resize(len);
+ return true;
+ }
+ void Fill()
+ {
+ S9xSyncSound();
+ S9xMainLoop();
+ this->Mix();
+ }
+ void Mix()
+ {
+ unsigned bytes = (S9xGetSampleCount() << 1) & ~3;
+ unsigned bleft = (this->len - this->fil) & ~3;
+ if (!bytes)
+ return;
+ if (bytes > bleft)
+ bytes = bleft;
+ memset(&this->buf[this->fil], 0, bytes);
+ S9xMixSamples(&this->buf[this->fil], bytes >> 1);
+ this->fil += bytes;
+ }
+};
+static BUFFER buffer;
+
+bool S9xOpenSoundDevice()
+{
+ return true;
+}
+
+static void Map2SFSection(const std::vector<uint8_t> §ion, int level)
+{
+ auto &data = loaderwork.rom;
+
+ uint32_t offset = Get32BitsLE(§ion[0]), size = Get32BitsLE(§ion[4]), finalSize = size + offset;
+ if (!loaderwork.first)
+ {
+ loaderwork.first = true;
+ loaderwork.base = offset;
+ }
+ else
+ offset += loaderwork.base;
+ offset &= 0x1FFFFFFF;
+ if (data.empty())
+ data.resize(finalSize, 0);
+ else if (data.size() < size + offset)
+ data.resize(offset + finalSize);
+ memcpy(&data[offset], §ion[8], size);
+}
+
+static bool Map2SF(XSFFile *xSF, int level)
+{
+ if (!xSF->IsValidType(0x23))
+ return false;
+
+ auto &reservedSection = xSF->GetReservedSection(), &programSection = xSF->GetProgramSection();
+
+ if (!reservedSection.empty())
+ {
+ size_t reservedPosition = 0, reservedSize = reservedSection.size();
+ while (reservedPosition + 8 < reservedSize)
+ {
+ uint32_t type = Get32BitsLE(&reservedSection[reservedPosition]), size = Get32BitsLE(&reservedSection[reservedPosition + 4]);
+ if (!type)
+ {
+ if (loaderwork.sram.empty())
+ loaderwork.sram.resize(0x20000, 0xFF);
+ if (reservedPosition + 8 + size > reservedSize)
+ return false;
+ uint32_t offset = Get32BitsLE(&reservedSection[reservedPosition + 8]);
+ if (size > 4 && loaderwork.sram.size() > offset)
+ {
+ auto len = std::min(size - 4, loaderwork.sram.size() - offset);
+ memcpy(&loaderwork.sram[offset], &reservedSection[reservedPosition + 12], len);
+ }
+ }
+ reservedPosition += size + 8;
+ }
+ }
+
+ if (!programSection.empty())
+ Map2SFSection(programSection, level);
+
+ return true;
+}
+
+static bool RecursiveLoad2SF(XSFFile *xSF, int level)
+{
+ if (level <= 10 && xSF->GetTagExists("_lib"))
+ {
+#ifdef _WIN32
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetWStr()) + xSF->GetTagValue("_lib").GetWStr(), 4, 8));
+#else
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetAnsi()) + xSF->GetTagValue("_lib").GetAnsi(), 4, 8));
+#endif
+ if (!RecursiveLoad2SF(libxSF.get(), level + 1))
+ return false;
+ }
+
+ if (!Map2SF(xSF, level))
+ return false;
+
+ unsigned n = 2;
+ bool found;
+ do
+ {
+ found = false;
+ std::string libTag = "_lib" + stringify(n++);
+ if (xSF->GetTagExists(libTag))
+ {
+ found = true;
+#ifdef _WIN32
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetWStr()) + xSF->GetTagValue(libTag).GetWStr(), 4, 8));
+#else
+ auto libxSF = std::auto_ptr<XSFFile>(new XSFFile(ExtractDirectoryFromPath(xSF->GetFilename().GetAnsi()) + xSF->GetTagValue(libTag).GetAnsi(), 4, 8));
+#endif
+ if (!RecursiveLoad2SF(libxSF.get(), level + 1))
+ return false;
+ }
+ } while (found);
+
+ return true;
+}
+
+static bool Load2SF(XSFFile *xSF)
+{
+ loaderwork.rom.clear();
+ loaderwork.sram.clear();
+ loaderwork.first = false;
+ loaderwork.base = 0;
+
+ return RecursiveLoad2SF(xSF, 1);
+}
+
+XSFPlayer_SNSF::XSFPlayer_SNSF(const std::string &filename) : XSFPlayer()
+{
+ this->xSF = new XSFFile(filename, 4, 8);
+}
+
+XSFPlayer_SNSF::XSFPlayer_SNSF(const std::wstring &filename) : XSFPlayer()
+{
+ this->xSF = new XSFFile(filename, 4, 8);
+}
+
+bool XSFPlayer_SNSF::Load()
+{
+ if (!Load2SF(this->xSF))
+ return false;
+
+ 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);
+ if (xSFConfig_SNSF->resampler)
+ S9xInitSound<HermiteResampler>(10, 0);
+ else
+ S9xInitSound<LinearResampler>(10, 0);
+
+ if (!buffer.Init())
+ return false;
+
+ if (!Memory.LoadROMSNSF(&loaderwork.rom[0], loaderwork.rom.size(), &loaderwork.sram[0], loaderwork.sram.size()))
+ return false;
+
+ //S9xSetPlaybackRate(Settings.SoundPlaybackRate);
+ S9xSetSoundMute(false);
+
+ // bad hack for gradius3snsf.rar
+ //Settings.TurboMode = true;
+
+ return XSFPlayer::Load();
+}
+
+void XSFPlayer_SNSF::GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples)
+{
+ unsigned bytes = samples << 2;
+ while (bytes)
+ {
+ unsigned remain = buffer.fil - buffer.cur;
+ while (!remain)
+ {
+ buffer.cur = buffer.fil = 0;
+ buffer.Fill();
+
+ remain = buffer.fil - buffer.cur;
+ }
+ unsigned len = remain;
+ if (len > bytes)
+ len = bytes;
+ memcpy(&buf[offset], &buffer.buf[buffer.cur], len);
+ bytes -= len;
+ offset += len;
+ buffer.cur += len;
+ }
+}
+
+void XSFPlayer_SNSF::Terminate()
+{
+ S9xReset();
+ Memory.Deinit();
+ S9xDeinitAPU();
+
+ loaderwork.rom.clear();
+ loaderwork.sram.clear();
+ loaderwork.first = false;
+ loaderwork.base = 0;
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/65c816.h
@@ -1,1 +1,278 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _65C816_H_
+#define _65C816_H_
+
+#define Carry 1
+#define Zero 2
+#define IRQ 4
+#define Decimal 8
+#define IndexFlag 16
+#define MemoryFlag 32
+#define Overflow 64
+#define Negative 128
+#define Emulation 256
+
+#define SetCarry() (ICPU._Carry = 1)
+#define ClearCarry() (ICPU._Carry = 0)
+#define SetZero() (ICPU._Zero = 0)
+#define ClearZero() (ICPU._Zero = 1)
+#define SetIRQ() (Registers.PL |= IRQ)
+#define ClearIRQ() (Registers.PL &= ~IRQ)
+#define SetDecimal() (Registers.PL |= Decimal)
+#define ClearDecimal() (Registers.PL &= ~Decimal)
+#define SetIndex() (Registers.PL |= IndexFlag)
+#define ClearIndex() (Registers.PL &= ~IndexFlag)
+#define SetMemory() (Registers.PL |= MemoryFlag)
+#define ClearMemory() (Registers.PL &= ~MemoryFlag)
+#define SetOverflow() (ICPU._Overflow = 1)
+#define ClearOverflow() (ICPU._Overflow = 0)
+#define SetNegative() (ICPU._Negative = 0x80)
+#define ClearNegative() (ICPU._Negative = 0)
+
+#define CheckCarry() (ICPU._Carry)
+#define CheckZero() (ICPU._Zero == 0)
+#define CheckIRQ() (Registers.PL & IRQ)
+#define CheckDecimal() (Registers.PL & Decimal)
+#define CheckIndex() (Registers.PL & IndexFlag)
+#define CheckMemory() (Registers.PL & MemoryFlag)
+#define CheckOverflow() (ICPU._Overflow)
+#define CheckNegative() (ICPU._Negative & 0x80)
+#define CheckEmulation() (Registers.P.W & Emulation)
+
+#define SetFlags(f) (Registers.P.W |= (f))
+#define ClearFlags(f) (Registers.P.W &= ~(f))
+#define CheckFlag(f) (Registers.PL & (f))
+
+typedef union
+{
+#ifdef LSB_FIRST
+ struct { uint8_t l, h; } B;
+#else
+ struct { uint8_t h, l; } B;
+#endif
+ uint16_t W;
+} pair;
+
+typedef union
+{
+#ifdef LSB_FIRST
+ struct { uint8_t xPCl, xPCh, xPB, z; } B;
+ struct { uint16_t xPC, d; } W;
+#else
+ struct { uint8_t z, xPB, xPCh, xPCl; } B;
+ struct { uint16_t d, xPC; } W;
+#endif
+ uint32_t xPBPC;
+} PC_t;
+
+struct SRegisters
+{
+ uint8_t DB;
+ pair P;
+ pair A;
+ pair D;
+ pair S;
+ pair X;
+ pair Y;
+ PC_t PC;
+};
+
+#define AL A.B.l
+#define AH A.B.h
+#define XL X.B.l
+#define XH X.B.h
+#define YL Y.B.l
+#define YH Y.B.h
+#define SL S.B.l
+#define SH S.B.h
+#define DL D.B.l
+#define DH D.B.h
+#define PL P.B.l
+#define PH P.B.h
+#define PBPC PC.xPBPC
+#define PCw PC.W.xPC
+#define PCh PC.B.xPCh
+#define PCl PC.B.xPCl
+#define PB PC.B.xPB
+
+extern struct SRegisters Registers;
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/SNES_SPC.cpp
@@ -1,1 +1,565 @@
-
+// Core SPC emulation: CPU, timers, SMP registers, memory
+
+// snes_spc 0.9.0. http://www.slack.net/~ant/
+
+#include "SNES_SPC.h"
+
+#include <string.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 */
+
+#include "blargg_source.h"
+
+#define RAM (m.ram.ram)
+#define REGS (m.smp_regs [0])
+#define REGS_IN (m.smp_regs [1])
+
+// (n ? n : 256)
+#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1)
+
+// Note: SPC_MORE_ACCURACY exists mainly so I can run my validation tests, which
+// do crazy echo buffer accesses.
+#ifndef SPC_MORE_ACCURACY
+ #define SPC_MORE_ACCURACY 0
+#endif
+
+#ifdef BLARGG_ENABLE_OPTIMIZER
+ #include BLARGG_ENABLE_OPTIMIZER
+#endif
+
+
+//// Timers
+
+#if SPC_DISABLE_TEMPO
+ #define TIMER_DIV( t, n ) ((n) >> t->prescaler)
+ #define TIMER_MUL( t, n ) ((n) << t->prescaler)
+#else
+ #define TIMER_DIV( t, n ) ((n) / t->prescaler)
+ #define TIMER_MUL( t, n ) ((n) * t->prescaler)
+#endif
+
+SNES_SPC::Timer* SNES_SPC::run_timer_( Timer* t, rel_time_t time )
+{
+ 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 = (uint8_t) divider;
+ }
+ return t;
+}
+
+inline SNES_SPC::Timer* SNES_SPC::run_timer( Timer* t, rel_time_t time )
+{
+ if ( time >= t->next_time )
+ t = run_timer_( t, time );
+ return t;
+}
+
+
+//// ROM
+
+void SNES_SPC::enable_rom( int enable )
+{
+ if ( m.rom_enabled != enable )
+ {
+ m.rom_enabled = dsp.rom_enabled = enable;
+ if ( enable )
+ memcpy( m.hi_ram, &RAM [rom_addr], sizeof m.hi_ram );
+ memcpy( &RAM [rom_addr], (enable ? m.rom : m.hi_ram), rom_size );
+ // TODO: ROM can still get overwritten when DSP writes to echo buffer
+ }
+}
+
+
+//// DSP
+
+#if SPC_LESS_ACCURATE
+ int const max_reg_time = 29;
+
+ signed char const SNES_SPC::reg_times_ [256] =
+ {
+ -1, 0,-11,-10,-15,-11, -2, -2, 4, 3, 14, 14, 26, 26, 14, 22,
+ 2, 3, 0, 1,-12, 0, 1, 1, 7, 6, 14, 14, 27, 14, 14, 23,
+ 5, 6, 3, 4, -1, 3, 4, 4, 10, 9, 14, 14, 26, -5, 14, 23,
+ 8, 9, 6, 7, 2, 6, 7, 7, 13, 12, 14, 14, 27, -4, 14, 24,
+ 11, 12, 9, 10, 5, 9, 10, 10, 16, 15, 14, 14, -2, -4, 14, 24,
+ 14, 15, 12, 13, 8, 12, 13, 13, 19, 18, 14, 14, -2,-36, 14, 24,
+ 17, 18, 15, 16, 11, 15, 16, 16, 22, 21, 14, 14, 28, -3, 14, 25,
+ 20, 21, 18, 19, 14, 18, 19, 19, 25, 24, 14, 14, 14, 29, 14, 25,
+
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ };
+
+ #define RUN_DSP( time, offset ) \
+ int count = (time) - (offset) - m.dsp_time;\
+ if ( count >= 0 )\
+ {\
+ int clock_count = (count & ~(clocks_per_sample - 1)) + clocks_per_sample;\
+ m.dsp_time += clock_count;\
+ dsp.run( clock_count );\
+ }
+#else
+ #define RUN_DSP( time, offset ) \
+ {\
+ int count = (time) - m.dsp_time;\
+ if ( !SPC_MORE_ACCURACY || count )\
+ {\
+ assert( count > 0 );\
+ m.dsp_time = (time);\
+ dsp.run( count );\
+ }\
+ }
+#endif
+
+int SNES_SPC::dsp_read( rel_time_t time )
+{
+ RUN_DSP( time, reg_times [REGS [r_dspaddr] & 0x7F] );
+
+ int result = dsp.read( REGS [r_dspaddr] & 0x7F );
+
+ #ifdef SPC_DSP_READ_HOOK
+ SPC_DSP_READ_HOOK( spc_time + time, (REGS [r_dspaddr] & 0x7F), result );
+ #endif
+
+ return result;
+}
+
+inline void SNES_SPC::dsp_write( int data, rel_time_t time )
+{
+ RUN_DSP( time, reg_times [REGS [r_dspaddr]] )
+ #if SPC_LESS_ACCURATE
+ else if ( m.dsp_time == skipping_time )
+ {
+ int r = REGS [r_dspaddr];
+ if ( r == SPC_DSP::r_kon )
+ m.skipped_kon |= data & ~dsp.read( SPC_DSP::r_koff );
+
+ if ( r == SPC_DSP::r_koff )
+ {
+ m.skipped_koff |= data;
+ m.skipped_kon &= ~data;
+ }
+ }
+ #endif
+
+ #ifdef SPC_DSP_WRITE_HOOK
+ SPC_DSP_WRITE_HOOK( m.spc_time + time, REGS [r_dspaddr], (uint8_t) data );
+ #endif
+
+ if ( REGS [r_dspaddr] <= 0x7F )
+ dsp.write( REGS [r_dspaddr], data );
+ else if ( !SPC_MORE_ACCURACY )
+ dprintf( "SPC wrote to DSP register > $7F\n" );
+}
+
+
+//// Memory access extras
+
+#if SPC_MORE_ACCURACY
+ #define MEM_ACCESS( time, addr ) \
+ {\
+ if ( time >= m.dsp_time )\
+ {\
+ RUN_DSP( time, max_reg_time );\
+ }\
+ }
+#elif !defined (NDEBUG)
+ // Debug-only check for read/write within echo buffer, since this might result in
+ // inaccurate emulation due to the DSP not being caught up to the present.
+
+ bool SNES_SPC::check_echo_access( int addr )
+ {
+ if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) )
+ {
+ int start = 0x100 * dsp.read( SPC_DSP::r_esa );
+ int size = 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F);
+ int end = start + (size ? size : 4);
+ if ( start <= addr && addr < end )
+ {
+ if ( !m.echo_accessed )
+ {
+ m.echo_accessed = 1;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ #define MEM_ACCESS( time, addr ) check( !check_echo_access( (uint16_t) addr ) );
+#else
+ #define MEM_ACCESS( time, addr )
+#endif
+
+
+//// CPU write
+
+#if SPC_MORE_ACCURACY
+static unsigned char const glitch_probs [3] [256] =
+{
+ 0xC3,0x92,0x5B,0x1C,0xD1,0x92,0x5B,0x1C,0xDB,0x9C,0x72,0x18,0xCD,0x5C,0x38,0x0B,
+ 0xE1,0x9C,0x74,0x17,0xCF,0x75,0x45,0x0C,0xCF,0x6E,0x4A,0x0D,0xA3,0x3A,0x1D,0x08,
+ 0xDB,0xA0,0x82,0x19,0xD9,0x73,0x3C,0x0E,0xCB,0x76,0x52,0x0B,0xA5,0x46,0x1D,0x09,
+ 0xDA,0x74,0x55,0x0F,0xA2,0x3F,0x21,0x05,0x9A,0x40,0x20,0x07,0x63,0x1E,0x10,0x01,
+ 0xDF,0xA9,0x85,0x1D,0xD3,0x84,0x4B,0x0E,0xCF,0x6F,0x49,0x0F,0xB3,0x48,0x1E,0x05,
+ 0xD8,0x77,0x52,0x12,0xB7,0x49,0x23,0x06,0xAA,0x45,0x28,0x07,0x7D,0x28,0x0F,0x07,
+ 0xCC,0x7B,0x4A,0x0E,0xB2,0x4F,0x24,0x07,0xAD,0x43,0x2C,0x06,0x86,0x29,0x11,0x07,
+ 0xAE,0x48,0x1F,0x0A,0x76,0x21,0x19,0x05,0x76,0x21,0x14,0x05,0x44,0x11,0x0B,0x01,
+ 0xE7,0xAD,0x96,0x23,0xDC,0x86,0x59,0x0E,0xDC,0x7C,0x5F,0x15,0xBB,0x53,0x2E,0x09,
+ 0xD6,0x7C,0x4A,0x16,0xBB,0x4A,0x25,0x08,0xB3,0x4F,0x28,0x0B,0x8E,0x23,0x15,0x08,
+ 0xCF,0x7F,0x57,0x11,0xB5,0x4A,0x23,0x0A,0xAA,0x42,0x28,0x05,0x7D,0x22,0x12,0x03,
+ 0xA6,0x49,0x28,0x09,0x82,0x2B,0x0D,0x04,0x7A,0x20,0x0F,0x04,0x3D,0x0F,0x09,0x03,
+ 0xD1,0x7C,0x4C,0x0F,0xAF,0x4E,0x21,0x09,0xA8,0x46,0x2A,0x07,0x85,0x1F,0x0E,0x07,
+ 0xA6,0x3F,0x26,0x07,0x7C,0x24,0x14,0x07,0x78,0x22,0x16,0x04,0x46,0x12,0x0A,0x02,
+ 0xA6,0x41,0x2C,0x0A,0x7E,0x28,0x11,0x05,0x73,0x1B,0x14,0x05,0x3D,0x11,0x0A,0x02,
+ 0x70,0x22,0x17,0x05,0x48,0x13,0x08,0x03,0x3C,0x07,0x0D,0x07,0x26,0x07,0x06,0x01,
+
+ 0xE0,0x9F,0xDA,0x7C,0x4F,0x18,0x28,0x0D,0xE9,0x9F,0xDA,0x7C,0x4F,0x18,0x1F,0x07,
+ 0xE6,0x97,0xD8,0x72,0x64,0x13,0x26,0x09,0xDC,0x67,0xA9,0x38,0x21,0x07,0x15,0x06,
+ 0xE9,0x91,0xD2,0x6B,0x63,0x14,0x2B,0x0E,0xD6,0x61,0xB7,0x41,0x2B,0x0E,0x10,0x09,
+ 0xCF,0x59,0xB0,0x2F,0x35,0x08,0x0F,0x07,0xB6,0x30,0x7A,0x21,0x17,0x07,0x09,0x03,
+ 0xE7,0xA3,0xE5,0x6B,0x65,0x1F,0x34,0x09,0xD8,0x6B,0xBE,0x45,0x27,0x07,0x10,0x07,
+ 0xDA,0x54,0xB1,0x39,0x2E,0x0E,0x17,0x08,0xA9,0x3C,0x86,0x22,0x16,0x06,0x07,0x03,
+ 0xD4,0x51,0xBC,0x3D,0x38,0x0A,0x13,0x06,0xB2,0x37,0x79,0x1C,0x17,0x05,0x0E,0x06,
+ 0xA7,0x31,0x74,0x1C,0x11,0x06,0x0C,0x02,0x6D,0x1A,0x38,0x10,0x0B,0x05,0x06,0x03,
+ 0xEB,0x9A,0xE1,0x7A,0x6F,0x13,0x34,0x0E,0xE6,0x75,0xC5,0x45,0x3E,0x0B,0x1A,0x05,
+ 0xD8,0x63,0xC1,0x40,0x3C,0x1B,0x19,0x06,0xB3,0x42,0x83,0x29,0x18,0x0A,0x08,0x04,
+ 0xD4,0x58,0xBA,0x43,0x3F,0x0A,0x1F,0x09,0xB1,0x33,0x8A,0x1F,0x1F,0x06,0x0D,0x05,
+ 0xAF,0x3C,0x7A,0x1F,0x16,0x08,0x0A,0x01,0x72,0x1B,0x52,0x0D,0x0B,0x09,0x06,0x01,
+ 0xCF,0x63,0xB7,0x47,0x40,0x10,0x14,0x06,0xC0,0x41,0x96,0x20,0x1C,0x09,0x10,0x05,
+ 0xA6,0x35,0x82,0x1A,0x20,0x0C,0x0E,0x04,0x80,0x1F,0x53,0x0F,0x0B,0x02,0x06,0x01,
+ 0xA6,0x31,0x81,0x1B,0x1D,0x01,0x08,0x08,0x7B,0x20,0x4D,0x19,0x0E,0x05,0x07,0x03,
+ 0x6B,0x17,0x49,0x07,0x0E,0x03,0x0A,0x05,0x37,0x0B,0x1F,0x06,0x04,0x02,0x07,0x01,
+
+ 0xF0,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x47,0x1E,0x6E,0x1B,0x32,0x0A,
+ 0xF0,0xD6,0xEA,0xA4,0xED,0xC4,0xDE,0x82,0x98,0x1F,0x50,0x13,0x52,0x15,0x2A,0x0A,
+ 0xF1,0xD1,0xEB,0xA2,0xEB,0xB7,0xD8,0x69,0xA2,0x1F,0x5B,0x18,0x55,0x18,0x2C,0x0A,
+ 0xED,0xB5,0xDE,0x7E,0xE6,0x85,0xD3,0x59,0x59,0x0F,0x2C,0x09,0x24,0x07,0x15,0x09,
+ 0xF1,0xD6,0xEA,0xA0,0xEC,0xBB,0xDA,0x77,0xA9,0x23,0x58,0x14,0x5D,0x12,0x2F,0x09,
+ 0xF1,0xC1,0xE3,0x86,0xE4,0x87,0xD2,0x4E,0x68,0x15,0x26,0x0B,0x27,0x09,0x15,0x02,
+ 0xEE,0xA6,0xE0,0x5C,0xE0,0x77,0xC3,0x41,0x67,0x1B,0x3C,0x07,0x2A,0x06,0x19,0x07,
+ 0xE4,0x75,0xC6,0x43,0xCC,0x50,0x95,0x23,0x35,0x09,0x14,0x04,0x15,0x05,0x0B,0x04,
+ 0xEE,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x56,0x14,0x5A,0x12,0x26,0x0A,
+ 0xEE,0xBB,0xE7,0x7E,0xE9,0x8D,0xCB,0x49,0x67,0x11,0x34,0x07,0x2B,0x0B,0x14,0x07,
+ 0xED,0xA7,0xE5,0x76,0xE3,0x7E,0xC4,0x4B,0x77,0x14,0x34,0x08,0x27,0x07,0x14,0x04,
+ 0xE7,0x8B,0xD2,0x4C,0xCA,0x56,0x9E,0x31,0x36,0x0C,0x11,0x07,0x14,0x04,0x0A,0x02,
+ 0xF0,0x9B,0xEA,0x6F,0xE5,0x81,0xC4,0x43,0x74,0x10,0x30,0x0B,0x2D,0x08,0x1B,0x06,
+ 0xE6,0x83,0xCA,0x48,0xD9,0x56,0xA7,0x23,0x3B,0x09,0x12,0x09,0x15,0x07,0x0A,0x03,
+ 0xE5,0x5F,0xCB,0x3C,0xCF,0x48,0x91,0x22,0x31,0x0A,0x17,0x08,0x15,0x04,0x0D,0x02,
+ 0xD1,0x43,0x91,0x20,0xA9,0x2D,0x54,0x12,0x17,0x07,0x09,0x02,0x0C,0x04,0x05,0x03,
+};
+#endif
+
+// 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
+int const 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: {
+ Timer* t = &m.timers [addr - r_t0target];
+ int period = IF_0_THEN_256( data );
+ if ( t->period != period )
+ {
+ t = run_timer( t, time );
+ #if SPC_MORE_ACCURACY
+ // Insane behavior when target is written just after counter is
+ // clocked and counter matches new period and new period isn't 1, 2, 4, or 8
+ if ( t->divider == (period & 0xFF) &&
+ t->next_time == time + TIMER_MUL( t, 1 ) &&
+ ((period - 1) | ~0x0F) & period )
+ {
+ //dprintf( "SPC pathological timer target write\n" );
+
+ // If the period is 3, 5, or 9, there's a probability this behavior won't occur,
+ // based on the previous period
+ int prob = 0xFF;
+ int old_period = t->period & 0xFF;
+ if ( period == 3 ) prob = glitch_probs [0] [old_period];
+ if ( period == 5 ) prob = glitch_probs [1] [old_period];
+ if ( period == 9 ) prob = glitch_probs [2] [old_period];
+
+ // The glitch suppresses incrementing of one of the counter bits, based on
+ // the lowest set bit in the new period
+ int b = 1;
+ while ( !(period & b) )
+ b <<= 1;
+
+ if ( (rand() >> 4 & 0xFF) <= prob )
+ t->divider = (t->divider - b) & 0xFF;
+ }
+ #endif
+ t->period = period;
+ }
+ break;
+ }
+
+ case r_t0out:
+ case r_t1out:
+ case r_t2out:
+ if ( !SPC_MORE_ACCURACY )
+ dprintf( "SPC wrote to counter %d\n", (int) addr - r_t0out );
+
+ if ( data < no_read_before_write / 2 )
+ run_timer( &m.timers [addr - r_t0out], time - 1 )->counter = 0;
+ break;
+
+ // Registers that act like RAM
+ case 0x8:
+ case 0x9:
+ REGS_IN [addr] = (uint8_t) data;
+ break;
+
+ case r_test:
+ if ( (uint8_t) data != 0x0A )
+ dprintf( "SPC wrote to test register\n" );
+ break;
+
+ case r_control:
+ // port clears
+ if ( data & 0x10 )
+ {
+ REGS_IN [r_cpuio0] = 0;
+ REGS_IN [r_cpuio1] = 0;
+ }
+ if ( data & 0x20 )
+ {
+ REGS_IN [r_cpuio2] = 0;
+ REGS_IN [r_cpuio3] = 0;
+ }
+
+ // timers
+ {
+ for ( int i = 0; i < timer_count; i++ )
+ {
+ Timer* t = &m.timers [i];
+ int enabled = data >> i & 1;
+ if ( t->enabled != enabled )
+ {
+ t = run_timer( t, time );
+ t->enabled = enabled;
+ if ( enabled )
+ {
+ t->divider = 0;
+ t->counter = 0;
+ }
+ }
+ }
+ }
+ enable_rom( data & 0x80 );
+ break;
+ }
+}
+
+void SNES_SPC::cpu_write_smp_reg( int data, rel_time_t time, int addr )
+{
+ if ( addr == r_dspdata ) // 99%
+ dsp_write( data, time );
+ else
+ 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 )
+ {
+ m.hi_ram [i] = (uint8_t) data;
+ if ( m.rom_enabled )
+ RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM
+ }
+ else
+ {
+ assert( *(&(RAM [0]) + i + rom_addr) == (uint8_t) data );
+ *(&(RAM [0]) + i + rom_addr) = cpu_pad_fill; // restore overwritten padding
+ cpu_write( data, i + rom_addr - 0x10000, time );
+ }
+}
+
+int const bits_in_int = CHAR_BIT * sizeof (int);
+
+void SNES_SPC::cpu_write( int data, int addr, rel_time_t time )
+{
+ MEM_ACCESS( time, addr )
+
+ // RAM
+ RAM [addr] = (uint8_t) data;
+ int reg = addr - 0xF0;
+ if ( reg >= 0 ) // 64%
+ {
+ // $F0-$FF
+ if ( reg < reg_count ) // 87%
+ {
+ REGS [reg] = (uint8_t) data;
+
+ // Ports
+ #ifdef SPC_PORT_WRITE_HOOK
+ if ( (unsigned) (reg - r_cpuio0) < port_count )
+ SPC_PORT_WRITE_HOOK( m.spc_time + time, (reg - r_cpuio0),
+ (uint8_t) data, ®S [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%
+ 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
+ cpu_write_high( data, reg, time );
+ }
+ }
+}
+
+
+//// CPU read
+
+inline int SNES_SPC::cpu_read_smp_reg( int reg, rel_time_t time )
+{
+ int result = REGS_IN [reg];
+ reg -= r_dspaddr;
+ // DSP addr and data
+ if ( (unsigned) reg <= 1 ) // 4% 0xF2 and 0xF3
+ {
+ result = REGS [r_dspaddr];
+ if ( (unsigned) reg == 1 )
+ result = dsp_read( time ); // 0xF3
+ }
+ return result;
+}
+
+int SNES_SPC::cpu_read( int addr, rel_time_t time )
+{
+ MEM_ACCESS( time, addr )
+
+ // RAM
+ int result = RAM [addr];
+ int reg = addr - 0xF0;
+ if ( reg >= 0 ) // 40%
+ {
+ reg -= 0x10;
+ if ( (unsigned) reg >= 0xFF00 ) // 21%
+ {
+ reg += 0x10 - r_t0out;
+
+ // Timers
+ if ( (unsigned) reg < timer_count ) // 90%
+ {
+ Timer* t = &m.timers [reg];
+ if ( time >= t->next_time )
+ t = run_timer_( t, time );
+ result = t->counter;
+ t->counter = 0;
+ }
+ // Other registers
+ else if ( reg < 0 ) // 10%
+ {
+ result = cpu_read_smp_reg( reg + r_t0out, time );
+ }
+ else // 1%
+ {
+ assert( reg + (r_t0out + 0xF0 - 0x10000) < 0x100 );
+ result = cpu_read( reg + (r_t0out + 0xF0 - 0x10000), time );
+ }
+ }
+ }
+
+ return result;
+}
+
+
+//// Run
+
+// Prefix and suffix for CPU emulator function
+#define SPC_CPU_RUN_FUNC \
+BOOST::uint8_t* SNES_SPC::run_until_( time_t end_time )\
+{\
+ rel_time_t rel_time = m.spc_time - end_time;\
+ /*assert( rel_time <= 0 );*/\
+ m.spc_time = end_time;\
+ m.dsp_time += rel_time;\
+ m.timers [0].next_time += rel_time;\
+ m.timers [1].next_time += rel_time;\
+ m.timers [2].next_time += rel_time;
+
+#define SPC_CPU_RUN_FUNC_END \
+ m.spc_time += rel_time;\
+ m.dsp_time -= rel_time;\
+ m.timers [0].next_time -= rel_time;\
+ m.timers [1].next_time -= rel_time;\
+ m.timers [2].next_time -= rel_time;\
+ /*assert( m.spc_time >= end_time );*/\
+ return ®S [r_cpuio0];\
+}
+
+int const 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 > m.spc_time )
+ run_until_( end_time );
+
+ m.spc_time -= end_time;
+ 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 <= m.spc_time && m.spc_time <= cpu_lag_max );
+
+ // Catch timers up to CPU
+ for ( int i = 0; i < timer_count; i++ )
+ run_timer( &m.timers [i], 0 );
+
+ // Catch DSP up to CPU
+ if ( m.dsp_time < 0 )
+ {
+ RUN_DSP( 0, max_reg_time );
+ }
+
+ // Save any extra samples beyond what should be generated
+ if ( m.buf_begin )
+ save_extra();
+}
+
+// Inclusion here allows static memory access functions and better optimization
+#include "SPC_CPU.h"
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/SNES_SPC.h
@@ -1,1 +1,317 @@
-
+// SNES SPC-700 APU emulator
+
+// snes_spc 0.9.0
+#ifndef SNES_SPC_H
+#define SNES_SPC_H
+
+#include "SPC_DSP.h"
+#include "blargg_endian.h"
+
+#ifdef DEBUGGER
+#include "snes9x.h"
+#include "display.h"
+#include "debug.h"
+#endif
+
+struct SNES_SPC {
+public:
+ typedef BOOST::uint8_t uint8_t;
+
+ // Must be called once before using
+ blargg_err_t 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( uint8_t const 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
+
+ // Loads SPC data into emulator
+ enum { spc_min_file_size = 0x10180 };
+ enum { spc_file_size = 0x10200 };
+ blargg_err_t load_spc( void const* in, long size );
+
+ // 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.
+ blargg_err_t play( int count, sample_t* out );
+
+ // Skips count samples. Several times faster than play() when using fast DSP.
+ blargg_err_t skip( int count );
+
+// State save/load (only available with accurate DSP)
+
+#if !SPC_NO_COPY_STATE_FUNCS
+ // Saves/loads state
+ enum { state_size = 68 * 1024L }; // maximum space needed when saving
+ typedef SPC_DSP::copy_func_t copy_func_t;
+ void copy_state( unsigned char** io, copy_func_t );
+
+ // Writes minimal header to spc_out
+ static void init_header( void* spc_out );
+
+ // Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out.
+ // Does not set up SPC header; use init_header() for that.
+ void save_spc( void* spc_out );
+
+ // Returns true if new key-on events occurred since last check. Useful for
+ // trimming silence while saving an SPC.
+ bool check_kon();
+#endif
+
+//// Snes9x Accessor
+
+ void spc_allow_time_overflow( bool );
+
+ void dsp_set_spc_snapshot_callback(void (*callback)());
+ void dsp_dump_spc_snapshot();
+ void dsp_set_stereo_switch( int );
+ uint8_t dsp_reg_value( int, int );
+ int dsp_envx_value( int );
+
+//// Snes9x Debugger
+
+#ifdef DEBUGGER
+ void debug_toggle_trace();
+ bool debug_is_enabled();
+ void debug_do_trace( int, int, int, uint8_t const *, uint8_t *, int, int, int, int );
+ void debug_op_print( char *, int, int, int, uint8_t const *, uint8_t *, int, int, int, int );
+ void debug_io_print( char * );
+#endif
+
+public:
+ BLARGG_DISABLE_NOTHROW
+
+ typedef BOOST::uint16_t uint16_t;
+
+ // 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;
+ int enabled;
+ int counter;
+ };
+ enum { reg_count = 0x10 };
+ enum { timer_count = 3 };
+ enum { extra_size = SPC_DSP::extra_size };
+
+ enum { signature_size = 35 };
+
+private:
+ SPC_DSP dsp;
+
+ #if SPC_LESS_ACCURATE
+ static signed char const reg_times_ [256];
+ signed char reg_times [256];
+ #endif
+
+ 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;
+ bool echo_accessed;
+
+ int tempo;
+ int skipped_kon;
+ int skipped_koff;
+ const char* cpu_error;
+
+ int extra_clocks;
+ sample_t* buf_begin;
+ sample_t const* buf_end;
+ sample_t* extra_pos;
+ sample_t extra_buf [extra_size];
+
+ int 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( int enable );
+ void reset_buf();
+ void save_extra();
+ void load_regs( uint8_t const 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 );
+ 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 ( uint8_t const* pc, rel_time_t );
+
+ bool check_echo_access ( int addr );
+ uint8_t* run_until_( time_t end_time );
+
+ struct spc_file_t
+ {
+ char signature [signature_size];
+ uint8_t has_id666;
+ uint8_t version;
+ uint8_t pcl, pch;
+ uint8_t a;
+ uint8_t x;
+ uint8_t y;
+ uint8_t psw;
+ uint8_t sp;
+ char text [212];
+ uint8_t ram [0x10000];
+ uint8_t dsp [128];
+ uint8_t unused [0x40];
+ uint8_t ipl_rom [0x40];
+ };
+
+ static char const signature [signature_size + 1];
+
+ void save_regs( uint8_t out [reg_count] );
+
+// Snes9x timing hack
+ bool allow_time_overflow;
+// Snes9x debugger
+#ifdef DEBUGGER
+ FILE *apu_trace;
+ bool debug_trace;
+#endif
+};
+
+#include <assert.h>
+
+inline int SNES_SPC::sample_count() const { return (m.extra_clocks >> 5) * 2; }
+
+inline int SNES_SPC::read_port( time_t t, int port )
+{
+ assert( (unsigned) port < port_count );
+ return run_until_( t ) [port];
+}
+
+inline void SNES_SPC::write_port( time_t t, int port, int data )
+{
+ assert( (unsigned) port < port_count );
+ run_until_( t ) [0x10 + port] = data;
+ m.ram.ram [0xF4 + port] = data;
+}
+
+inline void SNES_SPC::mute_voices( int mask ) { dsp.mute_voices( mask ); }
+
+inline void SNES_SPC::disable_surround( bool disable ) { dsp.disable_surround( disable ); }
+
+#if !SPC_NO_COPY_STATE_FUNCS
+inline bool SNES_SPC::check_kon() { return dsp.check_kon(); }
+#endif
+
+inline void SNES_SPC::spc_allow_time_overflow( bool allow ) { allow_time_overflow = allow; }
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/SNES_SPC_misc.cpp
@@ -1,1 +1,856 @@
-
+// SPC emulation support: init, sample buffering, reset, SPC loading
+
+// snes_spc 0.9.0. http://www.slack.net/~ant/
+
+#include "SNES_SPC.h"
+
+#include <string.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 */
+
+#include "blargg_source.h"
+
+#define RAM (m.ram.ram)
+#define REGS (m.smp_regs [0])
+#define REGS_IN (m.smp_regs [1])
+
+// (n ? n : 256)
+#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1)
+
+
+//// Init
+
+blargg_err_t SNES_SPC::init()
+{
+ memset( &m, 0, sizeof m );
+ dsp.init( RAM );
+
+ m.tempo = tempo_unit;
+
+ // Most SPC music doesn't need ROM, and almost all the rest only rely
+ // on these two bytes
+ m.rom [0x3E] = 0xFF;
+ m.rom [0x3F] = 0xC0;
+
+ static unsigned char const cycle_table [128] =
+ {// 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];
+ m.cycle_table [i * 2 + 0] = n >> 4;
+ m.cycle_table [i * 2 + 1] = n & 0x0F;
+ }
+
+ allow_time_overflow = false;
+
+ dsp.rom = m.rom;
+ dsp.hi_ram = m.hi_ram;
+
+#ifdef DEBUGGER
+ apu_trace = NULL;
+ debug_trace = false;
+#endif
+
+ #if SPC_LESS_ACCURATE
+ memcpy( reg_times, reg_times_, sizeof reg_times );
+ #endif
+
+ reset();
+ return 0;
+}
+
+void SNES_SPC::init_rom( uint8_t const in [rom_size] )
+{
+ memcpy( m.rom, in, sizeof m.rom );
+}
+
+void SNES_SPC::set_tempo( int t )
+{
+ m.tempo = t;
+ int const timer2_shift = 4; // 64 kHz
+ int const other_shift = 3; // 8 kHz
+
+ #if SPC_DISABLE_TEMPO
+ m.timers [2].prescaler = timer2_shift;
+ m.timers [1].prescaler = timer2_shift + other_shift;
+ m.timers [0].prescaler = timer2_shift + other_shift;
+ #else
+ if ( !t )
+ t = 1;
+ int const 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
+ m.timers [2].prescaler = rate;
+ m.timers [1].prescaler = rate << other_shift;
+ 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()
+{
+ int i;
+ for ( i = 0; i < timer_count; i++ )
+ {
+ Timer* t = &m.timers [i];
+ t->period = IF_0_THEN_256( REGS [r_t0target + i] );
+ t->enabled = REGS [r_control] >> i & 1;
+ t->counter = REGS_IN [r_t0out + i] & 0x0F;
+ }
+
+ set_tempo( m.tempo );
+}
+
+// Loads registers from unified 16-byte format
+void SNES_SPC::load_regs( uint8_t const in [reg_count] )
+{
+ memcpy( REGS, in, reg_count );
+ memcpy( REGS_IN, REGS, reg_count );
+
+ // These always read back as 0
+ REGS_IN [r_test ] = 0;
+ REGS_IN [r_control ] = 0;
+ REGS_IN [r_t0target] = 0;
+ REGS_IN [r_t1target] = 0;
+ REGS_IN [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()
+{
+ m.rom_enabled = dsp.rom_enabled = 0;
+ load_regs( &RAM [0xF0] );
+
+ // Put STOP instruction around memory to catch PC underflow/overflow
+ memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 );
+ memset( m.ram.padding2, cpu_pad_fill, sizeof m.ram.padding2 );
+}
+
+// Registers were just loaded. Applies these new values.
+void SNES_SPC::regs_loaded()
+{
+ enable_rom( REGS [r_control] & 0x80 );
+ timers_loaded();
+}
+
+void SNES_SPC::reset_time_regs()
+{
+ m.cpu_error = 0;
+ m.echo_accessed = 0;
+ m.spc_time = 0;
+ m.dsp_time = 0;
+ #if SPC_LESS_ACCURATE
+ m.dsp_time = clocks_per_sample + 1;
+ #endif
+
+ for ( int i = 0; i < timer_count; i++ )
+ {
+ Timer* t = &m.timers [i];
+ t->next_time = 1;
+ t->divider = 0;
+ }
+
+ regs_loaded();
+
+ m.extra_clocks = 0;
+ reset_buf();
+}
+
+void SNES_SPC::reset_common( int timer_counter_init )
+{
+ int i;
+ for ( i = 0; i < timer_count; i++ )
+ REGS_IN [r_t0out + i] = timer_counter_init;
+
+ // Run IPL ROM
+ memset( &m.cpu_regs, 0, sizeof m.cpu_regs );
+ m.cpu_regs.pc = rom_addr;
+
+ REGS [r_test ] = 0x0A;
+ REGS [r_control] = 0xB0; // ROM enabled, clear ports
+ for ( i = 0; i < port_count; i++ )
+ REGS_IN [r_cpuio0 + i] = 0;
+
+ reset_time_regs();
+}
+
+void SNES_SPC::soft_reset()
+{
+ reset_common( 0 );
+ dsp.soft_reset();
+}
+
+void SNES_SPC::reset()
+{
+ m.cpu_regs.pc = 0xFFC0;
+ m.cpu_regs.a = 0x00;
+ m.cpu_regs.x = 0x00;
+ m.cpu_regs.y = 0x00;
+ m.cpu_regs.psw = 0x02;
+ m.cpu_regs.sp = 0xEF;
+ memset( RAM, 0x00, 0x10000 );
+ ram_loaded();
+ reset_common( 0x0F );
+ dsp.reset();
+}
+
+char const SNES_SPC::signature [signature_size + 1] =
+ "SNES-SPC700 Sound File Data v0.30\x1A\x1A";
+
+blargg_err_t SNES_SPC::load_spc( void const* data, long size )
+{
+ spc_file_t const* const spc = (spc_file_t const*) data;
+
+ // be sure compiler didn't insert any padding into fle_t
+ assert( sizeof (spc_file_t) == spc_min_file_size + 0x80 );
+
+ // Check signature and file size
+ if ( size < signature_size || memcmp( spc, signature, 27 ) )
+ return "Not an SPC file";
+
+ if ( size < spc_min_file_size )
+ return "Corrupt SPC file";
+
+ // CPU registers
+ m.cpu_regs.pc = spc->pch * 0x100 + spc->pcl;
+ m.cpu_regs.a = spc->a;
+ m.cpu_regs.x = spc->x;
+ m.cpu_regs.y = spc->y;
+ m.cpu_regs.psw = spc->psw;
+ m.cpu_regs.sp = spc->sp;
+
+ // RAM and registers
+ memcpy( RAM, spc->ram, 0x10000 );
+ ram_loaded();
+
+ // DSP registers
+ dsp.load( spc->dsp );
+
+ reset_time_regs();
+
+ return 0;
+}
+
+void SNES_SPC::clear_echo()
+{
+ if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) )
+ {
+ int addr = 0x100 * dsp.read( SPC_DSP::r_esa );
+ int end = addr + 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F);
+ if ( end > 0x10000 )
+ end = 0x10000;
+ memset( &RAM [addr], 0xFF, end - addr );
+ }
+}
+
+
+//// Sample output
+
+void SNES_SPC::reset_buf()
+{
+ // Start with half extra buffer of silence
+ sample_t* out = m.extra_buf;
+ while ( out < &m.extra_buf [extra_size / 2] )
+ *out++ = 0;
+
+ m.extra_pos = out;
+ m.buf_begin = 0;
+
+ dsp.set_output( 0, 0 );
+}
+
+void SNES_SPC::set_output( sample_t* out, int size )
+{
+ require( (size & 1) == 0 ); // size must be even
+
+ m.extra_clocks &= clocks_per_sample - 1;
+ if ( out )
+ {
+ sample_t const* out_end = out + size;
+ m.buf_begin = out;
+ m.buf_end = out_end;
+
+ // Copy extra to output
+ sample_t const* in = m.extra_buf;
+ while ( in < 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 = dsp.extra();
+ out_end = &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 );
+ }
+
+ dsp.set_output( out, out_end - out );
+ }
+ else
+ {
+ reset_buf();
+ }
+}
+
+void SNES_SPC::save_extra()
+{
+ // Get end pointers
+ sample_t const* main_end = m.buf_end; // end of data written to buf
+ sample_t const* dsp_end = dsp.out_pos(); // end of data written to dsp.extra()
+ if ( m.buf_begin <= dsp_end && dsp_end <= main_end )
+ {
+ main_end = dsp_end;
+ dsp_end = dsp.extra(); // nothing in DSP's extra
+ }
+
+ // Copy any extra samples at these ends into extra_buf
+ sample_t* out = m.extra_buf;
+ sample_t const* in;
+ for ( in = m.buf_begin + sample_count(); in < main_end; in++ )
+ *out++ = *in;
+ for ( in = dsp.extra(); in < dsp_end ; in++ )
+ *out++ = *in;
+
+ m.extra_pos = out;
+ assert( out <= &m.extra_buf [extra_size] );
+}
+
+blargg_err_t SNES_SPC::play( int count, sample_t* out )
+{
+ require( (count & 1) == 0 ); // must be even
+ if ( count )
+ {
+ set_output( out, count );
+ end_frame( count * (clocks_per_sample / 2) );
+ }
+
+ const char* err = m.cpu_error;
+ m.cpu_error = 0;
+ return err;
+}
+
+blargg_err_t SNES_SPC::skip( int count )
+{
+ #if SPC_LESS_ACCURATE
+ if ( count > 2 * sample_rate * 2 )
+ {
+ set_output( 0, 0 );
+
+ // Skip a multiple of 4 samples
+ time_t end = count;
+ count = (count & 3) + 1 * sample_rate * 2;
+ end = (end - count) * (clocks_per_sample / 2);
+
+ m.skipped_kon = 0;
+ m.skipped_koff = 0;
+
+ // Preserve DSP and timer synchronization
+ // TODO: verify that this really preserves it
+ int old_dsp_time = m.dsp_time + m.spc_time;
+ m.dsp_time = end - m.spc_time + skipping_time;
+ end_frame( end );
+ m.dsp_time = m.dsp_time - skipping_time + old_dsp_time;
+
+ dsp.write( SPC_DSP::r_koff, m.skipped_koff & ~m.skipped_kon );
+ dsp.write( SPC_DSP::r_kon , m.skipped_kon );
+ clear_echo();
+ }
+ #endif
+
+ return play( count, 0 );
+}
+
+//// Snes9x Accessor
+
+void SNES_SPC::dsp_set_spc_snapshot_callback(void (*callback)())
+{
+ dsp.set_spc_snapshot_callback( callback );
+}
+
+void SNES_SPC::dsp_dump_spc_snapshot()
+{
+ dsp.dump_spc_snapshot();
+}
+
+void SNES_SPC::dsp_set_stereo_switch( int value )
+{
+ dsp.set_stereo_switch( value );
+}
+
+SNES_SPC::uint8_t SNES_SPC::dsp_reg_value( int ch, int addr )
+{
+ return dsp.reg_value( ch, addr );
+}
+
+int SNES_SPC::dsp_envx_value( int ch )
+{
+ return dsp.envx_value( ch );
+}
+
+//// Snes9x debugger
+
+#ifdef DEBUGGER
+
+void SNES_SPC::debug_toggle_trace()
+{
+ debug_trace = !debug_trace;
+
+ if (debug_trace)
+ {
+ printf("APU tracing enabled.\n");
+ ENSURE_TRACE_OPEN(apu_trace, "apu_trace.log", "wb")
+ }
+ else
+ {
+ printf("APU tracing disabled.\n");
+ fclose(apu_trace);
+ apu_trace = NULL;
+ }
+}
+
+bool SNES_SPC::debug_is_enabled() { return debug_trace; }
+
+void SNES_SPC::debug_do_trace( int a, int x, int y, uint8_t const *pc, uint8_t *sp, int psw, int c, int nz, int dp )
+{
+ char msg[512];
+
+ ENSURE_TRACE_OPEN(apu_trace, "apu_trace.log", "a")
+
+ debug_op_print(msg, a, x, y, pc, sp, psw, c, nz, dp);
+ fprintf(apu_trace, "%s ", msg);
+ debug_io_print(msg);
+ fprintf(apu_trace, "%s ", msg);
+ S9xPrintHVPosition(msg);
+ fprintf(apu_trace, "%s\n", msg);
+}
+
+void SNES_SPC::debug_op_print( char *buffer, int a, int x, int y, uint8_t const *pc, uint8_t *sp, int psw, int c, int nz, int dp )
+{
+ static char mnemonics[256][20] =
+ {
+ "NOP",
+ "TCALL 0",
+ "SET1 $%02X.0",
+ "BBS $%02X.0,$%04X",
+ "OR A,$%02X",
+ "OR A,!$%04X",
+ "OR A,(X)",
+ "OR A,[$%02X+X]",
+ "OR A,#$%02X",
+ "OR $%02X,$%02X",
+ "OR1 C,$%04X.%d",
+ "ASL $%02X",
+ "MOV !$%04X,Y",
+ "PUSH PSW",
+ "TSET1 !$%04X",
+ "BRK",
+ "BPL $%04X",
+ "TCALL 1",
+ "CLR1 $%02X.0",
+ "BBC $%02X.0,$%04X",
+ "OR A,$%02X+X",
+ "OR A,!$%04X+X",
+ "OR A,!$%04X+Y",
+ "OR A,[$%02X]+Y",
+ "OR $%02X,#$%02X",
+ "OR (X),(Y)",
+ "DECW $%02X",
+ "ASL $%02X+X",
+ "ASL A",
+ "DEC X",
+ "CMP X,!$%04X",
+ "JMP [!$%04X+X]",
+ "CLRP",
+ "TCALL 2",
+ "SET1 $%02X.1",
+ "BBS $%02X.1,$%04X",
+ "AND A,$%02X",
+ "AND A,!$%04X",
+ "AND A,(X)",
+ "AND A,[$%02X+X]",
+ "AND A,#$%02X",
+ "AND $%02X,$%02X",
+ "OR1 C,/$%04X.%d",
+ "ROL $%02X",
+ "ROL !$%04X",
+ "PUSH A",
+ "CBNE $%02X,$%04X",
+ "BRA $%04X",
+ "BMI $%04X",
+ "TCALL 3",
+ "CLR1 $%02X.1",
+ "BBC $%02X.1,$%04X",
+ "AND A,$%02X+X",
+ "AND A,!$%04X+X",
+ "AND A,!$%04X+Y",
+ "AND A,[$%02X]+Y",
+ "AND $%02X,#$%02X",
+ "AND (X),(Y)",
+ "INCW $%02X",
+ "ROL $%02X+X",
+ "ROL A",
+ "INC X",
+ "CMP X,$%02X",
+ "CALL !$%04X",
+ "SETP",
+ "TCALL 4",
+ "SET1 $%02X.2",
+ "BBS $%02X.2,$%04X",
+ "EOR A,$%02X",
+ "EOR A,!$%04X",
+ "EOR A,(X)",
+ "EOR A,[$%02X+X]",
+ "EOR A,#$%02X",
+ "EOR $%02X,$%02X",
+ "AND1 C,$%04X.%d",
+ "LSR $%02X",
+ "LSR !$%04X",
+ "PUSH X",
+ "TCLR1 !$%04X",
+ "PCALL $%02X",
+ "BVC $%04X",
+ "TCALL 5",
+ "CLR1 $%02X.2",
+ "BBC $%02X.2,$%04X",
+ "EOR A,$%02X+X",
+ "EOR A,!$%04X+X",
+ "EOR A,!$%04X+Y",
+ "EOR A,[$%02X]+Y",
+ "EOR $%02X,#$%02X",
+ "EOR (X),(Y)",
+ "CMPW YA,$%02X",
+ "LSR $%02X+X",
+ "LSR A",
+ "MOV X,A",
+ "CMP Y,!$%04X",
+ "JMP !$%04X",
+ "CLRC",
+ "TCALL 6",
+ "SET1 $%02X.3",
+ "BBS $%02X.3,$%04X",
+ "CMP A,$%02X",
+ "CMP A,!$%04X",
+ "CMP A,(X)",
+ "CMP A,[$%02X+X]",
+ "CMP A,#$%02X",
+ "CMP $%02X,$%02X",
+ "AND1 C,/$%04X.%d",
+ "ROR $%02X",
+ "ROR !$%04X",
+ "PUSH Y",
+ "DBNZ $%02X,$%04X",
+ "RET",
+ "BVS $%04X",
+ "TCALL 7",
+ "CLR1 $%02X.3",
+ "BBC $%02X.3,$%04X",
+ "CMP A,$%02X+X",
+ "CMP A,!$%04X+X",
+ "CMP A,!$%04X+Y",
+ "CMP A,[$%02X]+Y",
+ "CMP $%02X,#$%02X",
+ "CMP (X),(Y)",
+ "ADDW YA,$%02X",
+ "ROR $%02X+X",
+ "ROR A",
+ "MOV A,X",
+ "CMP Y,$%02X",
+ "RET1",
+ "SETC",
+ "TCALL 8",
+ "SET1 $%02X.4",
+ "BBS $%02X.4,$%04X",
+ "ADC A,$%02X",
+ "ADC A,!$%04X",
+ "ADC A,(X)",
+ "ADC A,[$%02X+X]",
+ "ADC A,#$%02X",
+ "ADC $%02X,$%02X",
+ "EOR1 C,$%04X.%d",
+ "DEC $%02X",
+ "DEC !$%04X",
+ "MOV Y,#$%02X",
+ "POP PSW",
+ "MOV $%02X,#$%02X",
+ "BCC $%04X",
+ "TCALL 9",
+ "CLR1 $%02X.4",
+ "BBC $%02X.4,$%04X",
+ "ADC A,$%02X+X",
+ "ADC A,!$%04X+X",
+ "ADC A,!$%04X+Y",
+ "ADC A,[$%02X]+Y",
+ "ADC $%02X,#$%02X",
+ "ADC (X),(Y)",
+ "SUBW YA,$%02X",
+ "DEC $%02X+X",
+ "DEC A",
+ "MOV X,SP",
+ "DIV YA,X",
+ "XCN A",
+ "EI",
+ "TCALL 10",
+ "SET1 $%02X.5",
+ "BBS $%02X.5,$%04X",
+ "SBC A,$%02X",
+ "SBC A,!$%04X",
+ "SBC A,(X)",
+ "SBC A,[$%02X+X]",
+ "SBC A,#$%02X",
+ "SBC $%02X,$%02X",
+ "MOV1 C,$%04X.%d",
+ "INC $%02X",
+ "INC !$%04X",
+ "CMP Y,#$%02X",
+ "POP A",
+ "MOV (X)+,A",
+ "BCS $%04X",
+ "TCALL 11",
+ "CLR1 $%02X.5",
+ "BBC $%02X.5,$%04X",
+ "SBC A,$%02X+X",
+ "SBC A,!$%04X+X",
+ "SBC A,!$%04X+Y",
+ "SBC A,[$%02X]+Y",
+ "SBC $%02X,#$%02X",
+ "SBC (X),(Y)",
+ "MOVW YA,$%02X",
+ "INC $%02X+X",
+ "INC A",
+ "MOV SP,X",
+ "DAS A",
+ "MOV A,(X)+",
+ "DI",
+ "TCALL 12",
+ "SET1 $%02X.6",
+ "BBS $%02X.6,$%04X",
+ "MOV $%02X,A",
+ "MOV !$%04X,A",
+ "MOV (X),A",
+ "MOV [$%02X+X],A",
+ "CMP X,#$%02X",
+ "MOV !$%04X,X",
+ "MOV1 $%04X.%d,C",
+ "MOV $%02X,Y",
+ "ASL !$%04X",
+ "MOV X,#$%02X",
+ "POP X",
+ "MUL YA",
+ "BNE $%04X",
+ "TCALL 13",
+ "CLR1 $%02X.6",
+ "BBC $%02X.6,$%04X",
+ "MOV $%02X+X,A",
+ "MOV !$%04X+X,A",
+ "MOV !$%04X+Y,A",
+ "MOV [$%02X]+Y,A",
+ "MOV $%02X,X",
+ "MOV $%02X+Y,X",
+ "MOVW $%02X,YA",
+ "MOV $%02X+X,Y",
+ "DEC Y",
+ "MOV A,Y",
+ "CBNE $%02X+X,$%04X",
+ "DAA A",
+ "CLRV",
+ "TCALL 14",
+ "SET1 $%02X.7",
+ "BBS $%02X.7,$%04X",
+ "MOV A,$%02X",
+ "MOV A,!$%04X",
+ "MOV A,(X)",
+ "MOV A,[$%02X+X]",
+ "MOV A,#$%02X",
+ "MOV X,!$%04X",
+ "NOT1 $%04X.%d",
+ "MOV Y,$%02X",
+ "MOV Y,!$%04X",
+ "NOTC",
+ "POP Y",
+ "SLEEP",
+ "BEQ $%04X",
+ "TCALL 15",
+ "CLR1 $%02X.7",
+ "BBC $%02X.7,$%04X",
+ "MOV A,$%02X+X",
+ "MOV A,!$%04X+X",
+ "MOV A,!$%04X+Y",
+ "MOV A,[$%02X]+Y",
+ "MOV X,$%02X",
+ "MOV X,$%02X+Y",
+ "MOV $%02X,$%02X",
+ "MOV Y,$%02X+X",
+ "INC Y",
+ "MOV Y,A",
+ "DBNZ Y,$%04X",
+ "STOP"
+ };
+
+ static int modes[256] =
+ {
+ 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 1, 2,
+ 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 1, 1,
+ 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 5, 7,
+ 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 0, 1,
+ 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 1, 0,
+ 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 1, 1,
+ 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 5, 2,
+ 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 0, 2,
+ 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 0, 2, 4,
+ 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 2, 2,
+ 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 0, 2, 2,
+ 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 2, 2,
+ 2, 2, 0, 5, 0, 1, 2, 0, 0, 1, 6, 0, 1, 0, 2, 2,
+ 7, 2, 0, 5, 0, 1, 1, 0, 0, 0, 0, 0, 2, 2, 5, 2,
+ 2, 2, 0, 5, 0, 1, 2, 0, 0, 1, 6, 0, 1, 2, 2, 2,
+ 7, 2, 0, 5, 0, 1, 1, 0, 0, 0, 3, 0, 2, 2, 7, 2
+ };
+
+ static int modesToBytes[] =
+ {
+ 2, 3, 1, 3, 3, 3, 3, 2
+ };
+
+ int const n80 = 0x80; // nz
+ int const p20 = 0x20; // dp
+ int const z02 = 0x02; // nz
+ int const c01 = 0x01; // c
+
+ #define GET_PC() (pc - ram)
+ #define GET_SP() (sp - 0x101 - ram)
+ #define GET_PSW( out )\
+ {\
+ out = psw & ~(n80 | p20 | z02 | c01);\
+ out |= c >> 8 & c01;\
+ out |= dp >> 3 & p20;\
+ out |= ((nz >> 4) | nz) & n80;\
+ if ( !(uint8_t) nz ) out |= z02;\
+ }
+
+ uint8_t const *ram = RAM;
+
+ int addr;
+ int tsp, tpsw;
+ uint8_t d0, d1, d2;
+
+ addr = GET_PC();
+ tsp = GET_SP();
+ GET_PSW(tpsw);
+
+ d0 = *pc;
+ d1 = (addr < 0xffff) ? *(pc + 1) : 0;
+ d2 = (addr < 0xfffe) ? *(pc + 2) : 0;
+
+ int mode = modes[d0];
+ int bytes = modesToBytes[mode];
+ char mnem[100];
+
+ switch (bytes)
+ {
+ case 1:
+ sprintf(buffer, "%04X %02X ", addr, d0);
+ break;
+
+ case 2:
+ sprintf(buffer, "%04X %02X %02X ", addr, d0, d1);
+ break;
+
+ case 3:
+ sprintf(buffer, "%04X %02X %02X %02X ", addr, d0, d1, d2);
+ break;
+ }
+
+ switch (mode)
+ {
+ case 0:
+ sprintf(mnem, mnemonics[d0], d1);
+ break;
+
+ case 1:
+ sprintf(mnem, mnemonics[d0], d1 + (d2 << 8));
+ break;
+
+ case 2:
+ strcpy (mnem, mnemonics[d0]);
+ break;
+
+ case 3:
+ sprintf(mnem, mnemonics[d0], d2, d1);
+ break;
+
+ case 4:
+ sprintf(mnem, mnemonics[d0], d2, d1);
+ break;
+
+ case 5:
+ sprintf(mnem, mnemonics[d0], d1, addr + 3 + (int8_t) d2);
+ break;
+
+ case 6:
+ sprintf(mnem, mnemonics[d0], (d1 + (d2 << 8)) & 0x1fff, d2 >> 5);
+ break;
+
+ case 7:
+ sprintf(mnem, mnemonics[d0], addr + 2 + (int8_t) d1);
+ break;
+ }
+
+ sprintf(buffer, "%s %-20s A:%02X X:%02X Y:%02X S:%02X P:%c%c%c%c%c%c%c%c ROM:%d",
+ buffer, mnem, a, x, y, tsp,
+ (tpsw & 0x80) ? 'N' : 'n',
+ (tpsw & 0x40) ? 'V' : 'v',
+ (tpsw & 0x20) ? 'P' : 'p',
+ (tpsw & 0x10) ? 'B' : 'b',
+ (tpsw & 0x08) ? 'H' : 'h',
+ (tpsw & 0x04) ? 'I' : 'i',
+ (tpsw & 0x02) ? 'Z' : 'z',
+ (tpsw & 0x01) ? 'C' : 'c',
+ m.rom_enabled ? 1 : 0);
+}
+
+void SNES_SPC::debug_io_print( char *buffer )
+{
+ sprintf(buffer, "i/o %02X/%02X %02X/%02X %02X/%02X %02X/%02X",
+ m.smp_regs[1][r_cpuio0], m.smp_regs[0][r_cpuio0],
+ m.smp_regs[1][r_cpuio1], m.smp_regs[0][r_cpuio1],
+ m.smp_regs[1][r_cpuio2], m.smp_regs[0][r_cpuio2],
+ m.smp_regs[1][r_cpuio3], m.smp_regs[0][r_cpuio3]);
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/SNES_SPC_state.cpp
@@ -1,1 +1,143 @@
+// SPC emulation state save/load: copy_state(), save_spc()
+// Separate file to avoid linking in unless needed
+// snes_spc 0.9.0. http://www.slack.net/‾ant/
+
+#include "SNES_SPC.h"
+
+#if !SPC_NO_COPY_STATE_FUNCS
+
+#include <string.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 */
+
+#include <stdio.h>
+#include "blargg_source.h"
+
+#define RAM (m.ram.ram)
+#define REGS (m.smp_regs [0])
+#define REGS_IN (m.smp_regs [1])
+
+void SNES_SPC::save_regs( uint8_t out [reg_count] )
+{
+ // Use current timer counter values
+ for ( int i = 0; i < timer_count; i++ )
+ out [r_t0out + i] = m.timers [i].counter;
+
+ // Last written values
+ memcpy( out, REGS, r_t0out );
+}
+
+void SNES_SPC::init_header( void* spc_out )
+{
+ spc_file_t* const spc = (spc_file_t*) spc_out;
+
+ spc->has_id666 = 26; // has none
+ spc->version = 30;
+ memcpy( spc, signature, sizeof spc->signature );
+ memset( spc->text, 0, sizeof spc->text );
+}
+
+void SNES_SPC::save_spc( void* spc_out )
+{
+ spc_file_t* const spc = (spc_file_t*) spc_out;
+
+ // CPU
+ spc->pcl = (uint8_t) (m.cpu_regs.pc >> 0);
+ spc->pch = (uint8_t) (m.cpu_regs.pc >> 8);
+ spc->a = m.cpu_regs.a;
+ spc->x = m.cpu_regs.x;
+ spc->y = m.cpu_regs.y;
+ spc->psw = m.cpu_regs.psw;
+ spc->sp = m.cpu_regs.sp;
+
+ // RAM, ROM
+ memcpy( spc->ram, RAM, sizeof spc->ram );
+ if ( m.rom_enabled )
+ memcpy( spc->ram + rom_addr, m.hi_ram, sizeof m.hi_ram );
+ memset( spc->unused, 0, sizeof spc->unused );
+ memcpy( spc->ipl_rom, m.rom, sizeof spc->ipl_rom );
+
+ // SMP registers
+ save_regs( &spc->ram [0xF0] );
+ int i;
+ for ( i = 0; i < port_count; i++ )
+ spc->ram [0xF0 + r_cpuio0 + i] = REGS_IN [r_cpuio0 + i];
+
+ // DSP registers
+ for ( i = 0; i < SPC_DSP::register_count; i++ )
+ spc->dsp [i] = dsp.read( i );
+}
+
+#undef IF_0_THEN_256
+#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1)
+void SNES_SPC::copy_state( unsigned char** io, copy_func_t copy )
+{
+ SPC_State_Copier copier( io, copy );
+
+ // Make state data more readable by putting 64K RAM, 16 SMP registers,
+ // then DSP (with its 128 registers) first
+
+ // RAM
+ enable_rom( 0 ); // will get re-enabled if necessary in regs_loaded() below
+ copier.copy( RAM, 0x10000 );
+
+ {
+ // SMP registers
+ uint8_t regs [reg_count];
+ uint8_t regs_in [reg_count];
+
+ memcpy( regs, REGS, reg_count );
+ memcpy( regs_in, REGS_IN, reg_count );
+
+ copier.copy( regs, sizeof regs );
+ copier.copy( regs_in, sizeof regs_in );
+
+ memcpy( REGS, regs, reg_count);
+ memcpy( REGS_IN, regs_in, reg_count );
+
+ enable_rom( REGS [r_control] & 0x80 );
+ }
+
+ // CPU registers
+ SPC_COPY( uint16_t, m.cpu_regs.pc );
+ SPC_COPY( uint8_t, m.cpu_regs.a );
+ SPC_COPY( uint8_t, m.cpu_regs.x );
+ SPC_COPY( uint8_t, m.cpu_regs.y );
+ SPC_COPY( uint8_t, m.cpu_regs.psw );
+ SPC_COPY( uint8_t, m.cpu_regs.sp );
+ copier.extra();
+
+ SPC_COPY( int16_t, m.spc_time );
+ SPC_COPY( int16_t, m.dsp_time );
+
+ // DSP
+ dsp.copy_state( io, copy );
+
+ // Timers
+ for ( int i = 0; i < timer_count; i++ )
+ {
+ Timer* t = &m.timers [i];
+ t->period = IF_0_THEN_256( REGS [r_t0target + i] );
+ t->enabled = REGS [r_control] >> i & 1;
+ SPC_COPY( int16_t, t->next_time );
+ SPC_COPY( uint8_t, t->divider );
+ SPC_COPY( uint8_t, t->counter );
+ copier.extra();
+ }
+
+ set_tempo( m.tempo );
+
+ copier.extra();
+}
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/SPC_CPU.h
@@ -1,1 +1,1229 @@
-
+// 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 */
+
+//// Memory access
+
+#if SPC_MORE_ACCURACY
+ #define SUSPICIOUS_OPCODE( name ) ((void) 0)
+#else
+ #define SUSPICIOUS_OPCODE( name ) dprintf( "SPC: suspicious opcode: " name "\n" )
+#endif
+
+#define CPU_READ( time, offset, addr )\
+ cpu_read( addr, time + offset )
+
+#define CPU_WRITE( time, offset, addr, data )\
+ cpu_write( data, addr, time + offset )
+
+#if SPC_MORE_ACCURACY
+ #define CPU_READ_TIMER( time, offset, addr, out )\
+ { out = CPU_READ( time, offset, addr ); }
+
+#else
+ // timers are by far the most common thing read from dp
+ #define CPU_READ_TIMER( time, offset, addr_, out )\
+ {\
+ rel_time_t adj_time = time + offset;\
+ int dp_addr = addr_;\
+ int ti = dp_addr - (r_t0out + 0xF0);\
+ if ( (unsigned) ti < timer_count )\
+ {\
+ Timer* t = &m.timers [ti];\
+ if ( adj_time >= t->next_time )\
+ t = run_timer_( t, adj_time );\
+ out = t->counter;\
+ t->counter = 0;\
+ }\
+ else\
+ {\
+ out = ram [dp_addr];\
+ int i = dp_addr - 0xF0;\
+ if ( (unsigned) i < 0x10 )\
+ out = cpu_read_smp_reg( i, adj_time );\
+ }\
+ }
+#endif
+
+#define TIME_ADJ( n ) (n)
+
+#define READ_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), (addr), out )
+#define READ( time, addr ) CPU_READ ( rel_time, TIME_ADJ(time), (addr) )
+#define WRITE( time, addr, data ) CPU_WRITE( rel_time, TIME_ADJ(time), (addr), (data) )
+
+#define DP_ADDR( addr ) (dp + (addr))
+
+#define READ_DP_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), DP_ADDR( addr ), out )
+#define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) )
+#define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data )
+
+#define READ_PROG16( addr ) GET_LE16( ram + (addr) )
+
+#define SET_PC( n ) (pc = ram + (n))
+#define GET_PC() (pc - ram)
+#define READ_PC( pc ) (*(pc))
+#define READ_PC16( pc ) GET_LE16( pc )
+
+// TODO: remove non-wrapping versions?
+#define SPC_NO_SP_WRAPAROUND 0
+
+#define SET_SP( v ) (sp = ram + 0x101 + (v))
+#define GET_SP() (sp - 0x101 - ram)
+
+#if SPC_NO_SP_WRAPAROUND
+#define PUSH16( v ) (sp -= 2, SET_LE16( sp, v ))
+#define PUSH( v ) (void) (*--sp = (uint8_t) (v))
+#define POP( out ) (void) ((out) = *sp++)
+
+#else
+#define PUSH16( data )\
+{\
+ int addr = (sp -= 2) - ram;\
+ if ( addr > 0x100 )\
+ {\
+ SET_LE16( sp, data );\
+ }\
+ else\
+ {\
+ ram [(uint8_t) addr + 0x100] = (uint8_t) data;\
+ sp [1] = (uint8_t) (data >> 8);\
+ sp += 0x100;\
+ }\
+}
+
+#define PUSH( data )\
+{\
+ *--sp = (uint8_t) (data);\
+ if ( sp - ram == 0x100 )\
+ sp += 0x100;\
+}
+
+#define POP( out )\
+{\
+ out = *sp++;\
+ if ( sp - ram == 0x201 )\
+ {\
+ out = sp [-0x101];\
+ sp -= 0x100;\
+ }\
+}
+
+#endif
+
+#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel )
+
+unsigned SNES_SPC::CPU_mem_bit( uint8_t const* pc, rel_time_t rel_time )
+{
+ unsigned addr = READ_PC16( pc );
+ unsigned t = READ( 0, addr & 0x1FFF ) >> (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
+int const n80 = 0x80; // nz
+int const v40 = 0x40; // psw
+int const p20 = 0x20; // dp
+int const b10 = 0x10; // psw
+int const h08 = 0x08; // psw
+int const i04 = 0x04; // psw
+int const z02 = 0x02; // nz
+int const c01 = 0x01; // c
+
+int const nz_neg_mask = 0x880; // either bit set indicates N flag set
+
+#define GET_PSW( out )\
+{\
+ out = psw & ~(n80 | p20 | z02 | c01);\
+ out |= c >> 8 & c01;\
+ out |= dp >> 3 & p20;\
+ out |= ((nz >> 4) | nz) & n80;\
+ if ( !(uint8_t) nz ) out |= z02;\
+}
+
+#define SET_PSW( in )\
+{\
+ psw = in;\
+ c = in << 8;\
+ dp = in << 3 & 0x100;\
+ nz = (in << 4 & 0x800) | (~in & z02);\
+}
+
+SPC_CPU_RUN_FUNC
+{
+ uint8_t* const ram = RAM;
+ int a = m.cpu_regs.a;
+ int x = m.cpu_regs.x;
+ int y = m.cpu_regs.y;
+ uint8_t const* pc;
+ uint8_t* sp;
+ int psw;
+ int c;
+ int nz;
+ int dp;
+
+ SET_PC( m.cpu_regs.pc );
+ SET_SP( m.cpu_regs.sp );
+ SET_PSW( m.cpu_regs.psw );
+
+ goto loop;
+
+
+ // Main loop
+
+cbranch_taken_loop:
+ pc += *(BOOST::int8_t const*) pc;
+inc_pc_loop:
+ pc++;
+loop:
+{
+ unsigned opcode;
+ unsigned data;
+
+ check( (unsigned) a < 0x100 );
+ check( (unsigned) x < 0x100 );
+ check( (unsigned) y < 0x100 );
+
+ opcode = *pc;
+ if (allow_time_overflow && rel_time >= 0 )
+ goto stop;
+ if ( (rel_time += m.cycle_table [opcode]) > 0 && !allow_time_overflow)
+ goto out_of_time;
+
+ #ifdef SPC_CPU_OPCODE_HOOK
+ SPC_CPU_OPCODE_HOOK( GET_PC(), opcode );
+ #endif
+ /*
+ //SUB_CASE_COUNTER( 1 );
+ #define PROFILE_TIMER_LOOP( op, addr, len )\
+ if ( opcode == op )\
+ {\
+ int cond = (unsigned) ((addr) - 0xFD) < 3 &&\
+ pc [len] == 0xF0 && pc [len+1] == 0xFE - len;\
+ SUB_CASE_COUNTER( op && cond );\
+ }
+
+ PROFILE_TIMER_LOOP( 0xEC, GET_LE16( pc + 1 ), 3 );
+ PROFILE_TIMER_LOOP( 0xEB, pc [1], 2 );
+ PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 );
+ */
+
+#ifdef DEBUGGER
+ if (debug_trace)
+ debug_do_trace(a, x, y, pc, sp, psw, c, nz, dp);
+#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 += (BOOST::int8_t) data;\
+ if ( cond )\
+ goto loop;\
+ pc -= (BOOST::int8_t) data;\
+ rel_time -= 2;\
+ goto loop;\
+}
+
+ case 0xF0: // BEQ
+ BRANCH( !(uint8_t) nz ) // 89% taken
+
+ case 0xD0: // BNE
+ BRANCH( (uint8_t) nz )
+
+ case 0x3F:{// CALL
+ int old_addr = GET_PC() + 2;
+ SET_PC( READ_PC16( 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 [(uint8_t) addr + 0x100] );
+ sp -= 0x100;
+ }
+ #endif
+ goto loop;
+
+ case 0xE4: // MOV a,dp
+ ++pc;
+ // 80% from timer
+ READ_DP_TIMER( 0, data, a = nz );
+ goto loop;
+
+ case 0xFA:{// MOV dp,dp
+ int temp;
+ READ_DP_TIMER( -2, data, temp );
+ data = temp + no_read_before_write ;
+ }
+ // fall through
+ case 0x8F:{// MOV dp,#imm
+ int temp = READ_PC( pc + 1 );
+ pc += 2;
+
+ #if !SPC_MORE_ACCURACY
+ {
+ int i = dp + temp;
+ ram [i] = (uint8_t) data;
+ i -= 0xF0;
+ if ( (unsigned) i < 0x10 ) // 76%
+ {
+ REGS [i] = (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%
+ cpu_write_smp_reg( data, rel_time, i );
+ }
+ }
+ #else
+ WRITE_DP( 0, temp, data );
+ #endif
+ goto loop;
+ }
+
+ case 0xC4: // MOV dp,a
+ ++pc;
+ #if !SPC_MORE_ACCURACY
+ {
+ int i = dp + data;
+ ram [i] = (uint8_t) a;
+ i -= 0xF0;
+ if ( (unsigned) i < 0x10 ) // 39%
+ {
+ unsigned sel = i - 2;
+ REGS [i] = (uint8_t) a;
+
+ if ( sel == 1 ) // 51% $F3
+ dsp_write( a, rel_time );
+ else if ( sel > 1 ) // 1% not $F2 or $F3
+ cpu_write_smp_reg_( a, rel_time, i );
+ }
+ }
+ #else
+ WRITE_DP( 0, data, a );
+ #endif
+ 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( ((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 * READ_PC( ++pc );\
+ goto end_##op;\
+ CASE( op + 0x0C ) /* dp+X */\
+ data = (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 = READ( 0, data );
+ goto inc_pc_loop;
+
+ case 0xBF:{// MOV A,(X)+
+ int temp = x + dp;
+ x = (uint8_t) (x + 1);
+ a = nz = READ( -1, temp );
+ goto loop;
+ }
+
+ case 0xE8: // MOV A,imm
+ a = data;
+ nz = data;
+ goto inc_pc_loop;
+
+ case 0xF9: // MOV X,dp+Y
+ data = (uint8_t) (data + y);
+ case 0xF8: // MOV X,dp
+ READ_DP_TIMER( 0, data, x = nz );
+ goto inc_pc_loop;
+
+ case 0xE9: // MOV X,abs
+ data = READ_PC16( pc );
+ ++pc;
+ data = READ( 0, data );
+ case 0xCD: // MOV X,imm
+ x = data;
+ nz = data;
+ goto inc_pc_loop;
+
+ case 0xFB: // MOV Y,dp+X
+ data = (uint8_t) (data + x);
+ case 0xEB: // MOV Y,dp
+ // 70% from timer
+ pc++;
+ READ_DP_TIMER( 0, data, y = nz );
+ goto loop;
+
+ case 0xEC:{// MOV Y,abs
+ int temp = READ_PC16( pc );
+ pc += 2;
+ READ_TIMER( 0, temp, y = nz );
+ //y = nz = READ( 0, temp );
+ 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
+ WRITE( 0, data, a );
+ 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:
+ WRITE( 0, READ_PC16( pc ), temp );
+ pc += 2;
+ goto loop;
+ }
+
+ case 0xD9: // MOV dp+Y,X
+ data = (uint8_t) (data + y);
+ case 0xD8: // MOV dp,X
+ WRITE( 0, data + dp, x );
+ goto inc_pc_loop;
+
+ case 0xDB: // MOV dp+X,Y
+ data = (uint8_t) (data + x);
+ case 0xCB: // MOV dp,Y
+ WRITE( 0, data + dp, y );
+ goto inc_pc_loop;
+
+// 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3.
+
+ case 0x7D: // MOV A,X
+ a = x;
+ nz = x;
+ goto loop;
+
+ case 0xDD: // MOV A,Y
+ a = y;
+ nz = y;
+ goto loop;
+
+ case 0x5D: // MOV X,A
+ x = a;
+ nz = a;
+ goto loop;
+
+ case 0xFD: // MOV Y,A
+ y = a;
+ 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
+ WRITE_DP( 0, x, a + no_read_before_write );
+ x++;
+ goto loop;
+
+// 5. 8-BIT LOGIC OPERATION COMMANDS
+
+#define LOGICAL_OP( op, func )\
+ ADDR_MODES( op ) /* addr */\
+ data = READ( 0, data );\
+ case op: /* imm */\
+ nz = a func##= data;\
+ goto inc_pc_loop;\
+ { unsigned addr;\
+ case op + 0x11: /* X,Y */\
+ data = READ_DP( -2, y );\
+ addr = x + dp;\
+ goto addr_##op;\
+ case op + 0x01: /* dp,dp */\
+ data = READ_DP( -3, data );\
+ case op + 0x10:{/*dp,imm*/\
+ uint8_t const* addr2 = pc + 1;\
+ pc += 2;\
+ addr = READ_PC( addr2 ) + dp;\
+ }\
+ addr_##op:\
+ nz = data func READ( -1, addr );\
+ WRITE( 0, addr, nz );\
+ 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 = READ( 0, data );
+ case 0x68: // CMP imm
+ nz = a - data;
+ c = ~nz;
+ nz &= 0xFF;
+ goto inc_pc_loop;
+
+ case 0x79: // CMP (X),(Y)
+ data = READ_DP( -2, y );
+ nz = READ_DP( -1, x ) - data;
+ c = ~nz;
+ nz &= 0xFF;
+ goto loop;
+
+ case 0x69: // CMP dp,dp
+ data = READ_DP( -3, data );
+ case 0x78: // CMP dp,imm
+ nz = READ_DP( -1, READ_PC( ++pc ) ) - 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 = READ_PC16( pc );
+ pc++;
+ cmp_x_addr:
+ data = READ( 0, data );
+ 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 = READ_PC16( pc );
+ pc++;
+ cmp_y_addr:
+ data = READ( 0, data );
+ 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 = READ_DP( -2, y );
+ addr = x + dp;
+ goto adc_addr;
+ case 0xA9: // SBC dp,dp
+ case 0x89: // ADC dp,dp
+ data = READ_DP( -3, data );
+ case 0xB8: // SBC dp,imm
+ case 0x98: // ADC dp,imm
+ addr = READ_PC( ++pc ) + dp;
+ adc_addr:
+ nz = READ( -1, addr );
+ 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 = READ( 0, data );
+ 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 = (uint8_t) nz;
+ goto inc_pc_loop;
+ }
+ WRITE( 0, addr, /*(uint8_t)*/ nz );
+ goto inc_pc_loop;
+ }
+
+ }
+
+// 6. ADDITION & SUBTRACTION COMMANDS
+
+#define INC_DEC_REG( reg, op )\
+ nz = reg op;\
+ reg = (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 = (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 = READ_PC16( pc );
+ pc++;
+ inc_abs:
+ nz = (opcode >> 4 & 2) - 1;
+ nz += READ( -1, data );
+ WRITE( 0, data, /*(uint8_t)*/ nz );
+ 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 = (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 = (uint8_t) (data + x);
+ case 0x2B: // ROL dp
+ data += dp;
+ goto rol_mem;
+ case 0x0C: // ASL abs
+ c = 0;
+ case 0x2C: // ROL abs
+ data = READ_PC16( pc );
+ pc++;
+ rol_mem:
+ nz = c >> 8 & 1;
+ nz |= (c = READ( -1, data ) << 1);
+ WRITE( 0, data, /*(uint8_t)*/ nz );
+ 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 = (uint8_t) (data + x);
+ case 0x6B: // ROR dp
+ data += dp;
+ goto ror_mem;
+ case 0x4C: // LSR abs
+ c = 0;
+ case 0x6C: // ROR abs
+ data = READ_PC16( pc );
+ pc++;
+ ror_mem: {
+ int temp = READ( -1, data );
+ nz = (c >> 1 & 0x80) | (temp >> 1);
+ c = temp << 8;
+ WRITE( 0, data, nz );
+ goto inc_pc_loop;
+ }
+
+ case 0x9F: // XCN
+ nz = a = (a >> 4) | (uint8_t) (a << 4);
+ goto loop;
+
+// 8. 16-BIT TRANSMISION COMMANDS
+
+ case 0xBA: // MOVW YA,dp
+ a = READ_DP( -2, data );
+ nz = (a & 0x7F) | (a >> 1);
+ y = READ_DP( 0, (uint8_t) (data + 1) );
+ nz |= y;
+ goto inc_pc_loop;
+
+ case 0xDA: // MOVW dp,YA
+ WRITE_DP( -1, data, a );
+ WRITE_DP( 0, (uint8_t) (data + 1), y + no_read_before_write );
+ goto inc_pc_loop;
+
+// 9. 16-BIT OPERATION COMMANDS
+
+ case 0x3A: // INCW dp
+ case 0x1A:{// DECW dp
+ int temp;
+ // low byte
+ data += dp;
+ temp = READ( -3, data );
+ temp += (opcode >> 4 & 2) - 1; // +1 for INCW, -1 for DECW
+ nz = ((temp >> 1) | temp) & 0x7F;
+ WRITE( -2, data, /*(uint8_t)*/ temp );
+
+ // high byte
+ data = (uint8_t) (data + 1) + dp;
+ temp = (uint8_t) ((temp >> 8) + READ( -1, data ));
+ nz |= temp;
+ WRITE( 0, data, temp );
+
+ goto inc_pc_loop;
+ }
+
+ case 0x7A: // ADDW YA,dp
+ case 0x9A:{// SUBW YA,dp
+ int lo = READ_DP( -2, data );
+ int hi = READ_DP( 0, (uint8_t) (data + 1) );
+ int result;
+ int flags;
+
+ if ( opcode == 0x9A ) // SUBW
+ {
+ lo = (lo ^ 0xFF) + 1;
+ hi ^= 0xFF;
+ }
+
+ lo += a;
+ result = y + hi + (lo >> 8);
+ flags = hi ^ y ^ result;
+
+ psw = (psw & ~(v40 | h08)) |
+ (flags >> 1 & h08) |
+ ((flags + 0x80) >> 2 & v40);
+ c = result;
+ a = (uint8_t) lo;
+ result = (uint8_t) result;
+ y = result;
+ nz = (((lo >> 1) | lo) & 0x7F) | result;
+
+ goto inc_pc_loop;
+ }
+
+ case 0x5A: { // CMPW YA,dp
+ int temp = a - READ_DP( -1, data );
+ nz = ((temp >> 1) | temp) & 0x7F;
+ temp = y + (temp >> 8);
+ temp -= READ_DP( 0, (uint8_t) (data + 1) );
+ nz |= temp;
+ c = ~temp;
+ nz &= 0xFF;
+ goto inc_pc_loop;
+ }
+
+// 10. MULTIPLICATION & DIVISON COMMANDS
+
+ case 0xCF: { // MUL YA
+ unsigned temp = y * a;
+ a = (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 = (uint8_t) a;
+ a = (uint8_t) a;
+
+ goto loop;
+ }
+
+// 11. DECIMAL COMPENSATION COMMANDS
+
+ case 0xDF: // DAA
+ SUSPICIOUS_OPCODE( "DAA" );
+ if ( a > 0x99 || c & 0x100 )
+ {
+ a += 0x60;
+ c = 0x100;
+ }
+
+ if ( (a & 0x0F) > 9 || psw & h08 )
+ a += 0x06;
+
+ nz = a;
+ a = (uint8_t) a;
+ goto loop;
+
+ case 0xBE: // DAS
+ SUSPICIOUS_OPCODE( "DAS" );
+ if ( a > 0x99 || !(c & 0x100) )
+ {
+ a -= 0x60;
+ c = 0;
+ }
+
+ if ( (a & 0x0F) > 9 || !(psw & h08) )
+ a -= 0x06;
+
+ nz = a;
+ a = (uint8_t) a;
+ goto loop;
+
+// 12. BRANCHING COMMANDS
+
+ case 0x2F: // BRA rel
+ pc += (BOOST::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( READ_DP( -4, data ) >> (opcode >> 5) & 1 )
+
+ case 0x13: // BBC dp.bit,rel
+ case 0x33:
+ case 0x53:
+ case 0x73:
+ case 0x93:
+ case 0xB3:
+ case 0xD3:
+ case 0xF3:
+ CBRANCH( !(READ_DP( -4, data ) >> (opcode >> 5) & 1) )
+
+ case 0xDE: // CBNE dp+X,rel
+ data = (uint8_t) (data + x);
+ // fall through
+ case 0x2E:{// CBNE dp,rel
+ int temp;
+ // 61% from timer
+ READ_DP_TIMER( -4, data, temp );
+ CBRANCH( temp != a )
+ }
+
+ case 0x6E: { // DBNZ dp,rel
+ unsigned temp = READ_DP( -4, data ) - 1;
+ WRITE_DP( -3, (uint8_t) data, /*(uint8_t)*/ temp + no_read_before_write );
+ CBRANCH( temp )
+ }
+
+ case 0xFE: // DBNZ Y,rel
+ y = (uint8_t) (y - 1);
+ BRANCH( y )
+
+ case 0x1F: // JMP [abs+X]
+ SET_PC( READ_PC16( pc ) + x );
+ // fall through
+ case 0x5F: // JMP abs
+ SET_PC( READ_PC16( pc ) );
+ goto loop;
+
+// 13. SUB-ROUTINE CALL RETURN COMMANDS
+
+ case 0x0F:{// BRK
+ int temp;
+ int ret_addr = GET_PC();
+ SUSPICIOUS_OPCODE( "BRK" );
+ 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;
+ WRITE( 0, data, (READ( -1, data ) & mask) | bit );
+ goto inc_pc_loop;
+ }
+
+ case 0x0E: // TSET1 abs
+ case 0x4E: // TCLR1 abs
+ data = READ_PC16( pc );
+ pc += 2;
+ {
+ unsigned temp = READ( -2, data );
+ nz = (uint8_t) (a - temp);
+ temp &= ~a;
+ if ( opcode == 0x0E )
+ temp |= a;
+ WRITE( 0, data, temp );
+ }
+ 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 = READ_PC16( pc );
+ pc += 2;
+ {
+ unsigned temp = READ( -1, data & 0x1FFF );
+ temp ^= 1 << (data >> 13);
+ WRITE( 0, data & 0x1FFF, temp );
+ }
+ goto loop;
+
+ case 0xCA: // MOV1 mem.bit,C
+ data = READ_PC16( pc );
+ pc += 2;
+ {
+ unsigned temp = READ( -2, data & 0x1FFF );
+ unsigned bit = data >> 13;
+ temp = (temp & ~(1 << bit)) | ((c >> 8 & 1) << bit);
+ WRITE( 0, data & 0x1FFF, temp + no_read_before_write );
+ }
+ 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
+ SUSPICIOUS_OPCODE( "EI" );
+ psw |= i04;
+ goto loop;
+
+ case 0xC0: // DI
+ SUSPICIOUS_OPCODE( "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 );
+ dprintf( "SPC: PC wrapped around\n" );
+ goto loop;
+ }
+ }
+ // fall through
+ case 0xEF: // SLEEP
+ SUSPICIOUS_OPCODE( "STOP/SLEEP" );
+ --pc;
+ rel_time = 0;
+ m.cpu_error = "SPC emulation error";
+ goto stop;
+ } // switch
+
+ assert( 0 ); // catch any unhandled instructions
+}
+out_of_time:
+ rel_time -= m.cycle_table [*pc]; // undo partial execution of opcode
+stop:
+
+ // Uncache registers
+ if ( GET_PC() >= 0x10000 )
+ dprintf( "SPC: PC wrapped around\n" );
+ m.cpu_regs.pc = (uint16_t) GET_PC();
+ m.cpu_regs.sp = ( uint8_t) GET_SP();
+ m.cpu_regs.a = ( uint8_t) a;
+ m.cpu_regs.x = ( uint8_t) x;
+ m.cpu_regs.y = ( uint8_t) y;
+ {
+ int temp;
+ GET_PSW( temp );
+ m.cpu_regs.psw = (uint8_t) temp;
+ }
+}
+SPC_CPU_RUN_FUNC_END
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/SPC_DSP.cpp
@@ -1,1 +1,1069 @@
-
+// snes_spc 0.9.0. http://www.slack.net/~ant/
+
+#include "SPC_DSP.h"
+
+#include "blargg_endian.h"
+#include <string.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 */
+
+#include "blargg_source.h"
+
+#ifdef BLARGG_ENABLE_OPTIMIZER
+ #include BLARGG_ENABLE_OPTIMIZER
+#endif
+
+#if INT_MAX < 0x7FFFFFFF
+ #error "Requires that int type have at least 32 bits"
+#endif
+
+// TODO: add to blargg_endian.h
+#define GET_LE16SA( addr ) ((BOOST::int16_t) GET_LE16( addr ))
+#define GET_LE16A( addr ) GET_LE16( addr )
+#define SET_LE16A( addr, data ) SET_LE16( addr, data )
+
+static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] =
+{
+ 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;
+#define CLAMP16( io )\
+{\
+ if ( (int16_t) io != io )\
+ io = (io >> 31) ^ 0x7FFF;\
+}
+
+// Access global DSP register
+#define REG(n) m.regs [r_##n]
+
+// Access voice DSP register
+#define VREG(r,n) r [v_##n]
+
+#define WRITE_SAMPLES( l, r, out ) \
+{\
+ out [0] = l;\
+ out [1] = r;\
+ out += 2;\
+ if ( out >= m.out_end )\
+ {\
+ check( out == m.out_end );\
+ check( m.out_end != &m.extra [extra_size] || \
+ (m.extra <= m.out_begin && m.extra < &m.extra [extra_size]) );\
+ out = m.extra;\
+ m.out_end = &m.extra [extra_size];\
+ }\
+}\
+
+void SPC_DSP::set_output( sample_t* out, int size )
+{
+ require( (size & 1) == 0 ); // must be even
+ if ( !out )
+ {
+ out = m.extra;
+ size = extra_size;
+ }
+ m.out_begin = out;
+ m.out = out;
+ 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 short const gauss [512] =
+{
+ 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,
+};
+
+inline int SPC_DSP::interpolate( voice_t const* v )
+{
+ // Make pointers into gaussian based on fractional position between samples
+ int offset = v->interp_pos >> 4 & 0xFF;
+ short const* fwd = gauss + 255 - offset;
+ short const* rev = gauss + offset; // mirror left half of gaussian
+
+ int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos];
+ int out;
+ out = (fwd [ 0] * in [0]) >> 11;
+ out += (fwd [256] * in [1]) >> 11;
+ out += (rev [256] * in [2]) >> 11;
+ out = (int16_t) out;
+ out += (rev [ 0] * in [3]) >> 11;
+
+ CLAMP16( out );
+ out &= ~1;
+ return out;
+}
+
+
+//// Counters
+
+int const simple_counter_range = 2048 * 5 * 3; // 30720
+
+static unsigned const counter_rates [32] =
+{
+ 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 unsigned const counter_offsets [32] =
+{
+ 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
+};
+
+inline void SPC_DSP::init_counter()
+{
+ m.counter = 0;
+}
+
+inline void SPC_DSP::run_counters()
+{
+ if ( --m.counter < 0 )
+ m.counter = simple_counter_range - 1;
+}
+
+inline unsigned SPC_DSP::read_counter( int rate )
+{
+ return ((unsigned) m.counter + counter_offsets [rate]) % counter_rates [rate];
+}
+
+
+//// Envelope
+
+inline 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 = VREG(v->regs,adsr1);
+ if ( 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 = (m.t_adsr0 >> 3 & 0x0E) + 0x10;
+ }
+ else // env_attack
+ {
+ rate = (m.t_adsr0 & 0x0F) * 2 + 1;
+ env += rate < 31 ? 0x20 : 0x400;
+ }
+ }
+ else // GAIN
+ {
+ int mode;
+ env_data = VREG(v->regs,gain);
+ 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 && (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 ( (unsigned) env > 0x7FF )
+ {
+ env = (env < 0 ? 0 : 0x7FF);
+ if ( v->env_mode == env_attack )
+ v->env_mode = env_decay;
+ }
+
+ if ( !read_counter( rate ) )
+ v->env = env; // nothing else is controlled by the counter
+ }
+}
+
+
+//// BRR Decoding
+
+inline void SPC_DSP::decode_brr( voice_t* v )
+{
+ // Arrange the four input nybbles in 0xABCD order for easy decoding
+ int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF];
+
+ int const header = 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 = (int16_t) nybbles >> 12;
+
+ // Shift sample based on header
+ int const 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 const filter = header & 0x0C;
+ int const p1 = pos [brr_buf_size - 1];
+ int const 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 = (int16_t) (s * 2);
+ pos [brr_buf_size] = pos [0] = s; // second copy simplifies wrap-around
+ }
+}
+
+
+//// Misc
+
+#define MISC_CLOCK( n ) inline void SPC_DSP::misc_##n()
+
+MISC_CLOCK( 27 )
+{
+ m.t_pmon = REG(pmon) & 0xFE; // voice 0 doesn't support PMON
+}
+MISC_CLOCK( 28 )
+{
+ m.t_non = REG(non);
+ m.t_eon = REG(eon);
+ m.t_dir = REG(dir);
+}
+MISC_CLOCK( 29 )
+{
+ if ( (m.every_other_sample ^= 1) != 0 )
+ m.new_kon &= ~m.kon; // clears KON 63 clocks after it was last read
+}
+MISC_CLOCK( 30 )
+{
+ if ( m.every_other_sample )
+ {
+ m.kon = m.new_kon;
+ m.t_koff = REG(koff) | m.mute_mask;
+ }
+
+ run_counters();
+
+ // Noise
+ if ( !read_counter( REG(flg) & 0x1F ) )
+ {
+ int feedback = (m.noise << 13) ^ (m.noise << 14);
+ m.noise = (feedback & 0x4000) ^ (m.noise >> 1);
+ }
+}
+
+
+//// Voices
+
+#define VOICE_CLOCK( n ) void SPC_DSP::voice_##n( voice_t* const v )
+
+inline VOICE_CLOCK( V1 )
+{
+ m.t_dir_addr = m.t_dir * 0x100 + m.t_srcn * 4;
+ m.t_srcn = VREG(v->regs,srcn);
+}
+inline VOICE_CLOCK( V2 )
+{
+ // Read sample pointer (ignored if not needed)
+ uint8_t const* entry = &m.ram [m.t_dir_addr];
+ if ( !v->kon_delay )
+ entry += 2;
+ m.t_brr_next_addr = GET_LE16A( entry );
+
+ m.t_adsr0 = VREG(v->regs,adsr0);
+
+ // Read pitch, spread over two clocks
+ m.t_pitch = VREG(v->regs,pitchl);
+}
+inline VOICE_CLOCK( V3a )
+{
+ m.t_pitch += (VREG(v->regs,pitchh) & 0x3F) << 8;
+}
+inline VOICE_CLOCK( V3b )
+{
+ // Read BRR header and byte
+ m.t_brr_byte = m.ram [(v->brr_addr + v->brr_offset) & 0xFFFF];
+ m.t_brr_header = m.ram [v->brr_addr]; // brr_addr doesn't need masking
+}
+VOICE_CLOCK( V3c )
+{
+ // Pitch modulation using previous voice's output
+ if ( m.t_pmon & v->vbit )
+ m.t_pitch += ((m.t_output >> 5) * 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 = m.t_brr_next_addr;
+ v->brr_offset = 1;
+ v->buf_pos = 0;
+ m.t_brr_header = 0; // header is ignored on this sample
+ m.kon_check = true;
+
+ if (take_spc_snapshot)
+ {
+ take_spc_snapshot = 0;
+ if (spc_snapshot_callback)
+ spc_snapshot_callback();
+ }
+ }
+
+ // 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
+ m.t_pitch = 0;
+ }
+
+ // Gaussian interpolation
+ {
+ int output = interpolate( v );
+
+ // Noise
+ if ( m.t_non & v->vbit )
+ output = (int16_t) (m.noise * 2);
+
+ // Apply envelope
+ m.t_output = (output * v->env) >> 11 & ~1;
+ v->t_envx_out = (uint8_t) (v->env >> 4);
+ }
+
+ // Immediate silence due to end of sample or soft reset
+ if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 )
+ {
+ v->env_mode = env_release;
+ v->env = 0;
+ }
+
+ if ( m.every_other_sample )
+ {
+ // KOFF
+ if ( m.t_koff & v->vbit )
+ v->env_mode = env_release;
+
+ // KON
+ if ( m.kon & v->vbit )
+ {
+ v->kon_delay = 5;
+ v->env_mode = env_attack;
+ }
+ }
+
+ // Run envelope for next sample
+ if ( !v->kon_delay )
+ run_envelope( v );
+}
+
+inline void SPC_DSP::voice_output( voice_t const* v, int ch )
+{
+ // Apply left/right volume
+ int amp = (m.t_output * (int8_t) VREG(v->regs,voll + ch)) >> 7;
+ amp *= ((stereo_switch & (1 << (v->voice_number + ch * voice_count))) ? 1 : 0);
+
+ // Add to output total
+ m.t_main_out [ch] += amp;
+ CLAMP16( m.t_main_out [ch] );
+
+ // Optionally add to echo total
+ if ( m.t_eon & v->vbit )
+ {
+ m.t_echo_out [ch] += amp;
+ CLAMP16( m.t_echo_out [ch] );
+ }
+}
+VOICE_CLOCK( V4 )
+{
+ // Decode BRR
+ m.t_looped = 0;
+ if ( v->interp_pos >= 0x4000 )
+ {
+ 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 ( m.t_brr_header & 1 )
+ {
+ v->brr_addr = m.t_brr_next_addr;
+ 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
+ voice_output( v, 0 );
+}
+inline VOICE_CLOCK( V5 )
+{
+ // Output right
+ voice_output( v, 1 );
+
+ // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier
+ int endx_buf = REG(endx) | m.t_looped;
+
+ // Clear bit in ENDX if KON just began
+ if ( v->kon_delay == 5 )
+ endx_buf &= ~v->vbit;
+ m.endx_buf = (uint8_t) endx_buf;
+}
+inline VOICE_CLOCK( V6 )
+{
+ (void) v; // avoid compiler warning about unused v
+ m.outx_buf = (uint8_t) (m.t_output >> 8);
+}
+inline VOICE_CLOCK( V7 )
+{
+ // Update ENDX
+ REG(endx) = m.endx_buf;
+
+ m.envx_buf = v->t_envx_out;
+}
+inline VOICE_CLOCK( V8 )
+{
+ // Update OUTX
+ VREG(v->regs,outx) = m.outx_buf;
+}
+inline VOICE_CLOCK( V9 )
+{
+ // Update ENVX
+ VREG(v->regs,envx) = m.envx_buf;
+}
+
+// Most voices do all these in one clock, so make a handy composite
+inline VOICE_CLOCK( V3 )
+{
+ voice_V3a( v );
+ voice_V3b( v );
+ 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.
+VOICE_CLOCK(V7_V4_V1) { voice_V7(v); voice_V1(v+3); voice_V4(v+1); }
+VOICE_CLOCK(V8_V5_V2) { voice_V8(v); voice_V5(v+1); voice_V2(v+2); }
+VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); }
+
+
+//// Echo
+
+// Current echo buffer pointer for left/right channel
+#define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2])
+
+// Sample in echo history buffer, where 0 is the oldest
+#define ECHO_FIR( i ) (m.echo_hist_pos [i])
+
+// Calculate FIR point for left/right channel
+#define CALC_FIR( i, ch ) ((ECHO_FIR( i + 1 ) [ch] * (int8_t) REG(fir + i * 0x10)) >> 6)
+
+#define ECHO_CLOCK( n ) inline void SPC_DSP::echo_##n()
+
+inline void SPC_DSP::echo_read( int ch )
+{
+ int s = GET_LE16SA( ECHO_PTR( ch ) );
+ // second copy simplifies wrap-around handling
+ ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1;
+}
+
+ECHO_CLOCK( 22 )
+{
+ // History
+ if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] )
+ m.echo_hist_pos = m.echo_hist;
+
+ m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF;
+ echo_read( 0 );
+
+ // FIR (using l and r temporaries below helps compiler optimize)
+ int l = CALC_FIR( 0, 0 );
+ int r = CALC_FIR( 0, 1 );
+
+ m.t_echo_in [0] = l;
+ m.t_echo_in [1] = r;
+}
+ECHO_CLOCK( 23 )
+{
+ int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 );
+ int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 );
+
+ m.t_echo_in [0] += l;
+ m.t_echo_in [1] += r;
+
+ echo_read( 1 );
+}
+ECHO_CLOCK( 24 )
+{
+ int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 );
+ int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 );
+
+ m.t_echo_in [0] += l;
+ m.t_echo_in [1] += r;
+}
+ECHO_CLOCK( 25 )
+{
+ int l = m.t_echo_in [0] + CALC_FIR( 6, 0 );
+ int r = m.t_echo_in [1] + CALC_FIR( 6, 1 );
+
+ l = (int16_t) l;
+ r = (int16_t) r;
+
+ l += (int16_t) CALC_FIR( 7, 0 );
+ r += (int16_t) CALC_FIR( 7, 1 );
+
+ CLAMP16( l );
+ CLAMP16( r );
+
+ m.t_echo_in [0] = l & ~1;
+ m.t_echo_in [1] = r & ~1;
+}
+inline int SPC_DSP::echo_output( int ch )
+{
+ int out = (int16_t) ((m.t_main_out [ch] * (int8_t) REG(mvoll + ch * 0x10)) >> 7) +
+ (int16_t) ((m.t_echo_in [ch] * (int8_t) REG(evoll + ch * 0x10)) >> 7);
+ CLAMP16( out );
+ return out;
+}
+ECHO_CLOCK( 26 )
+{
+ // Left output volumes
+ // (save sample for next clock so we can output both together)
+ m.t_main_out [0] = echo_output( 0 );
+
+ // Echo feedback
+ int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7);
+ int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7);
+
+ CLAMP16( l );
+ CLAMP16( r );
+
+ m.t_echo_out [0] = l & ~1;
+ m.t_echo_out [1] = r & ~1;
+}
+ECHO_CLOCK( 27 )
+{
+ // Output
+ int l = m.t_main_out [0];
+ int r = echo_output( 1 );
+ m.t_main_out [0] = 0;
+ 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 ( REG(flg) & 0x40 )
+ {
+ l = 0;
+ r = 0;
+ }
+
+ // Output sample to DAC
+ #ifdef SPC_DSP_OUT_HOOK
+ SPC_DSP_OUT_HOOK( l, r );
+ #else
+ sample_t* out = m.out;
+ WRITE_SAMPLES( l, r, out );
+ m.out = out;
+ #endif
+}
+ECHO_CLOCK( 28 )
+{
+ m.t_echo_enabled = REG(flg);
+}
+inline void SPC_DSP::echo_write( int ch )
+{
+ if ( !(m.t_echo_enabled & 0x20) )
+ {
+ if ( m.t_echo_ptr >= 0xffc0 && rom_enabled )
+ SET_LE16A( &hi_ram [m.t_echo_ptr + ch * 2 - 0xffc0], m.t_echo_out [ch] );
+ else
+ SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] );
+ }
+
+ m.t_echo_out [ch] = 0;
+}
+ECHO_CLOCK( 29 )
+{
+ m.t_esa = REG(esa);
+
+ if ( !m.echo_offset )
+ m.echo_length = (REG(edl) & 0x0F) * 0x800;
+
+ m.echo_offset += 4;
+ if ( m.echo_offset >= m.echo_length )
+ m.echo_offset = 0;
+
+ // Write left echo
+ echo_write( 0 );
+
+ m.t_echo_enabled = REG(flg);
+}
+ECHO_CLOCK( 30 )
+{
+ // Write right echo
+ echo_write( 1 );
+}
+
+
+//// Timing
+
+// Execute clock for a particular voice
+#define V( clock, voice ) voice_##clock( &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)\
+
+#if !SPC_DSP_CUSTOM_RUN
+
+void SPC_DSP::run( int clocks_remain )
+{
+ require( clocks_remain > 0 );
+
+ int const phase = m.phase;
+ 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( void* ram_64k )
+{
+ m.ram = (uint8_t*) ram_64k;
+ mute_voices( 0 );
+ disable_surround( false );
+ set_output( 0, 0 );
+ reset();
+
+ stereo_switch = 0xffff;
+ take_spc_snapshot = 0;
+ spc_snapshot_callback = 0;
+
+ #ifndef NDEBUG
+ // be sure this sign-extends
+ assert( (int16_t) 0x8000 == -0x8000 );
+
+ // be sure right shift preserves sign
+ assert( (-1 >> 1) == -1 );
+
+ // check clamp macro
+ int i;
+ 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()
+{
+ require( m.ram ); // init() must have been called already
+
+ m.noise = 0x4000;
+ m.echo_hist_pos = m.echo_hist;
+ m.every_other_sample = 1;
+ m.echo_offset = 0;
+ m.phase = 0;
+
+ init_counter();
+
+ for (int i = 0; i < voice_count; i++)
+ m.voices[i].voice_number = i;
+}
+
+void SPC_DSP::soft_reset()
+{
+ REG(flg) = 0xE0;
+ soft_reset_common();
+}
+
+void SPC_DSP::load( uint8_t const regs [register_count] )
+{
+ memcpy( m.regs, regs, sizeof m.regs );
+ memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count );
+
+ // Internal state
+ for ( int i = voice_count; --i >= 0; )
+ {
+ voice_t* v = &m.voices [i];
+ v->brr_offset = 1;
+ v->vbit = 1 << i;
+ v->regs = &m.regs [i * 0x10];
+ }
+ m.new_kon = REG(kon);
+ m.t_dir = REG(dir);
+ m.t_esa = REG(esa);
+
+ soft_reset_common();
+}
+
+void SPC_DSP::reset() { load( initial_regs ); }
+
+
+//// State save/load
+
+#if !SPC_NO_COPY_STATE_FUNCS
+
+void SPC_State_Copier::copy( void* state, size_t size )
+{
+ func( buf, state, size );
+}
+
+int SPC_State_Copier::copy_int( int state, int size )
+{
+ BOOST::uint8_t s [2];
+ SET_LE16( s, state );
+ func( buf, &s, size );
+ return GET_LE16( s );
+}
+
+void SPC_State_Copier::skip( int count )
+{
+ if ( count > 0 )
+ {
+ char temp [64];
+ memset( temp, 0, sizeof temp );
+ do
+ {
+ int n = sizeof temp;
+ if ( n > count )
+ n = count;
+ count -= n;
+ func( buf, temp, n );
+ }
+ while ( count );
+ }
+}
+
+void SPC_State_Copier::extra()
+{
+ int n = 0;
+ SPC_State_Copier& copier = *this;
+ SPC_COPY( uint8_t, n );
+ skip( n );
+}
+
+void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy )
+{
+ SPC_State_Copier copier( io, copy );
+
+ // DSP registers
+ copier.copy( m.regs, register_count );
+
+ // Internal state
+
+ // Voices
+ int i;
+ for ( i = 0; i < voice_count; i++ )
+ {
+ voice_t* v = &m.voices [i];
+
+ // BRR buffer
+ int i;
+ for ( i = 0; i < brr_buf_size; i++ )
+ {
+ int s = v->buf [i];
+ SPC_COPY( int16_t, s );
+ v->buf [i] = v->buf [i + brr_buf_size] = s;
+ }
+
+ SPC_COPY( uint16_t, v->interp_pos );
+ SPC_COPY( uint16_t, v->brr_addr );
+ SPC_COPY( uint16_t, v->env );
+ SPC_COPY( int16_t, v->hidden_env );
+ SPC_COPY( uint8_t, v->buf_pos );
+ SPC_COPY( uint8_t, v->brr_offset );
+ SPC_COPY( uint8_t, v->kon_delay );
+ {
+ int m = v->env_mode;
+ SPC_COPY( uint8_t, m );
+ v->env_mode = (enum env_mode_t) m;
+ }
+ SPC_COPY( uint8_t, v->t_envx_out );
+
+ copier.extra();
+ }
+
+ // Echo history
+ for ( i = 0; i < echo_hist_size; i++ )
+ {
+ int j;
+ for ( j = 0; j < 2; j++ )
+ {
+ int s = m.echo_hist_pos [i] [j];
+ SPC_COPY( int16_t, s );
+ m.echo_hist [i] [j] = s; // write back at offset 0
+ }
+ }
+ m.echo_hist_pos = m.echo_hist;
+ memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] );
+
+ // Misc
+ SPC_COPY( uint8_t, m.every_other_sample );
+ SPC_COPY( uint8_t, m.kon );
+
+ SPC_COPY( uint16_t, m.noise );
+ SPC_COPY( uint16_t, m.counter );
+ SPC_COPY( uint16_t, m.echo_offset );
+ SPC_COPY( uint16_t, m.echo_length );
+ SPC_COPY( uint8_t, m.phase );
+
+ SPC_COPY( uint8_t, m.new_kon );
+ SPC_COPY( uint8_t, m.endx_buf );
+ SPC_COPY( uint8_t, m.envx_buf );
+ SPC_COPY( uint8_t, m.outx_buf );
+
+ SPC_COPY( uint8_t, m.t_pmon );
+ SPC_COPY( uint8_t, m.t_non );
+ SPC_COPY( uint8_t, m.t_eon );
+ SPC_COPY( uint8_t, m.t_dir );
+ SPC_COPY( uint8_t, m.t_koff );
+
+ SPC_COPY( uint16_t, m.t_brr_next_addr );
+ SPC_COPY( uint8_t, m.t_adsr0 );
+ SPC_COPY( uint8_t, m.t_brr_header );
+ SPC_COPY( uint8_t, m.t_brr_byte );
+ SPC_COPY( uint8_t, m.t_srcn );
+ SPC_COPY( uint8_t, m.t_esa );
+ SPC_COPY( uint8_t, m.t_echo_enabled );
+
+ SPC_COPY( int16_t, m.t_main_out [0] );
+ SPC_COPY( int16_t, m.t_main_out [1] );
+ SPC_COPY( int16_t, m.t_echo_out [0] );
+ SPC_COPY( int16_t, m.t_echo_out [1] );
+ SPC_COPY( int16_t, m.t_echo_in [0] );
+ SPC_COPY( int16_t, m.t_echo_in [1] );
+
+ SPC_COPY( uint16_t, m.t_dir_addr );
+ SPC_COPY( uint16_t, m.t_pitch );
+ SPC_COPY( int16_t, m.t_output );
+ SPC_COPY( uint16_t, m.t_echo_ptr );
+ SPC_COPY( uint8_t, m.t_looped );
+
+ copier.extra();
+}
+#endif
+
+
+//// Snes9x Accessor
+
+void SPC_DSP::set_spc_snapshot_callback(void (*callback)())
+{
+ spc_snapshot_callback = callback;
+}
+
+void SPC_DSP::dump_spc_snapshot()
+{
+ take_spc_snapshot = 1;
+}
+
+void SPC_DSP::set_stereo_switch( int value )
+{
+ stereo_switch = value;
+}
+
+SPC_DSP::uint8_t SPC_DSP::reg_value( int ch, int addr )
+{
+ return m.voices[ch].regs[addr];
+}
+
+int SPC_DSP::envx_value( int ch )
+{
+ return m.voices[ch].env;
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/SPC_DSP.h
@@ -1,1 +1,320 @@
-
+// Highly accurate SNES SPC-700 DSP emulator
+
+// snes_spc 0.9.0
+#ifndef SPC_DSP_H
+#define SPC_DSP_H
+
+#include "blargg_common.h"
+
+extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, size_t ); }
+
+class SPC_DSP {
+public:
+ typedef BOOST::uint8_t uint8_t;
+
+// Setup
+
+ // Initializes DSP and has it use the 64K RAM provided
+ void init( void* 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( uint8_t const regs [register_count] );
+
+ // Saves/loads exact emulator state
+ enum { state_size = 640 }; // maximum space needed when saving
+ typedef dsp_copy_func_t copy_func_t;
+ void copy_state( unsigned char** io, copy_func_t );
+
+ // Returns non-zero if new key-on events occurred since last call
+ bool check_kon();
+
+// Snes9x Accessor
+
+ int stereo_switch;
+ int take_spc_snapshot;
+ int rom_enabled; // mirror
+ uint8_t *rom, *hi_ram; // mirror
+ void (*spc_snapshot_callback)();
+
+ void set_spc_snapshot_callback(void (*callback)());
+ void dump_spc_snapshot();
+ 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 m.extra; }
+ sample_t const* out_pos() const { return m.out; }
+ void disable_surround( bool ) { } // not supported
+public:
+ BLARGG_DISABLE_NOTHROW
+
+ typedef BOOST::int8_t int8_t;
+ typedef BOOST::int16_t int16_t;
+
+ 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]
+
+ int 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)
+ bool kon_check; // set when a new KON occurs
+
+ // 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( voice_t const* 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( voice_t const* 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 );
+
+ 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();
+};
+
+#include <assert.h>
+
+inline int SPC_DSP::sample_count() const { return m.out - m.out_begin; }
+
+inline int SPC_DSP::read( int addr ) const
+{
+ assert( (unsigned) addr < register_count );
+ return m.regs [addr];
+}
+
+inline void SPC_DSP::write( int addr, int data )
+{
+ assert( (unsigned) addr < register_count );
+
+ m.regs [addr] = (uint8_t) data;
+ switch ( addr & 0x0F )
+ {
+ case v_envx:
+ m.envx_buf = (uint8_t) data;
+ break;
+
+ case v_outx:
+ m.outx_buf = (uint8_t) data;
+ break;
+
+ case 0x0C:
+ if ( addr == r_kon )
+ m.new_kon = (uint8_t) data;
+
+ if ( addr == r_endx ) // always cleared, regardless of data written
+ {
+ m.endx_buf = 0;
+ m.regs [r_endx] = 0;
+ }
+ break;
+ }
+}
+
+inline void SPC_DSP::mute_voices( int mask ) { m.mute_mask = mask; }
+
+inline bool SPC_DSP::check_kon()
+{
+ bool old = m.kon_check;
+ m.kon_check = 0;
+ return old;
+}
+
+#if !SPC_NO_COPY_STATE_FUNCS
+
+class SPC_State_Copier {
+ SPC_DSP::copy_func_t func;
+ unsigned char** buf;
+public:
+ SPC_State_Copier( unsigned char** p, SPC_DSP::copy_func_t f ) { func = f; buf = p; }
+ void copy( void* state, size_t size );
+ int copy_int( int state, int size );
+ void skip( int count );
+ void extra();
+};
+
+#define SPC_COPY( type, state )\
+{\
+ state = (BOOST::type) copier.copy_int( state, sizeof (BOOST::type) );\
+ assert( (BOOST::type) state == state );\
+}
+
+#endif
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/apu.cpp
@@ -1,1 +1,671 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#include <math.h>
+#include "snes9x.h"
+#include "apu.h"
+//#include "snapshot.h"
+//#include "display.h"
+#include "linear_resampler.h"
+#include "hermite_resampler.h"
+
+#define APU_DEFAULT_INPUT_RATE 32000
+#define APU_MINIMUM_SAMPLE_COUNT 512
+#define APU_MINIMUM_SAMPLE_BLOCK 128
+#define APU_NUMERATOR_NTSC 15664
+#define APU_DENOMINATOR_NTSC 328125
+#define APU_NUMERATOR_PAL 34176
+#define APU_DENOMINATOR_PAL 709379
+#define APU_DEFAULT_RESAMPLER HermiteResampler
+
+SNES_SPC *spc_core = NULL;
+
+static uint8_t APUROM[64] =
+{
+ 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
+};
+
+namespace spc
+{
+ static apu_callback sa_callback = NULL;
+ static void *extra_data = NULL;
+
+ 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 uint8_t *landing_buffer = NULL;
+ static uint8_t *shrink_buffer = NULL;
+
+ static Resampler *resampler = NULL;
+
+ 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;
+ /* 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 *, int);
+static void DeStereo (uint8_t *, int);
+static void ReverseStereo (uint8_t *, int);
+static void UpdatePlaybackRate();
+static void from_apu_to_state (uint8_t **, void *, size_t);
+static void to_apu_from_state (uint8_t **, void *, size_t);
+//static void SPCSnapshotCallback();
+static inline int S9xAPUGetClock (int32_t);
+static inline int S9xAPUGetClockRemainder (int32_t);
+
+
+static void EightBitize (uint8_t *buffer, int sample_count)
+{
+ uint8_t *buf8 = (uint8_t *) buffer;
+ int16_t *buf16 = (int16_t *) buffer;
+
+ for (int i = 0; i < sample_count; i++)
+ buf8[i] = (uint8_t) ((buf16[i] / 256) + 128);
+}
+
+static void DeStereo (uint8_t *buffer, int sample_count)
+{
+ int16_t *buf = (int16_t *) buffer;
+ int32_t s1, s2;
+
+ for (int i = 0; i < sample_count >> 1; i++)
+ {
+ s1 = (int32_t) buf[2 * i];
+ s2 = (int32_t) buf[2 * i + 1];
+ buf[i] = (int16_t) ((s1 + s2) >> 1);
+ }
+}
+
+static void ReverseStereo (uint8_t *src_buffer, int sample_count)
+{
+ int16_t *buffer = (int16_t *) src_buffer;
+
+ for (int i = 0; i < sample_count; i += 2)
+ {
+ buffer[i + 1] ^= buffer[i];
+ buffer[i] ^= buffer[i + 1];
+ buffer[i + 1] ^= buffer[i];
+ }
+}
+
+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))
+ {
+ delete[] spc::shrink_buffer;
+ spc::shrink_buffer = new uint8_t[sample_count << 1];
+ shrink_buffer_size = sample_count << 1;
+ }
+
+ dest = spc::shrink_buffer;
+ }
+ else
+ dest = buffer;
+
+ if (Settings.Mute)
+ {
+ memset(dest, 0, sample_count << 1);
+ spc::resampler->clear();
+
+ return false;
+ }
+ else
+ {
+ if (spc::resampler->avail() >= (sample_count + spc::lag))
+ {
+ spc::resampler->read((short *) dest, sample_count);
+ if (spc::lag == spc::lag_master)
+ spc::lag = 0;
+ }
+ else
+ {
+ memset(buffer, (Settings.SixteenBitSound ? 0 : 128), (sample_count << (Settings.SixteenBitSound ? 1 : 0)) >> (Settings.Stereo ? 0 : 1));
+ if (spc::lag == 0)
+ spc::lag = spc::lag_master;
+
+ 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);
+
+ memcpy(buffer, dest, (sample_count << (Settings.SixteenBitSound ? 1 : 0)));
+ }
+
+ return true;
+}
+
+int S9xGetSampleCount()
+{
+ return spc::resampler->avail() >> (Settings.Stereo ? 0 : 1);
+}
+
+void S9xFinalizeSamples()
+{
+ if (!Settings.Mute)
+ {
+ if (!spc::resampler->push((short *) spc::landing_buffer, 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;
+ }
+ }
+
+ if (!Settings.SoundSync || Settings.TurboMode || Settings.Mute)
+ spc::sound_in_sync = true;
+ else
+ if (spc::resampler->space_empty() >= spc::resampler->space_filled())
+ spc::sound_in_sync = true;
+ else
+ spc::sound_in_sync = false;
+
+ spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
+}
+
+void S9xLandSamples()
+{
+ if (spc::sa_callback != NULL)
+ spc::sa_callback(spc::extra_data);
+ else
+ S9xFinalizeSamples();
+}
+
+void S9xClearSamples()
+{
+ spc::resampler->clear();
+ spc::lag = spc::lag_master;
+}
+
+bool S9xSyncSound()
+{
+ if (!Settings.SoundSync || spc::sound_in_sync)
+ return true;
+
+ S9xLandSamples();
+
+ return spc::sound_in_sync;
+}
+
+void S9xSetSamplesAvailableCallback (apu_callback callback, void *data)
+{
+ spc::sa_callback = callback;
+ spc::extra_data = data;
+}
+
+static void UpdatePlaybackRate()
+{
+ if (Settings.SoundInputRate == 0)
+ Settings.SoundInputRate = APU_DEFAULT_INPUT_RATE;
+
+ double time_ratio = (double) Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator);
+ 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;
+
+ printf("Sound buffer size: %d (%d samples)\n", spc::buffer_size, sample_count);
+
+ if (spc::landing_buffer)
+ delete[] spc::landing_buffer;
+ spc::landing_buffer = new uint8_t[spc::buffer_size * 2];
+ if (!spc::landing_buffer)
+ return false;
+
+ /* The resampler and spc unit use samples (16-bit short) as
+ /* arguments. Use 2x in the resampler for buffer leveling with SoundSync */
+ /*if (!spc::resampler)
+ {*/
+ if (spc::resampler)
+ delete spc::resampler;
+
+ spc::resampler = new ResamplerClass(spc::buffer_size >> (Settings.SoundSync ? 0 : 1));
+ if (!spc::resampler)
+ {
+ delete[] spc::landing_buffer;
+ return false;
+ }
+ /*}
+ else
+ spc::resampler->resize(spc::buffer_size >> (Settings.SoundSync ? 0 : 1));*/
+
+ spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
+
+ UpdatePlaybackRate();
+
+ spc::sound_enabled = S9xOpenSoundDevice();
+
+ return spc::sound_enabled;
+}
+
+template bool S9xInitSound<LinearResampler>(int, int);
+template bool S9xInitSound<HermiteResampler>(int, int);
+
+void S9xSetSoundControl (uint8_t voice_switch)
+{
+ spc_core->dsp_set_stereo_switch(voice_switch << 8 | voice_switch);
+}
+
+void S9xSetSoundMute (bool mute)
+{
+ Settings.Mute = mute;
+ if (!spc::sound_enabled)
+ Settings.Mute = true;
+}
+
+void S9xDumpSPCSnapshot()
+{
+ spc_core->dsp_dump_spc_snapshot();
+}
+
+/*static void SPCSnapshotCallback()
+{
+ S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR));
+ printf("Dumped key-on triggered spc snapshot.\n");
+}*/
+
+bool S9xInitAPU()
+{
+ spc_core = new SNES_SPC;
+ if (!spc_core)
+ return false;
+
+ spc_core->init();
+ spc_core->init_rom(APUROM);
+
+ //spc_core->dsp_set_spc_snapshot_callback(SPCSnapshotCallback);
+
+ spc::landing_buffer = NULL;
+ spc::shrink_buffer = NULL;
+ spc::resampler = NULL;
+
+ return true;
+}
+
+void S9xDeinitAPU()
+{
+ if (spc_core)
+ {
+ delete spc_core;
+ spc_core = NULL;
+ }
+
+ if (spc::resampler)
+ {
+ delete spc::resampler;
+ spc::resampler = NULL;
+ }
+
+ if (spc::landing_buffer)
+ {
+ delete[] spc::landing_buffer;
+ spc::landing_buffer = NULL;
+ }
+
+ if (spc::shrink_buffer)
+ {
+ delete[] spc::shrink_buffer;
+ spc::shrink_buffer = NULL;
+ }
+}
+
+static inline int S9xAPUGetClock (int32_t cpucycles)
+{
+ return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) /
+ spc::ratio_denominator;
+}
+
+static inline int S9xAPUGetClockRemainder (int32_t cpucycles)
+{
+ return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) %
+ spc::ratio_denominator;
+}
+
+uint8_t S9xAPUReadPort (int port)
+{
+ return (uint8_t) spc_core->read_port(S9xAPUGetClock(CPU.Cycles), port);
+}
+
+void S9xAPUWritePort (int port, uint8_t byte)
+{
+ spc_core->write_port(S9xAPUGetClock(CPU.Cycles), port, byte);
+}
+
+void S9xAPUSetReferenceTime (int32_t cpucycles)
+{
+ 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)
+ S9xLandSamples();
+}
+
+void S9xAPUTimingSetSpeedup (int ticks)
+{
+ if (ticks != 0)
+ printf("APU speedup hack: %d\n", ticks);
+
+ spc::timing_hack_denominator = SNES_SPC::tempo_unit - ticks;
+ spc_core->set_tempo(spc::timing_hack_denominator);
+
+ spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC;
+ spc::ratio_denominator = Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC;
+ spc::ratio_denominator = spc::ratio_denominator * spc::timing_hack_denominator / spc::timing_hack_numerator;
+
+ UpdatePlaybackRate();
+}
+
+void S9xAPUAllowTimeOverflow (bool allow)
+{
+ if (allow)
+ printf("APU time overflow allowed\n");
+
+ spc_core->spc_allow_time_overflow(allow);
+}
+
+void S9xResetAPU()
+{
+ spc::reference_time = 0;
+ spc::remainder = 0;
+ spc_core->reset();
+ spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
+
+ spc::resampler->clear();
+}
+
+void S9xSoftResetAPU()
+{
+ spc::reference_time = 0;
+ spc::remainder = 0;
+ spc_core->soft_reset();
+ spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
+
+ spc::resampler->clear();
+}
+
+static void from_apu_to_state (uint8_t **buf, void *var, size_t size)
+{
+ memcpy(*buf, var, size);
+ *buf += size;
+}
+
+static void to_apu_from_state (uint8_t **buf, void *var, size_t size)
+{
+ memcpy(var, *buf, size);
+ *buf += size;
+}
+
+void S9xAPUSaveState (uint8_t *block)
+{
+ uint8_t *ptr = block;
+
+ spc_core->copy_state(&ptr, from_apu_to_state);
+
+ SET_LE32(ptr, spc::reference_time);
+ ptr += sizeof(int32_t);
+ SET_LE32(ptr, spc::remainder);
+}
+
+void S9xAPULoadState (uint8_t *block)
+{
+ uint8_t *ptr = block;
+
+ S9xResetAPU();
+
+ spc_core->copy_state(&ptr, to_apu_from_state);
+
+ spc::reference_time = GET_LE32(ptr);
+ ptr += sizeof(int32_t);
+ spc::remainder = GET_LE32(ptr);
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/apu.h
@@ -1,1 +1,220 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _APU_H_
+#define _APU_H_
+
+#include "snes9x.h"
+#include "SNES_SPC.h"
+
+typedef void (*apu_callback) (void *);
+
+#define SPC_SAVE_STATE_BLOCK_SIZE (SNES_SPC::state_size + 8)
+
+bool S9xInitAPU();
+void S9xDeinitAPU();
+void S9xResetAPU();
+void S9xSoftResetAPU();
+uint8_t S9xAPUReadPort (int);
+void S9xAPUWritePort (int, uint8_t);
+void S9xAPUExecute();
+void S9xAPUEndScanline();
+void S9xAPUSetReferenceTime (int32_t);
+void S9xAPUTimingSetSpeedup (int);
+void S9xAPUAllowTimeOverflow (bool);
+void S9xAPULoadState (uint8_t *);
+void S9xAPUSaveState (uint8_t *);
+void S9xDumpSPCSnapshot();
+
+template<class ResamplerClass> bool S9xInitSound (int, int);
+bool S9xOpenSoundDevice();
+
+bool S9xSyncSound();
+int S9xGetSampleCount();
+void S9xSetSoundControl (uint8_t);
+void S9xSetSoundMute (bool);
+void S9xLandSamples();
+void S9xFinalizeSamples();
+void S9xClearSamples();
+bool S9xMixSamples (uint8_t *, int);
+void S9xSetSamplesAvailableCallback (apu_callback, void *);
+
+extern SNES_SPC *spc_core;
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/blargg_common.h
@@ -1,1 +1,187 @@
+// Sets up common environment for Shay Green's libraries.
+// To change configuration options, modify blargg_config.h, not this file.
+// snes_spc 0.9.0
+#ifndef BLARGG_COMMON_H
+#define BLARGG_COMMON_H
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+
+#undef BLARGG_COMMON_H
+// allow blargg_config.h to #include blargg_common.h
+#include "blargg_config.h"
+#ifndef BLARGG_COMMON_H
+#define BLARGG_COMMON_H
+
+// BLARGG_RESTRICT: equivalent to restrict, where supported
+#if defined (__GNUC__) || _MSC_VER >= 1100
+ #define BLARGG_RESTRICT __restrict
+#else
+ #define BLARGG_RESTRICT
+#endif
+
+// STATIC_CAST(T,expr): Used in place of static_cast<T> (expr)
+#ifndef STATIC_CAST
+ #define STATIC_CAST(T,expr) ((T) (expr))
+#endif
+
+// blargg_err_t (0 on success, otherwise error string)
+#ifndef blargg_err_t
+ typedef const char* blargg_err_t;
+#endif
+
+// blargg_vector - very lightweight vector of POD types (no constructor/destructor)
+template<class T>
+class blargg_vector {
+ T* begin_;
+ size_t size_;
+public:
+ blargg_vector() : begin_( 0 ), size_( 0 ) { }
+ ~blargg_vector() { free( begin_ ); }
+ size_t size() const { return size_; }
+ T* begin() const { return begin_; }
+ T* end() const { return begin_ + size_; }
+ blargg_err_t resize( size_t n )
+ {
+ // TODO: blargg_common.cpp to hold this as an outline function, ugh
+ void* p = realloc( begin_, n * sizeof (T) );
+ if ( p )
+ begin_ = (T*) p;
+ else if ( n > size_ ) // realloc failure only a problem if expanding
+ return "Out of memory";
+ size_ = n;
+ return 0;
+ }
+ void clear() { void* p = begin_; begin_ = 0; size_ = 0; free( p ); }
+ T& operator [] ( size_t n ) const
+ {
+ assert( n <= size_ ); // <= to allow past-the-end value
+ return begin_ [n];
+ }
+};
+
+#ifndef BLARGG_DISABLE_NOTHROW
+ // throw spec mandatory in ISO C++ if operator new can return NULL
+ #if __cplusplus >= 199711 || defined (__GNUC__)
+ #define BLARGG_THROWS( spec ) throw spec
+ #else
+ #define BLARGG_THROWS( spec )
+ #endif
+ #define BLARGG_DISABLE_NOTHROW \
+ void* operator new ( size_t s ) BLARGG_THROWS(()) { return malloc( s ); }\
+ void operator delete ( void* p ) { free( p ); }
+ #define BLARGG_NEW new
+#else
+ #include <new>
+ #define BLARGG_NEW new (std::nothrow)
+#endif
+
+// BLARGG_4CHAR('a','b','c','d') = 'abcd' (four character integer constant)
+#define BLARGG_4CHAR( a, b, c, d ) \
+ ((a&0xFF)*0x1000000L + (b&0xFF)*0x10000L + (c&0xFF)*0x100L + (d&0xFF))
+
+// BOOST_STATIC_ASSERT( expr ): Generates compile error if expr is 0.
+#ifndef BOOST_STATIC_ASSERT
+ #ifdef _MSC_VER
+ // MSVC6 (_MSC_VER < 1300) fails for use of __LINE__ when /Zl is specified
+ #define BOOST_STATIC_ASSERT( expr ) \
+ void blargg_failed_( int (*arg) [2 / (int) !!(expr) - 1] )
+ #else
+ // Some other compilers fail when declaring same function multiple times in class,
+ // so differentiate them by line
+ #define BOOST_STATIC_ASSERT( expr ) \
+ void blargg_failed_( int (*arg) [2 / !!(expr) - 1] [__LINE__] )
+ #endif
+#endif
+
+// BLARGG_COMPILER_HAS_BOOL: If 0, provides bool support for old compiler. If 1,
+// compiler is assumed to support bool. If undefined, availability is determined.
+#ifndef BLARGG_COMPILER_HAS_BOOL
+ #if defined (__MWERKS__)
+ #if !__option(bool)
+ #define BLARGG_COMPILER_HAS_BOOL 0
+ #endif
+ #elif defined (_MSC_VER)
+ #if _MSC_VER < 1100
+ #define BLARGG_COMPILER_HAS_BOOL 0
+ #endif
+ #elif defined (__GNUC__)
+ // supports bool
+ #elif __cplusplus < 199711
+ #define BLARGG_COMPILER_HAS_BOOL 0
+ #endif
+#endif
+#if defined (BLARGG_COMPILER_HAS_BOOL) && !BLARGG_COMPILER_HAS_BOOL
+ // If you get errors here, modify your blargg_config.h file
+ typedef int bool;
+ const bool true = 1;
+ const bool false = 0;
+#endif
+
+// blargg_long/blargg_ulong = at least 32 bits, int if it's big enough
+
+#if INT_MAX < 0x7FFFFFFF || LONG_MAX == 0x7FFFFFFF
+ typedef long blargg_long;
+#else
+ typedef int blargg_long;
+#endif
+
+#if UINT_MAX < 0xFFFFFFFF || ULONG_MAX == 0xFFFFFFFF
+ typedef unsigned long blargg_ulong;
+#else
+ typedef unsigned blargg_ulong;
+#endif
+
+// BOOST::int8_t etc.
+
+// HAVE_STDINT_H: If defined, use <stdint.h> for int8_t etc.
+#if defined (HAVE_STDINT_H)
+ #include <stdint.h>
+ #define BOOST
+
+// HAVE_INTTYPES_H: If defined, use <stdint.h> for int8_t etc.
+#elif defined (HAVE_INTTYPES_H)
+ #include <inttypes.h>
+ #define BOOST
+
+#else
+ struct BOOST
+ {
+ #if UCHAR_MAX == 0xFF && SCHAR_MAX == 0x7F
+ typedef signed char int8_t;
+ typedef unsigned char uint8_t;
+ #else
+ // No suitable 8-bit type available
+ typedef struct see_blargg_common_h int8_t;
+ typedef struct see_blargg_common_h uint8_t;
+ #endif
+
+ #if USHRT_MAX == 0xFFFF
+ typedef short int16_t;
+ typedef unsigned short uint16_t;
+ #else
+ // No suitable 16-bit type available
+ typedef struct see_blargg_common_h int16_t;
+ typedef struct see_blargg_common_h uint16_t;
+ #endif
+
+ #if ULONG_MAX == 0xFFFFFFFF
+ typedef long int32_t;
+ typedef unsigned long uint32_t;
+ #elif UINT_MAX == 0xFFFFFFFF
+ typedef int int32_t;
+ typedef unsigned int uint32_t;
+ #else
+ // No suitable 32-bit type available
+ typedef struct see_blargg_common_h int32_t;
+ typedef struct see_blargg_common_h uint32_t;
+ #endif
+ };
+#endif
+
+#endif
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/blargg_config.h
@@ -1,1 +1,25 @@
+// snes_spc 0.9.0 user configuration file. Don't replace when updating library.
+// snes_spc 0.9.0
+#ifndef BLARGG_CONFIG_H
+#define BLARGG_CONFIG_H
+
+// Uncomment to disable debugging checks
+//#define NDEBUG 1
+
+// Uncomment to enable platform-specific (and possibly non-portable) optimizations
+//#define BLARGG_NONPORTABLE 1
+
+// Uncomment if automatic byte-order determination doesn't work
+//#define BLARGG_BIG_ENDIAN 1
+
+// Uncomment if you get errors in the bool section of blargg_common.h
+//#define BLARGG_COMPILER_HAS_BOOL 1
+
+// Use standard config.h if present
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/blargg_endian.h
@@ -1,1 +1,186 @@
+// CPU Byte Order Utilities
+// snes_spc 0.9.0
+#ifndef BLARGG_ENDIAN
+#define BLARGG_ENDIAN
+
+#include "blargg_common.h"
+
+// BLARGG_CPU_CISC: Defined if CPU has very few general-purpose registers (< 16)
+#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
+ defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
+ #define BLARGG_CPU_X86 1
+ #define BLARGG_CPU_CISC 1
+#endif
+
+#if defined (__powerpc__) || defined (__ppc__) || defined (__POWERPC__) || defined (__powerc)
+ #define BLARGG_CPU_POWERPC 1
+ #define BLARGG_CPU_RISC 1
+#endif
+
+// BLARGG_BIG_ENDIAN, BLARGG_LITTLE_ENDIAN: Determined automatically, otherwise only
+// one may be #defined to 1. Only needed if something actually depends on byte order.
+#if !defined (BLARGG_BIG_ENDIAN) && !defined (BLARGG_LITTLE_ENDIAN)
+#ifdef __GLIBC__
+ // GCC handles this for us
+ #include <endian.h>
+ #if __BYTE_ORDER == __LITTLE_ENDIAN
+ #define BLARGG_LITTLE_ENDIAN 1
+ #elif __BYTE_ORDER == __BIG_ENDIAN
+ #define BLARGG_BIG_ENDIAN 1
+ #endif
+#else
+
+#if defined (LSB_FIRST) || defined (__LITTLE_ENDIAN__) || BLARGG_CPU_X86 || \
+ (defined (LITTLE_ENDIAN) && LITTLE_ENDIAN+0 != 1234)
+ #define BLARGG_LITTLE_ENDIAN 1
+#endif
+
+#if defined (MSB_FIRST) || defined (__BIG_ENDIAN__) || defined (WORDS_BIGENDIAN) || \
+ defined (__sparc__) || BLARGG_CPU_POWERPC || \
+ (defined (BIG_ENDIAN) && BIG_ENDIAN+0 != 4321)
+ #define BLARGG_BIG_ENDIAN 1
+#elif !defined (__mips__)
+ // No endian specified; assume little-endian, since it's most common
+ #define BLARGG_LITTLE_ENDIAN 1
+#endif
+#endif
+#endif
+
+#if BLARGG_LITTLE_ENDIAN && BLARGG_BIG_ENDIAN
+ #undef BLARGG_LITTLE_ENDIAN
+ #undef BLARGG_BIG_ENDIAN
+#endif
+
+inline void blargg_verify_byte_order()
+{
+ #ifndef NDEBUG
+ #if BLARGG_BIG_ENDIAN
+ volatile int i = 1;
+ assert( *(volatile char*) &i == 0 );
+ #elif BLARGG_LITTLE_ENDIAN
+ volatile int i = 1;
+ assert( *(volatile char*) &i != 0 );
+ #endif
+ #endif
+}
+
+inline unsigned get_le16( void const* p )
+{
+ return (unsigned) ((unsigned char const*) p) [1] << 8 |
+ (unsigned) ((unsigned char const*) p) [0];
+}
+
+inline unsigned get_be16( void const* p )
+{
+ return (unsigned) ((unsigned char const*) p) [0] << 8 |
+ (unsigned) ((unsigned char const*) p) [1];
+}
+
+inline blargg_ulong get_le32( void const* p )
+{
+ return (blargg_ulong) ((unsigned char const*) p) [3] << 24 |
+ (blargg_ulong) ((unsigned char const*) p) [2] << 16 |
+ (blargg_ulong) ((unsigned char const*) p) [1] << 8 |
+ (blargg_ulong) ((unsigned char const*) p) [0];
+}
+
+inline blargg_ulong get_be32( void const* p )
+{
+ return (blargg_ulong) ((unsigned char const*) p) [0] << 24 |
+ (blargg_ulong) ((unsigned char const*) p) [1] << 16 |
+ (blargg_ulong) ((unsigned char const*) p) [2] << 8 |
+ (blargg_ulong) ((unsigned char const*) p) [3];
+}
+
+inline void set_le16( void* p, unsigned n )
+{
+ ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
+ ((unsigned char*) p) [0] = (unsigned char) n;
+}
+
+inline void set_be16( void* p, unsigned n )
+{
+ ((unsigned char*) p) [0] = (unsigned char) (n >> 8);
+ ((unsigned char*) p) [1] = (unsigned char) n;
+}
+
+inline void set_le32( void* p, blargg_ulong n )
+{
+ ((unsigned char*) p) [0] = (unsigned char) n;
+ ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
+ ((unsigned char*) p) [2] = (unsigned char) (n >> 16);
+ ((unsigned char*) p) [3] = (unsigned char) (n >> 24);
+}
+
+inline void set_be32( void* p, blargg_ulong n )
+{
+ ((unsigned char*) p) [3] = (unsigned char) n;
+ ((unsigned char*) p) [2] = (unsigned char) (n >> 8);
+ ((unsigned char*) p) [1] = (unsigned char) (n >> 16);
+ ((unsigned char*) p) [0] = (unsigned char) (n >> 24);
+}
+
+#if BLARGG_NONPORTABLE
+ // Optimized implementation if byte order is known
+ #if BLARGG_LITTLE_ENDIAN
+ #define GET_LE16( addr ) (*(BOOST::uint16_t*) (addr))
+ #define GET_LE32( addr ) (*(BOOST::uint32_t*) (addr))
+ #define SET_LE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
+ #define SET_LE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
+ #elif BLARGG_BIG_ENDIAN
+ #define GET_BE16( addr ) (*(BOOST::uint16_t*) (addr))
+ #define GET_BE32( addr ) (*(BOOST::uint32_t*) (addr))
+ #define SET_BE16( addr, data ) (void) (*(BOOST::uint16_t*) (addr) = (data))
+ #define SET_BE32( addr, data ) (void) (*(BOOST::uint32_t*) (addr) = (data))
+
+ #if BLARGG_CPU_POWERPC
+ // PowerPC has special byte-reversed instructions
+ #if defined (__MWERKS__)
+ #define GET_LE16( addr ) (__lhbrx( addr, 0 ))
+ #define GET_LE32( addr ) (__lwbrx( addr, 0 ))
+ #define SET_LE16( addr, in ) (__sthbrx( in, addr, 0 ))
+ #define SET_LE32( addr, in ) (__stwbrx( in, addr, 0 ))
+ #elif defined (__GNUC__)
+ #define GET_LE16( addr ) ({unsigned ppc_lhbrx_; asm( "lhbrx %0,0,%1" : "=r" (ppc_lhbrx_) : "r" (addr), "0" (ppc_lhbrx_) ); ppc_lhbrx_;})
+ #define GET_LE32( addr ) ({unsigned ppc_lwbrx_; asm( "lwbrx %0,0,%1" : "=r" (ppc_lwbrx_) : "r" (addr), "0" (ppc_lwbrx_) ); ppc_lwbrx_;})
+ #define SET_LE16( addr, in ) ({asm( "sthbrx %0,0,%1" : : "r" (in), "r" (addr) );})
+ #define SET_LE32( addr, in ) ({asm( "stwbrx %0,0,%1" : : "r" (in), "r" (addr) );})
+ #endif
+ #endif
+ #endif
+#endif
+
+#ifndef GET_LE16
+ #define GET_LE16( addr ) get_le16( addr )
+ #define SET_LE16( addr, data ) set_le16( addr, data )
+#endif
+
+#ifndef GET_LE32
+ #define GET_LE32( addr ) get_le32( addr )
+ #define SET_LE32( addr, data ) set_le32( addr, data )
+#endif
+
+#ifndef GET_BE16
+ #define GET_BE16( addr ) get_be16( addr )
+ #define SET_BE16( addr, data ) set_be16( addr, data )
+#endif
+
+#ifndef GET_BE32
+ #define GET_BE32( addr ) get_be32( addr )
+ #define SET_BE32( addr, data ) set_be32( addr, data )
+#endif
+
+// auto-selecting versions
+
+inline void set_le( BOOST::uint16_t* p, unsigned n ) { SET_LE16( p, n ); }
+inline void set_le( BOOST::uint32_t* p, blargg_ulong n ) { SET_LE32( p, n ); }
+inline void set_be( BOOST::uint16_t* p, unsigned n ) { SET_BE16( p, n ); }
+inline void set_be( BOOST::uint32_t* p, blargg_ulong n ) { SET_BE32( p, n ); }
+inline unsigned get_le( BOOST::uint16_t* p ) { return GET_LE16( p ); }
+inline blargg_ulong get_le( BOOST::uint32_t* p ) { return GET_LE32( p ); }
+inline unsigned get_be( BOOST::uint16_t* p ) { return GET_BE16( p ); }
+inline blargg_ulong get_be( BOOST::uint32_t* p ) { return GET_BE32( p ); }
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/blargg_source.h
@@ -1,1 +1,101 @@
+/* Included at the beginning of library source files, after all other #include lines.
+Sets up helpful macros and services used in my source code. They don't need
+module an annoying module prefix on their names since they are defined after
+all other #include lines. */
+// snes_spc 0.9.0
+#ifndef BLARGG_SOURCE_H
+#define BLARGG_SOURCE_H
+
+// If debugging is enabled, abort program if expr is false. Meant for checking
+// internal state and consistency. A failed assertion indicates a bug in the module.
+// void assert( bool expr );
+#include <assert.h>
+
+// If debugging is enabled and expr is false, abort program. Meant for checking
+// caller-supplied parameters and operations that are outside the control of the
+// module. A failed requirement indicates a bug outside the module.
+// void require( bool expr );
+#undef require
+#define require( expr ) assert( expr )
+
+// Like printf() except output goes to debug log file. Might be defined to do
+// nothing (not even evaluate its arguments).
+// void dprintf( const char* format, ... );
+static inline void blargg_dprintf_( const char*, ... ) { }
+#undef dprintf
+#define dprintf (1) ? (void) 0 : blargg_dprintf_
+
+// If enabled, evaluate expr and if false, make debug log entry with source file
+// and line. Meant for finding situations that should be examined further, but that
+// don't indicate a problem. In all cases, execution continues normally.
+#undef check
+#define check( expr ) ((void) 0)
+
+// If expr yields error string, return it from current function, otherwise continue.
+#undef RETURN_ERR
+#define RETURN_ERR( expr ) do { \
+ blargg_err_t blargg_return_err_ = (expr); \
+ if ( blargg_return_err_ ) return blargg_return_err_; \
+ } while ( 0 )
+
+// If ptr is 0, return out of memory error string.
+#undef CHECK_ALLOC
+#define CHECK_ALLOC( ptr ) do { if ( (ptr) == 0 ) return "Out of memory"; } while ( 0 )
+
+// Avoid any macros which evaluate their arguments multiple times
+#undef min
+#undef max
+
+#define DEF_MIN_MAX( type ) \
+ static inline type min( type x, type y ) { if ( x < y ) return x; return y; }\
+ static inline type max( type x, type y ) { if ( y < x ) return x; return y; }
+
+DEF_MIN_MAX( int )
+DEF_MIN_MAX( unsigned )
+DEF_MIN_MAX( long )
+DEF_MIN_MAX( unsigned long )
+DEF_MIN_MAX( float )
+DEF_MIN_MAX( double )
+
+#undef DEF_MIN_MAX
+
+/*
+// using const references generates crappy code, and I am currenly only using these
+// for built-in types, so they take arguments by value
+
+// TODO: remove
+inline int min( int x, int y )
+template<class T>
+inline T min( T x, T y )
+{
+ if ( x < y )
+ return x;
+ return y;
+}
+
+template<class T>
+inline T max( T x, T y )
+{
+ if ( x < y )
+ return y;
+ return x;
+}
+*/
+
+// TODO: good idea? bad idea?
+#undef byte
+#define byte byte_
+typedef unsigned char byte;
+
+// deprecated
+#define BLARGG_CHECK_ALLOC CHECK_ALLOC
+#define BLARGG_RETURN_ERR RETURN_ERR
+
+// BLARGG_SOURCE_BEGIN: If defined, #included, allowing redefition of dprintf and check
+#ifdef BLARGG_SOURCE_BEGIN
+ #include BLARGG_SOURCE_BEGIN
+#endif
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/hermite_resampler.h
@@ -1,1 +1,145 @@
+/* Simple resampler based on bsnes's ruby audio library */
+#ifndef __HERMITE_RESAMPLER_H
+#define __HERMITE_RESAMPLER_H
+
+#include "resampler.h"
+
+#undef CLAMP
+#undef SHORT_CLAMP
+#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+#define SHORT_CLAMP(n) ((short) CLAMP((n), -32768, 32767))
+
+class HermiteResampler : public Resampler
+{
+ protected:
+
+ double r_step;
+ double r_frac;
+ int r_left[4], r_right[4];
+
+ double
+ hermite (double mu1, double a, double b, double c, double d)
+ {
+ const double tension = 0.0; //-1 = low, 0 = normal, 1 = high
+ 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)
+ {
+ clear ();
+ }
+
+ ~HermiteResampler ()
+ {
+ }
+
+ void
+ time_ratio (double ratio)
+ {
+ r_step = ratio;
+ clear ();
+ }
+
+ void
+ clear()
+ {
+ ring_buffer::clear ();
+ r_frac = 1.0;
+ r_left [0] = r_left [1] = r_left [2] = r_left [3] = 0;
+ r_right[0] = r_right[1] = r_right[2] = r_right[3] = 0;
+ }
+
+ void
+ read (short *data, int num_samples)
+ {
+ int i_position = start >> 1;
+ short *internal_buffer = (short *) buffer;
+ int o_position = 0;
+ int consumed = 0;
+
+ while (o_position < num_samples && consumed < buffer_size)
+ {
+ int s_left = internal_buffer[i_position];
+ int s_right = internal_buffer[i_position + 1];
+ int max_samples = buffer_size >> 1;
+ const double margin_of_error = 1.0e-10;
+
+ if (fabs(r_step - 1.0) < margin_of_error)
+ {
+ data[o_position] = (short) s_left;
+ data[o_position + 1] = (short) s_right;
+
+ o_position += 2;
+ i_position += 2;
+ if (i_position >= max_samples)
+ i_position -= max_samples;
+ consumed += 2;
+
+ continue;
+ }
+
+ while (r_frac <= 1.0 && o_position < num_samples)
+ {
+ data[o_position] = SHORT_CLAMP (hermite (r_frac, r_left [0], r_left [1], r_left [2], r_left [3]));
+ data[o_position + 1] = SHORT_CLAMP (hermite (r_frac, r_right[0], r_right[1], r_right[2], r_right[3]));
+
+ o_position += 2;
+
+ r_frac += r_step;
+ }
+
+ if (r_frac > 1.0)
+ {
+ r_left [0] = r_left [1];
+ r_left [1] = r_left [2];
+ r_left [2] = r_left [3];
+ r_left [3] = s_left;
+
+ r_right[0] = r_right[1];
+ r_right[1] = r_right[2];
+ r_right[2] = r_right[3];
+ r_right[3] = s_right;
+
+ r_frac -= 1.0;
+
+ i_position += 2;
+ if (i_position >= max_samples)
+ i_position -= max_samples;
+ consumed += 2;
+ }
+ }
+
+ size -= consumed << 1;
+ start += consumed << 1;
+ if (start >= buffer_size)
+ start -= buffer_size;
+ }
+
+ inline int
+ avail()
+ {
+ return (int) floor (((size >> 2) - r_frac) / r_step) * 2;
+ }
+};
+
+#endif /* __HERMITE_RESAMPLER_H */
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/license.txt
@@ -1,1 +1,505 @@
-
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library 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 library 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 library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/linear_resampler.h
@@ -1,1 +1,116 @@
+/* Simple fixed-point linear resampler by BearOso*/
+#ifndef __LINEAR_RESAMPLER_H
+#define __LINEAR_RESAMPLER_H
+
+#include "resampler.h"
+#include "snes9x.h"
+
+static const int f_prec = 15;
+static const uint32_t f__one = (1 << f_prec);
+
+#define lerp(t, a, b) (((((b) - (a)) * (t)) >> f_prec) + (a))
+
+class LinearResampler : public Resampler
+{
+ protected:
+ uint32_t f__r_step;
+ uint32_t f__inv_r_step;
+ uint32_t f__r_frac;
+ int r_left, r_right;
+
+ public:
+ LinearResampler (int num_samples) : Resampler (num_samples)
+ {
+ f__r_frac = 0;
+ }
+
+ ~LinearResampler ()
+ {
+ }
+
+ void
+ time_ratio (double ratio)
+ {
+ if (ratio == 0.0)
+ ratio = 1.0;
+ f__r_step = (uint32_t) (ratio * f__one);
+ f__inv_r_step = (uint32_t) (f__one / ratio);
+ clear ();
+ }
+
+ void
+ clear()
+ {
+ ring_buffer::clear ();
+ f__r_frac = 0;
+ r_left = 0;
+ r_right = 0;
+ }
+
+ void
+ read (short *data, int num_samples)
+ {
+ int i_position = start >> 1;
+ short *internal_buffer = (short *) buffer;
+ int o_position = 0;
+ int consumed = 0;
+ int max_samples = (buffer_size >> 1);
+
+ while (o_position < num_samples && consumed < buffer_size)
+ {
+ if (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 (f__r_frac <= f__one && o_position < num_samples)
+ {
+ data[o_position] = lerp (f__r_frac,
+ r_left,
+ internal_buffer[i_position]);
+ data[o_position + 1] = lerp (f__r_frac,
+ r_right,
+ internal_buffer[i_position + 1]);
+
+ o_position += 2;
+
+ f__r_frac += f__r_step;
+ }
+
+ if (f__r_frac > f__one)
+ {
+ f__r_frac -= f__one;
+ r_left = internal_buffer[i_position];
+ r_right = internal_buffer[i_position + 1];
+ i_position += 2;
+ if (i_position >= max_samples)
+ i_position -= max_samples;
+ consumed += 2;
+ }
+ }
+
+ size -= consumed << 1;
+ start += consumed << 1;
+ if (start >= buffer_size)
+ start -= buffer_size;
+ }
+
+ inline int
+ avail()
+ {
+ return (((size >> 2) * f__inv_r_step) - ((f__r_frac * f__inv_r_step) >> f_prec)) >> (f_prec - 1);
+ }
+};
+
+#endif /* __LINEAR_RESAMPLER_H */
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/resampler.h
@@ -1,1 +1,61 @@
+/* Simple resampler based on bsnes's ruby audio library */
+#ifndef __RESAMPLER_H
+#define __RESAMPLER_H
+
+#include "ring_buffer.h"
+
+class Resampler : public ring_buffer
+{
+ public:
+ virtual void clear() = 0;
+ virtual void time_ratio (double) = 0;
+ virtual void read (short *, int) = 0;
+ virtual int avail() = 0;
+
+ Resampler (int num_samples) : ring_buffer (num_samples << 1)
+ {
+ }
+
+ ~Resampler ()
+ {
+ }
+
+ inline bool
+ push (short *src, int num_samples)
+ {
+ if (max_write () < num_samples)
+ return false;
+
+ !num_samples || ring_buffer::push ((unsigned char *) src, num_samples << 1);
+
+ return true;
+ }
+
+ inline int
+ space_empty()
+ {
+ return buffer_size - size;
+ }
+
+ inline int
+ space_filled()
+ {
+ return size;
+ }
+
+ inline int
+ max_write()
+ {
+ return space_empty () >> 1;
+ }
+
+ inline void
+ resize (int num_samples)
+ {
+ ring_buffer::resize (num_samples << 1);
+ }
+};
+
+#endif /* __RESAMPLER_H */
+
--- /dev/null
+++ b/src/in_snsf/snes9x/apu/ring_buffer.h
@@ -1,1 +1,112 @@
+/* Simple byte-based ring buffer. Licensed under public domain (C) BearOso. */
+#ifndef __RING_BUFFER_H
+#define __RING_BUFFER_H
+
+#include <string.h>
+
+#undef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+class ring_buffer
+{
+protected:
+ int size;
+ int buffer_size;
+ int start;
+ unsigned char *buffer;
+
+public:
+ ring_buffer (int buffer_size)
+ {
+ this->buffer_size = buffer_size;
+ buffer = new unsigned char[this->buffer_size];
+ memset (buffer, 0, this->buffer_size);
+
+ size = 0;
+ start = 0;
+ }
+
+ ~ring_buffer()
+ {
+ delete[] buffer;
+ }
+
+ bool
+ push (unsigned char *src, int bytes)
+ {
+ if (space_empty () < bytes)
+ return false;
+
+ int end = (start + size) % buffer_size;
+ int first_write_size = MIN (bytes, buffer_size - end);
+
+ memcpy (buffer + end, src, first_write_size);
+
+ if (bytes > first_write_size)
+ memcpy (buffer, src + first_write_size, bytes - first_write_size);
+
+ size += bytes;
+
+ return true;
+ }
+
+ bool
+ pull (unsigned char *dst, int bytes)
+ {
+ if (space_filled () < bytes)
+ return false;
+
+ memcpy (dst, buffer + start, MIN (bytes, buffer_size - start));
+
+ if (bytes > (buffer_size - start))
+ memcpy (dst + (buffer_size - start), buffer, bytes - (buffer_size - start));
+
+ start = (start + bytes) % buffer_size;
+ size -= bytes;
+
+ return true;
+ }
+
+ inline int
+ space_empty()
+ {
+ return buffer_size - size;
+ }
+
+ inline int
+ space_filled()
+ {
+ return size;
+ }
+
+ void
+ clear()
+ {
+ start = 0;
+ size = 0;
+ memset (buffer, 0, buffer_size);
+ }
+
+ void
+ resize (int size)
+ {
+ delete[] buffer;
+ buffer_size = size;
+ buffer = new unsigned char[buffer_size];
+ memset (buffer, 0, this->buffer_size);
+
+ size = 0;
+ start = 0;
+ }
+
+ inline void
+ cache_silence()
+ {
+ clear ();
+ size = buffer_size;
+ }
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/cpu.cpp
@@ -1,1 +1,338 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+#include "snes9x.h"
+#include "memmap.h"
+#include "dma.h"
+#include "apu/apu.h"
+//#include "fxemu.h"
+#include "sdd1.h"
+//#include "srtc.h"
+//#include "snapshot.h"
+//#include "cheats.h"
+//#include "logger.h"
+#ifdef DEBUGGER
+#include "debug.h"
+#endif
+
+//static void S9xResetCPU();
+//static void S9xSoftResetCPU();
+
+static void S9xSoftResetCPU()
+{
+ CPU.Cycles = 182; // Or 188. This is the cycle count just after the jump to the Reset Vector.
+ CPU.PrevCycles = CPU.Cycles;
+ CPU.V_Counter = 0;
+ CPU.Flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG);
+ CPU.PCBase = NULL;
+ CPU.NMILine = false;
+ CPU.IRQLine = false;
+ CPU.IRQTransition = false;
+ CPU.IRQLastState = false;
+ CPU.IRQExternal = false;
+ CPU.IRQPending = Timings.IRQPendCount;
+ CPU.MemSpeed = SLOW_ONE_CYCLE;
+ CPU.MemSpeedx2 = SLOW_ONE_CYCLE * 2;
+ CPU.FastROMSpeed = SLOW_ONE_CYCLE;
+ CPU.InDMA = false;
+ CPU.InHDMA = false;
+ CPU.InDMAorHDMA = false;
+ CPU.InWRAMDMAorHDMA = false;
+ CPU.HDMARanInDMA = 0;
+ CPU.CurrentDMAorHDMAChannel = -1;
+ CPU.WhichEvent = HC_RENDER_EVENT;
+ CPU.NextEvent = Timings.RenderPos;
+ CPU.WaitingForInterrupt = false;
+ CPU.AutoSaveTimer = 0;
+ CPU.SRAMModified = false;
+
+ Registers.PBPC = 0;
+ Registers.PB = 0;
+ Registers.PCw = S9xGetWord(0xfffc);
+ OpenBus = Registers.PCh;
+ Registers.D.W = 0;
+ Registers.DB = 0;
+ Registers.SH = 1;
+ Registers.SL -= 3;
+ Registers.XH = 0;
+ Registers.YH = 0;
+
+ ICPU.ShiftedPB = 0;
+ ICPU.ShiftedDB = 0;
+ SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation);
+ ClearFlags(Decimal);
+
+ Timings.InterlaceField = false;
+ Timings.H_Max = Timings.H_Max_Master;
+ Timings.V_Max = Timings.V_Max_Master;
+ Timings.NMITriggerPos = 0xffff;
+ if (Model->_5A22 == 2)
+ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2;
+ else
+ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1;
+
+ S9xSetPCBase(Registers.PBPC);
+
+ ICPU.S9xOpcodes = S9xOpcodesE1;
+ ICPU.S9xOpLengths = S9xOpLengthsM1X1;
+
+ S9xUnpackStatus();
+}
+
+static void S9xResetCPU()
+{
+ S9xSoftResetCPU();
+ Registers.SL = 0xff;
+ Registers.P.W = 0;
+ Registers.A.W = 0;
+ Registers.X.W = 0;
+ Registers.Y.W = 0;
+ SetFlags(MemoryFlag | IndexFlag | IRQ | Emulation);
+ ClearFlags(Decimal);
+}
+
+void S9xReset()
+{
+ /*S9xResetSaveTimer(false);
+ S9xResetLogger();*/
+
+ memset(Memory.RAM, 0x55, 0x20000);
+ memset(Memory.VRAM, 0x00, 0x10000);
+ ZeroMemory(Memory.FillRAM, 0x8000);
+
+ /*if (Settings.BS)
+ S9xResetBSX();*/
+
+ S9xResetCPU();
+ S9xResetPPU();
+ S9xResetDMA();
+ S9xResetAPU();
+
+ /*if (Settings.DSP)
+ S9xResetDSP();
+ if (Settings.SuperFX)
+ S9xResetSuperFX();
+ if (Settings.SA1)
+ S9xSA1Init();*/
+ if (Settings.SDD1)
+ S9xResetSDD1();
+ /*if (Settings.SPC7110)
+ S9xResetSPC7110();
+ if (Settings.C4)
+ S9xInitC4();
+ if (Settings.OBC1)
+ S9xResetOBC1();
+ if (Settings.SRTC)
+ S9xResetSRTC();
+
+ S9xInitCheatData();*/
+}
+
+void S9xSoftReset()
+{
+ //S9xResetSaveTimer(false);
+
+ ZeroMemory(Memory.FillRAM, 0x8000);
+
+ /*if (Settings.BS)
+ S9xResetBSX();*/
+
+ S9xSoftResetCPU();
+ S9xSoftResetPPU();
+ S9xResetDMA();
+ S9xSoftResetAPU();
+
+ /*if (Settings.DSP)
+ S9xResetDSP();
+ if (Settings.SuperFX)
+ S9xResetSuperFX();
+ if (Settings.SA1)
+ S9xSA1Init();*/
+ if (Settings.SDD1)
+ S9xResetSDD1();
+ /*if (Settings.SPC7110)
+ S9xResetSPC7110();
+ if (Settings.C4)
+ S9xInitC4();
+ if (Settings.OBC1)
+ S9xResetOBC1();
+ if (Settings.SRTC)
+ S9xResetSRTC();
+
+ S9xInitCheatData();*/
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/cpuaddr.h
@@ -1,1 +1,692 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _CPUADDR_H_
+#define _CPUADDR_H_
+
+typedef enum
+{
+ NONE = 0,
+ READ = 1,
+ WRITE = 2,
+ MODIFY = 3,
+ JUMP = 5,
+ JSR = 8
+} AccessMode;
+
+static inline uint8_t Immediate8Slow (AccessMode a)
+{
+ uint8_t val = S9xGetByte(Registers.PBPC);
+ if (a & READ)
+ OpenBus = val;
+ Registers.PCw++;
+
+ return val;
+}
+
+static inline uint8_t Immediate8 (AccessMode a)
+{
+ uint8_t val = CPU.PCBase[Registers.PCw];
+ if (a & READ)
+ OpenBus = val;
+ AddCycles(CPU.MemSpeed);
+ Registers.PCw++;
+
+ return val;
+}
+
+static inline uint16_t Immediate16Slow (AccessMode a)
+{
+ uint16_t val = S9xGetWord(Registers.PBPC, WRAP_BANK);
+ if (a & READ)
+ OpenBus = (uint8_t) (val >> 8);
+ Registers.PCw += 2;
+
+ return val;
+}
+
+static inline uint16_t Immediate16 (AccessMode a)
+{
+ uint16_t val = READ_WORD(CPU.PCBase + Registers.PCw);
+ if (a & READ)
+ OpenBus = (uint8_t) (val >> 8);
+ AddCycles(CPU.MemSpeedx2);
+ Registers.PCw += 2;
+
+ return val;
+}
+
+static inline uint32_t RelativeSlow (AccessMode a) // branch $xx
+{
+ int8_t offset = Immediate8Slow(a);
+
+ return ((int16_t) Registers.PCw + offset) & 0xffff;
+}
+
+static inline uint32_t Relative (AccessMode a) // branch $xx
+{
+ int8_t offset = Immediate8(a);
+
+ return ((int16_t) Registers.PCw + offset) & 0xffff;
+}
+
+static inline uint32_t RelativeLongSlow (AccessMode a) // BRL $xxxx
+{
+ int16_t offset = Immediate16Slow(a);
+
+ return ((int32_t) Registers.PCw + offset) & 0xffff;
+}
+
+static inline uint32_t RelativeLong (AccessMode a) // BRL $xxxx
+{
+ int16_t offset = Immediate16(a);
+
+ return ((int32_t) Registers.PCw + offset) & 0xffff;
+}
+
+static inline uint32_t AbsoluteIndexedIndirectSlow (AccessMode a) // (a,X)
+{
+ uint16_t addr;
+
+ if (a & JSR)
+ {
+ // JSR (a,X) pushes the old address in the middle of loading the new.
+ // OpenBus needs to be set to account for this.
+ addr = Immediate8Slow(READ);
+ if (a == JSR)
+ OpenBus = Registers.PCl;
+ addr |= Immediate8Slow(READ) << 8;
+ }
+ else
+ addr = Immediate16Slow(READ);
+
+ AddCycles(ONE_CYCLE);
+ addr += Registers.X.W;
+
+ // Address load wraps within the bank
+ uint16_t addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK);
+ OpenBus = addr2 >> 8;
+
+ return addr2;
+}
+
+static inline uint32_t AbsoluteIndexedIndirect (AccessMode a) // (a,X)
+{
+ uint16_t addr = Immediate16Slow(READ);
+ addr += Registers.X.W;
+
+ // Address load wraps within the bank
+ uint16_t addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK);
+ OpenBus = addr2 >> 8;
+
+ return addr2;
+}
+
+static inline uint32_t AbsoluteIndirectLongSlow (AccessMode a) // [a]
+{
+ uint16_t addr = Immediate16Slow(READ);
+
+ // No info on wrapping, but it doesn't matter anyway due to mirroring
+ uint32_t addr2 = S9xGetWord(addr);
+ OpenBus = addr2 >> 8;
+ addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16;
+
+ return addr2;
+}
+
+static inline uint32_t AbsoluteIndirectLong (AccessMode a) // [a]
+{
+ uint16_t addr = Immediate16(READ);
+
+ // No info on wrapping, but it doesn't matter anyway due to mirroring
+ uint32_t addr2 = S9xGetWord(addr);
+ OpenBus = addr2 >> 8;
+ addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16;
+
+ return addr2;
+}
+
+static inline uint32_t AbsoluteIndirectSlow (AccessMode a) // (a)
+{
+ // No info on wrapping, but it doesn't matter anyway due to mirroring
+ uint16_t addr2 = S9xGetWord(Immediate16Slow(READ));
+ OpenBus = addr2 >> 8;
+
+ return addr2;
+}
+
+static inline uint32_t AbsoluteIndirect (AccessMode a) // (a)
+{
+ // No info on wrapping, but it doesn't matter anyway due to mirroring
+ uint16_t addr2 = S9xGetWord(Immediate16(READ));
+ OpenBus = addr2 >> 8;
+
+ return addr2;
+}
+
+static inline uint32_t AbsoluteSlow (AccessMode a) // a
+{
+ return ICPU.ShiftedDB | Immediate16Slow(a);
+}
+
+static inline uint32_t Absolute (AccessMode a) // a
+{
+ return ICPU.ShiftedDB | Immediate16(a);
+}
+
+static inline uint32_t AbsoluteLongSlow (AccessMode a) // l
+{
+ uint32_t addr = Immediate16Slow(READ);
+
+ // JSR l pushes the old bank in the middle of loading the new.
+ // OpenBus needs to be set to account for this.
+ if (a == JSR)
+ OpenBus = Registers.PB;
+
+ addr |= Immediate8Slow(a) << 16;
+
+ return addr;
+}
+
+static inline uint32_t AbsoluteLong (AccessMode a) // l
+{
+ uint32_t addr = READ_3WORD(CPU.PCBase + Registers.PCw);
+ AddCycles(CPU.MemSpeedx2 + CPU.MemSpeed);
+ if (a & READ)
+ OpenBus = addr >> 16;
+ Registers.PCw += 3;
+
+ return addr;
+}
+
+static inline uint32_t DirectSlow (AccessMode a) // d
+{
+ uint16_t addr = Immediate8Slow(a) + Registers.D.W;
+ if (Registers.DL != 0)
+ AddCycles(ONE_CYCLE);
+
+ return addr;
+}
+
+static inline uint32_t Direct (AccessMode a) // d
+{
+ uint16_t addr = Immediate8(a) + Registers.D.W;
+ if (Registers.DL != 0)
+ AddCycles(ONE_CYCLE);
+
+ return addr;
+}
+
+static inline uint32_t DirectIndirectSlow (AccessMode a) // (d)
+{
+ uint32_t addr = S9xGetWord(DirectSlow(READ), (!CheckEmulation() || Registers.DL) ? WRAP_BANK : WRAP_PAGE);
+ if (a & READ)
+ OpenBus = (uint8_t) (addr >> 8);
+ addr |= ICPU.ShiftedDB;
+
+ return addr;
+}
+
+static inline uint32_t DirectIndirectE0 (AccessMode a) // (d)
+{
+ uint32_t addr = S9xGetWord(Direct(READ));
+ if (a & READ)
+ OpenBus = (uint8_t) (addr >> 8);
+ addr |= ICPU.ShiftedDB;
+
+ return addr;
+}
+
+static inline uint32_t DirectIndirectE1 (AccessMode a) // (d)
+{
+ uint32_t addr = S9xGetWord(DirectSlow(READ), Registers.DL ? WRAP_BANK : WRAP_PAGE);
+ if (a & READ)
+ OpenBus = (uint8_t) (addr >> 8);
+ addr |= ICPU.ShiftedDB;
+
+ return addr;
+}
+
+static inline uint32_t DirectIndirectIndexedSlow (AccessMode a) // (d),Y
+{
+ uint32_t addr = DirectIndirectSlow(a);
+ if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.YL >= 0x100)
+ AddCycles(ONE_CYCLE);
+
+ return addr + Registers.Y.W;
+}
+
+static inline uint32_t DirectIndirectIndexedE0X0 (AccessMode a) // (d),Y
+{
+ uint32_t addr = DirectIndirectE0(a);
+ AddCycles(ONE_CYCLE);
+
+ return addr + Registers.Y.W;
+}
+
+static inline uint32_t DirectIndirectIndexedE0X1 (AccessMode a) // (d),Y
+{
+ uint32_t addr = DirectIndirectE0(a);
+ if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100)
+ AddCycles(ONE_CYCLE);
+
+ return addr + Registers.Y.W;
+}
+
+static inline uint32_t DirectIndirectIndexedE1 (AccessMode a) // (d),Y
+{
+ uint32_t addr = DirectIndirectE1(a);
+ if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100)
+ AddCycles(ONE_CYCLE);
+
+ return addr + Registers.Y.W;
+}
+
+static inline uint32_t DirectIndirectLongSlow (AccessMode a) // [d]
+{
+ uint16_t addr = DirectSlow(READ);
+ uint32_t addr2 = S9xGetWord(addr);
+ OpenBus = addr2 >> 8;
+ addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16;
+
+ return addr2;
+}
+
+static inline uint32_t DirectIndirectLong (AccessMode a) // [d]
+{
+ uint16_t addr = Direct(READ);
+ uint32_t addr2 = S9xGetWord(addr);
+ OpenBus = addr2 >> 8;
+ addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16;
+
+ return addr2;
+}
+
+static inline uint32_t DirectIndirectIndexedLongSlow (AccessMode a) // [d],Y
+{
+ return DirectIndirectLongSlow(a) + Registers.Y.W;
+}
+
+static inline uint32_t DirectIndirectIndexedLong (AccessMode a) // [d],Y
+{
+ return DirectIndirectLong(a) + Registers.Y.W;
+}
+
+static inline uint32_t DirectIndexedXSlow (AccessMode a) // d,X
+{
+ pair addr;
+ addr.W = DirectSlow(a);
+ if (!CheckEmulation() || Registers.DL)
+ addr.W += Registers.X.W;
+ else
+ addr.B.l += Registers.XL;
+
+ AddCycles(ONE_CYCLE);
+
+ return addr.W;
+}
+
+static inline uint32_t DirectIndexedXE0 (AccessMode a) // d,X
+{
+ uint16_t addr = Direct(a) + Registers.X.W;
+ AddCycles(ONE_CYCLE);
+
+ return addr;
+}
+
+static inline uint32_t DirectIndexedXE1 (AccessMode a) // d,X
+{
+ if (Registers.DL)
+ return DirectIndexedXE0(a);
+ else
+ {
+ pair addr;
+ addr.W = Direct(a);
+ addr.B.l += Registers.XL;
+ AddCycles(ONE_CYCLE);
+
+ return addr.W;
+ }
+}
+
+static inline uint32_t DirectIndexedYSlow (AccessMode a) // d,Y
+{
+ pair addr;
+ addr.W = DirectSlow(a);
+ if (!CheckEmulation() || Registers.DL)
+ addr.W += Registers.Y.W;
+ else
+ addr.B.l += Registers.YL;
+
+ AddCycles(ONE_CYCLE);
+
+ return addr.W;
+}
+
+static inline uint32_t DirectIndexedYE0 (AccessMode a) // d,Y
+{
+ uint16_t addr = Direct(a) + Registers.Y.W;
+ AddCycles(ONE_CYCLE);
+
+ return addr;
+}
+
+static inline uint32_t DirectIndexedYE1 (AccessMode a) // d,Y
+{
+ if (Registers.DL)
+ return DirectIndexedYE0(a);
+ else
+ {
+ pair addr;
+ addr.W = Direct(a);
+ addr.B.l += Registers.YL;
+ AddCycles(ONE_CYCLE);
+
+ return addr.W;
+ }
+}
+
+static inline uint32_t DirectIndexedIndirectSlow (AccessMode a) // (d,X)
+{
+ uint32_t addr = S9xGetWord(DirectIndexedXSlow(READ), (!CheckEmulation() || Registers.DL) ? WRAP_BANK : WRAP_PAGE);
+ if (a & READ)
+ OpenBus = (uint8_t) (addr >> 8);
+
+ return ICPU.ShiftedDB | addr;
+}
+
+static inline uint32_t DirectIndexedIndirectE0 (AccessMode a) // (d,X)
+{
+ uint32_t addr = S9xGetWord(DirectIndexedXE0(READ));
+ if (a & READ)
+ OpenBus = (uint8_t) (addr >> 8);
+
+ return ICPU.ShiftedDB | addr;
+}
+
+static inline uint32_t DirectIndexedIndirectE1 (AccessMode a) // (d,X)
+{
+ uint32_t addr = S9xGetWord(DirectIndexedXE1(READ), Registers.DL ? WRAP_BANK : WRAP_PAGE);
+ if (a & READ)
+ OpenBus = (uint8_t) (addr >> 8);
+
+ return ICPU.ShiftedDB | addr;
+}
+
+static inline uint32_t AbsoluteIndexedXSlow (AccessMode a) // a,X
+{
+ uint32_t addr = AbsoluteSlow(a);
+ if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.XL >= 0x100)
+ AddCycles(ONE_CYCLE);
+
+ return addr + Registers.X.W;
+}
+
+static inline uint32_t AbsoluteIndexedXX0 (AccessMode a) // a,X
+{
+ uint32_t addr = Absolute(a);
+ AddCycles(ONE_CYCLE);
+
+ return addr + Registers.X.W;
+}
+
+static inline uint32_t AbsoluteIndexedXX1 (AccessMode a) // a,X
+{
+ uint32_t addr = Absolute(a);
+ if (a & WRITE || (addr & 0xff) + Registers.XL >= 0x100)
+ AddCycles(ONE_CYCLE);
+
+ return addr + Registers.X.W;
+}
+
+static inline uint32_t AbsoluteIndexedYSlow (AccessMode a) // a,Y
+{
+ uint32_t addr = AbsoluteSlow(a);
+ if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.YL >= 0x100)
+ AddCycles(ONE_CYCLE);
+
+ return addr + Registers.Y.W;
+}
+
+static inline uint32_t AbsoluteIndexedYX0 (AccessMode a) // a,Y
+{
+ uint32_t addr = Absolute(a);
+ AddCycles(ONE_CYCLE);
+
+ return addr + Registers.Y.W;
+}
+
+static inline uint32_t AbsoluteIndexedYX1 (AccessMode a) // a,Y
+{
+ uint32_t addr = Absolute(a);
+ if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100)
+ AddCycles(ONE_CYCLE);
+
+ return addr + Registers.Y.W;
+}
+
+static inline uint32_t AbsoluteLongIndexedXSlow (AccessMode a) // l,X
+{
+ return AbsoluteLongSlow(a) + Registers.X.W;
+}
+
+static inline uint32_t AbsoluteLongIndexedX (AccessMode a) // l,X
+{
+ return AbsoluteLong(a) + Registers.X.W;
+}
+
+static inline uint32_t StackRelativeSlow (AccessMode a) // d,S
+{
+ uint16_t addr = Immediate8Slow(a) + Registers.S.W;
+ AddCycles(ONE_CYCLE);
+
+ return addr;
+}
+
+static inline uint32_t StackRelative (AccessMode a) // d,S
+{
+ uint16_t addr = Immediate8(a) + Registers.S.W;
+ AddCycles(ONE_CYCLE);
+
+ return addr;
+}
+
+static inline uint32_t StackRelativeIndirectIndexedSlow (AccessMode a) // (d,S),Y
+{
+ uint32_t addr = S9xGetWord(StackRelativeSlow(READ));
+ if (a & READ)
+ OpenBus = (uint8_t) (addr >> 8);
+ addr = (addr + Registers.Y.W + ICPU.ShiftedDB) & 0xffffff;
+ AddCycles(ONE_CYCLE);
+
+ return addr;
+}
+
+static inline uint32_t StackRelativeIndirectIndexed (AccessMode a) // (d,S),Y
+{
+ uint32_t addr = S9xGetWord(StackRelative(READ));
+ if (a & READ)
+ OpenBus = (uint8_t) (addr >> 8);
+ addr = (addr + Registers.Y.W + ICPU.ShiftedDB) & 0xffffff;
+ AddCycles(ONE_CYCLE);
+
+ return addr;
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/cpuexec.cpp
@@ -1,1 +1,550 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+#include "snes9x.h"
+#include "memmap.h"
+#include "cpuops.h"
+#include "dma.h"
+#include "apu/apu.h"
+//#include "fxemu.h"
+//#include "snapshot.h"
+#ifdef DEBUGGER
+#include "debug.h"
+#include "missing.h"
+#endif
+
+static inline void S9xReschedule()
+{
+ switch (CPU.WhichEvent)
+ {
+ case HC_HBLANK_START_EVENT:
+ CPU.WhichEvent = HC_HDMA_START_EVENT;
+ CPU.NextEvent = Timings.HDMAStart;
+ break;
+
+ case HC_HDMA_START_EVENT:
+ CPU.WhichEvent = HC_HCOUNTER_MAX_EVENT;
+ CPU.NextEvent = Timings.H_Max;
+ break;
+
+ case HC_HCOUNTER_MAX_EVENT:
+ CPU.WhichEvent = HC_HDMA_INIT_EVENT;
+ CPU.NextEvent = Timings.HDMAInit;
+ break;
+
+ case HC_HDMA_INIT_EVENT:
+ CPU.WhichEvent = HC_RENDER_EVENT;
+ CPU.NextEvent = Timings.RenderPos;
+ break;
+
+ case HC_RENDER_EVENT:
+ CPU.WhichEvent = HC_WRAM_REFRESH_EVENT;
+ CPU.NextEvent = Timings.WRAMRefreshPos;
+ break;
+
+ case HC_WRAM_REFRESH_EVENT:
+ CPU.WhichEvent = HC_HBLANK_START_EVENT;
+ CPU.NextEvent = Timings.HBlankStart;
+ break;
+ }
+}
+
+void S9xMainLoop()
+{
+ for (;;)
+ {
+ if (CPU.NMILine)
+ {
+ if (Timings.NMITriggerPos <= CPU.Cycles)
+ {
+ CPU.NMILine = false;
+ Timings.NMITriggerPos = 0xffff;
+ if (CPU.WaitingForInterrupt)
+ {
+ CPU.WaitingForInterrupt = false;
+ Registers.PCw++;
+ }
+
+ S9xOpcode_NMI();
+ }
+ }
+
+ if (CPU.IRQTransition || CPU.IRQExternal)
+ {
+ if (CPU.IRQPending)
+ CPU.IRQPending--;
+ else
+ {
+ if (CPU.WaitingForInterrupt)
+ {
+ CPU.WaitingForInterrupt = false;
+ Registers.PCw++;
+ }
+
+ CPU.IRQTransition = false;
+ CPU.IRQPending = Timings.IRQPendCount;
+
+ if (!CheckFlag(IRQ))
+ S9xOpcode_IRQ();
+ }
+ }
+
+ #ifdef DEBUGGER
+ if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG))
+ {
+ for (int Break = 0; Break != 6; Break++)
+ {
+ if (S9xBreakpoint[Break].Enabled &&
+ S9xBreakpoint[Break].Bank == Registers.PB &&
+ S9xBreakpoint[Break].Address == Registers.PCw)
+ {
+ if (S9xBreakpoint[Break].Enabled == 2)
+ S9xBreakpoint[Break].Enabled = true;
+ else
+ CPU.Flags |= DEBUG_MODE_FLAG;
+ }
+ }
+ }
+
+ if (CPU.Flags & DEBUG_MODE_FLAG)
+ break;
+
+ if (CPU.Flags & TRACE_FLAG)
+ S9xTrace();
+
+ if (CPU.Flags & SINGLE_STEP_FLAG)
+ {
+ CPU.Flags &= ~SINGLE_STEP_FLAG;
+ CPU.Flags |= DEBUG_MODE_FLAG;
+ }
+ #endif
+
+ if (CPU.Flags & SCAN_KEYS_FLAG)
+ break;
+
+ register uint8_t Op;
+ register struct SOpcodes *Opcodes;
+
+ if (CPU.PCBase)
+ {
+ Op = CPU.PCBase[Registers.PCw];
+ CPU.PrevCycles = CPU.Cycles;
+ CPU.Cycles += CPU.MemSpeed;
+ S9xCheckInterrupts();
+ Opcodes = ICPU.S9xOpcodes;
+ }
+ else
+ {
+ Op = S9xGetByte(Registers.PBPC);
+ OpenBus = Op;
+ Opcodes = S9xOpcodesSlow;
+ }
+
+ if ((Registers.PCw & MEMMAP_MASK) + ICPU.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE)
+ {
+ uint8_t *oldPCBase = CPU.PCBase;
+
+ CPU.PCBase = S9xGetBasePointer(ICPU.ShiftedPB + ((uint16_t) (Registers.PCw + 4)));
+ if (oldPCBase != CPU.PCBase || (Registers.PCw & ~MEMMAP_MASK) == (0xffff & ~MEMMAP_MASK))
+ Opcodes = S9xOpcodesSlow;
+ }
+
+ Registers.PCw++;
+ (*Opcodes[Op].S9xOpcode)();
+
+ /*if (Settings.SA1)
+ S9xSA1MainLoop();*/
+ }
+
+ S9xPackStatus();
+
+ if (CPU.Flags & SCAN_KEYS_FLAG)
+ {
+ /*#ifdef DEBUGGER
+ if (!(CPU.Flags & FRAME_ADVANCE_FLAG))
+ #endif
+ S9xSyncSpeed();*/
+ CPU.Flags &= ~SCAN_KEYS_FLAG;
+ }
+}
+
+void S9xDoHEventProcessing()
+{
+#ifdef DEBUGGER
+ static char eventname[7][32] =
+ {
+ "",
+ "HC_HBLANK_START_EVENT",
+ "HC_HDMA_START_EVENT ",
+ "HC_HCOUNTER_MAX_EVENT",
+ "HC_HDMA_INIT_EVENT ",
+ "HC_RENDER_EVENT ",
+ "HC_WRAM_REFRESH_EVENT"
+ };
+#endif
+
+#ifdef DEBUGGER
+ if (Settings.TraceHCEvent)
+ S9xTraceFormattedMessage("--- HC event processing (%s) expected HC:%04d executed HC:%04d",
+ eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles);
+#endif
+
+ switch (CPU.WhichEvent)
+ {
+ case HC_HBLANK_START_EVENT:
+ S9xReschedule();
+ break;
+
+ case HC_HDMA_START_EVENT:
+ S9xReschedule();
+
+ if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight)
+ {
+ #ifdef DEBUGGER
+ S9xTraceFormattedMessage("*** HDMA Transfer HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA);
+ #endif
+ PPU.HDMA = S9xDoHDMA(PPU.HDMA);
+ }
+
+ break;
+
+ case HC_HCOUNTER_MAX_EVENT:
+ /*if (Settings.SuperFX)
+ {
+ if (!SuperFX.oneLineDone)
+ S9xSuperFXExec();
+ SuperFX.oneLineDone = false;
+ }*/
+
+ S9xAPUEndScanline();
+ CPU.Cycles -= Timings.H_Max;
+ CPU.PrevCycles -= 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
+ {
+ CPU.V_Counter = 0;
+ Timings.InterlaceField ^= 1;
+
+ // From byuu:
+ // [NTSC]
+ // interlace mode has 525 scanlines: 263 on the even frame, and 262 on the odd.
+ // non-interlace mode has 524 scanlines: 262 scanlines on both even and odd frames.
+ // [PAL] <PAL info is unverified on hardware>
+ // interlace mode has 625 scanlines: 313 on the even frame, and 312 on the odd.
+ // non-interlace mode has 624 scanlines: 312 scanlines on both even and odd frames.
+ if (IPPU.Interlace && !Timings.InterlaceField)
+ Timings.V_Max = Timings.V_Max_Master + 1; // 263 (NTSC), 313?(PAL)
+ else
+ Timings.V_Max = Timings.V_Max_Master; // 262 (NTSC), 312?(PAL)
+
+ Memory.FillRAM[0x213F] ^= 0x80;
+ PPU.RangeTimeOver = 0;
+
+ // 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;
+
+ ICPU.Frame++;
+ PPU.HVBeamCounterLatched = 0;
+ CPU.Flags |= SCAN_KEYS_FLAG;
+ }
+
+ // From byuu:
+ // In non-interlace mode, there are 341 dots per scanline, and 262 scanlines per frame.
+ // On odd frames, scanline 240 is one dot short.
+ // In interlace mode, there are always 341 dots per scanline. Even frames have 263 scanlines,
+ // and odd frames have 262 scanlines.
+ // Interlace mode scanline 240 on odd frames is not missing a dot.
+ if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField) // V=240
+ Timings.H_Max = Timings.H_Max_Master - ONE_DOT_CYCLE; // HC=1360
+ else
+ Timings.H_Max = Timings.H_Max_Master; // HC=1364
+
+ if (Model->_5A22 == 2)
+ {
+ if (CPU.V_Counter != 240 || IPPU.Interlace || !Timings.InterlaceField) // V=240
+ {
+ if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE) // HC=534
+ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; // HC=538
+ else
+ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2 - ONE_DOT_CYCLE; // HC=534
+ }
+ }
+ else
+ Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v1;
+
+ if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) // VBlank starts from V=225(240).
+ {
+ //S9xEndScreenRefresh();
+ PPU.HDMA = 0;
+ // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU.
+ #ifdef DEBUGGER
+ missing.dma_this_frame = 0;
+ #endif
+ IPPU.MaxBrightness = PPU.Brightness;
+ PPU.ForcedBlanking = (Memory.FillRAM[0x2100] >> 7) & 1;
+
+ if (!PPU.ForcedBlanking)
+ {
+ PPU.OAMAddr = PPU.SavedOAMAddr;
+
+ uint8_t tmp = 0;
+
+ if (PPU.OAMPriorityRotation)
+ tmp = (PPU.OAMAddr & 0xFE) >> 1;
+ if ((PPU.OAMFlip & 1) || PPU.FirstSprite != tmp)
+ {
+ PPU.FirstSprite = tmp;
+ IPPU.OBJChanged = true;
+ }
+
+ PPU.OAMFlip = 0;
+ }
+
+ // FIXME: writing to $4210 will wait 6 cycles.
+ Memory.FillRAM[0x4210] = 0x80 | Model->_5A22;
+ if (Memory.FillRAM[0x4200] & 0x80)
+ {
+ // FIXME: triggered at HC=6, checked just before the final CPU cycle,
+ // then, when to call S9xOpcode_NMI()?
+ CPU.NMILine = true;
+ Timings.NMITriggerPos = 6 + 6;
+ }
+
+ }
+
+ /*if (CPU.V_Counter == PPU.ScreenHeight + 3) // FIXME: not true
+ {
+ if (Memory.FillRAM[0x4200] & 1)
+ S9xDoAutoJoypad();
+ }*/
+
+ /*if (CPU.V_Counter == FIRST_VISIBLE_LINE) // V=1
+ S9xStartScreenRefresh();*/
+
+ S9xReschedule();
+
+ break;
+
+ case HC_HDMA_INIT_EVENT:
+ S9xReschedule();
+
+ if (CPU.V_Counter == 0)
+ {
+ #ifdef DEBUGGER
+ S9xTraceFormattedMessage("*** HDMA Init HC:%04d, Channel:%02x", CPU.Cycles, PPU.HDMA);
+ #endif
+ S9xStartHDMA();
+ }
+
+ break;
+
+ case HC_RENDER_EVENT:
+ /*if (CPU.V_Counter >= FIRST_VISIBLE_LINE && CPU.V_Counter <= PPU.ScreenHeight)
+ RenderLine((uint8_t) (CPU.V_Counter - FIRST_VISIBLE_LINE));*/
+
+ S9xReschedule();
+
+ break;
+
+ case HC_WRAM_REFRESH_EVENT:
+ #ifdef DEBUGGER
+ S9xTraceFormattedMessage("*** WRAM Refresh HC:%04d", CPU.Cycles);
+ #endif
+
+ CPU.PrevCycles = CPU.Cycles;
+ CPU.Cycles += SNES_WRAM_REFRESH_CYCLES;
+ S9xCheckInterrupts();
+
+ S9xReschedule();
+
+ break;
+ }
+
+#ifdef DEBUGGER
+ if (Settings.TraceHCEvent)
+ S9xTraceFormattedMessage("--- HC event rescheduled (%s) expected HC:%04d current HC:%04d",
+ eventname[CPU.WhichEvent], CPU.NextEvent, CPU.Cycles);
+#endif
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/cpuexec.h
@@ -1,1 +1,314 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _CPUEXEC_H_
+#define _CPUEXEC_H_
+
+#include "ppu.h"
+#ifdef DEBUGGER
+#include "debug.h"
+#endif
+
+struct SOpcodes
+{
+ void (*S9xOpcode)();
+};
+
+struct SICPU
+{
+ struct SOpcodes *S9xOpcodes;
+ uint8_t *S9xOpLengths;
+ uint8_t _Carry;
+ uint8_t _Zero;
+ uint8_t _Negative;
+ uint8_t _Overflow;
+ uint32_t ShiftedPB;
+ uint32_t ShiftedDB;
+ uint32_t Frame;
+ uint32_t FrameAdvanceCount;
+};
+
+extern struct SICPU ICPU;
+
+extern struct SOpcodes S9xOpcodesE1[256];
+extern struct SOpcodes S9xOpcodesM1X1[256];
+extern struct SOpcodes S9xOpcodesM1X0[256];
+extern struct SOpcodes S9xOpcodesM0X1[256];
+extern struct SOpcodes S9xOpcodesM0X0[256];
+extern struct SOpcodes S9xOpcodesSlow[256];
+extern uint8_t S9xOpLengthsM1X1[256];
+extern uint8_t S9xOpLengthsM1X0[256];
+extern uint8_t S9xOpLengthsM0X1[256];
+extern uint8_t S9xOpLengthsM0X0[256];
+
+void S9xMainLoop();
+void S9xReset();
+void S9xSoftReset();
+void S9xDoHEventProcessing();
+
+static inline void S9xUnpackStatus()
+{
+ ICPU._Zero = (Registers.PL & Zero) == 0;
+ ICPU._Negative = (Registers.PL & Negative);
+ ICPU._Carry = (Registers.PL & Carry);
+ ICPU._Overflow = (Registers.PL & Overflow) >> 6;
+}
+
+static inline void S9xPackStatus()
+{
+ Registers.PL &= ~(Zero | Negative | Carry | Overflow);
+ Registers.PL |= ICPU._Carry | ((ICPU._Zero == 0) << 1) | (ICPU._Negative & 0x80) | (ICPU._Overflow << 6);
+}
+
+static inline void S9xFixCycles()
+{
+ if (CheckEmulation())
+ {
+ ICPU.S9xOpcodes = S9xOpcodesE1;
+ ICPU.S9xOpLengths = S9xOpLengthsM1X1;
+ }
+ else
+ if (CheckMemory())
+ {
+ if (CheckIndex())
+ {
+ ICPU.S9xOpcodes = S9xOpcodesM1X1;
+ ICPU.S9xOpLengths = S9xOpLengthsM1X1;
+ }
+ else
+ {
+ ICPU.S9xOpcodes = S9xOpcodesM1X0;
+ ICPU.S9xOpLengths = S9xOpLengthsM1X0;
+ }
+ }
+ else
+ {
+ if (CheckIndex())
+ {
+ ICPU.S9xOpcodes = S9xOpcodesM0X1;
+ ICPU.S9xOpLengths = S9xOpLengthsM0X1;
+ }
+ else
+ {
+ ICPU.S9xOpcodes = S9xOpcodesM0X0;
+ ICPU.S9xOpLengths = S9xOpLengthsM0X0;
+ }
+ }
+}
+
+static 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)
+ {
+#ifdef DEBUGGER
+ S9xTraceFormattedMessage("--- /IRQ High->Low prev HC:%04d curr HC:%04d HTimer:%d Pos:%04d VTimer:%d Pos:%03d",
+ CPU.PrevCycles, CPU.Cycles, PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition);
+#endif
+ CPU.IRQLine = true;
+ }
+
+ CPU.IRQLastState = thisIRQ;
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/cpumacro.h
@@ -1,1 +1,893 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _CPUMACRO_H_
+#define _CPUMACRO_H_
+
+#define rOP8(OP, ADDR, WRAP, FUNC) \
+static void Op##OP() \
+{ \
+ uint8_t val = OpenBus = S9xGetByte(ADDR(READ)); \
+ FUNC(val); \
+}
+
+#define rOP16(OP, ADDR, WRAP, FUNC) \
+static void Op##OP() \
+{ \
+ uint16_t val = S9xGetWord(ADDR(READ), WRAP); \
+ OpenBus = (uint8_t) (val >> 8); \
+ FUNC(val); \
+}
+
+#define rOPC(OP, COND, ADDR, WRAP, FUNC) \
+static void Op##OP() \
+{ \
+ if (Check##COND()) \
+ { \
+ uint8_t val = OpenBus = S9xGetByte(ADDR(READ)); \
+ FUNC(val); \
+ } \
+ else \
+ { \
+ uint16_t val = S9xGetWord(ADDR(READ), WRAP); \
+ OpenBus = (uint8_t) (val >> 8); \
+ FUNC(val); \
+ } \
+}
+
+#define rOPM(OP, ADDR, WRAP, FUNC) \
+rOPC(OP, Memory, ADDR, WRAP, FUNC)
+
+#define rOPX(OP, ADDR, WRAP, FUNC) \
+rOPC(OP, Index, ADDR, WRAP, FUNC)
+
+#define wOP8(OP, ADDR, WRAP, FUNC) \
+static void Op##OP() \
+{ \
+ FUNC##8(ADDR(WRITE)); \
+}
+
+#define wOP16(OP, ADDR, WRAP, FUNC) \
+static void Op##OP() \
+{ \
+ FUNC##16(ADDR(WRITE), WRAP); \
+}
+
+#define wOPC(OP, COND, ADDR, WRAP, FUNC) \
+static void Op##OP() \
+{ \
+ if (Check##COND()) \
+ FUNC##8(ADDR(WRITE)); \
+ else \
+ FUNC##16(ADDR(WRITE), WRAP); \
+}
+
+#define wOPM(OP, ADDR, WRAP, FUNC) \
+wOPC(OP, Memory, ADDR, WRAP, FUNC)
+
+#define wOPX(OP, ADDR, WRAP, FUNC) \
+wOPC(OP, Index, ADDR, WRAP, FUNC)
+
+#define mOP8(OP, ADDR, WRAP, FUNC) \
+static void Op##OP() \
+{ \
+ FUNC##8(ADDR(MODIFY)); \
+}
+
+#define mOP16(OP, ADDR, WRAP, FUNC) \
+static void Op##OP() \
+{ \
+ FUNC##16(ADDR(MODIFY), WRAP); \
+}
+
+#define mOPC(OP, COND, ADDR, WRAP, FUNC) \
+static void Op##OP() \
+{ \
+ if (Check##COND()) \
+ FUNC##8(ADDR(MODIFY)); \
+ else \
+ FUNC##16(ADDR(MODIFY), WRAP); \
+}
+
+#define mOPM(OP, ADDR, WRAP, FUNC) \
+mOPC(OP, Memory, ADDR, WRAP, FUNC)
+
+#define bOP(OP, REL, COND, CHK, E) \
+static void Op##OP() \
+{ \
+ pair newPC; \
+ newPC.W = REL(JUMP); \
+ if (COND) \
+ { \
+ AddCycles(ONE_CYCLE); \
+ if (E && Registers.PCh != newPC.B.h) \
+ AddCycles(ONE_CYCLE); \
+ if ((Registers.PCw & ~MEMMAP_MASK) != (newPC.W & ~MEMMAP_MASK)) \
+ S9xSetPCBase(ICPU.ShiftedPB + newPC.W); \
+ else \
+ Registers.PCw = newPC.W; \
+ } \
+}
+
+
+static inline void SetZN (uint16_t Work16)
+{
+ ICPU._Zero = Work16 != 0;
+ ICPU._Negative = (uint8_t) (Work16 >> 8);
+}
+
+static inline void SetZN (uint8_t Work8)
+{
+ ICPU._Zero = Work8;
+ ICPU._Negative = Work8;
+}
+
+static inline void ADC (uint16_t Work16)
+{
+ 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;
+ 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;
+ SetZN(Registers.A.W);
+ }
+ else
+ {
+ uint32_t Ans32 = Registers.A.W + Work16 + CheckCarry();
+
+ ICPU._Carry = Ans32 >= 0x10000;
+
+ if (~(Registers.A.W ^ Work16) & (Work16 ^ (uint16_t) Ans32) & 0x8000)
+ SetOverflow();
+ else
+ ClearOverflow();
+
+ Registers.A.W = (uint16_t) Ans32;
+ SetZN(Registers.A.W);
+ }
+}
+
+static inline void ADC (uint8_t Work8)
+{
+ 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;
+ SetCarry();
+ }
+ else
+ ClearCarry();
+
+ uint8_t Ans8 = A2 | A1;
+
+ if (~(Registers.AL ^ Work8) & (Work8 ^ Ans8) & 0x80)
+ SetOverflow();
+ else
+ ClearOverflow();
+
+ Registers.AL = Ans8;
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ uint16_t Ans16 = Registers.AL + Work8 + CheckCarry();
+
+ ICPU._Carry = Ans16 >= 0x100;
+
+ if (~(Registers.AL ^ Work8) & (Work8 ^ (uint8_t) Ans16) & 0x80)
+ SetOverflow();
+ else
+ ClearOverflow();
+
+ Registers.AL = (uint8_t) Ans16;
+ SetZN(Registers.AL);
+ }
+}
+
+static inline void AND (uint16_t Work16)
+{
+ Registers.A.W &= Work16;
+ SetZN(Registers.A.W);
+}
+
+static inline void AND (uint8_t Work8)
+{
+ Registers.AL &= Work8;
+ SetZN(Registers.AL);
+}
+
+static inline void ASL16 (uint32_t OpAddress, s9xwrap_t w)
+{
+ uint16_t Work16 = S9xGetWord(OpAddress, w);
+ ICPU._Carry = (Work16 & 0x8000) != 0;
+ Work16 <<= 1;
+ AddCycles(ONE_CYCLE);
+ S9xSetWord(Work16, OpAddress, w, WRITE_10);
+ OpenBus = Work16 & 0xff;
+ SetZN(Work16);
+}
+
+static inline void ASL8 (uint32_t OpAddress)
+{
+ uint8_t Work8 = S9xGetByte(OpAddress);
+ ICPU._Carry = (Work8 & 0x80) != 0;
+ Work8 <<= 1;
+ AddCycles(ONE_CYCLE);
+ S9xSetByte(Work8, OpAddress);
+ OpenBus = Work8;
+ SetZN(Work8);
+}
+
+static inline void BIT (uint16_t Work16)
+{
+ ICPU._Overflow = (Work16 & 0x4000) != 0;
+ ICPU._Negative = (uint8_t) (Work16 >> 8);
+ ICPU._Zero = (Work16 & Registers.A.W) != 0;
+}
+
+static inline void BIT (uint8_t Work8)
+{
+ ICPU._Overflow = (Work8 & 0x40) != 0;
+ ICPU._Negative = Work8;
+ ICPU._Zero = Work8 & Registers.AL;
+}
+
+static inline void CMP (uint16_t val)
+{
+ int32_t Int32 = (int32_t) Registers.A.W - (int32_t) val;
+ ICPU._Carry = Int32 >= 0;
+ SetZN((uint16_t) Int32);
+}
+
+static inline void CMP (uint8_t val)
+{
+ int16_t Int16 = (int16_t) Registers.AL - (int16_t) val;
+ ICPU._Carry = Int16 >= 0;
+ SetZN((uint8_t) Int16);
+}
+
+static inline void CPX (uint16_t val)
+{
+ int32_t Int32 = (int32_t) Registers.X.W - (int32_t) val;
+ ICPU._Carry = Int32 >= 0;
+ SetZN((uint16_t) Int32);
+}
+
+static inline void CPX (uint8_t val)
+{
+ int16_t Int16 = (int16_t) Registers.XL - (int16_t) val;
+ ICPU._Carry = Int16 >= 0;
+ SetZN((uint8_t) Int16);
+}
+
+static inline void CPY (uint16_t val)
+{
+ int32_t Int32 = (int32_t) Registers.Y.W - (int32_t) val;
+ ICPU._Carry = Int32 >= 0;
+ SetZN((uint16_t) Int32);
+}
+
+static inline void CPY (uint8_t val)
+{
+ int16_t Int16 = (int16_t) Registers.YL - (int16_t) val;
+ ICPU._Carry = Int16 >= 0;
+ SetZN((uint8_t) Int16);
+}
+
+static inline void DEC16 (uint32_t OpAddress, s9xwrap_t w)
+{
+ uint16_t Work16 = S9xGetWord(OpAddress, w) - 1;
+ AddCycles(ONE_CYCLE);
+ S9xSetWord(Work16, OpAddress, w, WRITE_10);
+ OpenBus = Work16 & 0xff;
+ SetZN(Work16);
+}
+
+static inline void DEC8 (uint32_t OpAddress)
+{
+ uint8_t Work8 = S9xGetByte(OpAddress) - 1;
+ AddCycles(ONE_CYCLE);
+ S9xSetByte(Work8, OpAddress);
+ OpenBus = Work8;
+ SetZN(Work8);
+}
+
+static inline void EOR (uint16_t val)
+{
+ Registers.A.W ^= val;
+ SetZN(Registers.A.W);
+}
+
+static inline void EOR (uint8_t val)
+{
+ Registers.AL ^= val;
+ SetZN(Registers.AL);
+}
+
+static inline void INC16 (uint32_t OpAddress, s9xwrap_t w)
+{
+ uint16_t Work16 = S9xGetWord(OpAddress, w) + 1;
+ AddCycles(ONE_CYCLE);
+ S9xSetWord(Work16, OpAddress, w, WRITE_10);
+ OpenBus = Work16 & 0xff;
+ SetZN(Work16);
+}
+
+static inline void INC8 (uint32_t OpAddress)
+{
+ uint8_t Work8 = S9xGetByte(OpAddress) + 1;
+ AddCycles(ONE_CYCLE);
+ S9xSetByte(Work8, OpAddress);
+ OpenBus = Work8;
+ SetZN(Work8);
+}
+
+static inline void LDA (uint16_t val)
+{
+ Registers.A.W = val;
+ SetZN(Registers.A.W);
+}
+
+static inline void LDA (uint8_t val)
+{
+ Registers.AL = val;
+ SetZN(Registers.AL);
+}
+
+static inline void LDX (uint16_t val)
+{
+ Registers.X.W = val;
+ SetZN(Registers.X.W);
+}
+
+static inline void LDX (uint8_t val)
+{
+ Registers.XL = val;
+ SetZN(Registers.XL);
+}
+
+static inline void LDY (uint16_t val)
+{
+ Registers.Y.W = val;
+ SetZN(Registers.Y.W);
+}
+
+static inline void LDY (uint8_t val)
+{
+ Registers.YL = val;
+ SetZN(Registers.YL);
+}
+
+static inline void LSR16 (uint32_t OpAddress, s9xwrap_t w)
+{
+ uint16_t Work16 = S9xGetWord(OpAddress, w);
+ ICPU._Carry = Work16 & 1;
+ Work16 >>= 1;
+ AddCycles(ONE_CYCLE);
+ S9xSetWord(Work16, OpAddress, w, WRITE_10);
+ OpenBus = Work16 & 0xff;
+ SetZN(Work16);
+}
+
+static inline void LSR8 (uint32_t OpAddress)
+{
+ uint8_t Work8 = S9xGetByte(OpAddress);
+ ICPU._Carry = Work8 & 1;
+ Work8 >>= 1;
+ AddCycles(ONE_CYCLE);
+ S9xSetByte(Work8, OpAddress);
+ OpenBus = Work8;
+ SetZN(Work8);
+}
+
+static inline void ORA (uint16_t val)
+{
+ Registers.A.W |= val;
+ SetZN(Registers.A.W);
+}
+
+static inline void ORA (uint8_t val)
+{
+ Registers.AL |= val;
+ SetZN(Registers.AL);
+}
+
+static inline void ROL16 (uint32_t OpAddress, s9xwrap_t w)
+{
+ uint32_t Work32 = (((uint32_t) S9xGetWord(OpAddress, w)) << 1) | CheckCarry();
+ ICPU._Carry = Work32 >= 0x10000;
+ AddCycles(ONE_CYCLE);
+ S9xSetWord((uint16_t) Work32, OpAddress, w, WRITE_10);
+ OpenBus = Work32 & 0xff;
+ SetZN((uint16_t) Work32);
+}
+
+static inline void ROL8 (uint32_t OpAddress)
+{
+ uint16_t Work16 = (((uint16_t) S9xGetByte(OpAddress)) << 1) | CheckCarry();
+ ICPU._Carry = Work16 >= 0x100;
+ AddCycles(ONE_CYCLE);
+ S9xSetByte((uint8_t) Work16, OpAddress);
+ OpenBus = Work16 & 0xff;
+ SetZN((uint8_t) Work16);
+}
+
+static inline void ROR16 (uint32_t OpAddress, s9xwrap_t w)
+{
+ uint32_t Work32 = ((uint32_t) S9xGetWord(OpAddress, w)) | (((uint32_t) CheckCarry()) << 16);
+ ICPU._Carry = Work32 & 1;
+ Work32 >>= 1;
+ AddCycles(ONE_CYCLE);
+ S9xSetWord((uint16_t) Work32, OpAddress, w, WRITE_10);
+ OpenBus = Work32 & 0xff;
+ SetZN((uint16_t) Work32);
+}
+
+static inline void ROR8 (uint32_t OpAddress)
+{
+ uint16_t Work16 = ((uint16_t) S9xGetByte(OpAddress)) | (((uint16_t) CheckCarry()) << 8);
+ ICPU._Carry = Work16 & 1;
+ Work16 >>= 1;
+ AddCycles(ONE_CYCLE);
+ S9xSetByte((uint8_t) Work16, OpAddress);
+ OpenBus = Work16 & 0xff;
+ SetZN((uint8_t) Work16);
+}
+
+static inline void SBC (uint16_t Work16)
+{
+ 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;
+ 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;
+ SetZN(Registers.A.W);
+ }
+ else
+ {
+ int32_t Int32 = (int32_t) Registers.A.W - (int32_t) Work16 + (int32_t) CheckCarry() - 1;
+
+ ICPU._Carry = Int32 >= 0;
+
+ if ((Registers.A.W ^ Work16) & (Registers.A.W ^ (uint16_t) Int32) & 0x8000)
+ SetOverflow();
+ else
+ ClearOverflow();
+
+ Registers.A.W = (uint16_t) Int32;
+ SetZN(Registers.A.W);
+ }
+}
+
+static inline void SBC (uint8_t Work8)
+{
+ 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;
+ ClearCarry();
+ }
+ else
+ SetCarry();
+
+ uint8_t Ans8 = A2 | A1;
+
+ if ((Registers.AL ^ Work8) & (Registers.AL ^ Ans8) & 0x80)
+ SetOverflow();
+ else
+ ClearOverflow();
+
+ Registers.AL = Ans8;
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ int16_t Int16 = (int16_t) Registers.AL - (int16_t) Work8 + (int16_t) CheckCarry() - 1;
+
+ ICPU._Carry = Int16 >= 0;
+
+ if ((Registers.AL ^ Work8) & (Registers.AL ^ (uint8_t) Int16) & 0x80)
+ SetOverflow();
+ else
+ ClearOverflow();
+
+ Registers.AL = (uint8_t) Int16;
+ SetZN(Registers.AL);
+ }
+}
+
+static inline void STA16 (uint32_t OpAddress, enum s9xwrap_t w)
+{
+ S9xSetWord(Registers.A.W, OpAddress, w);
+ OpenBus = Registers.AH;
+}
+
+static inline void STA8 (uint32_t OpAddress)
+{
+ S9xSetByte(Registers.AL, OpAddress);
+ OpenBus = Registers.AL;
+}
+
+static inline void STX16 (uint32_t OpAddress, enum s9xwrap_t w)
+{
+ S9xSetWord(Registers.X.W, OpAddress, w);
+ OpenBus = Registers.XH;
+}
+
+static inline void STX8 (uint32_t OpAddress)
+{
+ S9xSetByte(Registers.XL, OpAddress);
+ OpenBus = Registers.XL;
+}
+
+static inline void STY16 (uint32_t OpAddress, enum s9xwrap_t w)
+{
+ S9xSetWord(Registers.Y.W, OpAddress, w);
+ OpenBus = Registers.YH;
+}
+
+static inline void STY8 (uint32_t OpAddress)
+{
+ S9xSetByte(Registers.YL, OpAddress);
+ OpenBus = Registers.YL;
+}
+
+static inline void STZ16 (uint32_t OpAddress, enum s9xwrap_t w)
+{
+ S9xSetWord(0, OpAddress, w);
+ OpenBus = 0;
+}
+
+static inline void STZ8 (uint32_t OpAddress)
+{
+ S9xSetByte(0, OpAddress);
+ OpenBus = 0;
+}
+
+static inline void TSB16 (uint32_t OpAddress, enum s9xwrap_t w)
+{
+ uint16_t Work16 = S9xGetWord(OpAddress, w);
+ ICPU._Zero = (Work16 & Registers.A.W) != 0;
+ Work16 |= Registers.A.W;
+ AddCycles(ONE_CYCLE);
+ S9xSetWord(Work16, OpAddress, w, WRITE_10);
+ OpenBus = Work16 & 0xff;
+}
+
+static inline void TSB8 (uint32_t OpAddress)
+{
+ uint8_t Work8 = S9xGetByte(OpAddress);
+ ICPU._Zero = Work8 & Registers.AL;
+ Work8 |= Registers.AL;
+ AddCycles(ONE_CYCLE);
+ S9xSetByte(Work8, OpAddress);
+ OpenBus = Work8;
+}
+
+static inline void TRB16 (uint32_t OpAddress, enum s9xwrap_t w)
+{
+ uint16_t Work16 = S9xGetWord(OpAddress, w);
+ ICPU._Zero = (Work16 & Registers.A.W) != 0;
+ Work16 &= ~Registers.A.W;
+ AddCycles(ONE_CYCLE);
+ S9xSetWord(Work16, OpAddress, w, WRITE_10);
+ OpenBus = Work16 & 0xff;
+}
+
+static inline void TRB8 (uint32_t OpAddress)
+{
+ uint8_t Work8 = S9xGetByte(OpAddress);
+ ICPU._Zero = Work8 & Registers.AL;
+ Work8 &= ~Registers.AL;
+ AddCycles(ONE_CYCLE);
+ S9xSetByte(Work8, OpAddress);
+ OpenBus = Work8;
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/cpuops.cpp
@@ -1,1 +1,3887 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+#include "snes9x.h"
+#include "memmap.h"
+#include "apu/apu.h"
+
+// for "Magic WDM" features
+#ifdef DEBUGGER
+#include "snapshot.h"
+#include "display.h"
+#include "debug.h"
+#include "missing.h"
+#endif
+
+#ifdef SA1_OPCODES
+//#define AddCycles(n) { SA1.Cycles += (n); }
+static inline void AddCycles(int32_t n) { SA1.Cycles += n; }
+#else
+//#define AddCycles(n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += (n); S9xCheckInterrupts(); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); }
+static inline void AddCycles(int32_t n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += n; S9xCheckInterrupts(); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); }
+#endif
+
+#include "cpuaddr.h"
+#include "cpuops.h"
+#include "cpumacro.h"
+
+/* ADC ********************************************************************* */
+
+static void Op69M1()
+{
+ ADC(Immediate8(READ));
+}
+
+static void Op69M0()
+{
+ ADC(Immediate16(READ));
+}
+
+static void Op69Slow()
+{
+ if (CheckMemory())
+ ADC(Immediate8Slow(READ));
+ else
+ ADC(Immediate16Slow(READ));
+}
+
+rOP8 (65M1, Direct, WRAP_BANK, ADC)
+rOP16(65M0, Direct, WRAP_BANK, ADC)
+rOPM (65Slow, DirectSlow, WRAP_BANK, ADC)
+
+rOP8 (75E1, DirectIndexedXE1, WRAP_BANK, ADC)
+rOP8 (75E0M1, DirectIndexedXE0, WRAP_BANK, ADC)
+rOP16(75E0M0, DirectIndexedXE0, WRAP_BANK, ADC)
+rOPM (75Slow, DirectIndexedXSlow, WRAP_BANK, ADC)
+
+rOP8 (72E1, DirectIndirectE1, WRAP_NONE, ADC)
+rOP8 (72E0M1, DirectIndirectE0, WRAP_NONE, ADC)
+rOP16(72E0M0, DirectIndirectE0, WRAP_NONE, ADC)
+rOPM (72Slow, DirectIndirectSlow, WRAP_NONE, ADC)
+
+rOP8 (61E1, DirectIndexedIndirectE1, WRAP_NONE, ADC)
+rOP8 (61E0M1, DirectIndexedIndirectE0, WRAP_NONE, ADC)
+rOP16(61E0M0, DirectIndexedIndirectE0, WRAP_NONE, ADC)
+rOPM (61Slow, DirectIndexedIndirectSlow, WRAP_NONE, ADC)
+
+rOP8 (71E1, DirectIndirectIndexedE1, WRAP_NONE, ADC)
+rOP8 (71E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, ADC)
+rOP16(71E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, ADC)
+rOP8 (71E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, ADC)
+rOP16(71E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, ADC)
+rOPM (71Slow, DirectIndirectIndexedSlow, WRAP_NONE, ADC)
+
+rOP8 (67M1, DirectIndirectLong, WRAP_NONE, ADC)
+rOP16(67M0, DirectIndirectLong, WRAP_NONE, ADC)
+rOPM (67Slow, DirectIndirectLongSlow, WRAP_NONE, ADC)
+
+rOP8 (77M1, DirectIndirectIndexedLong, WRAP_NONE, ADC)
+rOP16(77M0, DirectIndirectIndexedLong, WRAP_NONE, ADC)
+rOPM (77Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, ADC)
+
+rOP8 (6DM1, Absolute, WRAP_NONE, ADC)
+rOP16(6DM0, Absolute, WRAP_NONE, ADC)
+rOPM (6DSlow, AbsoluteSlow, WRAP_NONE, ADC)
+
+rOP8 (7DM1X1, AbsoluteIndexedXX1, WRAP_NONE, ADC)
+rOP16(7DM0X1, AbsoluteIndexedXX1, WRAP_NONE, ADC)
+rOP8 (7DM1X0, AbsoluteIndexedXX0, WRAP_NONE, ADC)
+rOP16(7DM0X0, AbsoluteIndexedXX0, WRAP_NONE, ADC)
+rOPM (7DSlow, AbsoluteIndexedXSlow, WRAP_NONE, ADC)
+
+rOP8 (79M1X1, AbsoluteIndexedYX1, WRAP_NONE, ADC)
+rOP16(79M0X1, AbsoluteIndexedYX1, WRAP_NONE, ADC)
+rOP8 (79M1X0, AbsoluteIndexedYX0, WRAP_NONE, ADC)
+rOP16(79M0X0, AbsoluteIndexedYX0, WRAP_NONE, ADC)
+rOPM (79Slow, AbsoluteIndexedYSlow, WRAP_NONE, ADC)
+
+rOP8 (6FM1, AbsoluteLong, WRAP_NONE, ADC)
+rOP16(6FM0, AbsoluteLong, WRAP_NONE, ADC)
+rOPM (6FSlow, AbsoluteLongSlow, WRAP_NONE, ADC)
+
+rOP8 (7FM1, AbsoluteLongIndexedX, WRAP_NONE, ADC)
+rOP16(7FM0, AbsoluteLongIndexedX, WRAP_NONE, ADC)
+rOPM (7FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, ADC)
+
+rOP8 (63M1, StackRelative, WRAP_NONE, ADC)
+rOP16(63M0, StackRelative, WRAP_NONE, ADC)
+rOPM (63Slow, StackRelativeSlow, WRAP_NONE, ADC)
+
+rOP8 (73M1, StackRelativeIndirectIndexed, WRAP_NONE, ADC)
+rOP16(73M0, StackRelativeIndirectIndexed, WRAP_NONE, ADC)
+rOPM (73Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, ADC)
+
+/* AND ********************************************************************* */
+
+static void Op29M1()
+{
+ Registers.AL &= Immediate8(READ);
+ SetZN(Registers.AL);
+}
+
+static void Op29M0()
+{
+ Registers.A.W &= Immediate16(READ);
+ SetZN(Registers.A.W);
+}
+
+static void Op29Slow()
+{
+ if (CheckMemory())
+ {
+ Registers.AL &= Immediate8Slow(READ);
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ Registers.A.W &= Immediate16Slow(READ);
+ SetZN(Registers.A.W);
+ }
+}
+
+rOP8 (25M1, Direct, WRAP_BANK, AND)
+rOP16(25M0, Direct, WRAP_BANK, AND)
+rOPM (25Slow, DirectSlow, WRAP_BANK, AND)
+
+rOP8 (35E1, DirectIndexedXE1, WRAP_BANK, AND)
+rOP8 (35E0M1, DirectIndexedXE0, WRAP_BANK, AND)
+rOP16(35E0M0, DirectIndexedXE0, WRAP_BANK, AND)
+rOPM (35Slow, DirectIndexedXSlow, WRAP_BANK, AND)
+
+rOP8 (32E1, DirectIndirectE1, WRAP_NONE, AND)
+rOP8 (32E0M1, DirectIndirectE0, WRAP_NONE, AND)
+rOP16(32E0M0, DirectIndirectE0, WRAP_NONE, AND)
+rOPM (32Slow, DirectIndirectSlow, WRAP_NONE, AND)
+
+rOP8 (21E1, DirectIndexedIndirectE1, WRAP_NONE, AND)
+rOP8 (21E0M1, DirectIndexedIndirectE0, WRAP_NONE, AND)
+rOP16(21E0M0, DirectIndexedIndirectE0, WRAP_NONE, AND)
+rOPM (21Slow, DirectIndexedIndirectSlow, WRAP_NONE, AND)
+
+rOP8 (31E1, DirectIndirectIndexedE1, WRAP_NONE, AND)
+rOP8 (31E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, AND)
+rOP16(31E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, AND)
+rOP8 (31E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, AND)
+rOP16(31E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, AND)
+rOPM (31Slow, DirectIndirectIndexedSlow, WRAP_NONE, AND)
+
+rOP8 (27M1, DirectIndirectLong, WRAP_NONE, AND)
+rOP16(27M0, DirectIndirectLong, WRAP_NONE, AND)
+rOPM (27Slow, DirectIndirectLongSlow, WRAP_NONE, AND)
+
+rOP8 (37M1, DirectIndirectIndexedLong, WRAP_NONE, AND)
+rOP16(37M0, DirectIndirectIndexedLong, WRAP_NONE, AND)
+rOPM (37Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, AND)
+
+rOP8 (2DM1, Absolute, WRAP_NONE, AND)
+rOP16(2DM0, Absolute, WRAP_NONE, AND)
+rOPM (2DSlow, AbsoluteSlow, WRAP_NONE, AND)
+
+rOP8 (3DM1X1, AbsoluteIndexedXX1, WRAP_NONE, AND)
+rOP16(3DM0X1, AbsoluteIndexedXX1, WRAP_NONE, AND)
+rOP8 (3DM1X0, AbsoluteIndexedXX0, WRAP_NONE, AND)
+rOP16(3DM0X0, AbsoluteIndexedXX0, WRAP_NONE, AND)
+rOPM (3DSlow, AbsoluteIndexedXSlow, WRAP_NONE, AND)
+
+rOP8 (39M1X1, AbsoluteIndexedYX1, WRAP_NONE, AND)
+rOP16(39M0X1, AbsoluteIndexedYX1, WRAP_NONE, AND)
+rOP8 (39M1X0, AbsoluteIndexedYX0, WRAP_NONE, AND)
+rOP16(39M0X0, AbsoluteIndexedYX0, WRAP_NONE, AND)
+rOPM (39Slow, AbsoluteIndexedYSlow, WRAP_NONE, AND)
+
+rOP8 (2FM1, AbsoluteLong, WRAP_NONE, AND)
+rOP16(2FM0, AbsoluteLong, WRAP_NONE, AND)
+rOPM (2FSlow, AbsoluteLongSlow, WRAP_NONE, AND)
+
+rOP8 (3FM1, AbsoluteLongIndexedX, WRAP_NONE, AND)
+rOP16(3FM0, AbsoluteLongIndexedX, WRAP_NONE, AND)
+rOPM (3FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, AND)
+
+rOP8 (23M1, StackRelative, WRAP_NONE, AND)
+rOP16(23M0, StackRelative, WRAP_NONE, AND)
+rOPM (23Slow, StackRelativeSlow, WRAP_NONE, AND)
+
+rOP8 (33M1, StackRelativeIndirectIndexed, WRAP_NONE, AND)
+rOP16(33M0, StackRelativeIndirectIndexed, WRAP_NONE, AND)
+rOPM (33Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, AND)
+
+/* ASL ********************************************************************* */
+
+static void Op0AM1()
+{
+ AddCycles(ONE_CYCLE);
+ ICPU._Carry = (Registers.AL & 0x80) != 0;
+ Registers.AL <<= 1;
+ SetZN(Registers.AL);
+}
+
+static void Op0AM0()
+{
+ AddCycles(ONE_CYCLE);
+ ICPU._Carry = (Registers.AH & 0x80) != 0;
+ Registers.A.W <<= 1;
+ SetZN(Registers.A.W);
+}
+
+static void Op0ASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckMemory())
+ {
+ ICPU._Carry = (Registers.AL & 0x80) != 0;
+ Registers.AL <<= 1;
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ ICPU._Carry = (Registers.AH & 0x80) != 0;
+ Registers.A.W <<= 1;
+ SetZN(Registers.A.W);
+ }
+}
+
+mOP8 (06M1, Direct, WRAP_BANK, ASL)
+mOP16(06M0, Direct, WRAP_BANK, ASL)
+mOPM (06Slow, DirectSlow, WRAP_BANK, ASL)
+
+mOP8 (16E1, DirectIndexedXE1, WRAP_BANK, ASL)
+mOP8 (16E0M1, DirectIndexedXE0, WRAP_BANK, ASL)
+mOP16(16E0M0, DirectIndexedXE0, WRAP_BANK, ASL)
+mOPM (16Slow, DirectIndexedXSlow, WRAP_BANK, ASL)
+
+mOP8 (0EM1, Absolute, WRAP_NONE, ASL)
+mOP16(0EM0, Absolute, WRAP_NONE, ASL)
+mOPM (0ESlow, AbsoluteSlow, WRAP_NONE, ASL)
+
+mOP8 (1EM1X1, AbsoluteIndexedXX1, WRAP_NONE, ASL)
+mOP16(1EM0X1, AbsoluteIndexedXX1, WRAP_NONE, ASL)
+mOP8 (1EM1X0, AbsoluteIndexedXX0, WRAP_NONE, ASL)
+mOP16(1EM0X0, AbsoluteIndexedXX0, WRAP_NONE, ASL)
+mOPM (1ESlow, AbsoluteIndexedXSlow, WRAP_NONE, ASL)
+
+/* BIT ********************************************************************* */
+
+static void Op89M1()
+{
+ ICPU._Zero = Registers.AL & Immediate8(READ);
+}
+
+static void Op89M0()
+{
+ ICPU._Zero = (Registers.A.W & Immediate16(READ)) != 0;
+}
+
+static void Op89Slow()
+{
+ if (CheckMemory())
+ ICPU._Zero = Registers.AL & Immediate8Slow(READ);
+ else
+ ICPU._Zero = (Registers.A.W & Immediate16Slow(READ)) != 0;
+}
+
+rOP8 (24M1, Direct, WRAP_BANK, BIT)
+rOP16(24M0, Direct, WRAP_BANK, BIT)
+rOPM (24Slow, DirectSlow, WRAP_BANK, BIT)
+
+rOP8 (34E1, DirectIndexedXE1, WRAP_BANK, BIT)
+rOP8 (34E0M1, DirectIndexedXE0, WRAP_BANK, BIT)
+rOP16(34E0M0, DirectIndexedXE0, WRAP_BANK, BIT)
+rOPM (34Slow, DirectIndexedXSlow, WRAP_BANK, BIT)
+
+rOP8 (2CM1, Absolute, WRAP_NONE, BIT)
+rOP16(2CM0, Absolute, WRAP_NONE, BIT)
+rOPM (2CSlow, AbsoluteSlow, WRAP_NONE, BIT)
+
+rOP8 (3CM1X1, AbsoluteIndexedXX1, WRAP_NONE, BIT)
+rOP16(3CM0X1, AbsoluteIndexedXX1, WRAP_NONE, BIT)
+rOP8 (3CM1X0, AbsoluteIndexedXX0, WRAP_NONE, BIT)
+rOP16(3CM0X0, AbsoluteIndexedXX0, WRAP_NONE, BIT)
+rOPM (3CSlow, AbsoluteIndexedXSlow, WRAP_NONE, BIT)
+
+/* CMP ********************************************************************* */
+
+static void OpC9M1()
+{
+ int16_t Int16 = (int16_t) Registers.AL - (int16_t) Immediate8(READ);
+ ICPU._Carry = Int16 >= 0;
+ SetZN((uint8_t) Int16);
+}
+
+static void OpC9M0()
+{
+ int32_t Int32 = (int32_t) Registers.A.W - (int32_t) Immediate16(READ);
+ ICPU._Carry = Int32 >= 0;
+ SetZN((uint16_t) Int32);
+}
+
+static void OpC9Slow()
+{
+ if (CheckMemory())
+ {
+ int16_t Int16 = (int16_t) Registers.AL - (int16_t) Immediate8Slow(READ);
+ ICPU._Carry = Int16 >= 0;
+ SetZN((uint8_t) Int16);
+ }
+ else
+ {
+ int32_t Int32 = (int32_t) Registers.A.W - (int32_t) Immediate16Slow(READ);
+ ICPU._Carry = Int32 >= 0;
+ SetZN((uint16_t) Int32);
+ }
+}
+
+rOP8 (C5M1, Direct, WRAP_BANK, CMP)
+rOP16(C5M0, Direct, WRAP_BANK, CMP)
+rOPM (C5Slow, DirectSlow, WRAP_BANK, CMP)
+
+rOP8 (D5E1, DirectIndexedXE1, WRAP_BANK, CMP)
+rOP8 (D5E0M1, DirectIndexedXE0, WRAP_BANK, CMP)
+rOP16(D5E0M0, DirectIndexedXE0, WRAP_BANK, CMP)
+rOPM (D5Slow, DirectIndexedXSlow, WRAP_BANK, CMP)
+
+rOP8 (D2E1, DirectIndirectE1, WRAP_NONE, CMP)
+rOP8 (D2E0M1, DirectIndirectE0, WRAP_NONE, CMP)
+rOP16(D2E0M0, DirectIndirectE0, WRAP_NONE, CMP)
+rOPM (D2Slow, DirectIndirectSlow, WRAP_NONE, CMP)
+
+rOP8 (C1E1, DirectIndexedIndirectE1, WRAP_NONE, CMP)
+rOP8 (C1E0M1, DirectIndexedIndirectE0, WRAP_NONE, CMP)
+rOP16(C1E0M0, DirectIndexedIndirectE0, WRAP_NONE, CMP)
+rOPM (C1Slow, DirectIndexedIndirectSlow, WRAP_NONE, CMP)
+
+rOP8 (D1E1, DirectIndirectIndexedE1, WRAP_NONE, CMP)
+rOP8 (D1E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, CMP)
+rOP16(D1E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, CMP)
+rOP8 (D1E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, CMP)
+rOP16(D1E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, CMP)
+rOPM (D1Slow, DirectIndirectIndexedSlow, WRAP_NONE, CMP)
+
+rOP8 (C7M1, DirectIndirectLong, WRAP_NONE, CMP)
+rOP16(C7M0, DirectIndirectLong, WRAP_NONE, CMP)
+rOPM (C7Slow, DirectIndirectLongSlow, WRAP_NONE, CMP)
+
+rOP8 (D7M1, DirectIndirectIndexedLong, WRAP_NONE, CMP)
+rOP16(D7M0, DirectIndirectIndexedLong, WRAP_NONE, CMP)
+rOPM (D7Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, CMP)
+
+rOP8 (CDM1, Absolute, WRAP_NONE, CMP)
+rOP16(CDM0, Absolute, WRAP_NONE, CMP)
+rOPM (CDSlow, AbsoluteSlow, WRAP_NONE, CMP)
+
+rOP8 (DDM1X1, AbsoluteIndexedXX1, WRAP_NONE, CMP)
+rOP16(DDM0X1, AbsoluteIndexedXX1, WRAP_NONE, CMP)
+rOP8 (DDM1X0, AbsoluteIndexedXX0, WRAP_NONE, CMP)
+rOP16(DDM0X0, AbsoluteIndexedXX0, WRAP_NONE, CMP)
+rOPM (DDSlow, AbsoluteIndexedXSlow, WRAP_NONE, CMP)
+
+rOP8 (D9M1X1, AbsoluteIndexedYX1, WRAP_NONE, CMP)
+rOP16(D9M0X1, AbsoluteIndexedYX1, WRAP_NONE, CMP)
+rOP8 (D9M1X0, AbsoluteIndexedYX0, WRAP_NONE, CMP)
+rOP16(D9M0X0, AbsoluteIndexedYX0, WRAP_NONE, CMP)
+rOPM (D9Slow, AbsoluteIndexedYSlow, WRAP_NONE, CMP)
+
+rOP8 (CFM1, AbsoluteLong, WRAP_NONE, CMP)
+rOP16(CFM0, AbsoluteLong, WRAP_NONE, CMP)
+rOPM (CFSlow, AbsoluteLongSlow, WRAP_NONE, CMP)
+
+rOP8 (DFM1, AbsoluteLongIndexedX, WRAP_NONE, CMP)
+rOP16(DFM0, AbsoluteLongIndexedX, WRAP_NONE, CMP)
+rOPM (DFSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, CMP)
+
+rOP8 (C3M1, StackRelative, WRAP_NONE, CMP)
+rOP16(C3M0, StackRelative, WRAP_NONE, CMP)
+rOPM (C3Slow, StackRelativeSlow, WRAP_NONE, CMP)
+
+rOP8 (D3M1, StackRelativeIndirectIndexed, WRAP_NONE, CMP)
+rOP16(D3M0, StackRelativeIndirectIndexed, WRAP_NONE, CMP)
+rOPM (D3Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, CMP)
+
+/* CPX ********************************************************************* */
+
+static void OpE0X1()
+{
+ int16_t Int16 = (int16_t) Registers.XL - (int16_t) Immediate8(READ);
+ ICPU._Carry = Int16 >= 0;
+ SetZN((uint8_t) Int16);
+}
+
+static void OpE0X0()
+{
+ int32_t Int32 = (int32_t) Registers.X.W - (int32_t) Immediate16(READ);
+ ICPU._Carry = Int32 >= 0;
+ SetZN((uint16_t) Int32);
+}
+
+static void OpE0Slow()
+{
+ if (CheckIndex())
+ {
+ int16_t Int16 = (int16_t) Registers.XL - (int16_t) Immediate8Slow(READ);
+ ICPU._Carry = Int16 >= 0;
+ SetZN((uint8_t) Int16);
+ }
+ else
+ {
+ int32_t Int32 = (int32_t) Registers.X.W - (int32_t) Immediate16Slow(READ);
+ ICPU._Carry = Int32 >= 0;
+ SetZN((uint16_t) Int32);
+ }
+}
+
+rOP8 (E4X1, Direct, WRAP_BANK, CPX)
+rOP16(E4X0, Direct, WRAP_BANK, CPX)
+rOPX (E4Slow, DirectSlow, WRAP_BANK, CPX)
+
+rOP8 (ECX1, Absolute, WRAP_NONE, CPX)
+rOP16(ECX0, Absolute, WRAP_NONE, CPX)
+rOPX (ECSlow, AbsoluteSlow, WRAP_NONE, CPX)
+
+/* CPY ********************************************************************* */
+
+static void OpC0X1()
+{
+ int16_t Int16 = (int16_t) Registers.YL - (int16_t) Immediate8(READ);
+ ICPU._Carry = Int16 >= 0;
+ SetZN((uint8_t) Int16);
+}
+
+static void OpC0X0()
+{
+ int32_t Int32 = (int32_t) Registers.Y.W - (int32_t) Immediate16(READ);
+ ICPU._Carry = Int32 >= 0;
+ SetZN((uint16_t) Int32);
+}
+
+static void OpC0Slow()
+{
+ if (CheckIndex())
+ {
+ int16_t Int16 = (int16_t) Registers.YL - (int16_t) Immediate8Slow(READ);
+ ICPU._Carry = Int16 >= 0;
+ SetZN((uint8_t) Int16);
+ }
+ else
+ {
+ int32_t Int32 = (int32_t) Registers.Y.W - (int32_t) Immediate16Slow(READ);
+ ICPU._Carry = Int32 >= 0;
+ SetZN((uint16_t) Int32);
+ }
+}
+
+rOP8 (C4X1, Direct, WRAP_BANK, CPY)
+rOP16(C4X0, Direct, WRAP_BANK, CPY)
+rOPX (C4Slow, DirectSlow, WRAP_BANK, CPY)
+
+rOP8 (CCX1, Absolute, WRAP_NONE, CPY)
+rOP16(CCX0, Absolute, WRAP_NONE, CPY)
+rOPX (CCSlow, AbsoluteSlow, WRAP_NONE, CPY)
+
+/* DEC ********************************************************************* */
+
+static void Op3AM1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.AL--;
+ SetZN(Registers.AL);
+}
+
+static void Op3AM0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.A.W--;
+ SetZN(Registers.A.W);
+}
+
+static void Op3ASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckMemory())
+ {
+ Registers.AL--;
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ Registers.A.W--;
+ SetZN(Registers.A.W);
+ }
+}
+
+mOP8 (C6M1, Direct, WRAP_BANK, DEC)
+mOP16(C6M0, Direct, WRAP_BANK, DEC)
+mOPM (C6Slow, DirectSlow, WRAP_BANK, DEC)
+
+mOP8 (D6E1, DirectIndexedXE1, WRAP_BANK, DEC)
+mOP8 (D6E0M1, DirectIndexedXE0, WRAP_BANK, DEC)
+mOP16(D6E0M0, DirectIndexedXE0, WRAP_BANK, DEC)
+mOPM (D6Slow, DirectIndexedXSlow, WRAP_BANK, DEC)
+
+mOP8 (CEM1, Absolute, WRAP_NONE, DEC)
+mOP16(CEM0, Absolute, WRAP_NONE, DEC)
+mOPM (CESlow, AbsoluteSlow, WRAP_NONE, DEC)
+
+mOP8 (DEM1X1, AbsoluteIndexedXX1, WRAP_NONE, DEC)
+mOP16(DEM0X1, AbsoluteIndexedXX1, WRAP_NONE, DEC)
+mOP8 (DEM1X0, AbsoluteIndexedXX0, WRAP_NONE, DEC)
+mOP16(DEM0X0, AbsoluteIndexedXX0, WRAP_NONE, DEC)
+mOPM (DESlow, AbsoluteIndexedXSlow, WRAP_NONE, DEC)
+
+/* EOR ********************************************************************* */
+
+static void Op49M1()
+{
+ Registers.AL ^= Immediate8(READ);
+ SetZN(Registers.AL);
+}
+
+static void Op49M0()
+{
+ Registers.A.W ^= Immediate16(READ);
+ SetZN(Registers.A.W);
+}
+
+static void Op49Slow()
+{
+ if (CheckMemory())
+ {
+ Registers.AL ^= Immediate8Slow(READ);
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ Registers.A.W ^= Immediate16Slow(READ);
+ SetZN(Registers.A.W);
+ }
+}
+
+rOP8 (45M1, Direct, WRAP_BANK, EOR)
+rOP16(45M0, Direct, WRAP_BANK, EOR)
+rOPM (45Slow, DirectSlow, WRAP_BANK, EOR)
+
+rOP8 (55E1, DirectIndexedXE1, WRAP_BANK, EOR)
+rOP8 (55E0M1, DirectIndexedXE0, WRAP_BANK, EOR)
+rOP16(55E0M0, DirectIndexedXE0, WRAP_BANK, EOR)
+rOPM (55Slow, DirectIndexedXSlow, WRAP_BANK, EOR)
+
+rOP8 (52E1, DirectIndirectE1, WRAP_NONE, EOR)
+rOP8 (52E0M1, DirectIndirectE0, WRAP_NONE, EOR)
+rOP16(52E0M0, DirectIndirectE0, WRAP_NONE, EOR)
+rOPM (52Slow, DirectIndirectSlow, WRAP_NONE, EOR)
+
+rOP8 (41E1, DirectIndexedIndirectE1, WRAP_NONE, EOR)
+rOP8 (41E0M1, DirectIndexedIndirectE0, WRAP_NONE, EOR)
+rOP16(41E0M0, DirectIndexedIndirectE0, WRAP_NONE, EOR)
+rOPM (41Slow, DirectIndexedIndirectSlow, WRAP_NONE, EOR)
+
+rOP8 (51E1, DirectIndirectIndexedE1, WRAP_NONE, EOR)
+rOP8 (51E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, EOR)
+rOP16(51E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, EOR)
+rOP8 (51E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, EOR)
+rOP16(51E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, EOR)
+rOPM (51Slow, DirectIndirectIndexedSlow, WRAP_NONE, EOR)
+
+rOP8 (47M1, DirectIndirectLong, WRAP_NONE, EOR)
+rOP16(47M0, DirectIndirectLong, WRAP_NONE, EOR)
+rOPM (47Slow, DirectIndirectLongSlow, WRAP_NONE, EOR)
+
+rOP8 (57M1, DirectIndirectIndexedLong, WRAP_NONE, EOR)
+rOP16(57M0, DirectIndirectIndexedLong, WRAP_NONE, EOR)
+rOPM (57Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, EOR)
+
+rOP8 (4DM1, Absolute, WRAP_NONE, EOR)
+rOP16(4DM0, Absolute, WRAP_NONE, EOR)
+rOPM (4DSlow, AbsoluteSlow, WRAP_NONE, EOR)
+
+rOP8 (5DM1X1, AbsoluteIndexedXX1, WRAP_NONE, EOR)
+rOP16(5DM0X1, AbsoluteIndexedXX1, WRAP_NONE, EOR)
+rOP8 (5DM1X0, AbsoluteIndexedXX0, WRAP_NONE, EOR)
+rOP16(5DM0X0, AbsoluteIndexedXX0, WRAP_NONE, EOR)
+rOPM (5DSlow, AbsoluteIndexedXSlow, WRAP_NONE, EOR)
+
+rOP8 (59M1X1, AbsoluteIndexedYX1, WRAP_NONE, EOR)
+rOP16(59M0X1, AbsoluteIndexedYX1, WRAP_NONE, EOR)
+rOP8 (59M1X0, AbsoluteIndexedYX0, WRAP_NONE, EOR)
+rOP16(59M0X0, AbsoluteIndexedYX0, WRAP_NONE, EOR)
+rOPM (59Slow, AbsoluteIndexedYSlow, WRAP_NONE, EOR)
+
+rOP8 (4FM1, AbsoluteLong, WRAP_NONE, EOR)
+rOP16(4FM0, AbsoluteLong, WRAP_NONE, EOR)
+rOPM (4FSlow, AbsoluteLongSlow, WRAP_NONE, EOR)
+
+rOP8 (5FM1, AbsoluteLongIndexedX, WRAP_NONE, EOR)
+rOP16(5FM0, AbsoluteLongIndexedX, WRAP_NONE, EOR)
+rOPM (5FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, EOR)
+
+rOP8 (43M1, StackRelative, WRAP_NONE, EOR)
+rOP16(43M0, StackRelative, WRAP_NONE, EOR)
+rOPM (43Slow, StackRelativeSlow, WRAP_NONE, EOR)
+
+rOP8 (53M1, StackRelativeIndirectIndexed, WRAP_NONE, EOR)
+rOP16(53M0, StackRelativeIndirectIndexed, WRAP_NONE, EOR)
+rOPM (53Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, EOR)
+
+/* INC ********************************************************************* */
+
+static void Op1AM1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.AL++;
+ SetZN(Registers.AL);
+}
+
+static void Op1AM0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.A.W++;
+ SetZN(Registers.A.W);
+}
+
+static void Op1ASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckMemory())
+ {
+ Registers.AL++;
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ Registers.A.W++;
+ SetZN(Registers.A.W);
+ }
+}
+
+mOP8 (E6M1, Direct, WRAP_BANK, INC)
+mOP16(E6M0, Direct, WRAP_BANK, INC)
+mOPM (E6Slow, DirectSlow, WRAP_BANK, INC)
+
+mOP8 (F6E1, DirectIndexedXE1, WRAP_BANK, INC)
+mOP8 (F6E0M1, DirectIndexedXE0, WRAP_BANK, INC)
+mOP16(F6E0M0, DirectIndexedXE0, WRAP_BANK, INC)
+mOPM (F6Slow, DirectIndexedXSlow, WRAP_BANK, INC)
+
+mOP8 (EEM1, Absolute, WRAP_NONE, INC)
+mOP16(EEM0, Absolute, WRAP_NONE, INC)
+mOPM (EESlow, AbsoluteSlow, WRAP_NONE, INC)
+
+mOP8 (FEM1X1, AbsoluteIndexedXX1, WRAP_NONE, INC)
+mOP16(FEM0X1, AbsoluteIndexedXX1, WRAP_NONE, INC)
+mOP8 (FEM1X0, AbsoluteIndexedXX0, WRAP_NONE, INC)
+mOP16(FEM0X0, AbsoluteIndexedXX0, WRAP_NONE, INC)
+mOPM (FESlow, AbsoluteIndexedXSlow, WRAP_NONE, INC)
+
+/* LDA ********************************************************************* */
+
+static void OpA9M1()
+{
+ Registers.AL = Immediate8(READ);
+ SetZN(Registers.AL);
+}
+
+static void OpA9M0()
+{
+ Registers.A.W = Immediate16(READ);
+ SetZN(Registers.A.W);
+}
+
+static void OpA9Slow()
+{
+ if (CheckMemory())
+ {
+ Registers.AL = Immediate8Slow(READ);
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ Registers.A.W = Immediate16Slow(READ);
+ SetZN(Registers.A.W);
+ }
+}
+
+rOP8 (A5M1, Direct, WRAP_BANK, LDA)
+rOP16(A5M0, Direct, WRAP_BANK, LDA)
+rOPM (A5Slow, DirectSlow, WRAP_BANK, LDA)
+
+rOP8 (B5E1, DirectIndexedXE1, WRAP_BANK, LDA)
+rOP8 (B5E0M1, DirectIndexedXE0, WRAP_BANK, LDA)
+rOP16(B5E0M0, DirectIndexedXE0, WRAP_BANK, LDA)
+rOPM (B5Slow, DirectIndexedXSlow, WRAP_BANK, LDA)
+
+rOP8 (B2E1, DirectIndirectE1, WRAP_NONE, LDA)
+rOP8 (B2E0M1, DirectIndirectE0, WRAP_NONE, LDA)
+rOP16(B2E0M0, DirectIndirectE0, WRAP_NONE, LDA)
+rOPM (B2Slow, DirectIndirectSlow, WRAP_NONE, LDA)
+
+rOP8 (A1E1, DirectIndexedIndirectE1, WRAP_NONE, LDA)
+rOP8 (A1E0M1, DirectIndexedIndirectE0, WRAP_NONE, LDA)
+rOP16(A1E0M0, DirectIndexedIndirectE0, WRAP_NONE, LDA)
+rOPM (A1Slow, DirectIndexedIndirectSlow, WRAP_NONE, LDA)
+
+rOP8 (B1E1, DirectIndirectIndexedE1, WRAP_NONE, LDA)
+rOP8 (B1E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, LDA)
+rOP16(B1E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, LDA)
+rOP8 (B1E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, LDA)
+rOP16(B1E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, LDA)
+rOPM (B1Slow, DirectIndirectIndexedSlow, WRAP_NONE, LDA)
+
+rOP8 (A7M1, DirectIndirectLong, WRAP_NONE, LDA)
+rOP16(A7M0, DirectIndirectLong, WRAP_NONE, LDA)
+rOPM (A7Slow, DirectIndirectLongSlow, WRAP_NONE, LDA)
+
+rOP8 (B7M1, DirectIndirectIndexedLong, WRAP_NONE, LDA)
+rOP16(B7M0, DirectIndirectIndexedLong, WRAP_NONE, LDA)
+rOPM (B7Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, LDA)
+
+rOP8 (ADM1, Absolute, WRAP_NONE, LDA)
+rOP16(ADM0, Absolute, WRAP_NONE, LDA)
+rOPM (ADSlow, AbsoluteSlow, WRAP_NONE, LDA)
+
+rOP8 (BDM1X1, AbsoluteIndexedXX1, WRAP_NONE, LDA)
+rOP16(BDM0X1, AbsoluteIndexedXX1, WRAP_NONE, LDA)
+rOP8 (BDM1X0, AbsoluteIndexedXX0, WRAP_NONE, LDA)
+rOP16(BDM0X0, AbsoluteIndexedXX0, WRAP_NONE, LDA)
+rOPM (BDSlow, AbsoluteIndexedXSlow, WRAP_NONE, LDA)
+
+rOP8 (B9M1X1, AbsoluteIndexedYX1, WRAP_NONE, LDA)
+rOP16(B9M0X1, AbsoluteIndexedYX1, WRAP_NONE, LDA)
+rOP8 (B9M1X0, AbsoluteIndexedYX0, WRAP_NONE, LDA)
+rOP16(B9M0X0, AbsoluteIndexedYX0, WRAP_NONE, LDA)
+rOPM (B9Slow, AbsoluteIndexedYSlow, WRAP_NONE, LDA)
+
+rOP8 (AFM1, AbsoluteLong, WRAP_NONE, LDA)
+rOP16(AFM0, AbsoluteLong, WRAP_NONE, LDA)
+rOPM (AFSlow, AbsoluteLongSlow, WRAP_NONE, LDA)
+
+rOP8 (BFM1, AbsoluteLongIndexedX, WRAP_NONE, LDA)
+rOP16(BFM0, AbsoluteLongIndexedX, WRAP_NONE, LDA)
+rOPM (BFSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, LDA)
+
+rOP8 (A3M1, StackRelative, WRAP_NONE, LDA)
+rOP16(A3M0, StackRelative, WRAP_NONE, LDA)
+rOPM (A3Slow, StackRelativeSlow, WRAP_NONE, LDA)
+
+rOP8 (B3M1, StackRelativeIndirectIndexed, WRAP_NONE, LDA)
+rOP16(B3M0, StackRelativeIndirectIndexed, WRAP_NONE, LDA)
+rOPM (B3Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, LDA)
+
+/* LDX ********************************************************************* */
+
+static void OpA2X1()
+{
+ Registers.XL = Immediate8(READ);
+ SetZN(Registers.XL);
+}
+
+static void OpA2X0()
+{
+ Registers.X.W = Immediate16(READ);
+ SetZN(Registers.X.W);
+}
+
+static void OpA2Slow()
+{
+ if (CheckIndex())
+ {
+ Registers.XL = Immediate8Slow(READ);
+ SetZN(Registers.XL);
+ }
+ else
+ {
+ Registers.X.W = Immediate16Slow(READ);
+ SetZN(Registers.X.W);
+ }
+}
+
+rOP8 (A6X1, Direct, WRAP_BANK, LDX)
+rOP16(A6X0, Direct, WRAP_BANK, LDX)
+rOPX (A6Slow, DirectSlow, WRAP_BANK, LDX)
+
+rOP8 (B6E1, DirectIndexedYE1, WRAP_BANK, LDX)
+rOP8 (B6E0X1, DirectIndexedYE0, WRAP_BANK, LDX)
+rOP16(B6E0X0, DirectIndexedYE0, WRAP_BANK, LDX)
+rOPX (B6Slow, DirectIndexedYSlow, WRAP_BANK, LDX)
+
+rOP8 (AEX1, Absolute, WRAP_BANK, LDX)
+rOP16(AEX0, Absolute, WRAP_BANK, LDX)
+rOPX (AESlow, AbsoluteSlow, WRAP_BANK, LDX)
+
+rOP8 (BEX1, AbsoluteIndexedYX1, WRAP_BANK, LDX)
+rOP16(BEX0, AbsoluteIndexedYX0, WRAP_BANK, LDX)
+rOPX (BESlow, AbsoluteIndexedYSlow, WRAP_BANK, LDX)
+
+/* LDY ********************************************************************* */
+
+static void OpA0X1()
+{
+ Registers.YL = Immediate8(READ);
+ SetZN(Registers.YL);
+}
+
+static void OpA0X0()
+{
+ Registers.Y.W = Immediate16(READ);
+ SetZN(Registers.Y.W);
+}
+
+static void OpA0Slow()
+{
+ if (CheckIndex())
+ {
+ Registers.YL = Immediate8Slow(READ);
+ SetZN(Registers.YL);
+ }
+ else
+ {
+ Registers.Y.W = Immediate16Slow(READ);
+ SetZN(Registers.Y.W);
+ }
+}
+
+rOP8 (A4X1, Direct, WRAP_BANK, LDY)
+rOP16(A4X0, Direct, WRAP_BANK, LDY)
+rOPX (A4Slow, DirectSlow, WRAP_BANK, LDY)
+
+rOP8 (B4E1, DirectIndexedXE1, WRAP_BANK, LDY)
+rOP8 (B4E0X1, DirectIndexedXE0, WRAP_BANK, LDY)
+rOP16(B4E0X0, DirectIndexedXE0, WRAP_BANK, LDY)
+rOPX (B4Slow, DirectIndexedXSlow, WRAP_BANK, LDY)
+
+rOP8 (ACX1, Absolute, WRAP_BANK, LDY)
+rOP16(ACX0, Absolute, WRAP_BANK, LDY)
+rOPX (ACSlow, AbsoluteSlow, WRAP_BANK, LDY)
+
+rOP8 (BCX1, AbsoluteIndexedXX1, WRAP_BANK, LDY)
+rOP16(BCX0, AbsoluteIndexedXX0, WRAP_BANK, LDY)
+rOPX (BCSlow, AbsoluteIndexedXSlow, WRAP_BANK, LDY)
+
+/* LSR ********************************************************************* */
+
+static void Op4AM1()
+{
+ AddCycles(ONE_CYCLE);
+ ICPU._Carry = Registers.AL & 1;
+ Registers.AL >>= 1;
+ SetZN(Registers.AL);
+}
+
+static void Op4AM0()
+{
+ AddCycles(ONE_CYCLE);
+ ICPU._Carry = Registers.A.W & 1;
+ Registers.A.W >>= 1;
+ SetZN(Registers.A.W);
+}
+
+static void Op4ASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckMemory())
+ {
+ ICPU._Carry = Registers.AL & 1;
+ Registers.AL >>= 1;
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ ICPU._Carry = Registers.A.W & 1;
+ Registers.A.W >>= 1;
+ SetZN(Registers.A.W);
+ }
+}
+
+mOP8 (46M1, Direct, WRAP_BANK, LSR)
+mOP16(46M0, Direct, WRAP_BANK, LSR)
+mOPM (46Slow, DirectSlow, WRAP_BANK, LSR)
+
+mOP8 (56E1, DirectIndexedXE1, WRAP_BANK, LSR)
+mOP8 (56E0M1, DirectIndexedXE0, WRAP_BANK, LSR)
+mOP16(56E0M0, DirectIndexedXE0, WRAP_BANK, LSR)
+mOPM (56Slow, DirectIndexedXSlow, WRAP_BANK, LSR)
+
+mOP8 (4EM1, Absolute, WRAP_NONE, LSR)
+mOP16(4EM0, Absolute, WRAP_NONE, LSR)
+mOPM (4ESlow, AbsoluteSlow, WRAP_NONE, LSR)
+
+mOP8 (5EM1X1, AbsoluteIndexedXX1, WRAP_NONE, LSR)
+mOP16(5EM0X1, AbsoluteIndexedXX1, WRAP_NONE, LSR)
+mOP8 (5EM1X0, AbsoluteIndexedXX0, WRAP_NONE, LSR)
+mOP16(5EM0X0, AbsoluteIndexedXX0, WRAP_NONE, LSR)
+mOPM (5ESlow, AbsoluteIndexedXSlow, WRAP_NONE, LSR)
+
+/* ORA ********************************************************************* */
+
+static void Op09M1()
+{
+ Registers.AL |= Immediate8(READ);
+ SetZN(Registers.AL);
+}
+
+static void Op09M0()
+{
+ Registers.A.W |= Immediate16(READ);
+ SetZN(Registers.A.W);
+}
+
+static void Op09Slow()
+{
+ if (CheckMemory())
+ {
+ Registers.AL |= Immediate8Slow(READ);
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ Registers.A.W |= Immediate16Slow(READ);
+ SetZN(Registers.A.W);
+ }
+}
+
+rOP8 (05M1, Direct, WRAP_BANK, ORA)
+rOP16(05M0, Direct, WRAP_BANK, ORA)
+rOPM (05Slow, DirectSlow, WRAP_BANK, ORA)
+
+rOP8 (15E1, DirectIndexedXE1, WRAP_BANK, ORA)
+rOP8 (15E0M1, DirectIndexedXE0, WRAP_BANK, ORA)
+rOP16(15E0M0, DirectIndexedXE0, WRAP_BANK, ORA)
+rOPM (15Slow, DirectIndexedXSlow, WRAP_BANK, ORA)
+
+rOP8 (12E1, DirectIndirectE1, WRAP_NONE, ORA)
+rOP8 (12E0M1, DirectIndirectE0, WRAP_NONE, ORA)
+rOP16(12E0M0, DirectIndirectE0, WRAP_NONE, ORA)
+rOPM (12Slow, DirectIndirectSlow, WRAP_NONE, ORA)
+
+rOP8 (01E1, DirectIndexedIndirectE1, WRAP_NONE, ORA)
+rOP8 (01E0M1, DirectIndexedIndirectE0, WRAP_NONE, ORA)
+rOP16(01E0M0, DirectIndexedIndirectE0, WRAP_NONE, ORA)
+rOPM (01Slow, DirectIndexedIndirectSlow, WRAP_NONE, ORA)
+
+rOP8 (11E1, DirectIndirectIndexedE1, WRAP_NONE, ORA)
+rOP8 (11E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, ORA)
+rOP16(11E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, ORA)
+rOP8 (11E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, ORA)
+rOP16(11E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, ORA)
+rOPM (11Slow, DirectIndirectIndexedSlow, WRAP_NONE, ORA)
+
+rOP8 (07M1, DirectIndirectLong, WRAP_NONE, ORA)
+rOP16(07M0, DirectIndirectLong, WRAP_NONE, ORA)
+rOPM (07Slow, DirectIndirectLongSlow, WRAP_NONE, ORA)
+
+rOP8 (17M1, DirectIndirectIndexedLong, WRAP_NONE, ORA)
+rOP16(17M0, DirectIndirectIndexedLong, WRAP_NONE, ORA)
+rOPM (17Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, ORA)
+
+rOP8 (0DM1, Absolute, WRAP_NONE, ORA)
+rOP16(0DM0, Absolute, WRAP_NONE, ORA)
+rOPM (0DSlow, AbsoluteSlow, WRAP_NONE, ORA)
+
+rOP8 (1DM1X1, AbsoluteIndexedXX1, WRAP_NONE, ORA)
+rOP16(1DM0X1, AbsoluteIndexedXX1, WRAP_NONE, ORA)
+rOP8 (1DM1X0, AbsoluteIndexedXX0, WRAP_NONE, ORA)
+rOP16(1DM0X0, AbsoluteIndexedXX0, WRAP_NONE, ORA)
+rOPM (1DSlow, AbsoluteIndexedXSlow, WRAP_NONE, ORA)
+
+rOP8 (19M1X1, AbsoluteIndexedYX1, WRAP_NONE, ORA)
+rOP16(19M0X1, AbsoluteIndexedYX1, WRAP_NONE, ORA)
+rOP8 (19M1X0, AbsoluteIndexedYX0, WRAP_NONE, ORA)
+rOP16(19M0X0, AbsoluteIndexedYX0, WRAP_NONE, ORA)
+rOPM (19Slow, AbsoluteIndexedYSlow, WRAP_NONE, ORA)
+
+rOP8 (0FM1, AbsoluteLong, WRAP_NONE, ORA)
+rOP16(0FM0, AbsoluteLong, WRAP_NONE, ORA)
+rOPM (0FSlow, AbsoluteLongSlow, WRAP_NONE, ORA)
+
+rOP8 (1FM1, AbsoluteLongIndexedX, WRAP_NONE, ORA)
+rOP16(1FM0, AbsoluteLongIndexedX, WRAP_NONE, ORA)
+rOPM (1FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, ORA)
+
+rOP8 (03M1, StackRelative, WRAP_NONE, ORA)
+rOP16(03M0, StackRelative, WRAP_NONE, ORA)
+rOPM (03Slow, StackRelativeSlow, WRAP_NONE, ORA)
+
+rOP8 (13M1, StackRelativeIndirectIndexed, WRAP_NONE, ORA)
+rOP16(13M0, StackRelativeIndirectIndexed, WRAP_NONE, ORA)
+rOPM (13Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, ORA)
+
+/* ROL ********************************************************************* */
+
+static void Op2AM1()
+{
+ AddCycles(ONE_CYCLE);
+ uint16_t w = (((uint16_t) Registers.AL) << 1) | CheckCarry();
+ ICPU._Carry = w >= 0x100;
+ Registers.AL = (uint8_t) w;
+ SetZN(Registers.AL);
+}
+
+static void Op2AM0()
+{
+ AddCycles(ONE_CYCLE);
+ uint32_t w = (((uint32_t) Registers.A.W) << 1) | CheckCarry();
+ ICPU._Carry = w >= 0x10000;
+ Registers.A.W = (uint16_t) w;
+ SetZN(Registers.A.W);
+}
+
+static void Op2ASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckMemory())
+ {
+ uint16_t w = (((uint16_t) Registers.AL) << 1) | CheckCarry();
+ ICPU._Carry = w >= 0x100;
+ Registers.AL = (uint8_t) w;
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ uint32_t w = (((uint32_t) Registers.A.W) << 1) | CheckCarry();
+ ICPU._Carry = w >= 0x10000;
+ Registers.A.W = (uint16_t) w;
+ SetZN(Registers.A.W);
+ }
+}
+
+mOP8 (26M1, Direct, WRAP_BANK, ROL)
+mOP16(26M0, Direct, WRAP_BANK, ROL)
+mOPM (26Slow, DirectSlow, WRAP_BANK, ROL)
+
+mOP8 (36E1, DirectIndexedXE1, WRAP_BANK, ROL)
+mOP8 (36E0M1, DirectIndexedXE0, WRAP_BANK, ROL)
+mOP16(36E0M0, DirectIndexedXE0, WRAP_BANK, ROL)
+mOPM (36Slow, DirectIndexedXSlow, WRAP_BANK, ROL)
+
+mOP8 (2EM1, Absolute, WRAP_NONE, ROL)
+mOP16(2EM0, Absolute, WRAP_NONE, ROL)
+mOPM (2ESlow, AbsoluteSlow, WRAP_NONE, ROL)
+
+mOP8 (3EM1X1, AbsoluteIndexedXX1, WRAP_NONE, ROL)
+mOP16(3EM0X1, AbsoluteIndexedXX1, WRAP_NONE, ROL)
+mOP8 (3EM1X0, AbsoluteIndexedXX0, WRAP_NONE, ROL)
+mOP16(3EM0X0, AbsoluteIndexedXX0, WRAP_NONE, ROL)
+mOPM (3ESlow, AbsoluteIndexedXSlow, WRAP_NONE, ROL)
+
+/* ROR ********************************************************************* */
+
+static void Op6AM1()
+{
+ AddCycles(ONE_CYCLE);
+ uint16_t w = ((uint16_t) Registers.AL) | (((uint16_t) CheckCarry()) << 8);
+ ICPU._Carry = w & 1;
+ w >>= 1;
+ Registers.AL = (uint8_t) w;
+ SetZN(Registers.AL);
+}
+
+static void Op6AM0()
+{
+ AddCycles(ONE_CYCLE);
+ uint32_t w = ((uint32_t) Registers.A.W) | (((uint32_t) CheckCarry()) << 16);
+ ICPU._Carry = w & 1;
+ w >>= 1;
+ Registers.A.W = (uint16_t) w;
+ SetZN(Registers.A.W);
+}
+
+static void Op6ASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckMemory())
+ {
+ uint16_t w = ((uint16_t) Registers.AL) | (((uint16_t) CheckCarry()) << 8);
+ ICPU._Carry = w & 1;
+ w >>= 1;
+ Registers.AL = (uint8_t) w;
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ uint32_t w = ((uint32_t) Registers.A.W) | (((uint32_t) CheckCarry()) << 16);
+ ICPU._Carry = w & 1;
+ w >>= 1;
+ Registers.A.W = (uint16_t) w;
+ SetZN(Registers.A.W);
+ }
+}
+
+mOP8 (66M1, Direct, WRAP_BANK, ROR)
+mOP16(66M0, Direct, WRAP_BANK, ROR)
+mOPM (66Slow, DirectSlow, WRAP_BANK, ROR)
+
+mOP8 (76E1, DirectIndexedXE1, WRAP_BANK, ROR)
+mOP8 (76E0M1, DirectIndexedXE0, WRAP_BANK, ROR)
+mOP16(76E0M0, DirectIndexedXE0, WRAP_BANK, ROR)
+mOPM (76Slow, DirectIndexedXSlow, WRAP_BANK, ROR)
+
+mOP8 (6EM1, Absolute, WRAP_NONE, ROR)
+mOP16(6EM0, Absolute, WRAP_NONE, ROR)
+mOPM (6ESlow, AbsoluteSlow, WRAP_NONE, ROR)
+
+mOP8 (7EM1X1, AbsoluteIndexedXX1, WRAP_NONE, ROR)
+mOP16(7EM0X1, AbsoluteIndexedXX1, WRAP_NONE, ROR)
+mOP8 (7EM1X0, AbsoluteIndexedXX0, WRAP_NONE, ROR)
+mOP16(7EM0X0, AbsoluteIndexedXX0, WRAP_NONE, ROR)
+mOPM (7ESlow, AbsoluteIndexedXSlow, WRAP_NONE, ROR)
+
+/* SBC ********************************************************************* */
+
+static void OpE9M1()
+{
+ SBC(Immediate8(READ));
+}
+
+static void OpE9M0()
+{
+ SBC(Immediate16(READ));
+}
+
+static void OpE9Slow()
+{
+ if (CheckMemory())
+ SBC(Immediate8Slow(READ));
+ else
+ SBC(Immediate16Slow(READ));
+}
+
+rOP8 (E5M1, Direct, WRAP_BANK, SBC)
+rOP16(E5M0, Direct, WRAP_BANK, SBC)
+rOPM (E5Slow, DirectSlow, WRAP_BANK, SBC)
+
+rOP8 (F5E1, DirectIndexedXE1, WRAP_BANK, SBC)
+rOP8 (F5E0M1, DirectIndexedXE0, WRAP_BANK, SBC)
+rOP16(F5E0M0, DirectIndexedXE0, WRAP_BANK, SBC)
+rOPM (F5Slow, DirectIndexedXSlow, WRAP_BANK, SBC)
+
+rOP8 (F2E1, DirectIndirectE1, WRAP_NONE, SBC)
+rOP8 (F2E0M1, DirectIndirectE0, WRAP_NONE, SBC)
+rOP16(F2E0M0, DirectIndirectE0, WRAP_NONE, SBC)
+rOPM (F2Slow, DirectIndirectSlow, WRAP_NONE, SBC)
+
+rOP8 (E1E1, DirectIndexedIndirectE1, WRAP_NONE, SBC)
+rOP8 (E1E0M1, DirectIndexedIndirectE0, WRAP_NONE, SBC)
+rOP16(E1E0M0, DirectIndexedIndirectE0, WRAP_NONE, SBC)
+rOPM (E1Slow, DirectIndexedIndirectSlow, WRAP_NONE, SBC)
+
+rOP8 (F1E1, DirectIndirectIndexedE1, WRAP_NONE, SBC)
+rOP8 (F1E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, SBC)
+rOP16(F1E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, SBC)
+rOP8 (F1E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, SBC)
+rOP16(F1E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, SBC)
+rOPM (F1Slow, DirectIndirectIndexedSlow, WRAP_NONE, SBC)
+
+rOP8 (E7M1, DirectIndirectLong, WRAP_NONE, SBC)
+rOP16(E7M0, DirectIndirectLong, WRAP_NONE, SBC)
+rOPM (E7Slow, DirectIndirectLongSlow, WRAP_NONE, SBC)
+
+rOP8 (F7M1, DirectIndirectIndexedLong, WRAP_NONE, SBC)
+rOP16(F7M0, DirectIndirectIndexedLong, WRAP_NONE, SBC)
+rOPM (F7Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, SBC)
+
+rOP8 (EDM1, Absolute, WRAP_NONE, SBC)
+rOP16(EDM0, Absolute, WRAP_NONE, SBC)
+rOPM (EDSlow, AbsoluteSlow, WRAP_NONE, SBC)
+
+rOP8 (FDM1X1, AbsoluteIndexedXX1, WRAP_NONE, SBC)
+rOP16(FDM0X1, AbsoluteIndexedXX1, WRAP_NONE, SBC)
+rOP8 (FDM1X0, AbsoluteIndexedXX0, WRAP_NONE, SBC)
+rOP16(FDM0X0, AbsoluteIndexedXX0, WRAP_NONE, SBC)
+rOPM (FDSlow, AbsoluteIndexedXSlow, WRAP_NONE, SBC)
+
+rOP8 (F9M1X1, AbsoluteIndexedYX1, WRAP_NONE, SBC)
+rOP16(F9M0X1, AbsoluteIndexedYX1, WRAP_NONE, SBC)
+rOP8 (F9M1X0, AbsoluteIndexedYX0, WRAP_NONE, SBC)
+rOP16(F9M0X0, AbsoluteIndexedYX0, WRAP_NONE, SBC)
+rOPM (F9Slow, AbsoluteIndexedYSlow, WRAP_NONE, SBC)
+
+rOP8 (EFM1, AbsoluteLong, WRAP_NONE, SBC)
+rOP16(EFM0, AbsoluteLong, WRAP_NONE, SBC)
+rOPM (EFSlow, AbsoluteLongSlow, WRAP_NONE, SBC)
+
+rOP8 (FFM1, AbsoluteLongIndexedX, WRAP_NONE, SBC)
+rOP16(FFM0, AbsoluteLongIndexedX, WRAP_NONE, SBC)
+rOPM (FFSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, SBC)
+
+rOP8 (E3M1, StackRelative, WRAP_NONE, SBC)
+rOP16(E3M0, StackRelative, WRAP_NONE, SBC)
+rOPM (E3Slow, StackRelativeSlow, WRAP_NONE, SBC)
+
+rOP8 (F3M1, StackRelativeIndirectIndexed, WRAP_NONE, SBC)
+rOP16(F3M0, StackRelativeIndirectIndexed, WRAP_NONE, SBC)
+rOPM (F3Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, SBC)
+
+/* STA ********************************************************************* */
+
+wOP8 (85M1, Direct, WRAP_BANK, STA)
+wOP16(85M0, Direct, WRAP_BANK, STA)
+wOPM (85Slow, DirectSlow, WRAP_BANK, STA)
+
+wOP8 (95E1, DirectIndexedXE1, WRAP_BANK, STA)
+wOP8 (95E0M1, DirectIndexedXE0, WRAP_BANK, STA)
+wOP16(95E0M0, DirectIndexedXE0, WRAP_BANK, STA)
+wOPM (95Slow, DirectIndexedXSlow, WRAP_BANK, STA)
+
+wOP8 (92E1, DirectIndirectE1, WRAP_NONE, STA)
+wOP8 (92E0M1, DirectIndirectE0, WRAP_NONE, STA)
+wOP16(92E0M0, DirectIndirectE0, WRAP_NONE, STA)
+wOPM (92Slow, DirectIndirectSlow, WRAP_NONE, STA)
+
+wOP8 (81E1, DirectIndexedIndirectE1, WRAP_NONE, STA)
+wOP8 (81E0M1, DirectIndexedIndirectE0, WRAP_NONE, STA)
+wOP16(81E0M0, DirectIndexedIndirectE0, WRAP_NONE, STA)
+wOPM (81Slow, DirectIndexedIndirectSlow, WRAP_NONE, STA)
+
+wOP8 (91E1, DirectIndirectIndexedE1, WRAP_NONE, STA)
+wOP8 (91E0M1X1, DirectIndirectIndexedE0X1, WRAP_NONE, STA)
+wOP16(91E0M0X1, DirectIndirectIndexedE0X1, WRAP_NONE, STA)
+wOP8 (91E0M1X0, DirectIndirectIndexedE0X0, WRAP_NONE, STA)
+wOP16(91E0M0X0, DirectIndirectIndexedE0X0, WRAP_NONE, STA)
+wOPM (91Slow, DirectIndirectIndexedSlow, WRAP_NONE, STA)
+
+wOP8 (87M1, DirectIndirectLong, WRAP_NONE, STA)
+wOP16(87M0, DirectIndirectLong, WRAP_NONE, STA)
+wOPM (87Slow, DirectIndirectLongSlow, WRAP_NONE, STA)
+
+wOP8 (97M1, DirectIndirectIndexedLong, WRAP_NONE, STA)
+wOP16(97M0, DirectIndirectIndexedLong, WRAP_NONE, STA)
+wOPM (97Slow, DirectIndirectIndexedLongSlow, WRAP_NONE, STA)
+
+wOP8 (8DM1, Absolute, WRAP_NONE, STA)
+wOP16(8DM0, Absolute, WRAP_NONE, STA)
+wOPM (8DSlow, AbsoluteSlow, WRAP_NONE, STA)
+
+wOP8 (9DM1X1, AbsoluteIndexedXX1, WRAP_NONE, STA)
+wOP16(9DM0X1, AbsoluteIndexedXX1, WRAP_NONE, STA)
+wOP8 (9DM1X0, AbsoluteIndexedXX0, WRAP_NONE, STA)
+wOP16(9DM0X0, AbsoluteIndexedXX0, WRAP_NONE, STA)
+wOPM (9DSlow, AbsoluteIndexedXSlow, WRAP_NONE, STA)
+
+wOP8 (99M1X1, AbsoluteIndexedYX1, WRAP_NONE, STA)
+wOP16(99M0X1, AbsoluteIndexedYX1, WRAP_NONE, STA)
+wOP8 (99M1X0, AbsoluteIndexedYX0, WRAP_NONE, STA)
+wOP16(99M0X0, AbsoluteIndexedYX0, WRAP_NONE, STA)
+wOPM (99Slow, AbsoluteIndexedYSlow, WRAP_NONE, STA)
+
+wOP8 (8FM1, AbsoluteLong, WRAP_NONE, STA)
+wOP16(8FM0, AbsoluteLong, WRAP_NONE, STA)
+wOPM (8FSlow, AbsoluteLongSlow, WRAP_NONE, STA)
+
+wOP8 (9FM1, AbsoluteLongIndexedX, WRAP_NONE, STA)
+wOP16(9FM0, AbsoluteLongIndexedX, WRAP_NONE, STA)
+wOPM (9FSlow, AbsoluteLongIndexedXSlow, WRAP_NONE, STA)
+
+wOP8 (83M1, StackRelative, WRAP_NONE, STA)
+wOP16(83M0, StackRelative, WRAP_NONE, STA)
+wOPM (83Slow, StackRelativeSlow, WRAP_NONE, STA)
+
+wOP8 (93M1, StackRelativeIndirectIndexed, WRAP_NONE, STA)
+wOP16(93M0, StackRelativeIndirectIndexed, WRAP_NONE, STA)
+wOPM (93Slow, StackRelativeIndirectIndexedSlow, WRAP_NONE, STA)
+
+/* STX ********************************************************************* */
+
+wOP8 (86X1, Direct, WRAP_BANK, STX)
+wOP16(86X0, Direct, WRAP_BANK, STX)
+wOPX (86Slow, DirectSlow, WRAP_BANK, STX)
+
+wOP8 (96E1, DirectIndexedYE1, WRAP_BANK, STX)
+wOP8 (96E0X1, DirectIndexedYE0, WRAP_BANK, STX)
+wOP16(96E0X0, DirectIndexedYE0, WRAP_BANK, STX)
+wOPX (96Slow, DirectIndexedYSlow, WRAP_BANK, STX)
+
+wOP8 (8EX1, Absolute, WRAP_BANK, STX)
+wOP16(8EX0, Absolute, WRAP_BANK, STX)
+wOPX (8ESlow, AbsoluteSlow, WRAP_BANK, STX)
+
+/* STY ********************************************************************* */
+
+wOP8 (84X1, Direct, WRAP_BANK, STY)
+wOP16(84X0, Direct, WRAP_BANK, STY)
+wOPX (84Slow, DirectSlow, WRAP_BANK, STY)
+
+wOP8 (94E1, DirectIndexedXE1, WRAP_BANK, STY)
+wOP8 (94E0X1, DirectIndexedXE0, WRAP_BANK, STY)
+wOP16(94E0X0, DirectIndexedXE0, WRAP_BANK, STY)
+wOPX (94Slow, DirectIndexedXSlow, WRAP_BANK, STY)
+
+wOP8 (8CX1, Absolute, WRAP_BANK, STY)
+wOP16(8CX0, Absolute, WRAP_BANK, STY)
+wOPX (8CSlow, AbsoluteSlow, WRAP_BANK, STY)
+
+/* STZ ********************************************************************* */
+
+wOP8 (64M1, Direct, WRAP_BANK, STZ)
+wOP16(64M0, Direct, WRAP_BANK, STZ)
+wOPM (64Slow, DirectSlow, WRAP_BANK, STZ)
+
+wOP8 (74E1, DirectIndexedXE1, WRAP_BANK, STZ)
+wOP8 (74E0M1, DirectIndexedXE0, WRAP_BANK, STZ)
+wOP16(74E0M0, DirectIndexedXE0, WRAP_BANK, STZ)
+wOPM (74Slow, DirectIndexedXSlow, WRAP_BANK, STZ)
+
+wOP8 (9CM1, Absolute, WRAP_NONE, STZ)
+wOP16(9CM0, Absolute, WRAP_NONE, STZ)
+wOPM (9CSlow, AbsoluteSlow, WRAP_NONE, STZ)
+
+wOP8 (9EM1X1, AbsoluteIndexedXX1, WRAP_NONE, STZ)
+wOP16(9EM0X1, AbsoluteIndexedXX1, WRAP_NONE, STZ)
+wOP8 (9EM1X0, AbsoluteIndexedXX0, WRAP_NONE, STZ)
+wOP16(9EM0X0, AbsoluteIndexedXX0, WRAP_NONE, STZ)
+wOPM (9ESlow, AbsoluteIndexedXSlow, WRAP_NONE, STZ)
+
+/* TRB ********************************************************************* */
+
+mOP8 (14M1, Direct, WRAP_BANK, TRB)
+mOP16(14M0, Direct, WRAP_BANK, TRB)
+mOPM (14Slow, DirectSlow, WRAP_BANK, TRB)
+
+mOP8 (1CM1, Absolute, WRAP_BANK, TRB)
+mOP16(1CM0, Absolute, WRAP_BANK, TRB)
+mOPM (1CSlow, AbsoluteSlow, WRAP_BANK, TRB)
+
+/* TSB ********************************************************************* */
+
+mOP8 (04M1, Direct, WRAP_BANK, TSB)
+mOP16(04M0, Direct, WRAP_BANK, TSB)
+mOPM (04Slow, DirectSlow, WRAP_BANK, TSB)
+
+mOP8 (0CM1, Absolute, WRAP_BANK, TSB)
+mOP16(0CM0, Absolute, WRAP_BANK, TSB)
+mOPM (0CSlow, AbsoluteSlow, WRAP_BANK, TSB)
+
+/* Branch Instructions ***************************************************** */
+
+// BCC
+bOP(90E0, Relative, !CheckCarry(), 0, 0)
+bOP(90E1, Relative, !CheckCarry(), 0, 1)
+bOP(90Slow, RelativeSlow, !CheckCarry(), 0, CheckEmulation())
+
+// BCS
+bOP(B0E0, Relative, CheckCarry(), 0, 0)
+bOP(B0E1, Relative, CheckCarry(), 0, 1)
+bOP(B0Slow, RelativeSlow, CheckCarry(), 0, CheckEmulation())
+
+// BEQ
+bOP(F0E0, Relative, CheckZero(), 2, 0)
+bOP(F0E1, Relative, CheckZero(), 2, 1)
+bOP(F0Slow, RelativeSlow, CheckZero(), 2, CheckEmulation())
+
+// BMI
+bOP(30E0, Relative, CheckNegative(), 1, 0)
+bOP(30E1, Relative, CheckNegative(), 1, 1)
+bOP(30Slow, RelativeSlow, CheckNegative(), 1, CheckEmulation())
+
+// BNE
+bOP(D0E0, Relative, !CheckZero(), 1, 0)
+bOP(D0E1, Relative, !CheckZero(), 1, 1)
+bOP(D0Slow, RelativeSlow, !CheckZero(), 1, CheckEmulation())
+
+// BPL
+bOP(10E0, Relative, !CheckNegative(), 1, 0)
+bOP(10E1, Relative, !CheckNegative(), 1, 1)
+bOP(10Slow, RelativeSlow, !CheckNegative(), 1, CheckEmulation())
+
+// BRA
+bOP(80E0, Relative, 1, X, 0)
+bOP(80E1, Relative, 1, X, 1)
+bOP(80Slow, RelativeSlow, 1, X, CheckEmulation())
+
+// BVC
+bOP(50E0, Relative, !CheckOverflow(), 0, 0)
+bOP(50E1, Relative, !CheckOverflow(), 0, 1)
+bOP(50Slow, RelativeSlow, !CheckOverflow(), 0, CheckEmulation())
+
+// BVS
+bOP(70E0, Relative, CheckOverflow(), 0, 0)
+bOP(70E1, Relative, CheckOverflow(), 0, 1)
+bOP(70Slow, RelativeSlow, CheckOverflow(), 0, CheckEmulation())
+
+// BRL
+static void Op82()
+{
+ S9xSetPCBase(ICPU.ShiftedPB + RelativeLong(JUMP));
+}
+
+static void Op82Slow()
+{
+ S9xSetPCBase(ICPU.ShiftedPB + RelativeLongSlow(JUMP));
+}
+
+/* Flag Instructions ******************************************************* */
+
+// CLC
+static void Op18()
+{
+ ClearCarry();
+ AddCycles(ONE_CYCLE);
+}
+
+// SEC
+static void Op38()
+{
+ SetCarry();
+ AddCycles(ONE_CYCLE);
+}
+
+// CLD
+static void OpD8()
+{
+ ClearDecimal();
+ AddCycles(ONE_CYCLE);
+}
+
+// SED
+static void OpF8()
+{
+ SetDecimal();
+ AddCycles(ONE_CYCLE);
+#ifdef DEBUGGER
+ missing.decimal_mode = 1;
+#endif
+}
+
+// CLI
+static void Op58()
+{
+ ClearIRQ();
+ AddCycles(ONE_CYCLE);
+ CHECK_FOR_IRQ();
+}
+
+// SEI
+static void Op78()
+{
+ SetIRQ();
+ AddCycles(ONE_CYCLE);
+}
+
+// CLV
+static void OpB8()
+{
+ ClearOverflow();
+ AddCycles(ONE_CYCLE);
+}
+
+/* DEX/DEY ***************************************************************** */
+
+static void OpCAX1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.XL--;
+ SetZN(Registers.XL);
+}
+
+static void OpCAX0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.X.W--;
+ SetZN(Registers.X.W);
+}
+
+static void OpCASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckIndex())
+ {
+ Registers.XL--;
+ SetZN(Registers.XL);
+ }
+ else
+ {
+ Registers.X.W--;
+ SetZN(Registers.X.W);
+ }
+}
+
+static void Op88X1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.YL--;
+ SetZN(Registers.YL);
+}
+
+static void Op88X0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.Y.W--;
+ SetZN(Registers.Y.W);
+}
+
+static void Op88Slow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckIndex())
+ {
+ Registers.YL--;
+ SetZN(Registers.YL);
+ }
+ else
+ {
+ Registers.Y.W--;
+ SetZN(Registers.Y.W);
+ }
+}
+
+/* INX/INY ***************************************************************** */
+
+static void OpE8X1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.XL++;
+ SetZN(Registers.XL);
+}
+
+static void OpE8X0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.X.W++;
+ SetZN(Registers.X.W);
+}
+
+static void OpE8Slow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckIndex())
+ {
+ Registers.XL++;
+ SetZN(Registers.XL);
+ }
+ else
+ {
+ Registers.X.W++;
+ SetZN(Registers.X.W);
+ }
+}
+
+static void OpC8X1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.YL++;
+ SetZN(Registers.YL);
+}
+
+static void OpC8X0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.Y.W++;
+ SetZN(Registers.Y.W);
+}
+
+static void OpC8Slow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckIndex())
+ {
+ Registers.YL--;
+ SetZN(Registers.YL);
+ }
+ else
+ {
+ Registers.Y.W--;
+ SetZN(Registers.Y.W);
+ }
+}
+
+/* NOP ********************************************************************* */
+
+static void OpEA()
+{
+ AddCycles(ONE_CYCLE);
+}
+
+/* PUSH Instructions ******************************************************* */
+
+#define PushW(w) \
+ S9xSetWord(w, Registers.S.W - 1, WRAP_BANK, WRITE_10); \
+ Registers.S.W -= 2;
+
+#define PushWE(w) \
+ Registers.SL--; \
+ S9xSetWord(w, Registers.S.W, WRAP_PAGE, WRITE_10); \
+ Registers.SL--;
+
+#define PushB(b) \
+ S9xSetByte(b, Registers.S.W--);
+
+#define PushBE(b) \
+ S9xSetByte(b, Registers.S.W); \
+ Registers.SL--;
+
+// PEA
+static void OpF4E0()
+{
+ uint16_t val = (uint16_t) Absolute(NONE);
+ PushW(val);
+ OpenBus = val & 0xff;
+}
+
+static void OpF4E1()
+{
+ // Note: PEA is a new instruction,
+ // and so doesn't respect the emu-mode stack bounds.
+ uint16_t val = (uint16_t) Absolute(NONE);
+ PushW(val);
+ OpenBus = val & 0xff;
+ Registers.SH = 1;
+}
+
+static void OpF4Slow()
+{
+ uint16_t val = (uint16_t) AbsoluteSlow(NONE);
+ PushW(val);
+ OpenBus = val & 0xff;
+ if (CheckEmulation())
+ Registers.SH = 1;
+}
+
+// PEI
+static void OpD4E0()
+{
+ uint16_t val = (uint16_t) DirectIndirectE0(NONE);
+ PushW(val);
+ OpenBus = val & 0xff;
+}
+
+static void OpD4E1()
+{
+ // Note: PEI is a new instruction,
+ // and so doesn't respect the emu-mode stack bounds.
+ uint16_t val = (uint16_t) DirectIndirectE1(NONE);
+ PushW(val);
+ OpenBus = val & 0xff;
+ Registers.SH = 1;
+}
+
+static void OpD4Slow()
+{
+ uint16_t val = (uint16_t) DirectIndirectSlow(NONE);
+ PushW(val);
+ OpenBus = val & 0xff;
+ if (CheckEmulation())
+ Registers.SH = 1;
+}
+
+// PER
+static void Op62E0()
+{
+ uint16_t val = (uint16_t) RelativeLong(NONE);
+ PushW(val);
+ OpenBus = val & 0xff;
+}
+
+static void Op62E1()
+{
+ // Note: PER is a new instruction,
+ // and so doesn't respect the emu-mode stack bounds.
+ uint16_t val = (uint16_t) RelativeLong(NONE);
+ PushW(val);
+ OpenBus = val & 0xff;
+ Registers.SH = 1;
+}
+
+static void Op62Slow()
+{
+ uint16_t val = (uint16_t) RelativeLongSlow(NONE);
+ PushW(val);
+ OpenBus = val & 0xff;
+ if (CheckEmulation())
+ Registers.SH = 1;
+}
+
+// PHA
+static void Op48E1()
+{
+ AddCycles(ONE_CYCLE);
+ PushBE(Registers.AL);
+ OpenBus = Registers.AL;
+}
+
+static void Op48E0M1()
+{
+ AddCycles(ONE_CYCLE);
+ PushB(Registers.AL);
+ OpenBus = Registers.AL;
+}
+
+static void Op48E0M0()
+{
+ AddCycles(ONE_CYCLE);
+ PushW(Registers.A.W);
+ OpenBus = Registers.AL;
+}
+
+static void Op48Slow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ PushBE(Registers.AL);
+ }
+ else
+ if (CheckMemory())
+ {
+ PushB(Registers.AL);
+ }
+ else
+ {
+ PushW(Registers.A.W);
+ }
+
+ OpenBus = Registers.AL;
+}
+
+// PHB
+static void Op8BE1()
+{
+ AddCycles(ONE_CYCLE);
+ PushBE(Registers.DB);
+ OpenBus = Registers.DB;
+}
+
+static void Op8BE0()
+{
+ AddCycles(ONE_CYCLE);
+ PushB(Registers.DB);
+ OpenBus = Registers.DB;
+}
+
+static void Op8BSlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ PushBE(Registers.DB);
+ }
+ else
+ {
+ PushB(Registers.DB);
+ }
+
+ OpenBus = Registers.DB;
+}
+
+// PHD
+static void Op0BE0()
+{
+ AddCycles(ONE_CYCLE);
+ PushW(Registers.D.W);
+ OpenBus = Registers.DL;
+}
+
+static void Op0BE1()
+{
+ // Note: PHD is a new instruction,
+ // and so doesn't respect the emu-mode stack bounds.
+ AddCycles(ONE_CYCLE);
+ PushW(Registers.D.W);
+ OpenBus = Registers.DL;
+ Registers.SH = 1;
+}
+
+static void Op0BSlow()
+{
+ AddCycles(ONE_CYCLE);
+ PushW(Registers.D.W);
+ OpenBus = Registers.DL;
+ if (CheckEmulation())
+ Registers.SH = 1;
+}
+
+// PHK
+static void Op4BE1()
+{
+ AddCycles(ONE_CYCLE);
+ PushBE(Registers.PB);
+ OpenBus = Registers.PB;
+}
+
+static void Op4BE0()
+{
+ AddCycles(ONE_CYCLE);
+ PushB(Registers.PB);
+ OpenBus = Registers.PB;
+}
+
+static void Op4BSlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ PushBE(Registers.PB);
+ }
+ else
+ {
+ PushB(Registers.PB);
+ }
+
+ OpenBus = Registers.PB;
+}
+
+// PHP
+static void Op08E0()
+{
+ S9xPackStatus();
+ AddCycles(ONE_CYCLE);
+ PushB(Registers.PL);
+ OpenBus = Registers.PL;
+}
+
+static void Op08E1()
+{
+ S9xPackStatus();
+ AddCycles(ONE_CYCLE);
+ PushBE(Registers.PL);
+ OpenBus = Registers.PL;
+}
+
+static void Op08Slow()
+{
+ S9xPackStatus();
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ PushBE(Registers.PL);
+ }
+ else
+ {
+ PushB(Registers.PL);
+ }
+
+ OpenBus = Registers.PL;
+}
+
+// PHX
+static void OpDAE1()
+{
+ AddCycles(ONE_CYCLE);
+ PushBE(Registers.XL);
+ OpenBus = Registers.XL;
+}
+
+static void OpDAE0X1()
+{
+ AddCycles(ONE_CYCLE);
+ PushB(Registers.XL);
+ OpenBus = Registers.XL;
+}
+
+static void OpDAE0X0()
+{
+ AddCycles(ONE_CYCLE);
+ PushW(Registers.X.W);
+ OpenBus = Registers.XL;
+}
+
+static void OpDASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ PushBE(Registers.XL);
+ }
+ else
+ if (CheckIndex())
+ {
+ PushB(Registers.XL);
+ }
+ else
+ {
+ PushW(Registers.X.W);
+ }
+
+ OpenBus = Registers.XL;
+}
+
+// PHY
+static void Op5AE1()
+{
+ AddCycles(ONE_CYCLE);
+ PushBE(Registers.YL);
+ OpenBus = Registers.YL;
+}
+
+static void Op5AE0X1()
+{
+ AddCycles(ONE_CYCLE);
+ PushB(Registers.YL);
+ OpenBus = Registers.YL;
+}
+
+static void Op5AE0X0()
+{
+ AddCycles(ONE_CYCLE);
+ PushW(Registers.Y.W);
+ OpenBus = Registers.YL;
+}
+
+static void Op5ASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ PushBE(Registers.YL);
+ }
+ else
+ if (CheckIndex())
+ {
+ PushB(Registers.YL);
+ }
+ else
+ {
+ PushW(Registers.Y.W);
+ }
+
+ OpenBus = Registers.YL;
+}
+
+/* PULL Instructions ******************************************************* */
+
+#define PullW(w) \
+ w = S9xGetWord(Registers.S.W + 1, WRAP_BANK); \
+ Registers.S.W += 2;
+
+#define PullWE(w) \
+ Registers.SL++; \
+ w = S9xGetWord(Registers.S.W, WRAP_PAGE); \
+ Registers.SL++;
+
+#define PullB(b) \
+ b = S9xGetByte(++Registers.S.W);
+
+#define PullBE(b) \
+ Registers.SL++; \
+ b = S9xGetByte(Registers.S.W);
+
+// PLA
+static void Op68E1()
+{
+ AddCycles(TWO_CYCLES);
+ PullBE(Registers.AL);
+ SetZN(Registers.AL);
+ OpenBus = Registers.AL;
+}
+
+static void Op68E0M1()
+{
+ AddCycles(TWO_CYCLES);
+ PullB(Registers.AL);
+ SetZN(Registers.AL);
+ OpenBus = Registers.AL;
+}
+
+static void Op68E0M0()
+{
+ AddCycles(TWO_CYCLES);
+ PullW(Registers.A.W);
+ SetZN(Registers.A.W);
+ OpenBus = Registers.AH;
+}
+
+static void Op68Slow()
+{
+ AddCycles(TWO_CYCLES);
+
+ if (CheckEmulation())
+ {
+ PullBE(Registers.AL);
+ SetZN(Registers.AL);
+ OpenBus = Registers.AL;
+ }
+ else
+ if (CheckMemory())
+ {
+ PullB(Registers.AL);
+ SetZN(Registers.AL);
+ OpenBus = Registers.AL;
+ }
+ else
+ {
+ PullW(Registers.A.W);
+ SetZN(Registers.A.W);
+ OpenBus = Registers.AH;
+ }
+}
+
+// PLB
+static void OpABE1()
+{
+ AddCycles(TWO_CYCLES);
+ PullBE(Registers.DB);
+ SetZN(Registers.DB);
+ ICPU.ShiftedDB = Registers.DB << 16;
+ OpenBus = Registers.DB;
+}
+
+static void OpABE0()
+{
+ AddCycles(TWO_CYCLES);
+ PullB(Registers.DB);
+ SetZN(Registers.DB);
+ ICPU.ShiftedDB = Registers.DB << 16;
+ OpenBus = Registers.DB;
+}
+
+static void OpABSlow()
+{
+ AddCycles(TWO_CYCLES);
+
+ if (CheckEmulation())
+ {
+ PullBE(Registers.DB);
+ }
+ else
+ {
+ PullB(Registers.DB);
+ }
+
+ SetZN(Registers.DB);
+ ICPU.ShiftedDB = Registers.DB << 16;
+ OpenBus = Registers.DB;
+}
+
+// PLD
+static void Op2BE0()
+{
+ AddCycles(TWO_CYCLES);
+ PullW(Registers.D.W);
+ SetZN(Registers.D.W);
+ OpenBus = Registers.DH;
+}
+
+static void Op2BE1()
+{
+ // Note: PLD is a new instruction,
+ // and so doesn't respect the emu-mode stack bounds.
+ AddCycles(TWO_CYCLES);
+ PullW(Registers.D.W);
+ SetZN(Registers.D.W);
+ OpenBus = Registers.DH;
+ Registers.SH = 1;
+}
+
+static void Op2BSlow()
+{
+ AddCycles(TWO_CYCLES);
+ PullW(Registers.D.W);
+ SetZN(Registers.D.W);
+ OpenBus = Registers.DH;
+ if (CheckEmulation())
+ Registers.SH = 1;
+}
+
+// PLP
+static void Op28E1()
+{
+ AddCycles(TWO_CYCLES);
+ PullBE(Registers.PL);
+ OpenBus = Registers.PL;
+ SetFlags(MemoryFlag | IndexFlag);
+ S9xUnpackStatus();
+ S9xFixCycles();
+ CHECK_FOR_IRQ();
+}
+
+static void Op28E0()
+{
+ AddCycles(TWO_CYCLES);
+ PullB(Registers.PL);
+ OpenBus = Registers.PL;
+ S9xUnpackStatus();
+
+ if (CheckIndex())
+ {
+ Registers.XH = 0;
+ Registers.YH = 0;
+ }
+
+ S9xFixCycles();
+ CHECK_FOR_IRQ();
+}
+
+static void Op28Slow()
+{
+ AddCycles(TWO_CYCLES);
+
+ if (CheckEmulation())
+ {
+ PullBE(Registers.PL);
+ OpenBus = Registers.PL;
+ SetFlags(MemoryFlag | IndexFlag);
+ }
+ else
+ {
+ PullB(Registers.PL);
+ OpenBus = Registers.PL;
+ }
+
+ S9xUnpackStatus();
+
+ if (CheckIndex())
+ {
+ Registers.XH = 0;
+ Registers.YH = 0;
+ }
+
+ S9xFixCycles();
+ CHECK_FOR_IRQ();
+}
+
+// PLX
+static void OpFAE1()
+{
+ AddCycles(TWO_CYCLES);
+ PullBE(Registers.XL);
+ SetZN(Registers.XL);
+ OpenBus = Registers.XL;
+}
+
+static void OpFAE0X1()
+{
+ AddCycles(TWO_CYCLES);
+ PullB(Registers.XL);
+ SetZN(Registers.XL);
+ OpenBus = Registers.XL;
+}
+
+static void OpFAE0X0()
+{
+ AddCycles(TWO_CYCLES);
+ PullW(Registers.X.W);
+ SetZN(Registers.X.W);
+ OpenBus = Registers.XH;
+}
+
+static void OpFASlow()
+{
+ AddCycles(TWO_CYCLES);
+
+ if (CheckEmulation())
+ {
+ PullBE(Registers.XL);
+ SetZN(Registers.XL);
+ OpenBus = Registers.XL;
+ }
+ else
+ if (CheckIndex())
+ {
+ PullB(Registers.XL);
+ SetZN(Registers.XL);
+ OpenBus = Registers.XL;
+ }
+ else
+ {
+ PullW(Registers.X.W);
+ SetZN(Registers.X.W);
+ OpenBus = Registers.XH;
+ }
+}
+
+// PLY
+static void Op7AE1()
+{
+ AddCycles(TWO_CYCLES);
+ PullBE(Registers.YL);
+ SetZN(Registers.YL);
+ OpenBus = Registers.YL;
+}
+
+static void Op7AE0X1()
+{
+ AddCycles(TWO_CYCLES);
+ PullB(Registers.YL);
+ SetZN(Registers.YL);
+ OpenBus = Registers.YL;
+}
+
+static void Op7AE0X0()
+{
+ AddCycles(TWO_CYCLES);
+ PullW(Registers.Y.W);
+ SetZN(Registers.Y.W);
+ OpenBus = Registers.YH;
+}
+
+static void Op7ASlow()
+{
+ AddCycles(TWO_CYCLES);
+
+ if (CheckEmulation())
+ {
+ PullBE(Registers.YL);
+ SetZN(Registers.YL);
+ OpenBus = Registers.YL;
+ }
+ else
+ if (CheckIndex())
+ {
+ PullB(Registers.YL);
+ SetZN(Registers.YL);
+ OpenBus = Registers.YL;
+ }
+ else
+ {
+ PullW(Registers.Y.W);
+ SetZN(Registers.Y.W);
+ OpenBus = Registers.YH;
+ }
+}
+
+/* Transfer Instructions *************************************************** */
+
+// TAX
+static void OpAAX1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.XL = Registers.AL;
+ SetZN(Registers.XL);
+}
+
+static void OpAAX0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.X.W = Registers.A.W;
+ SetZN(Registers.X.W);
+}
+
+static void OpAASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckIndex())
+ {
+ Registers.XL = Registers.AL;
+ SetZN(Registers.XL);
+ }
+ else
+ {
+ Registers.X.W = Registers.A.W;
+ SetZN(Registers.X.W);
+ }
+}
+
+// TAY
+static void OpA8X1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.YL = Registers.AL;
+ SetZN(Registers.YL);
+}
+
+static void OpA8X0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.Y.W = Registers.A.W;
+ SetZN(Registers.Y.W);
+}
+
+static void OpA8Slow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckIndex())
+ {
+ Registers.YL = Registers.AL;
+ SetZN(Registers.YL);
+ }
+ else
+ {
+ Registers.Y.W = Registers.A.W;
+ SetZN(Registers.Y.W);
+ }
+}
+
+// TCD
+static void Op5B()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.D.W = Registers.A.W;
+ SetZN(Registers.D.W);
+}
+
+// TCS
+static void Op1B()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.S.W = Registers.A.W;
+ if (CheckEmulation())
+ Registers.SH = 1;
+}
+
+// TDC
+static void Op7B()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.A.W = Registers.D.W;
+ SetZN(Registers.A.W);
+}
+
+// TSC
+static void Op3B()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.A.W = Registers.S.W;
+ SetZN(Registers.A.W);
+}
+
+// TSX
+static void OpBAX1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.XL = Registers.SL;
+ SetZN(Registers.XL);
+}
+
+static void OpBAX0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.X.W = Registers.S.W;
+ SetZN(Registers.X.W);
+}
+
+static void OpBASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckIndex())
+ {
+ Registers.XL = Registers.SL;
+ SetZN(Registers.XL);
+ }
+ else
+ {
+ Registers.X.W = Registers.S.W;
+ SetZN(Registers.X.W);
+ }
+}
+
+// TXA
+static void Op8AM1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.AL = Registers.XL;
+ SetZN(Registers.AL);
+}
+
+static void Op8AM0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.A.W = Registers.X.W;
+ SetZN(Registers.A.W);
+}
+
+static void Op8ASlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckMemory())
+ {
+ Registers.AL = Registers.XL;
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ Registers.A.W = Registers.X.W;
+ SetZN(Registers.A.W);
+ }
+}
+
+// TXS
+static void Op9A()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.S.W = Registers.X.W;
+ if (CheckEmulation())
+ Registers.SH = 1;
+}
+
+// TXY
+static void Op9BX1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.YL = Registers.XL;
+ SetZN(Registers.YL);
+}
+
+static void Op9BX0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.Y.W = Registers.X.W;
+ SetZN(Registers.Y.W);
+}
+
+static void Op9BSlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckIndex())
+ {
+ Registers.YL = Registers.XL;
+ SetZN(Registers.YL);
+ }
+ else
+ {
+ Registers.Y.W = Registers.X.W;
+ SetZN(Registers.Y.W);
+ }
+}
+
+// TYA
+static void Op98M1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.AL = Registers.YL;
+ SetZN(Registers.AL);
+}
+
+static void Op98M0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.A.W = Registers.Y.W;
+ SetZN(Registers.A.W);
+}
+
+static void Op98Slow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckMemory())
+ {
+ Registers.AL = Registers.YL;
+ SetZN(Registers.AL);
+ }
+ else
+ {
+ Registers.A.W = Registers.Y.W;
+ SetZN(Registers.A.W);
+ }
+}
+
+// TYX
+static void OpBBX1()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.XL = Registers.YL;
+ SetZN(Registers.XL);
+}
+
+static void OpBBX0()
+{
+ AddCycles(ONE_CYCLE);
+ Registers.X.W = Registers.Y.W;
+ SetZN(Registers.X.W);
+}
+
+static void OpBBSlow()
+{
+ AddCycles(ONE_CYCLE);
+
+ if (CheckIndex())
+ {
+ Registers.XL = Registers.YL;
+ SetZN(Registers.XL);
+ }
+ else
+ {
+ Registers.X.W = Registers.Y.W;
+ SetZN(Registers.X.W);
+ }
+}
+
+/* XCE ********************************************************************* */
+
+static void OpFB()
+{
+ AddCycles(ONE_CYCLE);
+
+ uint8_t A1 = ICPU._Carry;
+ uint8_t A2 = Registers.PH;
+
+ ICPU._Carry = A2 & 1;
+ Registers.PH = A1;
+
+ if (CheckEmulation())
+ {
+ SetFlags(MemoryFlag | IndexFlag);
+ Registers.SH = 1;
+ #ifdef DEBUGGER
+ missing.emulate6502 = 1;
+ #endif
+ }
+
+ if (CheckIndex())
+ {
+ Registers.XH = 0;
+ Registers.YH = 0;
+ }
+
+ S9xFixCycles();
+}
+
+/* BRK ********************************************************************* */
+
+static void Op00()
+{
+#ifdef DEBUGGER
+ if (CPU.Flags & TRACE_FLAG)
+ S9xTraceMessage("*** BRK");
+#endif
+
+ AddCycles(CPU.MemSpeed);
+
+ uint16_t addr;
+
+ if (!CheckEmulation())
+ {
+ PushB(Registers.PB);
+ PushW(Registers.PCw + 1);
+ S9xPackStatus();
+ PushB(Registers.PL);
+ OpenBus = Registers.PL;
+ ClearDecimal();
+ SetIRQ();
+
+ addr = S9xGetWord(0xFFE6);
+ }
+ else
+ {
+ PushWE(Registers.PCw + 1);
+ S9xPackStatus();
+ PushBE(Registers.PL);
+ OpenBus = Registers.PL;
+ ClearDecimal();
+ SetIRQ();
+
+ addr = S9xGetWord(0xFFFE);
+ }
+
+ S9xSetPCBase(addr);
+ OpenBus = addr >> 8;
+}
+
+/* IRQ ********************************************************************* */
+
+void S9xOpcode_IRQ()
+{
+#ifdef DEBUGGER
+ if (CPU.Flags & TRACE_FLAG)
+ #ifdef SA1_OPCODES
+ S9xTraceMessage("*** SA1 IRQ");
+ #else
+ S9xTraceMessage("*** IRQ");
+ #endif
+#endif
+
+ // IRQ and NMI do an opcode fetch as their first "IO" cycle.
+ AddCycles(CPU.MemSpeed + ONE_CYCLE);
+
+ if (!CheckEmulation())
+ {
+ PushB(Registers.PB);
+ PushW(Registers.PCw);
+ S9xPackStatus();
+ PushB(Registers.PL);
+ OpenBus = Registers.PL;
+ ClearDecimal();
+ SetIRQ();
+
+ #ifdef SA1_OPCODES
+ OpenBus = Memory.FillRAM[0x2208];
+ AddCycles(2 * SLOW_ONE_CYCLE);
+ S9xSA1SetPCBase(Memory.FillRAM[0x2207] | (Memory.FillRAM[0x2208] << 8));
+ #else
+ if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x40))
+ {
+ OpenBus = Memory.FillRAM[0x220f];
+ AddCycles(2 * SLOW_ONE_CYCLE);
+ S9xSetPCBase(Memory.FillRAM[0x220e] | (Memory.FillRAM[0x220f] << 8));
+ }
+ else
+ {
+ uint16_t addr = S9xGetWord(0xFFEE);
+ OpenBus = addr >> 8;
+ S9xSetPCBase(addr);
+ }
+ #endif
+ }
+ else
+ {
+ PushWE(Registers.PCw);
+ S9xPackStatus();
+ PushBE(Registers.PL);
+ OpenBus = Registers.PL;
+ ClearDecimal();
+ SetIRQ();
+
+ #ifdef SA1_OPCODES
+ OpenBus = Memory.FillRAM[0x2208];
+ AddCycles(2 * SLOW_ONE_CYCLE);
+ S9xSA1SetPCBase(Memory.FillRAM[0x2207] | (Memory.FillRAM[0x2208] << 8));
+ #else
+ if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x40))
+ {
+ OpenBus = Memory.FillRAM[0x220f];
+ AddCycles(2 * SLOW_ONE_CYCLE);
+ S9xSetPCBase(Memory.FillRAM[0x220e] | (Memory.FillRAM[0x220f] << 8));
+ }
+ else
+ {
+ uint16_t addr = S9xGetWord(0xFFFE);
+ OpenBus = addr >> 8;
+ S9xSetPCBase(addr);
+ }
+ #endif
+ }
+}
+
+/* NMI ********************************************************************* */
+
+void S9xOpcode_NMI()
+{
+#ifdef DEBUGGER
+ if (CPU.Flags & TRACE_FLAG)
+ #ifdef SA1_OPCODES
+ S9xTraceMessage("*** SA1 NMI");
+ #else
+ S9xTraceMessage("*** NMI");
+ #endif
+#endif
+
+ // IRQ and NMI do an opcode fetch as their first "IO" cycle.
+ AddCycles(CPU.MemSpeed + ONE_CYCLE);
+
+ if (!CheckEmulation())
+ {
+ PushB(Registers.PB);
+ PushW(Registers.PCw);
+ S9xPackStatus();
+ PushB(Registers.PL);
+ OpenBus = Registers.PL;
+ ClearDecimal();
+ SetIRQ();
+
+ #ifdef SA1_OPCODES
+ OpenBus = Memory.FillRAM[0x2206];
+ AddCycles(2 * SLOW_ONE_CYCLE);
+ S9xSA1SetPCBase(Memory.FillRAM[0x2205] | (Memory.FillRAM[0x2206] << 8));
+ #else
+ if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x10))
+ {
+ OpenBus = Memory.FillRAM[0x220d];
+ AddCycles(2 * SLOW_ONE_CYCLE);
+ S9xSetPCBase(Memory.FillRAM[0x220c] | (Memory.FillRAM[0x220d] << 8));
+ }
+ else
+ {
+ uint16_t addr = S9xGetWord(0xFFEA);
+ OpenBus = addr >> 8;
+ S9xSetPCBase(addr);
+ }
+ #endif
+ }
+ else
+ {
+ PushWE(Registers.PCw);
+ S9xPackStatus();
+ PushBE(Registers.PL);
+ OpenBus = Registers.PL;
+ ClearDecimal();
+ SetIRQ();
+
+ #ifdef SA1_OPCODES
+ OpenBus = Memory.FillRAM[0x2206];
+ AddCycles(2 * SLOW_ONE_CYCLE);
+ S9xSA1SetPCBase(Memory.FillRAM[0x2205] | (Memory.FillRAM[0x2206] << 8));
+ #else
+ if (Settings.SA1 && (Memory.FillRAM[0x2209] & 0x10))
+ {
+ OpenBus = Memory.FillRAM[0x220d];
+ AddCycles(2 * SLOW_ONE_CYCLE);
+ S9xSetPCBase(Memory.FillRAM[0x220c] | (Memory.FillRAM[0x220d] << 8));
+ }
+ else
+ {
+ uint16_t addr = S9xGetWord(0xFFFA);
+ OpenBus = addr >> 8;
+ S9xSetPCBase(addr);
+ }
+ #endif
+ }
+}
+
+/* COP ********************************************************************* */
+
+static void Op02()
+{
+#ifdef DEBUGGER
+ if (CPU.Flags & TRACE_FLAG)
+ S9xTraceMessage("*** COP");
+#endif
+
+ AddCycles(CPU.MemSpeed);
+
+ uint16_t addr;
+
+ if (!CheckEmulation())
+ {
+ PushB(Registers.PB);
+ PushW(Registers.PCw + 1);
+ S9xPackStatus();
+ PushB(Registers.PL);
+ OpenBus = Registers.PL;
+ ClearDecimal();
+ SetIRQ();
+
+ addr = S9xGetWord(0xFFE4);
+ }
+ else
+ {
+ PushWE(Registers.PCw + 1);
+ S9xPackStatus();
+ PushBE(Registers.PL);
+ OpenBus = Registers.PL;
+ ClearDecimal();
+ SetIRQ();
+
+ addr = S9xGetWord(0xFFF4);
+ }
+
+ S9xSetPCBase(addr);
+ OpenBus = addr >> 8;
+}
+
+/* JML ********************************************************************* */
+
+static void OpDC()
+{
+ S9xSetPCBase(AbsoluteIndirectLong(JUMP));
+}
+
+static void OpDCSlow()
+{
+ S9xSetPCBase(AbsoluteIndirectLongSlow(JUMP));
+}
+
+static void Op5C()
+{
+ S9xSetPCBase(AbsoluteLong(JUMP));
+}
+
+static void Op5CSlow()
+{
+ S9xSetPCBase(AbsoluteLongSlow(JUMP));
+}
+
+/* JMP ********************************************************************* */
+
+static void Op4C()
+{
+ S9xSetPCBase(ICPU.ShiftedPB + ((uint16_t) Absolute(JUMP)));
+}
+
+static void Op4CSlow()
+{
+ S9xSetPCBase(ICPU.ShiftedPB + ((uint16_t) AbsoluteSlow(JUMP)));
+}
+
+static void Op6C()
+{
+ S9xSetPCBase(ICPU.ShiftedPB + ((uint16_t) AbsoluteIndirect(JUMP)));
+}
+
+static void Op6CSlow()
+{
+ S9xSetPCBase(ICPU.ShiftedPB + ((uint16_t) AbsoluteIndirectSlow(JUMP)));
+}
+
+static void Op7C()
+{
+ S9xSetPCBase(ICPU.ShiftedPB + ((uint16_t) AbsoluteIndexedIndirect(JUMP)));
+}
+
+static void Op7CSlow()
+{
+ S9xSetPCBase(ICPU.ShiftedPB + ((uint16_t) AbsoluteIndexedIndirectSlow(JUMP)));
+}
+
+/* JSL/RTL ***************************************************************** */
+
+static void Op22E1()
+{
+ // Note: JSL is a new instruction,
+ // and so doesn't respect the emu-mode stack bounds.
+ uint32_t addr = AbsoluteLong(JSR);
+ PushB(Registers.PB);
+ PushW(Registers.PCw - 1);
+ Registers.SH = 1;
+ S9xSetPCBase(addr);
+}
+
+static void Op22E0()
+{
+ uint32_t addr = AbsoluteLong(JSR);
+ PushB(Registers.PB);
+ PushW(Registers.PCw - 1);
+ S9xSetPCBase(addr);
+}
+
+static void Op22Slow()
+{
+ uint32_t addr = AbsoluteLongSlow(JSR);
+ PushB(Registers.PB);
+ PushW(Registers.PCw - 1);
+ if (CheckEmulation())
+ Registers.SH = 1;
+ S9xSetPCBase(addr);
+}
+
+static void Op6BE1()
+{
+ // Note: RTL is a new instruction,
+ // and so doesn't respect the emu-mode stack bounds.
+ AddCycles(TWO_CYCLES);
+ PullW(Registers.PCw);
+ PullB(Registers.PB);
+ Registers.SH = 1;
+ Registers.PCw++;
+ S9xSetPCBase(Registers.PBPC);
+}
+
+static void Op6BE0()
+{
+ AddCycles(TWO_CYCLES);
+ PullW(Registers.PCw);
+ PullB(Registers.PB);
+ Registers.PCw++;
+ S9xSetPCBase(Registers.PBPC);
+}
+
+static void Op6BSlow()
+{
+ AddCycles(TWO_CYCLES);
+ PullW(Registers.PCw);
+ PullB(Registers.PB);
+ if (CheckEmulation())
+ Registers.SH = 1;
+ Registers.PCw++;
+ S9xSetPCBase(Registers.PBPC);
+}
+
+/* JSR/RTS ***************************************************************** */
+
+static void Op20E1()
+{
+ uint16_t addr = Absolute(JSR);
+ AddCycles(ONE_CYCLE);
+ PushWE(Registers.PCw - 1);
+ S9xSetPCBase(ICPU.ShiftedPB + addr);
+}
+
+static void Op20E0()
+{
+ uint16_t addr = Absolute(JSR);
+ AddCycles(ONE_CYCLE);
+ PushW(Registers.PCw - 1);
+ S9xSetPCBase(ICPU.ShiftedPB + addr);
+}
+
+static void Op20Slow()
+{
+ uint16_t addr = AbsoluteSlow(JSR);
+
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ PushWE(Registers.PCw - 1);
+ }
+ else
+ {
+ PushW(Registers.PCw - 1);
+ }
+
+ S9xSetPCBase(ICPU.ShiftedPB + addr);
+}
+
+static void OpFCE1()
+{
+ // Note: JSR (a,X) is a new instruction,
+ // and so doesn't respect the emu-mode stack bounds.
+ uint16_t addr = AbsoluteIndexedIndirect(JSR);
+ PushW(Registers.PCw - 1);
+ Registers.SH = 1;
+ S9xSetPCBase(ICPU.ShiftedPB + addr);
+}
+
+static void OpFCE0()
+{
+ uint16_t addr = AbsoluteIndexedIndirect(JSR);
+ PushW(Registers.PCw - 1);
+ S9xSetPCBase(ICPU.ShiftedPB + addr);
+}
+
+static void OpFCSlow()
+{
+ uint16_t addr = AbsoluteIndexedIndirectSlow(JSR);
+ PushW(Registers.PCw - 1);
+ if (CheckEmulation())
+ Registers.SH = 1;
+ S9xSetPCBase(ICPU.ShiftedPB + addr);
+}
+
+static void Op60E1()
+{
+ AddCycles(TWO_CYCLES);
+ PullWE(Registers.PCw);
+ AddCycles(ONE_CYCLE);
+ Registers.PCw++;
+ S9xSetPCBase(Registers.PBPC);
+}
+
+static void Op60E0()
+{
+ AddCycles(TWO_CYCLES);
+ PullW(Registers.PCw);
+ AddCycles(ONE_CYCLE);
+ Registers.PCw++;
+ S9xSetPCBase(Registers.PBPC);
+}
+
+static void Op60Slow()
+{
+ AddCycles(TWO_CYCLES);
+
+ if (CheckEmulation())
+ {
+ PullWE(Registers.PCw);
+ }
+ else
+ {
+ PullW(Registers.PCw);
+ }
+
+ AddCycles(ONE_CYCLE);
+ Registers.PCw++;
+ S9xSetPCBase(Registers.PBPC);
+}
+
+/* MVN/MVP ***************************************************************** */
+
+static void Op54X1()
+{
+ uint32_t SrcBank;
+
+ Registers.DB = Immediate8(NONE);
+ ICPU.ShiftedDB = Registers.DB << 16;
+ OpenBus = SrcBank = Immediate8(NONE);
+
+ S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W);
+
+ Registers.XL++;
+ Registers.YL++;
+ Registers.A.W--;
+ if (Registers.A.W != 0xffff)
+ Registers.PCw -= 3;
+
+ AddCycles(TWO_CYCLES);
+}
+
+static void Op54X0()
+{
+ uint32_t SrcBank;
+
+ Registers.DB = Immediate8(NONE);
+ ICPU.ShiftedDB = Registers.DB << 16;
+ OpenBus = SrcBank = Immediate8(NONE);
+
+ S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W);
+
+ Registers.X.W++;
+ Registers.Y.W++;
+ Registers.A.W--;
+ if (Registers.A.W != 0xffff)
+ Registers.PCw -= 3;
+
+ AddCycles(TWO_CYCLES);
+}
+
+static void Op54Slow()
+{
+ uint32_t SrcBank;
+
+ OpenBus = Registers.DB = Immediate8Slow(NONE);
+ ICPU.ShiftedDB = Registers.DB << 16;
+ OpenBus = SrcBank = Immediate8Slow(NONE);
+
+ S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W);
+
+ if (CheckIndex())
+ {
+ Registers.XL++;
+ Registers.YL++;
+ }
+ else
+ {
+ Registers.X.W++;
+ Registers.Y.W++;
+ }
+
+ Registers.A.W--;
+ if (Registers.A.W != 0xffff)
+ Registers.PCw -= 3;
+
+ AddCycles(TWO_CYCLES);
+}
+
+static void Op44X1()
+{
+ uint32_t SrcBank;
+
+ Registers.DB = Immediate8(NONE);
+ ICPU.ShiftedDB = Registers.DB << 16;
+ OpenBus = SrcBank = Immediate8(NONE);
+
+ S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W);
+
+ Registers.XL--;
+ Registers.YL--;
+ Registers.A.W--;
+ if (Registers.A.W != 0xffff)
+ Registers.PCw -= 3;
+
+ AddCycles(TWO_CYCLES);
+}
+
+static void Op44X0()
+{
+ uint32_t SrcBank;
+
+ Registers.DB = Immediate8(NONE);
+ ICPU.ShiftedDB = Registers.DB << 16;
+ OpenBus = SrcBank = Immediate8(NONE);
+
+ S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W);
+
+ Registers.X.W--;
+ Registers.Y.W--;
+ Registers.A.W--;
+ if (Registers.A.W != 0xffff)
+ Registers.PCw -= 3;
+
+ AddCycles(TWO_CYCLES);
+}
+
+static void Op44Slow()
+{
+ uint32_t SrcBank;
+
+ OpenBus = Registers.DB = Immediate8Slow(NONE);
+ ICPU.ShiftedDB = Registers.DB << 16;
+ OpenBus = SrcBank = Immediate8Slow(NONE);
+
+ S9xSetByte(OpenBus = S9xGetByte((SrcBank << 16) + Registers.X.W), ICPU.ShiftedDB + Registers.Y.W);
+
+ if (CheckIndex())
+ {
+ Registers.XL--;
+ Registers.YL--;
+ }
+ else
+ {
+ Registers.X.W--;
+ Registers.Y.W--;
+ }
+
+ Registers.A.W--;
+ if (Registers.A.W != 0xffff)
+ Registers.PCw -= 3;
+
+ AddCycles(TWO_CYCLES);
+}
+
+/* REP/SEP ***************************************************************** */
+
+static void OpC2()
+{
+ uint8_t Work8 = ~Immediate8(READ);
+ Registers.PL &= Work8;
+ ICPU._Carry &= Work8;
+ ICPU._Overflow &= (Work8 >> 6);
+ ICPU._Negative &= Work8;
+ ICPU._Zero |= ~Work8 & Zero;
+
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ SetFlags(MemoryFlag | IndexFlag);
+ #ifdef DEBUGGER
+ missing.emulate6502 = 1;
+ #endif
+ }
+
+ if (CheckIndex())
+ {
+ Registers.XH = 0;
+ Registers.YH = 0;
+ }
+
+ S9xFixCycles();
+ CHECK_FOR_IRQ();
+}
+
+static void OpC2Slow()
+{
+ uint8_t Work8 = ~Immediate8Slow(READ);
+ Registers.PL &= Work8;
+ ICPU._Carry &= Work8;
+ ICPU._Overflow &= (Work8 >> 6);
+ ICPU._Negative &= Work8;
+ ICPU._Zero |= ~Work8 & Zero;
+
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ SetFlags(MemoryFlag | IndexFlag);
+ #ifdef DEBUGGER
+ missing.emulate6502 = 1;
+ #endif
+ }
+
+ if (CheckIndex())
+ {
+ Registers.XH = 0;
+ Registers.YH = 0;
+ }
+
+ S9xFixCycles();
+ CHECK_FOR_IRQ();
+}
+
+static void OpE2()
+{
+ uint8_t Work8 = Immediate8(READ);
+ Registers.PL |= Work8;
+ ICPU._Carry |= Work8 & 1;
+ ICPU._Overflow |= (Work8 >> 6) & 1;
+ ICPU._Negative |= Work8;
+ if (Work8 & Zero)
+ ICPU._Zero = 0;
+
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ SetFlags(MemoryFlag | IndexFlag);
+ #ifdef DEBUGGER
+ missing.emulate6502 = 1;
+ #endif
+ }
+
+ if (CheckIndex())
+ {
+ Registers.XH = 0;
+ Registers.YH = 0;
+ }
+
+ S9xFixCycles();
+}
+
+static void OpE2Slow()
+{
+ uint8_t Work8 = Immediate8Slow(READ);
+ Registers.PL |= Work8;
+ ICPU._Carry |= Work8 & 1;
+ ICPU._Overflow |= (Work8 >> 6) & 1;
+ ICPU._Negative |= Work8;
+ if (Work8 & Zero)
+ ICPU._Zero = 0;
+
+ AddCycles(ONE_CYCLE);
+
+ if (CheckEmulation())
+ {
+ SetFlags(MemoryFlag | IndexFlag);
+ #ifdef DEBUGGER
+ missing.emulate6502 = 1;
+ #endif
+ }
+
+ if (CheckIndex())
+ {
+ Registers.XH = 0;
+ Registers.YH = 0;
+ }
+
+ S9xFixCycles();
+}
+
+/* XBA ********************************************************************* */
+
+static void OpEB()
+{
+ uint8_t Work8 = Registers.AL;
+ Registers.AL = Registers.AH;
+ Registers.AH = Work8;
+ SetZN(Registers.AL);
+ AddCycles(TWO_CYCLES);
+}
+
+/* RTI ********************************************************************* */
+
+static void Op40Slow()
+{
+ AddCycles(TWO_CYCLES);
+
+ if (!CheckEmulation())
+ {
+ PullB(Registers.PL);
+ S9xUnpackStatus();
+ PullW(Registers.PCw);
+ PullB(Registers.PB);
+ OpenBus = Registers.PB;
+ ICPU.ShiftedPB = Registers.PB << 16;
+ }
+ else
+ {
+ PullBE(Registers.PL);
+ S9xUnpackStatus();
+ PullWE(Registers.PCw);
+ OpenBus = Registers.PCh;
+ SetFlags(MemoryFlag | IndexFlag);
+ #ifdef DEBUGGER
+ missing.emulate6502 = 1;
+ #endif
+ }
+
+ S9xSetPCBase(Registers.PBPC);
+
+ if (CheckIndex())
+ {
+ Registers.XH = 0;
+ Registers.YH = 0;
+ }
+
+ S9xFixCycles();
+ CHECK_FOR_IRQ();
+}
+
+/* STP/WAI ***************************************************************** */
+
+// WAI
+static void OpCB()
+{
+#ifdef SA1_OPCODES
+ SA1.WaitingForInterrupt = true;
+ Registers.PCw--;
+ AddCycles(TWO_CYCLES);
+#else
+ CPU.WaitingForInterrupt = true;
+ Registers.PCw--;
+ AddCycles(TWO_CYCLES);
+#endif
+}
+
+// STP
+static void OpDB()
+{
+ Registers.PCw--;
+ CPU.Flags |= DEBUG_MODE_FLAG | HALTED_FLAG;
+}
+
+/* WDM (Reserved S9xOpcode) ************************************************ */
+
+#ifdef DEBUGGER
+extern FILE *trace, *trace2;
+#endif
+
+static void Op42()
+{
+#ifdef DEBUGGER
+ uint8_t byte = (uint8_t) S9xGetWord(Registers.PBPC);
+#else
+ S9xGetWord(Registers.PBPC);
+#endif
+ Registers.PCw++;
+
+#ifdef DEBUGGER
+ // Hey, let's use this to trigger debug modes.
+ switch (byte)
+ {
+ case 0xdb: // "STP" = Enter debug mode
+ CPU.Flags |= DEBUG_MODE_FLAG;
+ break;
+
+ #ifndef SA1_OPCODES
+ case 0xe2: // "SEP" = Trace on
+ if (!(CPU.Flags & TRACE_FLAG))
+ {
+ char buf[25];
+ CPU.Flags |= TRACE_FLAG;
+ snprintf(buf, 25, "WDM trace on at $%02X:%04X", Registers.PB, Registers.PCw);
+ S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, buf);
+ if (trace != NULL)
+ fclose(trace);
+ ENSURE_TRACE_OPEN(trace, "WDMtrace.log", "ab")
+ }
+
+ break;
+
+ case 0xc2: // "REP" = Trace off
+ if (CPU.Flags & TRACE_FLAG)
+ {
+ char buf[26];
+ CPU.Flags &= ~TRACE_FLAG;
+ snprintf(buf, 26, "WDM trace off at $%02X:%04X", Registers.PB, Registers.PCw);
+ S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, buf);
+ if (trace != NULL)
+ fclose(trace);
+ trace = NULL;
+ }
+
+ break;
+ #endif
+
+ case 0x42: // "WDM" = Snapshot
+ char filename[PATH_MAX + 1], drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[PATH_MAX + 1], ext[_MAX_EXT + 1];
+
+ _splitpath(Memory.ROMFilename, drive, dir, def, ext);
+ snprintf(filename, PATH_MAX, "%s%s%s-%06X.wdm", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, Registers.PBPC & 0xffffff);
+ sprintf(def, "WDM Snapshot at $%02X:%04X: %s", Registers.PB, Registers.PCw, filename);
+ S9xMessage(S9X_DEBUG, S9X_DEBUG_OUTPUT, def);
+ S9xFreezeGame(filename);
+
+ break;
+
+ default:
+ break;
+ }
+#endif
+}
+
+/* CPU-S9xOpcodes Definitions ************************************************/
+
+struct SOpcodes S9xOpcodesM1X1[256] =
+{
+ { Op00 }, { Op01E0M1 }, { Op02 }, { Op03M1 }, { Op04M1 },
+ { Op05M1 }, { Op06M1 }, { Op07M1 }, { Op08E0 }, { Op09M1 },
+ { Op0AM1 }, { Op0BE0 }, { Op0CM1 }, { Op0DM1 }, { Op0EM1 },
+ { Op0FM1 }, { Op10E0 }, { Op11E0M1X1 }, { Op12E0M1 }, { Op13M1 },
+ { Op14M1 }, { Op15E0M1 }, { Op16E0M1 }, { Op17M1 }, { Op18 },
+ { Op19M1X1 }, { Op1AM1 }, { Op1B }, { Op1CM1 }, { Op1DM1X1 },
+ { Op1EM1X1 }, { Op1FM1 }, { Op20E0 }, { Op21E0M1 }, { Op22E0 },
+ { Op23M1 }, { Op24M1 }, { Op25M1 }, { Op26M1 }, { Op27M1 },
+ { Op28E0 }, { Op29M1 }, { Op2AM1 }, { Op2BE0 }, { Op2CM1 },
+ { Op2DM1 }, { Op2EM1 }, { Op2FM1 }, { Op30E0 }, { Op31E0M1X1 },
+ { Op32E0M1 }, { Op33M1 }, { Op34E0M1 }, { Op35E0M1 }, { Op36E0M1 },
+ { Op37M1 }, { Op38 }, { Op39M1X1 }, { Op3AM1 }, { Op3B },
+ { Op3CM1X1 }, { Op3DM1X1 }, { Op3EM1X1 }, { Op3FM1 }, { Op40Slow },
+ { Op41E0M1 }, { Op42 }, { Op43M1 }, { Op44X1 }, { Op45M1 },
+ { Op46M1 }, { Op47M1 }, { Op48E0M1 }, { Op49M1 }, { Op4AM1 },
+ { Op4BE0 }, { Op4C }, { Op4DM1 }, { Op4EM1 }, { Op4FM1 },
+ { Op50E0 }, { Op51E0M1X1 }, { Op52E0M1 }, { Op53M1 }, { Op54X1 },
+ { Op55E0M1 }, { Op56E0M1 }, { Op57M1 }, { Op58 }, { Op59M1X1 },
+ { Op5AE0X1 }, { Op5B }, { Op5C }, { Op5DM1X1 }, { Op5EM1X1 },
+ { Op5FM1 }, { Op60E0 }, { Op61E0M1 }, { Op62E0 }, { Op63M1 },
+ { Op64M1 }, { Op65M1 }, { Op66M1 }, { Op67M1 }, { Op68E0M1 },
+ { Op69M1 }, { Op6AM1 }, { Op6BE0 }, { Op6C }, { Op6DM1 },
+ { Op6EM1 }, { Op6FM1 }, { Op70E0 }, { Op71E0M1X1 }, { Op72E0M1 },
+ { Op73M1 }, { Op74E0M1 }, { Op75E0M1 }, { Op76E0M1 }, { Op77M1 },
+ { Op78 }, { Op79M1X1 }, { Op7AE0X1 }, { Op7B }, { Op7C },
+ { Op7DM1X1 }, { Op7EM1X1 }, { Op7FM1 }, { Op80E0 }, { Op81E0M1 },
+ { Op82 }, { Op83M1 }, { Op84X1 }, { Op85M1 }, { Op86X1 },
+ { Op87M1 }, { Op88X1 }, { Op89M1 }, { Op8AM1 }, { Op8BE0 },
+ { Op8CX1 }, { Op8DM1 }, { Op8EX1 }, { Op8FM1 }, { Op90E0 },
+ { Op91E0M1X1 }, { Op92E0M1 }, { Op93M1 }, { Op94E0X1 }, { Op95E0M1 },
+ { Op96E0X1 }, { Op97M1 }, { Op98M1 }, { Op99M1X1 }, { Op9A },
+ { Op9BX1 }, { Op9CM1 }, { Op9DM1X1 }, { Op9EM1X1 }, { Op9FM1 },
+ { OpA0X1 }, { OpA1E0M1 }, { OpA2X1 }, { OpA3M1 }, { OpA4X1 },
+ { OpA5M1 }, { OpA6X1 }, { OpA7M1 }, { OpA8X1 }, { OpA9M1 },
+ { OpAAX1 }, { OpABE0 }, { OpACX1 }, { OpADM1 }, { OpAEX1 },
+ { OpAFM1 }, { OpB0E0 }, { OpB1E0M1X1 }, { OpB2E0M1 }, { OpB3M1 },
+ { OpB4E0X1 }, { OpB5E0M1 }, { OpB6E0X1 }, { OpB7M1 }, { OpB8 },
+ { OpB9M1X1 }, { OpBAX1 }, { OpBBX1 }, { OpBCX1 }, { OpBDM1X1 },
+ { OpBEX1 }, { OpBFM1 }, { OpC0X1 }, { OpC1E0M1 }, { OpC2 },
+ { OpC3M1 }, { OpC4X1 }, { OpC5M1 }, { OpC6M1 }, { OpC7M1 },
+ { OpC8X1 }, { OpC9M1 }, { OpCAX1 }, { OpCB }, { OpCCX1 },
+ { OpCDM1 }, { OpCEM1 }, { OpCFM1 }, { OpD0E0 }, { OpD1E0M1X1 },
+ { OpD2E0M1 }, { OpD3M1 }, { OpD4E0 }, { OpD5E0M1 }, { OpD6E0M1 },
+ { OpD7M1 }, { OpD8 }, { OpD9M1X1 }, { OpDAE0X1 }, { OpDB },
+ { OpDC }, { OpDDM1X1 }, { OpDEM1X1 }, { OpDFM1 }, { OpE0X1 },
+ { OpE1E0M1 }, { OpE2 }, { OpE3M1 }, { OpE4X1 }, { OpE5M1 },
+ { OpE6M1 }, { OpE7M1 }, { OpE8X1 }, { OpE9M1 }, { OpEA },
+ { OpEB }, { OpECX1 }, { OpEDM1 }, { OpEEM1 }, { OpEFM1 },
+ { OpF0E0 }, { OpF1E0M1X1 }, { OpF2E0M1 }, { OpF3M1 }, { OpF4E0 },
+ { OpF5E0M1 }, { OpF6E0M1 }, { OpF7M1 }, { OpF8 }, { OpF9M1X1 },
+ { OpFAE0X1 }, { OpFB }, { OpFCE0 }, { OpFDM1X1 }, { OpFEM1X1 },
+ { OpFFM1 }
+};
+
+struct SOpcodes S9xOpcodesE1[256] =
+{
+ { Op00 }, { Op01E1 }, { Op02 }, { Op03M1 }, { Op04M1 },
+ { Op05M1 }, { Op06M1 }, { Op07M1 }, { Op08E1 }, { Op09M1 },
+ { Op0AM1 }, { Op0BE1 }, { Op0CM1 }, { Op0DM1 }, { Op0EM1 },
+ { Op0FM1 }, { Op10E1 }, { Op11E1 }, { Op12E1 }, { Op13M1 },
+ { Op14M1 }, { Op15E1 }, { Op16E1 }, { Op17M1 }, { Op18 },
+ { Op19M1X1 }, { Op1AM1 }, { Op1B }, { Op1CM1 }, { Op1DM1X1 },
+ { Op1EM1X1 }, { Op1FM1 }, { Op20E1 }, { Op21E1 }, { Op22E1 },
+ { Op23M1 }, { Op24M1 }, { Op25M1 }, { Op26M1 }, { Op27M1 },
+ { Op28E1 }, { Op29M1 }, { Op2AM1 }, { Op2BE1 }, { Op2CM1 },
+ { Op2DM1 }, { Op2EM1 }, { Op2FM1 }, { Op30E1 }, { Op31E1 },
+ { Op32E1 }, { Op33M1 }, { Op34E1 }, { Op35E1 }, { Op36E1 },
+ { Op37M1 }, { Op38 }, { Op39M1X1 }, { Op3AM1 }, { Op3B },
+ { Op3CM1X1 }, { Op3DM1X1 }, { Op3EM1X1 }, { Op3FM1 }, { Op40Slow },
+ { Op41E1 }, { Op42 }, { Op43M1 }, { Op44X1 }, { Op45M1 },
+ { Op46M1 }, { Op47M1 }, { Op48E1 }, { Op49M1 }, { Op4AM1 },
+ { Op4BE1 }, { Op4C }, { Op4DM1 }, { Op4EM1 }, { Op4FM1 },
+ { Op50E1 }, { Op51E1 }, { Op52E1 }, { Op53M1 }, { Op54X1 },
+ { Op55E1 }, { Op56E1 }, { Op57M1 }, { Op58 }, { Op59M1X1 },
+ { Op5AE1 }, { Op5B }, { Op5C }, { Op5DM1X1 }, { Op5EM1X1 },
+ { Op5FM1 }, { Op60E1 }, { Op61E1 }, { Op62E1 }, { Op63M1 },
+ { Op64M1 }, { Op65M1 }, { Op66M1 }, { Op67M1 }, { Op68E1 },
+ { Op69M1 }, { Op6AM1 }, { Op6BE1 }, { Op6C }, { Op6DM1 },
+ { Op6EM1 }, { Op6FM1 }, { Op70E1 }, { Op71E1 }, { Op72E1 },
+ { Op73M1 }, { Op74E1 }, { Op75E1 }, { Op76E1 }, { Op77M1 },
+ { Op78 }, { Op79M1X1 }, { Op7AE1 }, { Op7B }, { Op7C },
+ { Op7DM1X1 }, { Op7EM1X1 }, { Op7FM1 }, { Op80E1 }, { Op81E1 },
+ { Op82 }, { Op83M1 }, { Op84X1 }, { Op85M1 }, { Op86X1 },
+ { Op87M1 }, { Op88X1 }, { Op89M1 }, { Op8AM1 }, { Op8BE1 },
+ { Op8CX1 }, { Op8DM1 }, { Op8EX1 }, { Op8FM1 }, { Op90E1 },
+ { Op91E1 }, { Op92E1 }, { Op93M1 }, { Op94E1 }, { Op95E1 },
+ { Op96E1 }, { Op97M1 }, { Op98M1 }, { Op99M1X1 }, { Op9A },
+ { Op9BX1 }, { Op9CM1 }, { Op9DM1X1 }, { Op9EM1X1 }, { Op9FM1 },
+ { OpA0X1 }, { OpA1E1 }, { OpA2X1 }, { OpA3M1 }, { OpA4X1 },
+ { OpA5M1 }, { OpA6X1 }, { OpA7M1 }, { OpA8X1 }, { OpA9M1 },
+ { OpAAX1 }, { OpABE1 }, { OpACX1 }, { OpADM1 }, { OpAEX1 },
+ { OpAFM1 }, { OpB0E1 }, { OpB1E1 }, { OpB2E1 }, { OpB3M1 },
+ { OpB4E1 }, { OpB5E1 }, { OpB6E1 }, { OpB7M1 }, { OpB8 },
+ { OpB9M1X1 }, { OpBAX1 }, { OpBBX1 }, { OpBCX1 }, { OpBDM1X1 },
+ { OpBEX1 }, { OpBFM1 }, { OpC0X1 }, { OpC1E1 }, { OpC2 },
+ { OpC3M1 }, { OpC4X1 }, { OpC5M1 }, { OpC6M1 }, { OpC7M1 },
+ { OpC8X1 }, { OpC9M1 }, { OpCAX1 }, { OpCB }, { OpCCX1 },
+ { OpCDM1 }, { OpCEM1 }, { OpCFM1 }, { OpD0E1 }, { OpD1E1 },
+ { OpD2E1 }, { OpD3M1 }, { OpD4E1 }, { OpD5E1 }, { OpD6E1 },
+ { OpD7M1 }, { OpD8 }, { OpD9M1X1 }, { OpDAE1 }, { OpDB },
+ { OpDC }, { OpDDM1X1 }, { OpDEM1X1 }, { OpDFM1 }, { OpE0X1 },
+ { OpE1E1 }, { OpE2 }, { OpE3M1 }, { OpE4X1 }, { OpE5M1 },
+ { OpE6M1 }, { OpE7M1 }, { OpE8X1 }, { OpE9M1 }, { OpEA },
+ { OpEB }, { OpECX1 }, { OpEDM1 }, { OpEEM1 }, { OpEFM1 },
+ { OpF0E1 }, { OpF1E1 }, { OpF2E1 }, { OpF3M1 }, { OpF4E1 },
+ { OpF5E1 }, { OpF6E1 }, { OpF7M1 }, { OpF8 }, { OpF9M1X1 },
+ { OpFAE1 }, { OpFB }, { OpFCE1 }, { OpFDM1X1 }, { OpFEM1X1 },
+ { OpFFM1 }
+};
+
+struct SOpcodes S9xOpcodesM1X0[256] =
+{
+ { Op00 }, { Op01E0M1 }, { Op02 }, { Op03M1 }, { Op04M1 },
+ { Op05M1 }, { Op06M1 }, { Op07M1 }, { Op08E0 }, { Op09M1 },
+ { Op0AM1 }, { Op0BE0 }, { Op0CM1 }, { Op0DM1 }, { Op0EM1 },
+ { Op0FM1 }, { Op10E0 }, { Op11E0M1X0 }, { Op12E0M1 }, { Op13M1 },
+ { Op14M1 }, { Op15E0M1 }, { Op16E0M1 }, { Op17M1 }, { Op18 },
+ { Op19M1X0 }, { Op1AM1 }, { Op1B }, { Op1CM1 }, { Op1DM1X0 },
+ { Op1EM1X0 }, { Op1FM1 }, { Op20E0 }, { Op21E0M1 }, { Op22E0 },
+ { Op23M1 }, { Op24M1 }, { Op25M1 }, { Op26M1 }, { Op27M1 },
+ { Op28E0 }, { Op29M1 }, { Op2AM1 }, { Op2BE0 }, { Op2CM1 },
+ { Op2DM1 }, { Op2EM1 }, { Op2FM1 }, { Op30E0 }, { Op31E0M1X0 },
+ { Op32E0M1 }, { Op33M1 }, { Op34E0M1 }, { Op35E0M1 }, { Op36E0M1 },
+ { Op37M1 }, { Op38 }, { Op39M1X0 }, { Op3AM1 }, { Op3B },
+ { Op3CM1X0 }, { Op3DM1X0 }, { Op3EM1X0 }, { Op3FM1 }, { Op40Slow },
+ { Op41E0M1 }, { Op42 }, { Op43M1 }, { Op44X0 }, { Op45M1 },
+ { Op46M1 }, { Op47M1 }, { Op48E0M1 }, { Op49M1 }, { Op4AM1 },
+ { Op4BE0 }, { Op4C }, { Op4DM1 }, { Op4EM1 }, { Op4FM1 },
+ { Op50E0 }, { Op51E0M1X0 }, { Op52E0M1 }, { Op53M1 }, { Op54X0 },
+ { Op55E0M1 }, { Op56E0M1 }, { Op57M1 }, { Op58 }, { Op59M1X0 },
+ { Op5AE0X0 }, { Op5B }, { Op5C }, { Op5DM1X0 }, { Op5EM1X0 },
+ { Op5FM1 }, { Op60E0 }, { Op61E0M1 }, { Op62E0 }, { Op63M1 },
+ { Op64M1 }, { Op65M1 }, { Op66M1 }, { Op67M1 }, { Op68E0M1 },
+ { Op69M1 }, { Op6AM1 }, { Op6BE0 }, { Op6C }, { Op6DM1 },
+ { Op6EM1 }, { Op6FM1 }, { Op70E0 }, { Op71E0M1X0 }, { Op72E0M1 },
+ { Op73M1 }, { Op74E0M1 }, { Op75E0M1 }, { Op76E0M1 }, { Op77M1 },
+ { Op78 }, { Op79M1X0 }, { Op7AE0X0 }, { Op7B }, { Op7C },
+ { Op7DM1X0 }, { Op7EM1X0 }, { Op7FM1 }, { Op80E0 }, { Op81E0M1 },
+ { Op82 }, { Op83M1 }, { Op84X0 }, { Op85M1 }, { Op86X0 },
+ { Op87M1 }, { Op88X0 }, { Op89M1 }, { Op8AM1 }, { Op8BE0 },
+ { Op8CX0 }, { Op8DM1 }, { Op8EX0 }, { Op8FM1 }, { Op90E0 },
+ { Op91E0M1X0 }, { Op92E0M1 }, { Op93M1 }, { Op94E0X0 }, { Op95E0M1 },
+ { Op96E0X0 }, { Op97M1 }, { Op98M1 }, { Op99M1X0 }, { Op9A },
+ { Op9BX0 }, { Op9CM1 }, { Op9DM1X0 }, { Op9EM1X0 }, { Op9FM1 },
+ { OpA0X0 }, { OpA1E0M1 }, { OpA2X0 }, { OpA3M1 }, { OpA4X0 },
+ { OpA5M1 }, { OpA6X0 }, { OpA7M1 }, { OpA8X0 }, { OpA9M1 },
+ { OpAAX0 }, { OpABE0 }, { OpACX0 }, { OpADM1 }, { OpAEX0 },
+ { OpAFM1 }, { OpB0E0 }, { OpB1E0M1X0 }, { OpB2E0M1 }, { OpB3M1 },
+ { OpB4E0X0 }, { OpB5E0M1 }, { OpB6E0X0 }, { OpB7M1 }, { OpB8 },
+ { OpB9M1X0 }, { OpBAX0 }, { OpBBX0 }, { OpBCX0 }, { OpBDM1X0 },
+ { OpBEX0 }, { OpBFM1 }, { OpC0X0 }, { OpC1E0M1 }, { OpC2 },
+ { OpC3M1 }, { OpC4X0 }, { OpC5M1 }, { OpC6M1 }, { OpC7M1 },
+ { OpC8X0 }, { OpC9M1 }, { OpCAX0 }, { OpCB }, { OpCCX0 },
+ { OpCDM1 }, { OpCEM1 }, { OpCFM1 }, { OpD0E0 }, { OpD1E0M1X0 },
+ { OpD2E0M1 }, { OpD3M1 }, { OpD4E0 }, { OpD5E0M1 }, { OpD6E0M1 },
+ { OpD7M1 }, { OpD8 }, { OpD9M1X0 }, { OpDAE0X0 }, { OpDB },
+ { OpDC }, { OpDDM1X0 }, { OpDEM1X0 }, { OpDFM1 }, { OpE0X0 },
+ { OpE1E0M1 }, { OpE2 }, { OpE3M1 }, { OpE4X0 }, { OpE5M1 },
+ { OpE6M1 }, { OpE7M1 }, { OpE8X0 }, { OpE9M1 }, { OpEA },
+ { OpEB }, { OpECX0 }, { OpEDM1 }, { OpEEM1 }, { OpEFM1 },
+ { OpF0E0 }, { OpF1E0M1X0 }, { OpF2E0M1 }, { OpF3M1 }, { OpF4E0 },
+ { OpF5E0M1 }, { OpF6E0M1 }, { OpF7M1 }, { OpF8 }, { OpF9M1X0 },
+ { OpFAE0X0 }, { OpFB }, { OpFCE0 }, { OpFDM1X0 }, { OpFEM1X0 },
+ { OpFFM1 }
+};
+
+struct SOpcodes S9xOpcodesM0X0[256] =
+{
+ { Op00 }, { Op01E0M0 }, { Op02 }, { Op03M0 }, { Op04M0 },
+ { Op05M0 }, { Op06M0 }, { Op07M0 }, { Op08E0 }, { Op09M0 },
+ { Op0AM0 }, { Op0BE0 }, { Op0CM0 }, { Op0DM0 }, { Op0EM0 },
+ { Op0FM0 }, { Op10E0 }, { Op11E0M0X0 }, { Op12E0M0 }, { Op13M0 },
+ { Op14M0 }, { Op15E0M0 }, { Op16E0M0 }, { Op17M0 }, { Op18 },
+ { Op19M0X0 }, { Op1AM0 }, { Op1B }, { Op1CM0 }, { Op1DM0X0 },
+ { Op1EM0X0 }, { Op1FM0 }, { Op20E0 }, { Op21E0M0 }, { Op22E0 },
+ { Op23M0 }, { Op24M0 }, { Op25M0 }, { Op26M0 }, { Op27M0 },
+ { Op28E0 }, { Op29M0 }, { Op2AM0 }, { Op2BE0 }, { Op2CM0 },
+ { Op2DM0 }, { Op2EM0 }, { Op2FM0 }, { Op30E0 }, { Op31E0M0X0 },
+ { Op32E0M0 }, { Op33M0 }, { Op34E0M0 }, { Op35E0M0 }, { Op36E0M0 },
+ { Op37M0 }, { Op38 }, { Op39M0X0 }, { Op3AM0 }, { Op3B },
+ { Op3CM0X0 }, { Op3DM0X0 }, { Op3EM0X0 }, { Op3FM0 }, { Op40Slow },
+ { Op41E0M0 }, { Op42 }, { Op43M0 }, { Op44X0 }, { Op45M0 },
+ { Op46M0 }, { Op47M0 }, { Op48E0M0 }, { Op49M0 }, { Op4AM0 },
+ { Op4BE0 }, { Op4C }, { Op4DM0 }, { Op4EM0 }, { Op4FM0 },
+ { Op50E0 }, { Op51E0M0X0 }, { Op52E0M0 }, { Op53M0 }, { Op54X0 },
+ { Op55E0M0 }, { Op56E0M0 }, { Op57M0 }, { Op58 }, { Op59M0X0 },
+ { Op5AE0X0 }, { Op5B }, { Op5C }, { Op5DM0X0 }, { Op5EM0X0 },
+ { Op5FM0 }, { Op60E0 }, { Op61E0M0 }, { Op62E0 }, { Op63M0 },
+ { Op64M0 }, { Op65M0 }, { Op66M0 }, { Op67M0 }, { Op68E0M0 },
+ { Op69M0 }, { Op6AM0 }, { Op6BE0 }, { Op6C }, { Op6DM0 },
+ { Op6EM0 }, { Op6FM0 }, { Op70E0 }, { Op71E0M0X0 }, { Op72E0M0 },
+ { Op73M0 }, { Op74E0M0 }, { Op75E0M0 }, { Op76E0M0 }, { Op77M0 },
+ { Op78 }, { Op79M0X0 }, { Op7AE0X0 }, { Op7B }, { Op7C },
+ { Op7DM0X0 }, { Op7EM0X0 }, { Op7FM0 }, { Op80E0 }, { Op81E0M0 },
+ { Op82 }, { Op83M0 }, { Op84X0 }, { Op85M0 }, { Op86X0 },
+ { Op87M0 }, { Op88X0 }, { Op89M0 }, { Op8AM0 }, { Op8BE0 },
+ { Op8CX0 }, { Op8DM0 }, { Op8EX0 }, { Op8FM0 }, { Op90E0 },
+ { Op91E0M0X0 }, { Op92E0M0 }, { Op93M0 }, { Op94E0X0 }, { Op95E0M0 },
+ { Op96E0X0 }, { Op97M0 }, { Op98M0 }, { Op99M0X0 }, { Op9A },
+ { Op9BX0 }, { Op9CM0 }, { Op9DM0X0 }, { Op9EM0X0 }, { Op9FM0 },
+ { OpA0X0 }, { OpA1E0M0 }, { OpA2X0 }, { OpA3M0 }, { OpA4X0 },
+ { OpA5M0 }, { OpA6X0 }, { OpA7M0 }, { OpA8X0 }, { OpA9M0 },
+ { OpAAX0 }, { OpABE0 }, { OpACX0 }, { OpADM0 }, { OpAEX0 },
+ { OpAFM0 }, { OpB0E0 }, { OpB1E0M0X0 }, { OpB2E0M0 }, { OpB3M0 },
+ { OpB4E0X0 }, { OpB5E0M0 }, { OpB6E0X0 }, { OpB7M0 }, { OpB8 },
+ { OpB9M0X0 }, { OpBAX0 }, { OpBBX0 }, { OpBCX0 }, { OpBDM0X0 },
+ { OpBEX0 }, { OpBFM0 }, { OpC0X0 }, { OpC1E0M0 }, { OpC2 },
+ { OpC3M0 }, { OpC4X0 }, { OpC5M0 }, { OpC6M0 }, { OpC7M0 },
+ { OpC8X0 }, { OpC9M0 }, { OpCAX0 }, { OpCB }, { OpCCX0 },
+ { OpCDM0 }, { OpCEM0 }, { OpCFM0 }, { OpD0E0 }, { OpD1E0M0X0 },
+ { OpD2E0M0 }, { OpD3M0 }, { OpD4E0 }, { OpD5E0M0 }, { OpD6E0M0 },
+ { OpD7M0 }, { OpD8 }, { OpD9M0X0 }, { OpDAE0X0 }, { OpDB },
+ { OpDC }, { OpDDM0X0 }, { OpDEM0X0 }, { OpDFM0 }, { OpE0X0 },
+ { OpE1E0M0 }, { OpE2 }, { OpE3M0 }, { OpE4X0 }, { OpE5M0 },
+ { OpE6M0 }, { OpE7M0 }, { OpE8X0 }, { OpE9M0 }, { OpEA },
+ { OpEB }, { OpECX0 }, { OpEDM0 }, { OpEEM0 }, { OpEFM0 },
+ { OpF0E0 }, { OpF1E0M0X0 }, { OpF2E0M0 }, { OpF3M0 }, { OpF4E0 },
+ { OpF5E0M0 }, { OpF6E0M0 }, { OpF7M0 }, { OpF8 }, { OpF9M0X0 },
+ { OpFAE0X0 }, { OpFB }, { OpFCE0 }, { OpFDM0X0 }, { OpFEM0X0 },
+ { OpFFM0 }
+};
+
+struct SOpcodes S9xOpcodesM0X1[256] =
+{
+ { Op00 }, { Op01E0M0 }, { Op02 }, { Op03M0 }, { Op04M0 },
+ { Op05M0 }, { Op06M0 }, { Op07M0 }, { Op08E0 }, { Op09M0 },
+ { Op0AM0 }, { Op0BE0 }, { Op0CM0 }, { Op0DM0 }, { Op0EM0 },
+ { Op0FM0 }, { Op10E0 }, { Op11E0M0X1 }, { Op12E0M0 }, { Op13M0 },
+ { Op14M0 }, { Op15E0M0 }, { Op16E0M0 }, { Op17M0 }, { Op18 },
+ { Op19M0X1 }, { Op1AM0 }, { Op1B }, { Op1CM0 }, { Op1DM0X1 },
+ { Op1EM0X1 }, { Op1FM0 }, { Op20E0 }, { Op21E0M0 }, { Op22E0 },
+ { Op23M0 }, { Op24M0 }, { Op25M0 }, { Op26M0 }, { Op27M0 },
+ { Op28E0 }, { Op29M0 }, { Op2AM0 }, { Op2BE0 }, { Op2CM0 },
+ { Op2DM0 }, { Op2EM0 }, { Op2FM0 }, { Op30E0 }, { Op31E0M0X1 },
+ { Op32E0M0 }, { Op33M0 }, { Op34E0M0 }, { Op35E0M0 }, { Op36E0M0 },
+ { Op37M0 }, { Op38 }, { Op39M0X1 }, { Op3AM0 }, { Op3B },
+ { Op3CM0X1 }, { Op3DM0X1 }, { Op3EM0X1 }, { Op3FM0 }, { Op40Slow },
+ { Op41E0M0 }, { Op42 }, { Op43M0 }, { Op44X1 }, { Op45M0 },
+ { Op46M0 }, { Op47M0 }, { Op48E0M0 }, { Op49M0 }, { Op4AM0 },
+ { Op4BE0 }, { Op4C }, { Op4DM0 }, { Op4EM0 }, { Op4FM0 },
+ { Op50E0 }, { Op51E0M0X1 }, { Op52E0M0 }, { Op53M0 }, { Op54X1 },
+ { Op55E0M0 }, { Op56E0M0 }, { Op57M0 }, { Op58 }, { Op59M0X1 },
+ { Op5AE0X1 }, { Op5B }, { Op5C }, { Op5DM0X1 }, { Op5EM0X1 },
+ { Op5FM0 }, { Op60E0 }, { Op61E0M0 }, { Op62E0 }, { Op63M0 },
+ { Op64M0 }, { Op65M0 }, { Op66M0 }, { Op67M0 }, { Op68E0M0 },
+ { Op69M0 }, { Op6AM0 }, { Op6BE0 }, { Op6C }, { Op6DM0 },
+ { Op6EM0 }, { Op6FM0 }, { Op70E0 }, { Op71E0M0X1 }, { Op72E0M0 },
+ { Op73M0 }, { Op74E0M0 }, { Op75E0M0 }, { Op76E0M0 }, { Op77M0 },
+ { Op78 }, { Op79M0X1 }, { Op7AE0X1 }, { Op7B }, { Op7C },
+ { Op7DM0X1 }, { Op7EM0X1 }, { Op7FM0 }, { Op80E0 }, { Op81E0M0 },
+ { Op82 }, { Op83M0 }, { Op84X1 }, { Op85M0 }, { Op86X1 },
+ { Op87M0 }, { Op88X1 }, { Op89M0 }, { Op8AM0 }, { Op8BE0 },
+ { Op8CX1 }, { Op8DM0 }, { Op8EX1 }, { Op8FM0 }, { Op90E0 },
+ { Op91E0M0X1 }, { Op92E0M0 }, { Op93M0 }, { Op94E0X1 }, { Op95E0M0 },
+ { Op96E0X1 }, { Op97M0 }, { Op98M0 }, { Op99M0X1 }, { Op9A },
+ { Op9BX1 }, { Op9CM0 }, { Op9DM0X1 }, { Op9EM0X1 }, { Op9FM0 },
+ { OpA0X1 }, { OpA1E0M0 }, { OpA2X1 }, { OpA3M0 }, { OpA4X1 },
+ { OpA5M0 }, { OpA6X1 }, { OpA7M0 }, { OpA8X1 }, { OpA9M0 },
+ { OpAAX1 }, { OpABE0 }, { OpACX1 }, { OpADM0 }, { OpAEX1 },
+ { OpAFM0 }, { OpB0E0 }, { OpB1E0M0X1 }, { OpB2E0M0 }, { OpB3M0 },
+ { OpB4E0X1 }, { OpB5E0M0 }, { OpB6E0X1 }, { OpB7M0 }, { OpB8 },
+ { OpB9M0X1 }, { OpBAX1 }, { OpBBX1 }, { OpBCX1 }, { OpBDM0X1 },
+ { OpBEX1 }, { OpBFM0 }, { OpC0X1 }, { OpC1E0M0 }, { OpC2 },
+ { OpC3M0 }, { OpC4X1 }, { OpC5M0 }, { OpC6M0 }, { OpC7M0 },
+ { OpC8X1 }, { OpC9M0 }, { OpCAX1 }, { OpCB }, { OpCCX1 },
+ { OpCDM0 }, { OpCEM0 }, { OpCFM0 }, { OpD0E0 }, { OpD1E0M0X1 },
+ { OpD2E0M0 }, { OpD3M0 }, { OpD4E0 }, { OpD5E0M0 }, { OpD6E0M0 },
+ { OpD7M0 }, { OpD8 }, { OpD9M0X1 }, { OpDAE0X1 }, { OpDB },
+ { OpDC }, { OpDDM0X1 }, { OpDEM0X1 }, { OpDFM0 }, { OpE0X1 },
+ { OpE1E0M0 }, { OpE2 }, { OpE3M0 }, { OpE4X1 }, { OpE5M0 },
+ { OpE6M0 }, { OpE7M0 }, { OpE8X1 }, { OpE9M0 }, { OpEA },
+ { OpEB }, { OpECX1 }, { OpEDM0 }, { OpEEM0 }, { OpEFM0 },
+ { OpF0E0 }, { OpF1E0M0X1 }, { OpF2E0M0 }, { OpF3M0 }, { OpF4E0 },
+ { OpF5E0M0 }, { OpF6E0M0 }, { OpF7M0 }, { OpF8 }, { OpF9M0X1 },
+ { OpFAE0X1 }, { OpFB }, { OpFCE0 }, { OpFDM0X1 }, { OpFEM0X1 },
+ { OpFFM0 }
+};
+
+struct SOpcodes S9xOpcodesSlow[256] =
+{
+ { Op00 }, { Op01Slow }, { Op02 }, { Op03Slow }, { Op04Slow },
+ { Op05Slow }, { Op06Slow }, { Op07Slow }, { Op08Slow }, { Op09Slow },
+ { Op0ASlow }, { Op0BSlow }, { Op0CSlow }, { Op0DSlow }, { Op0ESlow },
+ { Op0FSlow }, { Op10Slow }, { Op11Slow }, { Op12Slow }, { Op13Slow },
+ { Op14Slow }, { Op15Slow }, { Op16Slow }, { Op17Slow }, { Op18 },
+ { Op19Slow }, { Op1ASlow }, { Op1B }, { Op1CSlow }, { Op1DSlow },
+ { Op1ESlow }, { Op1FSlow }, { Op20Slow }, { Op21Slow }, { Op22Slow },
+ { Op23Slow }, { Op24Slow }, { Op25Slow }, { Op26Slow }, { Op27Slow },
+ { Op28Slow }, { Op29Slow }, { Op2ASlow }, { Op2BSlow }, { Op2CSlow },
+ { Op2DSlow }, { Op2ESlow }, { Op2FSlow }, { Op30Slow }, { Op31Slow },
+ { Op32Slow }, { Op33Slow }, { Op34Slow }, { Op35Slow }, { Op36Slow },
+ { Op37Slow }, { Op38 }, { Op39Slow }, { Op3ASlow }, { Op3B },
+ { Op3CSlow }, { Op3DSlow }, { Op3ESlow }, { Op3FSlow }, { Op40Slow },
+ { Op41Slow }, { Op42 }, { Op43Slow }, { Op44Slow }, { Op45Slow },
+ { Op46Slow }, { Op47Slow }, { Op48Slow }, { Op49Slow }, { Op4ASlow },
+ { Op4BSlow }, { Op4CSlow }, { Op4DSlow }, { Op4ESlow }, { Op4FSlow },
+ { Op50Slow }, { Op51Slow }, { Op52Slow }, { Op53Slow }, { Op54Slow },
+ { Op55Slow }, { Op56Slow }, { Op57Slow }, { Op58 }, { Op59Slow },
+ { Op5ASlow }, { Op5B }, { Op5CSlow }, { Op5DSlow }, { Op5ESlow },
+ { Op5FSlow }, { Op60Slow }, { Op61Slow }, { Op62Slow }, { Op63Slow },
+ { Op64Slow }, { Op65Slow }, { Op66Slow }, { Op67Slow }, { Op68Slow },
+ { Op69Slow }, { Op6ASlow }, { Op6BSlow }, { Op6CSlow }, { Op6DSlow },
+ { Op6ESlow }, { Op6FSlow }, { Op70Slow }, { Op71Slow }, { Op72Slow },
+ { Op73Slow }, { Op74Slow }, { Op75Slow }, { Op76Slow }, { Op77Slow },
+ { Op78 }, { Op79Slow }, { Op7ASlow }, { Op7B }, { Op7CSlow },
+ { Op7DSlow }, { Op7ESlow }, { Op7FSlow }, { Op80Slow }, { Op81Slow },
+ { Op82Slow }, { Op83Slow }, { Op84Slow }, { Op85Slow }, { Op86Slow },
+ { Op87Slow }, { Op88Slow }, { Op89Slow }, { Op8ASlow }, { Op8BSlow },
+ { Op8CSlow }, { Op8DSlow }, { Op8ESlow }, { Op8FSlow }, { Op90Slow },
+ { Op91Slow }, { Op92Slow }, { Op93Slow }, { Op94Slow }, { Op95Slow },
+ { Op96Slow }, { Op97Slow }, { Op98Slow }, { Op99Slow }, { Op9A },
+ { Op9BSlow }, { Op9CSlow }, { Op9DSlow }, { Op9ESlow }, { Op9FSlow },
+ { OpA0Slow }, { OpA1Slow }, { OpA2Slow }, { OpA3Slow }, { OpA4Slow },
+ { OpA5Slow }, { OpA6Slow }, { OpA7Slow }, { OpA8Slow }, { OpA9Slow },
+ { OpAASlow }, { OpABSlow }, { OpACSlow }, { OpADSlow }, { OpAESlow },
+ { OpAFSlow }, { OpB0Slow }, { OpB1Slow }, { OpB2Slow }, { OpB3Slow },
+ { OpB4Slow }, { OpB5Slow }, { OpB6Slow }, { OpB7Slow }, { OpB8 },
+ { OpB9Slow }, { OpBASlow }, { OpBBSlow }, { OpBCSlow }, { OpBDSlow },
+ { OpBESlow }, { OpBFSlow }, { OpC0Slow }, { OpC1Slow }, { OpC2Slow },
+ { OpC3Slow }, { OpC4Slow }, { OpC5Slow }, { OpC6Slow }, { OpC7Slow },
+ { OpC8Slow }, { OpC9Slow }, { OpCASlow }, { OpCB }, { OpCCSlow },
+ { OpCDSlow }, { OpCESlow }, { OpCFSlow }, { OpD0Slow }, { OpD1Slow },
+ { OpD2Slow }, { OpD3Slow }, { OpD4Slow }, { OpD5Slow }, { OpD6Slow },
+ { OpD7Slow }, { OpD8 }, { OpD9Slow }, { OpDASlow }, { OpDB },
+ { OpDCSlow }, { OpDDSlow }, { OpDESlow }, { OpDFSlow }, { OpE0Slow },
+ { OpE1Slow }, { OpE2Slow }, { OpE3Slow }, { OpE4Slow }, { OpE5Slow },
+ { OpE6Slow }, { OpE7Slow }, { OpE8Slow }, { OpE9Slow }, { OpEA },
+ { OpEB }, { OpECSlow }, { OpEDSlow }, { OpEESlow }, { OpEFSlow },
+ { OpF0Slow }, { OpF1Slow }, { OpF2Slow }, { OpF3Slow }, { OpF4Slow },
+ { OpF5Slow }, { OpF6Slow }, { OpF7Slow }, { OpF8 }, { OpF9Slow },
+ { OpFASlow }, { OpFB }, { OpFCSlow }, { OpFDSlow }, { OpFESlow },
+ { OpFFSlow }
+};
+
--- /dev/null
+++ b/src/in_snsf/snes9x/cpuops.h
@@ -1,1 +1,191 @@
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _CPUOPS_H_
+#define _CPUOPS_H_
+
+void S9xOpcode_NMI();
+void S9xOpcode_IRQ();
+
+#ifndef SA1_OPCODES
+#define CHECK_FOR_IRQ() {} // if (CPU.IRQLine) S9xOpcode_IRQ(); }
+#else
+#define CHECK_FOR_IRQ() {}
+#endif
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/dma.cpp
@@ -1,1 +1,1798 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+#include "snes9x.h"
+#include "memmap.h"
+#include "dma.h"
+#include "apu/apu.h"
+//#include "sdd1emu.h"
+//#include "spc7110emu.h"
+#ifdef DEBUGGER
+#include "missing.h"
+#endif
+
+//#define ADD_CYCLES(n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += (n); S9xCheckInterrupts(); }
+static inline void ADD_CYCLES(int32_t n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += n; S9xCheckInterrupts(); }
+
+extern uint8_t *HDMAMemPointers[8];
+extern int HDMA_ModeByteCounts[8];
+//extern SPC7110 s7emu;
+
+static uint8_t sdd1_decode_buffer[0x10000];
+
+//static inline bool addCyclesInDMA (uint8_t);
+//static inline bool HDMAReadLineCount (int);
+
+
+static inline bool addCyclesInDMA (uint8_t dma_channel)
+{
+ // Add 8 cycles per byte, sync APU, and do HC related events.
+ // If HDMA was done in S9xDoHEventProcessing(), check if it used the same channel as DMA.
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ while (CPU.Cycles >= CPU.NextEvent)
+ S9xDoHEventProcessing();
+
+ if (CPU.HDMARanInDMA & (1 << dma_channel))
+ {
+ CPU.HDMARanInDMA = 0;
+ #ifdef DEBUGGER
+ printf("HDMA and DMA use the same channel %d!\n", dma_channel);
+ #endif
+ // If HDMA triggers in the middle of DMA transfer and it uses the same channel,
+ // it kills the DMA transfer immediately. $43x2 and $43x5 stop updating.
+ return false;
+ }
+
+ CPU.HDMARanInDMA = 0;
+ return true;
+}
+
+bool S9xDoDMA (uint8_t Channel)
+{
+ CPU.InDMA = true;
+ CPU.InDMAorHDMA = true;
+ CPU.CurrentDMAorHDMAChannel = Channel;
+
+ SDMA *d = &DMA[Channel];
+
+ // Check invalid DMA first
+ if ((d->ABank == 0x7E || d->ABank == 0x7F) && d->BAddress == 0x80 && !d->ReverseTransfer)
+ {
+ // Attempting a DMA from WRAM to $2180 will not work, WRAM will not be written.
+ // Attempting a DMA from $2180 to WRAM will similarly not work,
+ // the value written is (initially) the OpenBus value.
+ // In either case, the address in $2181-3 is not incremented.
+
+ // Does an invalid DMA actually take time?
+ // I'd say yes, since 'invalid' is probably just the WRAM chip
+ // not being able to read and write itself at the same time
+ // And no, PPU.WRAM should not be updated.
+
+ int32_t c = d->TransferBytes;
+ // Writing $0000 to $43x5 actually results in a transfer of $10000 bytes, not 0.
+ if (c == 0)
+ c = 0x10000;
+
+ // 8 cycles per channel
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ // 8 cycles per byte
+ while (c)
+ {
+ d->TransferBytes--;
+ d->AAddress++;
+ c--;
+ if (!addCyclesInDMA(Channel))
+ {
+ CPU.InDMA = false;
+ CPU.InDMAorHDMA = false;
+ CPU.CurrentDMAorHDMAChannel = -1;
+ return false;
+ }
+ }
+
+ #ifdef DEBUGGER
+ if (Settings.TraceDMA)
+ {
+ sprintf(String, "DMA[%d]: WRAM Bank:%02X->$2180", Channel, d->ABank);
+ S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
+ }
+ #endif
+
+ CPU.InDMA = false;
+ CPU.InDMAorHDMA = false;
+ CPU.CurrentDMAorHDMAChannel = -1;
+ return true;
+ }
+
+ // Prepare for accessing $2118-2119
+ /*switch (d->BAddress)
+ {
+ case 0x18:
+ case 0x19:
+ if (IPPU.RenderThisFrame)
+ FLUSH_REDRAW();
+ break;
+ }*/
+
+ int32_t inc = d->AAddressFixed ? 0 : (!d->AAddressDecrement ? 1 : -1);
+ int32_t count = d->TransferBytes;
+ // Writing $0000 to $43x5 actually results in a transfer of $10000 bytes, not 0.
+ if (count == 0)
+ count = 0x10000;
+
+ // Prepare for custom chip DMA
+
+ // S-DD1
+
+ uint8_t *in_sdd1_dma = NULL;
+
+ if (Settings.SDD1)
+ {
+ if (d->AAddressFixed && Memory.FillRAM[0x4801] > 0)
+ {
+ // XXX: Should probably verify that we're DMAing from ROM?
+ // And somewhere we should make sure we're not running across a mapping boundary too.
+ // Hacky support for pre-decompressed S-DD1 data
+ inc = !d->AAddressDecrement ? 1 : -1;
+
+ uint8_t *in_ptr = S9xGetBasePointer(((d->ABank << 16) | d->AAddress));
+ if (in_ptr)
+ {
+ in_ptr += d->AAddress;
+ //SDD1_decompress(sdd1_decode_buffer, in_ptr, d->TransferBytes);
+ }
+ #ifdef DEBUGGER
+ else
+ {
+ sprintf(String, "S-DD1: DMA from non-block address $%02X:%04X", d->ABank, d->AAddress);
+ S9xMessage(S9X_WARNING, S9X_DMA_TRACE, String);
+ }
+ #endif
+
+ in_sdd1_dma = sdd1_decode_buffer;
+ }
+
+ Memory.FillRAM[0x4801] = 0;
+ }
+
+ // SPC7110
+
+ //uint8_t *spc7110_dma = NULL;
+
+ /*if (Settings.SPC7110)
+ {
+ if (d->AAddress == 0x4800 || d->ABank == 0x50)
+ {
+ spc7110_dma = new uint8_t[d->TransferBytes];
+ for (int i = 0; i < d->TransferBytes; i++)
+ spc7110_dma[i] = s7emu.decomp.read();
+
+ int32_t icount = s7emu.r4809 | (s7emu.r480a << 8);
+ icount -= d->TransferBytes;
+ s7emu.r4809 = icount & 0x00ff;
+ s7emu.r480a = (icount & 0xff00) >> 8;
+
+ inc = 1;
+ d->AAddress -= count;
+ }
+ }*/
+
+ // SA-1
+
+ //bool in_sa1_dma = false;
+
+ /*if (Settings.SA1)
+ {
+ if (SA1.in_char_dma && d->BAddress == 0x18 && (d->ABank & 0xf0) == 0x40)
+ {
+ // Perform packed bitmap to PPU character format conversion on the data
+ // before transmitting it to V-RAM via-DMA.
+ int32_t num_chars = 1 << ((Memory.FillRAM[0x2231] >> 2) & 7);
+ int32_t depth = (Memory.FillRAM[0x2231] & 3) == 0 ? 8 : (Memory.FillRAM[0x2231] & 3) == 1 ? 4 : 2;
+ int32_t bytes_per_char = 8 * depth;
+ int32_t bytes_per_line = depth * num_chars;
+ int32_t char_line_bytes = bytes_per_char * num_chars;
+ uint32_t addr = (d->AAddress / char_line_bytes) * char_line_bytes;
+
+ uint8_t *base = S9xGetBasePointer((d->ABank << 16) + addr);
+ if (!base)
+ {
+ sprintf(String, "SA-1: DMA from non-block address $%02X:%04X", d->ABank, addr);
+ S9xMessage(S9X_WARNING, S9X_DMA_TRACE, String);
+ base = Memory.ROM;
+ }
+
+ base += addr;
+
+ uint8_t *buffer = &Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000];
+ uint8_t *p = buffer;
+ uint32_t inc_sa1 = char_line_bytes - (d->AAddress % char_line_bytes);
+ uint32_t char_count = inc_sa1 / bytes_per_char;
+
+ in_sa1_dma = true;
+
+ #if 0
+ printf("SA-1 DMA: %08x,", base);
+ printf("depth = %d, count = %d, bytes_per_char = %d, bytes_per_line = %d, num_chars = %d, char_line_bytes = %d\n",
+ depth, count, bytes_per_char, bytes_per_line, num_chars, char_line_bytes);
+ #endif
+
+ switch (depth)
+ {
+ case 2:
+ for (int32_t i = 0; i < count; i += inc_sa1, base += char_line_bytes, inc_sa1 = char_line_bytes, char_count = num_chars)
+ {
+ uint8_t *line = base + (num_chars - char_count) * 2;
+ for (uint32_t j = 0; j < char_count && p - buffer < count; j++, line += 2)
+ {
+ uint8_t *q = line;
+ for (int32_t l = 0; l < 8; l++, q += bytes_per_line)
+ {
+ for (int32_t b = 0; b < 2; b++)
+ {
+ uint8_t r = *(q + b);
+ *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
+ *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
+ *(p + 0) = (*(p + 0) << 1) | ((r >> 2) & 1);
+ *(p + 1) = (*(p + 1) << 1) | ((r >> 3) & 1);
+ *(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1);
+ *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1);
+ *(p + 0) = (*(p + 0) << 1) | ((r >> 6) & 1);
+ *(p + 1) = (*(p + 1) << 1) | ((r >> 7) & 1);
+ }
+
+ p += 2;
+ }
+ }
+ }
+
+ break;
+
+ case 4:
+ for (int32_t i = 0; i < count; i += inc_sa1, base += char_line_bytes, inc_sa1 = char_line_bytes, char_count = num_chars)
+ {
+ uint8_t *line = base + (num_chars - char_count) * 4;
+ for (uint32_t j = 0; j < char_count && p - buffer < count; j++, line += 4)
+ {
+ uint8_t *q = line;
+ for (int32_t l = 0; l < 8; l++, q += bytes_per_line)
+ {
+ for (int32_t b = 0; b < 4; b++)
+ {
+ uint8_t r = *(q + b);
+ *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
+ *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
+ *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
+ *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
+ *(p + 0) = (*(p + 0) << 1) | ((r >> 4) & 1);
+ *(p + 1) = (*(p + 1) << 1) | ((r >> 5) & 1);
+ *(p + 16) = (*(p + 16) << 1) | ((r >> 6) & 1);
+ *(p + 17) = (*(p + 17) << 1) | ((r >> 7) & 1);
+ }
+
+ p += 2;
+ }
+
+ p += 32 - 16;
+ }
+ }
+
+ break;
+
+ case 8:
+ for (int32_t i = 0; i < count; i += inc_sa1, base += char_line_bytes, inc_sa1 = char_line_bytes, char_count = num_chars)
+ {
+ uint8_t *line = base + (num_chars - char_count) * 8;
+ for (uint32_t j = 0; j < char_count && p - buffer < count; j++, line += 8)
+ {
+ uint8_t *q = line;
+ for (int32_t l = 0; l < 8; l++, q += bytes_per_line)
+ {
+ for (int32_t b = 0; b < 8; b++)
+ {
+ uint8_t r = *(q + b);
+ *(p + 0) = (*(p + 0) << 1) | ((r >> 0) & 1);
+ *(p + 1) = (*(p + 1) << 1) | ((r >> 1) & 1);
+ *(p + 16) = (*(p + 16) << 1) | ((r >> 2) & 1);
+ *(p + 17) = (*(p + 17) << 1) | ((r >> 3) & 1);
+ *(p + 32) = (*(p + 32) << 1) | ((r >> 4) & 1);
+ *(p + 33) = (*(p + 33) << 1) | ((r >> 5) & 1);
+ *(p + 48) = (*(p + 48) << 1) | ((r >> 6) & 1);
+ *(p + 49) = (*(p + 49) << 1) | ((r >> 7) & 1);
+ }
+
+ p += 2;
+ }
+
+ p += 64 - 16;
+ }
+ }
+
+ break;
+ }
+ }
+ }*/
+
+#ifdef DEBUGGER
+ if (Settings.TraceDMA)
+ {
+ sprintf(String, "DMA[%d]: %s Mode:%d 0x%02X%04X->0x21%02X Bytes:%d (%s) V:%03d",
+ Channel, d->ReverseTransfer ? "PPU->CPU" : "CPU->PPU", d->TransferMode, d->ABank, d->AAddress, d->BAddress,
+ d->TransferBytes, d->AAddressFixed ? "fixed" : (d->AAddressDecrement ? "dec" : "inc"), CPU.V_Counter);
+
+ if (d->BAddress == 0x18 || d->BAddress == 0x19 || d->BAddress == 0x39 || d->BAddress == 0x3a)
+ sprintf(String, "%s VRAM: %04X (%d,%d) %s", String,
+ PPU.VMA.Address, PPU.VMA.Increment, PPU.VMA.FullGraphicCount, PPU.VMA.High ? "word" : "byte");
+ else
+ if (d->BAddress == 0x22 || d->BAddress == 0x3b)
+ sprintf(String, "%s CGRAM: %02X (%x)", String, PPU.CGADD, PPU.CGFLIP);
+ else
+ if (d->BAddress == 0x04 || d->BAddress == 0x38)
+ sprintf(String, "%s OBJADDR: %04X", String, PPU.OAMAddr);
+
+ S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
+ }
+#endif
+
+ // Do Transfer
+
+ uint8_t Work;
+
+ // 8 cycles per channel
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+
+ if (!d->ReverseTransfer)
+ {
+ // CPU -> PPU
+ int32_t b = 0;
+ uint16_t p = d->AAddress;
+ uint8_t *base = S9xGetBasePointer((d->ABank << 16) + d->AAddress);
+ bool inWRAM_DMA;
+
+ int32_t rem = count;
+ // Transfer per block if d->AAdressFixed is false
+ count = d->AAddressFixed ? rem : (d->AAddressDecrement ? ((p & MEMMAP_MASK) + 1) : (MEMMAP_BLOCK_SIZE - (p & MEMMAP_MASK)));
+
+ // Settings for custom chip DMA
+ /*if (in_sa1_dma)
+ {
+ base = &Memory.ROM[CMemory::MAX_ROM_SIZE - 0x10000];
+ p = 0;
+ count = rem;
+ }
+ else*/
+ if (in_sdd1_dma)
+ {
+ base = in_sdd1_dma;
+ p = 0;
+ count = rem;
+ }
+ /*else
+ if (spc7110_dma)
+ {
+ base = spc7110_dma;
+ p = 0;
+ count = rem;
+ }*/
+
+ inWRAM_DMA = ((/*!in_sa1_dma && */!in_sdd1_dma/* && !spc7110_dma*/) &&
+ (d->ABank == 0x7e || d->ABank == 0x7f || (!(d->ABank & 0x40) && d->AAddress < 0x2000)));
+
+ // 8 cycles per byte
+ #define UPDATE_COUNTERS \
+ d->TransferBytes--; \
+ d->AAddress += inc; \
+ p += inc; \
+ if (!addCyclesInDMA(Channel)) \
+ { \
+ CPU.InDMA = false; \
+ CPU.InDMAorHDMA = false; \
+ CPU.InWRAMDMAorHDMA = false; \
+ CPU.CurrentDMAorHDMAChannel = -1; \
+ return false; \
+ }
+
+ while (1)
+ {
+ if (count > rem)
+ count = rem;
+ rem -= count;
+
+ CPU.InWRAMDMAorHDMA = inWRAM_DMA;
+
+ if (!base)
+ {
+ // DMA SLOW PATH
+ if (d->TransferMode == 0 || d->TransferMode == 2 || d->TransferMode == 6)
+ {
+ do
+ {
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ } while (--count > 0);
+ }
+ else
+ if (d->TransferMode == 1 || d->TransferMode == 5)
+ {
+ // This is a variation on Duff's Device. It is legal C/C++.
+ switch (b)
+ {
+ default:
+ while (count > 1)
+ {
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ count--;
+
+ case 1:
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2101 + d->BAddress);
+ UPDATE_COUNTERS;
+ count--;
+ }
+ }
+
+ if (count == 1)
+ {
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ b = 1;
+ }
+ else
+ b = 0;
+ }
+ else
+ if (d->TransferMode == 3 || d->TransferMode == 7)
+ {
+ switch (b)
+ {
+ default:
+ do
+ {
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 1;
+ break;
+ }
+
+ case 1:
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 2;
+ break;
+ }
+
+ case 2:
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2101 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 3;
+ break;
+ }
+
+ case 3:
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2101 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 0;
+ break;
+ }
+ } while (1);
+ }
+ }
+ else
+ if (d->TransferMode == 4)
+ {
+ switch (b)
+ {
+ default:
+ do
+ {
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 1;
+ break;
+ }
+
+ case 1:
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2101 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 2;
+ break;
+ }
+
+ case 2:
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2102 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 3;
+ break;
+ }
+
+ case 3:
+ Work = S9xGetByte((d->ABank << 16) + p);
+ S9xSetPPU(Work, 0x2103 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 0;
+ break;
+ }
+ } while (1);
+ }
+ }
+ #ifdef DEBUGGER
+ else
+ {
+ sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel);
+ S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
+ }
+ #endif
+ }
+ else
+ {
+ // DMA FAST PATH
+ if (d->TransferMode == 0 || d->TransferMode == 2 || d->TransferMode == 6)
+ {
+ switch (d->BAddress)
+ {
+ case 0x04: // OAMDATA
+ do
+ {
+ Work = *(base + p);
+ REGISTER_2104(Work);
+ UPDATE_COUNTERS;
+ } while (--count > 0);
+
+ break;
+
+ case 0x18: // VMDATAL
+ if (!PPU.VMA.FullGraphicCount)
+ {
+ do
+ {
+ Work = *(base + p);
+ REGISTER_2118_linear(Work);
+ UPDATE_COUNTERS;
+ } while (--count > 0);
+ }
+ else
+ {
+ do
+ {
+ Work = *(base + p);
+ REGISTER_2118_tile(Work);
+ UPDATE_COUNTERS;
+ } while (--count > 0);
+ }
+
+ break;
+
+ case 0x19: // VMDATAH
+ if (!PPU.VMA.FullGraphicCount)
+ {
+ do
+ {
+ Work = *(base + p);
+ REGISTER_2119_linear(Work);
+ UPDATE_COUNTERS;
+ } while (--count > 0);
+ }
+ else
+ {
+ do
+ {
+ Work = *(base + p);
+ REGISTER_2119_tile(Work);
+ UPDATE_COUNTERS;
+ } while (--count > 0);
+ }
+
+ break;
+
+ case 0x22: // CGDATA
+ do
+ {
+ Work = *(base + p);
+ //REGISTER_2122(Work);
+ UPDATE_COUNTERS;
+ } while (--count > 0);
+
+ break;
+
+ case 0x80: // WMDATA
+ if (!CPU.InWRAMDMAorHDMA)
+ {
+ do
+ {
+ Work = *(base + p);
+ REGISTER_2180(Work);
+ UPDATE_COUNTERS;
+ } while (--count > 0);
+ }
+ else
+ {
+ do
+ {
+ UPDATE_COUNTERS;
+ } while (--count > 0);
+ }
+
+ break;
+
+ default:
+ do
+ {
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ } while (--count > 0);
+
+ break;
+ }
+ }
+ else
+ if (d->TransferMode == 1 || d->TransferMode == 5)
+ {
+ if (d->BAddress == 0x18)
+ {
+ // VMDATAL
+ if (!PPU.VMA.FullGraphicCount)
+ {
+ switch (b)
+ {
+ default:
+ while (count > 1)
+ {
+ Work = *(base + p);
+ REGISTER_2118_linear(Work);
+ UPDATE_COUNTERS;
+ count--;
+
+ case 1:
+ Work = *(base + p);
+ REGISTER_2119_linear(Work);
+ UPDATE_COUNTERS;
+ count--;
+ }
+ }
+
+ if (count == 1)
+ {
+ Work = *(base + p);
+ REGISTER_2118_linear(Work);
+ UPDATE_COUNTERS;
+ b = 1;
+ }
+ else
+ b = 0;
+ }
+ else
+ {
+ switch (b)
+ {
+ default:
+ while (count > 1)
+ {
+ Work = *(base + p);
+ REGISTER_2118_tile(Work);
+ UPDATE_COUNTERS;
+ count--;
+
+ case 1:
+ Work = *(base + p);
+ REGISTER_2119_tile(Work);
+ UPDATE_COUNTERS;
+ count--;
+ }
+ }
+
+ if (count == 1)
+ {
+ Work = *(base + p);
+ REGISTER_2118_tile(Work);
+ UPDATE_COUNTERS;
+ b = 1;
+ }
+ else
+ b = 0;
+ }
+ }
+ else
+ {
+ // DMA mode 1 general case
+ switch (b)
+ {
+ default:
+ while (count > 1)
+ {
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ count--;
+
+ case 1:
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2101 + d->BAddress);
+ UPDATE_COUNTERS;
+ count--;
+ }
+ }
+
+ if (count == 1)
+ {
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ b = 1;
+ }
+ else
+ b = 0;
+ }
+ }
+ else
+ if (d->TransferMode == 3 || d->TransferMode == 7)
+ {
+ switch (b)
+ {
+ default:
+ do
+ {
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 1;
+ break;
+ }
+
+ case 1:
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 2;
+ break;
+ }
+
+ case 2:
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2101 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 3;
+ break;
+ }
+
+ case 3:
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2101 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 0;
+ break;
+ }
+ } while (1);
+ }
+ }
+ else
+ if (d->TransferMode == 4)
+ {
+ switch (b)
+ {
+ default:
+ do
+ {
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2100 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 1;
+ break;
+ }
+
+ case 1:
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2101 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 2;
+ break;
+ }
+
+ case 2:
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2102 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 3;
+ break;
+ }
+
+ case 3:
+ Work = *(base + p);
+ S9xSetPPU(Work, 0x2103 + d->BAddress);
+ UPDATE_COUNTERS;
+ if (--count <= 0)
+ {
+ b = 0;
+ break;
+ }
+ } while (1);
+ }
+ }
+ #ifdef DEBUGGER
+ else
+ {
+ sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel);
+ S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
+ }
+ #endif
+ }
+
+ if (rem <= 0)
+ break;
+
+ base = S9xGetBasePointer((d->ABank << 16) + d->AAddress);
+ count = MEMMAP_BLOCK_SIZE;
+ inWRAM_DMA = ((/*!in_sa1_dma && */!in_sdd1_dma/* && !spc7110_dma*/) &&
+ (d->ABank == 0x7e || d->ABank == 0x7f || (!(d->ABank & 0x40) && d->AAddress < 0x2000)));
+ }
+
+ #undef UPDATE_COUNTERS
+ }
+ else
+ {
+ // PPU -> CPU
+
+ // 8 cycles per byte
+ #define UPDATE_COUNTERS \
+ d->TransferBytes--; \
+ d->AAddress += inc; \
+ if (!addCyclesInDMA(Channel)) \
+ { \
+ CPU.InDMA = false; \
+ CPU.InDMAorHDMA = false; \
+ CPU.InWRAMDMAorHDMA = false; \
+ CPU.CurrentDMAorHDMAChannel = -1; \
+ return false; \
+ }
+
+ if (d->BAddress > 0x80 - 4 && d->BAddress <= 0x83 && !(d->ABank & 0x40))
+ {
+ // REVERSE-DMA REALLY-SLOW PATH
+ do
+ {
+ switch (d->TransferMode)
+ {
+ case 0:
+ case 2:
+ case 6:
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2100 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ count--;
+
+ break;
+
+ case 1:
+ case 5:
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2100 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2101 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ count--;
+
+ break;
+
+ case 3:
+ case 7:
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2100 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2100 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2101 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2101 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ count--;
+
+ break;
+
+ case 4:
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2100 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2101 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2102 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ CPU.InWRAMDMAorHDMA = (d->AAddress < 0x2000);
+ Work = S9xGetPPU(0x2103 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ count--;
+
+ break;
+
+ default:
+ #ifdef DEBUGGER
+ sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel);
+ S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
+ #endif
+ while (count)
+ {
+ UPDATE_COUNTERS;
+ count--;
+ }
+
+ break;
+ }
+ } while (count);
+ }
+ else
+ {
+ // REVERSE-DMA FASTER PATH
+ CPU.InWRAMDMAorHDMA = (d->ABank == 0x7e || d->ABank == 0x7f);
+ do
+ {
+ switch (d->TransferMode)
+ {
+ case 0:
+ case 2:
+ case 6:
+ Work = S9xGetPPU(0x2100 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ count--;
+
+ break;
+
+ case 1:
+ case 5:
+ Work = S9xGetPPU(0x2100 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ Work = S9xGetPPU(0x2101 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ count--;
+
+ break;
+
+ case 3:
+ case 7:
+ Work = S9xGetPPU(0x2100 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ Work = S9xGetPPU(0x2100 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ Work = S9xGetPPU(0x2101 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ Work = S9xGetPPU(0x2101 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ count--;
+
+ break;
+
+ case 4:
+ Work = S9xGetPPU(0x2100 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ Work = S9xGetPPU(0x2101 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ Work = S9xGetPPU(0x2102 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ if (!--count)
+ break;
+
+ Work = S9xGetPPU(0x2103 + d->BAddress);
+ S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
+ UPDATE_COUNTERS;
+ count--;
+
+ break;
+
+ default:
+ #ifdef DEBUGGER
+ sprintf(String, "Unknown DMA transfer mode: %d on channel %d\n", d->TransferMode, Channel);
+ S9xMessage(S9X_TRACE, S9X_DMA_TRACE, String);
+ #endif
+ while (count)
+ {
+ UPDATE_COUNTERS;
+ count--;
+ }
+
+ break;
+ }
+ } while (count);
+ }
+ }
+
+ if (CPU.NMILine && (Timings.NMITriggerPos != 0xffff))
+ {
+ Timings.NMITriggerPos = CPU.Cycles + Timings.NMIDMADelay;
+ if (Timings.NMITriggerPos >= Timings.H_Max)
+ Timings.NMITriggerPos -= Timings.H_Max;
+ }
+
+ // Release the memory used in SPC7110 DMA
+ /*if (Settings.SPC7110)
+ {
+ if (spc7110_dma)
+ delete [] spc7110_dma;
+ }*/
+
+#if 0
+ // sanity check
+ if (d->TransferBytes != 0)
+ fprintf(stderr,"DMA[%d] TransferBytes not 0! $21%02x Reverse:%d %04x\n", Channel, d->BAddress, d->ReverseTransfer, d->TransferBytes);
+#endif
+
+ CPU.InDMA = false;
+ CPU.InDMAorHDMA = false;
+ CPU.InWRAMDMAorHDMA = false;
+ CPU.CurrentDMAorHDMAChannel = -1;
+
+ return true;
+}
+
+static inline bool HDMAReadLineCount (int d)
+{
+ // CPU.InDMA is set, so S9xGetXXX() / S9xSetXXX() incur no charges.
+
+ uint8_t line;
+
+ line = S9xGetByte((DMA[d].ABank << 16) + DMA[d].Address);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+
+ if (!line)
+ {
+ DMA[d].Repeat = false;
+ DMA[d].LineCount = 128;
+
+ if (DMA[d].HDMAIndirectAddressing)
+ {
+ if (PPU.HDMA & (0xfe << d))
+ {
+ DMA[d].Address++;
+ ADD_CYCLES(SLOW_ONE_CYCLE << 1);
+ }
+ else
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+
+ DMA[d].IndirectAddress = S9xGetWord((DMA[d].ABank << 16) + DMA[d].Address);
+ DMA[d].Address++;
+ }
+
+ DMA[d].Address++;
+ HDMAMemPointers[d] = NULL;
+
+ return false;
+ }
+ else
+ if (line == 0x80)
+ {
+ DMA[d].Repeat = true;
+ DMA[d].LineCount = 128;
+ }
+ else
+ {
+ DMA[d].Repeat = !(line & 0x80);
+ DMA[d].LineCount = line & 0x7f;
+ }
+
+ DMA[d].Address++;
+ DMA[d].DoTransfer = true;
+
+ if (DMA[d].HDMAIndirectAddressing)
+ {
+ ADD_CYCLES(SLOW_ONE_CYCLE << 1);
+ DMA[d].IndirectAddress = S9xGetWord((DMA[d].ABank << 16) + DMA[d].Address);
+ DMA[d].Address += 2;
+ HDMAMemPointers[d] = S9xGetMemPointer((DMA[d].IndirectBank << 16) + DMA[d].IndirectAddress);
+ }
+ else
+ HDMAMemPointers[d] = S9xGetMemPointer((DMA[d].ABank << 16) + DMA[d].Address);
+
+ return true;
+}
+
+void S9xStartHDMA()
+{
+ PPU.HDMA = Memory.FillRAM[0x420c];
+
+#ifdef DEBUGGER
+ missing.hdma_this_frame = PPU.HDMA;
+#endif
+
+ PPU.HDMAEnded = 0;
+
+ int32_t tmpch;
+
+ CPU.InHDMA = true;
+ CPU.InDMAorHDMA = true;
+ tmpch = CPU.CurrentDMAorHDMAChannel;
+
+ // XXX: Not quite right...
+ if (PPU.HDMA != 0)
+ ADD_CYCLES(Timings.DMACPUSync);
+
+ for (uint8_t i = 0; i < 8; i++)
+ {
+ if (PPU.HDMA & (1 << i))
+ {
+ CPU.CurrentDMAorHDMAChannel = i;
+
+ DMA[i].Address = DMA[i].AAddress;
+
+ if (!HDMAReadLineCount(i))
+ {
+ PPU.HDMA &= ~(1 << i);
+ PPU.HDMAEnded |= (1 << i);
+ }
+ }
+ else
+ DMA[i].DoTransfer = false;
+ }
+
+ CPU.InHDMA = false;
+ CPU.InDMAorHDMA = CPU.InDMA;
+ CPU.HDMARanInDMA = CPU.InDMA ? PPU.HDMA : 0;
+ CPU.CurrentDMAorHDMAChannel = tmpch;
+}
+
+uint8_t S9xDoHDMA (uint8_t byte)
+{
+ struct SDMA *p = &DMA[0];
+
+ uint32_t ShiftedIBank;
+ uint16_t IAddr;
+ bool temp;
+ int32_t tmpch;
+ int d = 0;
+
+ CPU.InHDMA = true;
+ CPU.InDMAorHDMA = true;
+ CPU.HDMARanInDMA = CPU.InDMA ? byte : 0;
+ temp = CPU.InWRAMDMAorHDMA;
+ tmpch = CPU.CurrentDMAorHDMAChannel;
+
+ // XXX: Not quite right...
+ ADD_CYCLES(Timings.DMACPUSync);
+
+ for (uint8_t mask = 1; mask; mask <<= 1, p++, d++)
+ {
+ if (byte & mask)
+ {
+ CPU.InWRAMDMAorHDMA = false;
+ CPU.CurrentDMAorHDMAChannel = d;
+
+ if (p->HDMAIndirectAddressing)
+ {
+ ShiftedIBank = (p->IndirectBank << 16);
+ IAddr = p->IndirectAddress;
+ }
+ else
+ {
+ ShiftedIBank = (p->ABank << 16);
+ IAddr = p->Address;
+ }
+
+ if (!HDMAMemPointers[d])
+ HDMAMemPointers[d] = S9xGetMemPointer(ShiftedIBank + IAddr);
+
+ if (p->DoTransfer)
+ {
+ // XXX: Hack for Uniracers, because we don't understand
+ // OAM Address Invalidation
+ if (p->BAddress == 0x04)
+ {
+ if (SNESGameFixes.Uniracers)
+ {
+ PPU.OAMAddr = 0x10c;
+ PPU.OAMFlip = 0;
+ }
+ }
+
+ #ifdef DEBUGGER
+ if (Settings.TraceHDMA && p->DoTransfer)
+ {
+ sprintf(String, "H-DMA[%d] %s (%d) 0x%06X->0x21%02X %s, Count: %3d, Rep: %s, V-LINE: %3ld %02X%04X",
+ p-DMA, p->ReverseTransfer? "read" : "write",
+ p->TransferMode, ShiftedIBank+IAddr, p->BAddress,
+ p->HDMAIndirectAddressing ? "ind" : "abs",
+ p->LineCount,
+ p->Repeat ? "yes" : "no ", (long) CPU.V_Counter,
+ p->ABank, p->Address);
+ S9xMessage(S9X_TRACE, S9X_HDMA_TRACE, String);
+ }
+ #endif
+
+ if (!p->ReverseTransfer)
+ {
+ if ((IAddr & MEMMAP_MASK) + HDMA_ModeByteCounts[p->TransferMode] >= MEMMAP_BLOCK_SIZE)
+ {
+ // HDMA REALLY-SLOW PATH
+ HDMAMemPointers[d] = NULL;
+
+ #define DOBYTE(Addr, RegOff) \
+ CPU.InWRAMDMAorHDMA = (ShiftedIBank == 0x7e0000 || ShiftedIBank == 0x7f0000 || \
+ (!(ShiftedIBank & 0x400000) && ((uint16_t) (Addr)) < 0x2000)); \
+ S9xSetPPU(S9xGetByte(ShiftedIBank + ((uint16_t) (Addr))), 0x2100 + p->BAddress + (RegOff));
+
+ switch (p->TransferMode)
+ {
+ case 0:
+ DOBYTE(IAddr, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 5:
+ DOBYTE(IAddr + 0, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 1, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 2, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 3, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 1:
+ DOBYTE(IAddr + 0, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 1, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 2:
+ case 6:
+ DOBYTE(IAddr + 0, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 1, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 3:
+ case 7:
+ DOBYTE(IAddr + 0, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 1, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 2, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 3, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 4:
+ DOBYTE(IAddr + 0, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 1, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 2, 2);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 3, 3);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+ }
+
+ #undef DOBYTE
+ }
+ else
+ {
+ CPU.InWRAMDMAorHDMA = (ShiftedIBank == 0x7e0000 || ShiftedIBank == 0x7f0000 ||
+ (!(ShiftedIBank & 0x400000) && IAddr < 0x2000));
+
+ if (!HDMAMemPointers[d])
+ {
+ // HDMA SLOW PATH
+ uint32_t Addr = ShiftedIBank + IAddr;
+
+ switch (p->TransferMode)
+ {
+ case 0:
+ S9xSetPPU(S9xGetByte(Addr), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 5:
+ S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ Addr += 2;
+ /* fall through */
+ case 1:
+ S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 2:
+ case 6:
+ S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(S9xGetByte(Addr + 1), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 3:
+ case 7:
+ S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(S9xGetByte(Addr + 1), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(S9xGetByte(Addr + 2), 0x2101 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(S9xGetByte(Addr + 3), 0x2101 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 4:
+ S9xSetPPU(S9xGetByte(Addr + 0), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(S9xGetByte(Addr + 1), 0x2101 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(S9xGetByte(Addr + 2), 0x2102 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(S9xGetByte(Addr + 3), 0x2103 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+ }
+ }
+ else
+ {
+ // HDMA FAST PATH
+ switch (p->TransferMode)
+ {
+ case 0:
+ S9xSetPPU(*HDMAMemPointers[d]++, 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 5:
+ S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ HDMAMemPointers[d] += 2;
+ /* fall through */
+ case 1:
+ S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ HDMAMemPointers[d] += 2;
+ break;
+
+ case 2:
+ case 6:
+ S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ HDMAMemPointers[d] += 2;
+ break;
+
+ case 3:
+ case 7:
+ S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(*(HDMAMemPointers[d] + 2), 0x2101 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(*(HDMAMemPointers[d] + 3), 0x2101 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ HDMAMemPointers[d] += 4;
+ break;
+
+ case 4:
+ S9xSetPPU(*(HDMAMemPointers[d] + 0), 0x2100 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(*(HDMAMemPointers[d] + 1), 0x2101 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(*(HDMAMemPointers[d] + 2), 0x2102 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ S9xSetPPU(*(HDMAMemPointers[d] + 3), 0x2103 + p->BAddress);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ HDMAMemPointers[d] += 4;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // REVERSE HDMA REALLY-SLOW PATH
+ // anomie says: Since this is apparently never used
+ // (otherwise we would have noticed before now), let's not bother with faster paths.
+ HDMAMemPointers[d] = NULL;
+
+ #define DOBYTE(Addr, RegOff) \
+ CPU.InWRAMDMAorHDMA = (ShiftedIBank == 0x7e0000 || ShiftedIBank == 0x7f0000 || \
+ (!(ShiftedIBank & 0x400000) && ((uint16_t) (Addr)) < 0x2000)); \
+ S9xSetByte(S9xGetPPU(0x2100 + p->BAddress + (RegOff)), ShiftedIBank + ((uint16_t) (Addr)));
+
+ switch (p->TransferMode)
+ {
+ case 0:
+ DOBYTE(IAddr, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 5:
+ DOBYTE(IAddr + 0, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 1, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 2, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 3, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 1:
+ DOBYTE(IAddr + 0, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 1, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 2:
+ case 6:
+ DOBYTE(IAddr + 0, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 1, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 3:
+ case 7:
+ DOBYTE(IAddr + 0, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 1, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 2, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 3, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+
+ case 4:
+ DOBYTE(IAddr + 0, 0);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 1, 1);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 2, 2);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ DOBYTE(IAddr + 3, 3);
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ break;
+ }
+
+ #undef DOBYTE
+ }
+
+ if (p->HDMAIndirectAddressing)
+ p->IndirectAddress += HDMA_ModeByteCounts[p->TransferMode];
+ else
+ p->Address += HDMA_ModeByteCounts[p->TransferMode];
+ }
+
+ p->DoTransfer = !p->Repeat;
+
+ if (!--p->LineCount)
+ {
+ if (!HDMAReadLineCount(d))
+ {
+ byte &= ~mask;
+ PPU.HDMAEnded |= mask;
+ p->DoTransfer = false;
+ continue;
+ }
+ }
+ else
+ ADD_CYCLES(SLOW_ONE_CYCLE);
+ }
+ }
+
+ CPU.InHDMA = false;
+ CPU.InDMAorHDMA = CPU.InDMA;
+ CPU.InWRAMDMAorHDMA = temp;
+ CPU.CurrentDMAorHDMAChannel = tmpch;
+
+ return byte;
+}
+
+void S9xResetDMA()
+{
+ for (int d = 0; d < 8; d++)
+ {
+ DMA[d].ReverseTransfer = true;
+ DMA[d].HDMAIndirectAddressing = true;
+ DMA[d].AAddressFixed = true;
+ DMA[d].AAddressDecrement = true;
+ DMA[d].TransferMode = 7;
+ DMA[d].BAddress = 0xff;
+ DMA[d].AAddress = 0xffff;
+ DMA[d].ABank = 0xff;
+ DMA[d].DMACount_Or_HDMAIndirectAddress = 0xffff;
+ DMA[d].IndirectBank = 0xff;
+ DMA[d].Address = 0xffff;
+ DMA[d].Repeat = false;
+ DMA[d].LineCount = 0x7f;
+ DMA[d].UnknownByte = 0xff;
+ DMA[d].DoTransfer = false;
+ DMA[d].UnusedBit43x0 = 1;
+ }
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/dma.h
@@ -1,1 +1,213 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _DMA_H_
+#define _DMA_H_
+
+struct SDMA
+{
+ bool ReverseTransfer;
+ bool HDMAIndirectAddressing;
+ bool UnusedBit43x0;
+ bool AAddressFixed;
+ bool AAddressDecrement;
+ uint8_t TransferMode;
+ uint8_t BAddress;
+ uint16_t AAddress;
+ uint8_t ABank;
+ uint16_t DMACount_Or_HDMAIndirectAddress;
+ uint8_t IndirectBank;
+ uint16_t Address;
+ uint8_t Repeat;
+ uint8_t LineCount;
+ uint8_t UnknownByte;
+ uint8_t DoTransfer;
+};
+
+#define TransferBytes DMACount_Or_HDMAIndirectAddress
+#define IndirectAddress DMACount_Or_HDMAIndirectAddress
+
+extern struct SDMA DMA[8];
+
+bool S9xDoDMA (uint8_t);
+void S9xStartHDMA();
+uint8_t S9xDoHDMA (uint8_t);
+void S9xResetDMA();
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/docs/snes9x-license.txt
@@ -1,1 +1,174 @@
+ 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.
+
--- /dev/null
+++ b/src/in_snsf/snes9x/getset.h
@@ -1,1 +1,1033 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _GETSET_H_
+#define _GETSET_H_
+
+#include "cpuexec.h"
+//#include "dsp.h"
+//#include "sa1.h"
+//#include "spc7110.h"
+//#include "c4.h"
+//#include "obc1.h"
+//#include "seta.h"
+//#include "bsx.h"
+
+#define addCyclesInMemoryAccess \
+ if (!CPU.InDMAorHDMA) \
+ { \
+ CPU.PrevCycles = CPU.Cycles; \
+ CPU.Cycles += speed; \
+ S9xCheckInterrupts(); \
+ while (CPU.Cycles >= CPU.NextEvent) \
+ S9xDoHEventProcessing(); \
+ }
+
+#define addCyclesInMemoryAccess_x2 \
+ if (!CPU.InDMAorHDMA) \
+ { \
+ CPU.PrevCycles = CPU.Cycles; \
+ CPU.Cycles += speed << 1; \
+ S9xCheckInterrupts(); \
+ while (CPU.Cycles >= CPU.NextEvent) \
+ S9xDoHEventProcessing(); \
+ }
+
+extern uint8_t OpenBus;
+
+static inline int32_t memory_speed (uint32_t address)
+{
+ if (address & 0x408000)
+ {
+ if (address & 0x800000)
+ return CPU.FastROMSpeed;
+
+ return SLOW_ONE_CYCLE;
+ }
+
+ if ((address + 0x6000) & 0x4000)
+ return SLOW_ONE_CYCLE;
+
+ if ((address - 0x4000) & 0x7e00)
+ return ONE_CYCLE;
+
+ return TWO_CYCLES;
+}
+
+inline uint8_t S9xGetByte (uint32_t Address)
+{
+ int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
+ uint8_t *GetAddress = Memory.Map[block];
+ int32_t speed = memory_speed(Address);
+ uint8_t byte;
+
+ if (GetAddress >= (uint8_t *) CMemory::MAP_LAST)
+ {
+ byte = *(GetAddress + (Address & 0xffff));
+ addCyclesInMemoryAccess;
+ return byte;
+ }
+
+ switch ((intptr_t) GetAddress)
+ {
+ case CMemory::MAP_CPU:
+ byte = S9xGetCPU(Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_PPU:
+ if (CPU.InDMAorHDMA && (Address & 0xff00) == 0x2100)
+ return OpenBus;
+
+ byte = S9xGetPPU(Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_LOROM_SRAM:
+ case CMemory::MAP_SA1RAM:
+ // Address & 0x7fff : offset into bank
+ // Address & 0xff0000 : bank
+ // bank >> 1 | offset : SRAM address, unbound
+ // unbound & SRAMMask : SRAM offset
+ byte = *(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask));
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_LOROM_SRAM_B:
+ byte = *(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB));
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_HIROM_SRAM:
+ case CMemory::MAP_RONLY_SRAM:
+ byte = *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask));
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_BWRAM:
+ byte = *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000));
+ addCyclesInMemoryAccess;
+ return byte;
+
+ /*case CMemory::MAP_DSP:
+ byte = S9xGetDSP(Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_SPC7110_ROM:
+ byte = S9xGetSPC7110Byte(Address);
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_SPC7110_DRAM:
+ byte = S9xGetSPC7110(0x4800);
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_C4:
+ byte = S9xGetC4(Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_OBC_RAM:
+ byte = S9xGetOBC1(Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_SETA_DSP:
+ byte = S9xGetSetaDSP(Address);
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_SETA_RISC:
+ byte = S9xGetST018(Address);
+ addCyclesInMemoryAccess;
+ return byte;
+
+ case CMemory::MAP_BSX:
+ byte = S9xGetBSX(Address);
+ addCyclesInMemoryAccess;
+ return byte;*/
+
+ case CMemory::MAP_NONE:
+ default:
+ byte = OpenBus;
+ addCyclesInMemoryAccess;
+ return byte;
+ }
+}
+
+inline uint16_t S9xGetWord (uint32_t Address, enum s9xwrap_t w = WRAP_NONE)
+{
+ uint32_t mask = MEMMAP_MASK & (w == WRAP_PAGE ? 0xff : (w == WRAP_BANK ? 0xffff : 0xffffff));
+ if ((Address & mask) == mask)
+ {
+ PC_t a;
+
+ OpenBus = S9xGetByte(Address);
+
+ switch (w)
+ {
+ case WRAP_PAGE:
+ a.xPBPC = Address;
+ a.B.xPCl++;
+ return OpenBus | (S9xGetByte(a.xPBPC) << 8);
+
+ case WRAP_BANK:
+ a.xPBPC = Address;
+ a.W.xPC++;
+ return OpenBus | (S9xGetByte(a.xPBPC) << 8);
+
+ case WRAP_NONE:
+ default:
+ return OpenBus | (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 >= (uint8_t *) CMemory::MAP_LAST)
+ {
+ word = READ_WORD(GetAddress + (Address & 0xffff));
+ addCyclesInMemoryAccess_x2;
+ return word;
+ }
+
+ switch ((intptr_t) GetAddress)
+ {
+ case CMemory::MAP_CPU:
+ word = S9xGetCPU(Address & 0xffff);
+ addCyclesInMemoryAccess;
+ word |= S9xGetCPU((Address + 1) & 0xffff) << 8;
+ addCyclesInMemoryAccess;
+ return word;
+
+ case CMemory::MAP_PPU:
+ if (CPU.InDMAorHDMA)
+ {
+ OpenBus = S9xGetByte(Address);
+ return OpenBus | (S9xGetByte(Address + 1) << 8);
+ }
+
+ word = S9xGetPPU(Address & 0xffff);
+ addCyclesInMemoryAccess;
+ word |= S9xGetPPU((Address + 1) & 0xffff) << 8;
+ addCyclesInMemoryAccess;
+ return (word);
+
+ case CMemory::MAP_LOROM_SRAM:
+ case CMemory::MAP_SA1RAM:
+ if (Memory.SRAMMask >= MEMMAP_MASK)
+ word = READ_WORD(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask));
+ else
+ word = (*(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask))) |
+ ((*(Memory.SRAM + (((((Address + 1) & 0xff0000) >> 1) | ((Address + 1) & 0x7fff)) & Memory.SRAMMask))) << 8);
+ addCyclesInMemoryAccess_x2;
+ return word;
+
+ case CMemory::MAP_LOROM_SRAM_B:
+ if (Multi.sramMaskB >= MEMMAP_MASK)
+ word = READ_WORD(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB));
+ else
+ word = (*(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB))) |
+ ((*(Multi.sramB + (((((Address + 1) & 0xff0000) >> 1) | ((Address + 1) & 0x7fff)) & Multi.sramMaskB))) << 8);
+ addCyclesInMemoryAccess_x2;
+ return word;
+
+ case CMemory::MAP_HIROM_SRAM:
+ case CMemory::MAP_RONLY_SRAM:
+ if (Memory.SRAMMask >= MEMMAP_MASK)
+ word = READ_WORD(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask));
+ else
+ word = (*(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) |
+ (*(Memory.SRAM + ((((Address + 1) & 0x7fff) - 0x6000 + (((Address + 1) & 0xf0000) >> 3)) & Memory.SRAMMask)) << 8));
+ addCyclesInMemoryAccess_x2;
+ return word;
+
+ case CMemory::MAP_BWRAM:
+ word = READ_WORD(Memory.BWRAM + ((Address & 0x7fff) - 0x6000));
+ addCyclesInMemoryAccess_x2;
+ return word;
+
+ /*case CMemory::MAP_DSP:
+ word = S9xGetDSP(Address & 0xffff);
+ addCyclesInMemoryAccess;
+ word |= S9xGetDSP((Address + 1) & 0xffff) << 8;
+ addCyclesInMemoryAccess;
+ return word;
+
+ case CMemory::MAP_SPC7110_ROM:
+ word = S9xGetSPC7110Byte(Address);
+ addCyclesInMemoryAccess;
+ word |= S9xGetSPC7110Byte(Address + 1) << 8;
+ addCyclesInMemoryAccess;
+ return word;
+
+ case CMemory::MAP_SPC7110_DRAM:
+ word = S9xGetSPC7110(0x4800);
+ addCyclesInMemoryAccess;
+ word |= S9xGetSPC7110(0x4800) << 8;
+ addCyclesInMemoryAccess;
+ return word;
+
+ case CMemory::MAP_C4:
+ word = S9xGetC4(Address & 0xffff);
+ addCyclesInMemoryAccess;
+ word |= S9xGetC4((Address + 1) & 0xffff) << 8;
+ addCyclesInMemoryAccess;
+ return word;
+
+ case CMemory::MAP_OBC_RAM:
+ word = S9xGetOBC1(Address & 0xffff);
+ addCyclesInMemoryAccess;
+ word |= S9xGetOBC1((Address + 1) & 0xffff) << 8;
+ addCyclesInMemoryAccess;
+ return word;
+
+ case CMemory::MAP_SETA_DSP:
+ word = S9xGetSetaDSP(Address);
+ addCyclesInMemoryAccess;
+ word |= S9xGetSetaDSP(Address + 1) << 8;
+ addCyclesInMemoryAccess;
+ return word;
+
+ case CMemory::MAP_SETA_RISC:
+ word = S9xGetST018(Address);
+ addCyclesInMemoryAccess;
+ word |= S9xGetST018(Address + 1) << 8;
+ addCyclesInMemoryAccess;
+ return word;
+
+ case CMemory::MAP_BSX:
+ word = S9xGetBSX(Address);
+ addCyclesInMemoryAccess;
+ word |= S9xGetBSX(Address + 1) << 8;
+ addCyclesInMemoryAccess;
+ return word;*/
+
+ case CMemory::MAP_NONE:
+ default:
+ word = OpenBus | (OpenBus << 8);
+ addCyclesInMemoryAccess_x2;
+ return word;
+ }
+}
+
+inline void S9xSetByte (uint8_t Byte, uint32_t Address)
+{
+ int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
+ uint8_t *SetAddress = Memory.WriteMap[block];
+ int32_t speed = memory_speed(Address);
+
+ if (SetAddress >= (uint8_t *) CMemory::MAP_LAST)
+ {
+ *(SetAddress + (Address & 0xffff)) = Byte;
+ addCyclesInMemoryAccess;
+ return;
+ }
+
+ switch ((intptr_t) SetAddress)
+ {
+ case CMemory::MAP_CPU:
+ S9xSetCPU(Byte, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_PPU:
+ if (CPU.InDMAorHDMA && (Address & 0xff00) == 0x2100)
+ return;
+
+ S9xSetPPU(Byte, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_LOROM_SRAM:
+ if (Memory.SRAMMask)
+ {
+ *(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)) = Byte;
+ CPU.SRAMModified = true;
+ }
+
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_LOROM_SRAM_B:
+ if (Multi.sramMaskB)
+ {
+ *(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)) = Byte;
+ CPU.SRAMModified = true;
+ }
+
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_HIROM_SRAM:
+ if (Memory.SRAMMask)
+ {
+ *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) = Byte;
+ CPU.SRAMModified = true;
+ }
+
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_BWRAM:
+ *(Memory.BWRAM + ((Address & 0x7fff) - 0x6000)) = Byte;
+ CPU.SRAMModified = true;
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_SA1RAM:
+ *(Memory.SRAM + (Address & 0xffff)) = Byte;
+ addCyclesInMemoryAccess;
+ return;
+
+ /*case CMemory::MAP_DSP:
+ S9xSetDSP(Byte, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_C4:
+ S9xSetC4(Byte, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_OBC_RAM:
+ S9xSetOBC1(Byte, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_SETA_DSP:
+ S9xSetSetaDSP(Byte, Address);
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_SETA_RISC:
+ S9xSetST018(Byte, Address);
+ addCyclesInMemoryAccess;
+ return;
+
+ case CMemory::MAP_BSX:
+ S9xSetBSX(Byte, Address);
+ addCyclesInMemoryAccess;
+ return;*/
+
+ case CMemory::MAP_NONE:
+ default:
+ addCyclesInMemoryAccess;
+ return;
+ }
+}
+
+inline void S9xSetWord (uint16_t Word, uint32_t Address, enum s9xwrap_t w = WRAP_NONE, enum s9xwriteorder_t o = WRITE_01)
+{
+ uint32_t mask = MEMMAP_MASK & (w == WRAP_PAGE ? 0xff : (w == WRAP_BANK ? 0xffff : 0xffffff));
+ if ((Address & mask) == mask)
+ {
+ PC_t a;
+
+ if (!o)
+ S9xSetByte((uint8_t) Word, Address);
+
+ switch (w)
+ {
+ case WRAP_PAGE:
+ a.xPBPC = Address;
+ a.B.xPCl++;
+ S9xSetByte(Word >> 8, a.xPBPC);
+ break;
+
+ case WRAP_BANK:
+ a.xPBPC = Address;
+ a.W.xPC++;
+ S9xSetByte(Word >> 8, a.xPBPC);
+ break;
+
+ case WRAP_NONE:
+ default:
+ S9xSetByte(Word >> 8, Address + 1);
+ break;
+ }
+
+ if (o)
+ S9xSetByte((uint8_t) Word, Address);
+
+ return;
+ }
+
+ int block = (Address & 0xffffff) >> MEMMAP_SHIFT;
+ uint8_t *SetAddress = Memory.WriteMap[block];
+ int32_t speed = memory_speed(Address);
+
+ if (SetAddress >= (uint8_t *) CMemory::MAP_LAST)
+ {
+ WRITE_WORD(SetAddress + (Address & 0xffff), Word);
+ addCyclesInMemoryAccess_x2;
+ return;
+ }
+
+ switch ((intptr_t) SetAddress)
+ {
+ case CMemory::MAP_CPU:
+ if (o)
+ {
+ S9xSetCPU(Word >> 8, (Address + 1) & 0xffff);
+ addCyclesInMemoryAccess;
+ S9xSetCPU((uint8_t) Word, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+ }
+ else
+ {
+ S9xSetCPU((uint8_t) Word, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ S9xSetCPU(Word >> 8, (Address + 1) & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+ }
+
+ case CMemory::MAP_PPU:
+ if (CPU.InDMAorHDMA)
+ {
+ if ((Address & 0xff00) != 0x2100)
+ S9xSetPPU((uint8_t) Word, Address & 0xffff);
+ if (((Address + 1) & 0xff00) != 0x2100)
+ S9xSetPPU(Word >> 8, (Address + 1) & 0xffff);
+ return;
+ }
+
+ if (o)
+ {
+ S9xSetPPU(Word >> 8, (Address + 1) & 0xffff);
+ addCyclesInMemoryAccess;
+ S9xSetPPU((uint8_t) Word, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+ }
+ else
+ {
+ S9xSetPPU((uint8_t) Word, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ S9xSetPPU(Word >> 8, (Address + 1) & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+ }
+
+ case CMemory::MAP_LOROM_SRAM:
+ if (Memory.SRAMMask)
+ {
+ if (Memory.SRAMMask >= MEMMAP_MASK)
+ WRITE_WORD(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask), Word);
+ else
+ {
+ *(Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask)) = (uint8_t) Word;
+ *(Memory.SRAM + (((((Address + 1) & 0xff0000) >> 1) | ((Address + 1) & 0x7fff)) & Memory.SRAMMask)) = Word >> 8;
+ }
+
+ CPU.SRAMModified = true;
+ }
+
+ addCyclesInMemoryAccess_x2;
+ return;
+
+ case CMemory::MAP_LOROM_SRAM_B:
+ if (Multi.sramMaskB)
+ {
+ if (Multi.sramMaskB >= MEMMAP_MASK)
+ WRITE_WORD(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB), Word);
+ else
+ {
+ *(Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB)) = (uint8_t) Word;
+ *(Multi.sramB + (((((Address + 1) & 0xff0000) >> 1) | ((Address + 1) & 0x7fff)) & Multi.sramMaskB)) = Word >> 8;
+ }
+
+ CPU.SRAMModified = true;
+ }
+
+ addCyclesInMemoryAccess_x2;
+ return;
+
+ case CMemory::MAP_HIROM_SRAM:
+ if (Memory.SRAMMask)
+ {
+ if (Memory.SRAMMask >= MEMMAP_MASK)
+ WRITE_WORD(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask), Word);
+ else
+ {
+ *(Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask)) = (uint8_t) Word;
+ *(Memory.SRAM + ((((Address + 1) & 0x7fff) - 0x6000 + (((Address + 1) & 0xf0000) >> 3)) & Memory.SRAMMask)) = Word >> 8;
+ }
+
+ CPU.SRAMModified = true;
+ }
+
+ addCyclesInMemoryAccess_x2;
+ return;
+
+ case CMemory::MAP_BWRAM:
+ WRITE_WORD(Memory.BWRAM + ((Address & 0x7fff) - 0x6000), Word);
+ CPU.SRAMModified = true;
+ addCyclesInMemoryAccess_x2;
+ return;
+
+ case CMemory::MAP_SA1RAM:
+ WRITE_WORD(Memory.SRAM + (Address & 0xffff), Word);
+ addCyclesInMemoryAccess_x2;
+ return;
+
+ /*case CMemory::MAP_DSP:
+ if (o)
+ {
+ S9xSetDSP(Word >> 8, (Address + 1) & 0xffff);
+ addCyclesInMemoryAccess;
+ S9xSetDSP((uint8_t) Word, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+ }
+ else
+ {
+ S9xSetDSP((uint8_t) Word, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ S9xSetDSP(Word >> 8, (Address + 1) & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+ }
+
+ case CMemory::MAP_C4:
+ if (o)
+ {
+ S9xSetC4(Word >> 8, (Address + 1) & 0xffff);
+ addCyclesInMemoryAccess;
+ S9xSetC4((uint8_t) Word, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+ }
+ else
+ {
+ S9xSetC4((uint8_t) Word, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ S9xSetC4(Word >> 8, (Address + 1) & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+ }
+
+ case CMemory::MAP_OBC_RAM:
+ if (o)
+ {
+ S9xSetOBC1(Word >> 8, (Address + 1) & 0xffff);
+ addCyclesInMemoryAccess;
+ S9xSetOBC1((uint8_t) Word, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+ }
+ else
+ {
+ S9xSetOBC1((uint8_t) Word, Address & 0xffff);
+ addCyclesInMemoryAccess;
+ S9xSetOBC1(Word >> 8, (Address + 1) & 0xffff);
+ addCyclesInMemoryAccess;
+ return;
+ }
+
+ case CMemory::MAP_SETA_DSP:
+ if (o)
+ {
+ S9xSetSetaDSP(Word >> 8, Address + 1);
+ addCyclesInMemoryAccess;
+ S9xSetSetaDSP((uint8_t) Word, Address);
+ addCyclesInMemoryAccess;
+ return;
+ }
+ else
+ {
+ S9xSetSetaDSP((uint8_t) Word, Address);
+ addCyclesInMemoryAccess;
+ S9xSetSetaDSP(Word >> 8, Address + 1);
+ addCyclesInMemoryAccess;
+ return;
+ }
+
+ case CMemory::MAP_SETA_RISC:
+ if (o)
+ {
+ S9xSetST018(Word >> 8, Address + 1);
+ addCyclesInMemoryAccess;
+ S9xSetST018((uint8_t) Word, Address);
+ addCyclesInMemoryAccess;
+ return;
+ }
+ else
+ {
+ S9xSetST018((uint8_t) Word, Address);
+ addCyclesInMemoryAccess;
+ S9xSetST018(Word >> 8, Address + 1);
+ addCyclesInMemoryAccess;
+ return;
+ }
+
+ case CMemory::MAP_BSX:
+ if (o)
+ {
+ S9xSetBSX(Word >> 8, Address + 1);
+ addCyclesInMemoryAccess;
+ S9xSetBSX((uint8_t) Word, Address);
+ addCyclesInMemoryAccess;
+ return;
+ }
+ else
+ {
+ S9xSetBSX((uint8_t) Word, Address);
+ addCyclesInMemoryAccess;
+ S9xSetBSX(Word >> 8, Address + 1);
+ addCyclesInMemoryAccess;
+ return;
+ }*/
+
+ case CMemory::MAP_NONE:
+ default:
+ addCyclesInMemoryAccess_x2;
+ return;
+ }
+}
+
+inline void S9xSetPCBase (uint32_t Address)
+{
+ Registers.PBPC = Address & 0xffffff;
+ ICPU.ShiftedPB = Address & 0xff0000;
+
+ int block;
+ uint8_t *GetAddress = Memory.Map[block = ((Address & 0xffffff) >> MEMMAP_SHIFT)];
+
+ CPU.MemSpeed = memory_speed(Address);
+ CPU.MemSpeedx2 = CPU.MemSpeed << 1;
+
+ if (GetAddress >= (uint8_t *) CMemory::MAP_LAST)
+ {
+ CPU.PCBase = GetAddress;
+ return;
+ }
+
+ switch ((intptr_t) GetAddress)
+ {
+ case CMemory::MAP_LOROM_SRAM:
+ if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK)
+ CPU.PCBase = NULL;
+ else
+ CPU.PCBase = Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask) - (Address & 0xffff);
+ return;
+
+ case CMemory::MAP_LOROM_SRAM_B:
+ if ((Multi.sramMaskB & MEMMAP_MASK) != MEMMAP_MASK)
+ CPU.PCBase = NULL;
+ else
+ CPU.PCBase = Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB) - (Address & 0xffff);
+ return;
+
+ case CMemory::MAP_HIROM_SRAM:
+ if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK)
+ CPU.PCBase = NULL;
+ else
+ CPU.PCBase = Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask) - (Address & 0xffff);
+ return;
+
+ case CMemory::MAP_BWRAM:
+ CPU.PCBase = Memory.BWRAM - 0x6000 - (Address & 0x8000);
+ return;
+
+ case CMemory::MAP_SA1RAM:
+ CPU.PCBase = Memory.SRAM;
+ return;
+
+ /*case CMemory::MAP_SPC7110_ROM:
+ CPU.PCBase = S9xGetBasePointerSPC7110(Address);
+ return;
+
+ case CMemory::MAP_C4:
+ CPU.PCBase = S9xGetBasePointerC4(Address & 0xffff);
+ return;
+
+ case CMemory::MAP_OBC_RAM:
+ CPU.PCBase = S9xGetBasePointerOBC1(Address & 0xffff);
+ return;
+
+ case CMemory::MAP_BSX:
+ CPU.PCBase = S9xGetBasePointerBSX(Address);
+ return;*/
+
+ case CMemory::MAP_NONE:
+ default:
+ CPU.PCBase = NULL;
+ return;
+ }
+}
+
+inline uint8_t * S9xGetBasePointer (uint32_t Address)
+{
+ uint8_t *GetAddress = Memory.Map[(Address & 0xffffff) >> MEMMAP_SHIFT];
+
+ if (GetAddress >= (uint8_t *) CMemory::MAP_LAST)
+ return GetAddress;
+
+ switch ((intptr_t) GetAddress)
+ {
+ case CMemory::MAP_LOROM_SRAM:
+ if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK)
+ return NULL;
+ return Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask) - (Address & 0xffff);
+
+ case CMemory::MAP_LOROM_SRAM_B:
+ if ((Multi.sramMaskB & MEMMAP_MASK) != MEMMAP_MASK)
+ return NULL;
+ return Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB) - (Address & 0xffff);
+
+ case CMemory::MAP_HIROM_SRAM:
+ if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK)
+ return NULL;
+ return Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask) - (Address & 0xffff);
+
+ case CMemory::MAP_BWRAM:
+ return Memory.BWRAM - 0x6000 - (Address & 0x8000);
+
+ case CMemory::MAP_SA1RAM:
+ return Memory.SRAM;
+
+ /*case CMemory::MAP_SPC7110_ROM:
+ return S9xGetBasePointerSPC7110(Address);
+
+ case CMemory::MAP_C4:
+ return S9xGetBasePointerC4(Address & 0xffff);
+
+ case CMemory::MAP_OBC_RAM:
+ return S9xGetBasePointerOBC1(Address & 0xffff);*/
+
+ case CMemory::MAP_NONE:
+ default:
+ return NULL;
+ }
+}
+
+inline uint8_t * S9xGetMemPointer (uint32_t Address)
+{
+ uint8_t *GetAddress = Memory.Map[(Address & 0xffffff) >> MEMMAP_SHIFT];
+
+ if (GetAddress >= (uint8_t *) CMemory::MAP_LAST)
+ return GetAddress + (Address & 0xffff);
+
+ switch ((intptr_t) GetAddress)
+ {
+ case CMemory::MAP_LOROM_SRAM:
+ if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK)
+ return NULL;
+ return Memory.SRAM + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask);
+
+ case CMemory::MAP_LOROM_SRAM_B:
+ if ((Multi.sramMaskB & MEMMAP_MASK) != MEMMAP_MASK)
+ return NULL;
+ return Multi.sramB + ((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Multi.sramMaskB);
+
+ case CMemory::MAP_HIROM_SRAM:
+ if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK)
+ return NULL;
+ return Memory.SRAM + (((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask);
+
+ case CMemory::MAP_BWRAM:
+ return Memory.BWRAM - 0x6000 + (Address & 0x7fff);
+
+ case CMemory::MAP_SA1RAM:
+ return Memory.SRAM + (Address & 0xffff);
+
+ /*case CMemory::MAP_SPC7110_ROM:
+ return S9xGetBasePointerSPC7110(Address) + (Address & 0xffff);
+
+ case CMemory::MAP_C4:
+ return S9xGetMemPointerC4(Address & 0xffff);
+
+ case CMemory::MAP_OBC_RAM:
+ return S9xGetMemPointerOBC1(Address & 0xffff);*/
+
+ case CMemory::MAP_NONE:
+ default:
+ return NULL;
+ }
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/globals.cpp
@@ -1,1 +1,401 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#include "snes9x.h"
+#include "memmap.h"
+#include "dma.h"
+#include "apu/apu.h"
+//#include "fxinst.h"
+//#include "fxemu.h"
+//#include "srtc.h"
+//#include "cheats.h"
+#ifdef NETPLAY_SUPPORT
+#include "netplay.h"
+#endif
+#ifdef DEBUGGER
+#include "debug.h"
+#include "missing.h"
+#endif
+
+struct SCPUState CPU;
+struct SICPU ICPU;
+struct SRegisters Registers;
+struct SPPU PPU;
+struct InternalPPU IPPU;
+struct SDMA DMA[8];
+struct STimings Timings;
+/*struct SGFX GFX;
+struct SBG BG;
+struct SLineData LineData[240];
+struct SLineMatrixData LineMatrixData[240];
+struct SDSP0 DSP0;
+struct SDSP1 DSP1;
+struct SDSP2 DSP2;
+struct SDSP3 DSP3;
+struct SDSP4 DSP4;
+struct SSA1 SA1;
+struct SSA1Registers SA1Registers;
+struct FxRegs_s GSU;
+struct FxInfo_s SuperFX;
+struct SST010 ST010;
+struct SST011 ST011;
+struct SST018 ST018;
+struct SOBC1 OBC1;
+struct SSPC7110Snapshot s7snap;
+struct SSRTCSnapshot srtcsnap;
+struct SRTCData RTCData;
+struct SBSX BSX;*/
+struct SMulti Multi;
+struct SSettings Settings;
+struct SSNESGameFixes SNESGameFixes;
+#ifdef NETPLAY_SUPPORT
+struct SNetPlay NetPlay;
+#endif
+#ifdef DEBUGGER
+struct Missing missing;
+#endif
+/*struct SCheatData Cheat;
+struct Watch watches[16];*/
+CMemory Memory;
+
+//char String[513];
+uint8_t OpenBus = 0;
+uint8_t *HDMAMemPointers[8];
+uint16_t BlackColourMap[256];
+uint16_t DirectColourMaps[8][256];
+
+SnesModel M1SNES = { 1, 3, 2 };
+//SnesModel M2SNES = { 2, 4, 3 };
+SnesModel *Model = &M1SNES;
+
+#ifdef GFX_MULTI_FORMAT
+uint32_t RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_RGB565;
+uint32_t GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_RGB565;
+uint32_t BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_RGB565;
+uint32_t RED_HI_BIT_MASK = RED_HI_BIT_MASK_RGB565;
+uint32_t GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_RGB565;
+uint32_t BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_RGB565;
+uint32_t MAX_RED = MAX_RED_RGB565;
+uint32_t MAX_GREEN = MAX_GREEN_RGB565;
+uint32_t MAX_BLUE = MAX_BLUE_RGB565;
+uint32_t SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_RGB565;
+uint32_t GREEN_HI_BIT = (MAX_GREEN_RGB565 + 1) >> 1;
+uint32_t RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_RGB565 | GREEN_LOW_BIT_MASK_RGB565 | BLUE_LOW_BIT_MASK_RGB565);
+uint32_t RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_RGB565 | GREEN_HI_BIT_MASK_RGB565 | BLUE_HI_BIT_MASK_RGB565);
+uint32_t RGB_HI_BITS_MASKx2 = (RED_HI_BIT_MASK_RGB565 | GREEN_HI_BIT_MASK_RGB565 | BLUE_HI_BIT_MASK_RGB565) << 1;
+uint32_t RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK;
+uint32_t FIRST_COLOR_MASK = FIRST_COLOR_MASK_RGB565;
+uint32_t SECOND_COLOR_MASK = SECOND_COLOR_MASK_RGB565;
+uint32_t THIRD_COLOR_MASK = THIRD_COLOR_MASK_RGB565;
+uint32_t ALPHA_BITS_MASK = ALPHA_BITS_MASK_RGB565;
+uint32_t FIRST_THIRD_COLOR_MASK = 0;
+uint32_t TWO_LOW_BITS_MASK = 0;
+uint32_t HIGH_BITS_SHIFTED_TWO_MASK = 0;
+#endif
+
+uint16_t SignExtend[2] =
+{
+ 0x0000,
+ 0xff00
+};
+
+int HDMA_ModeByteCounts[8] =
+{
+ 1, 2, 2, 4, 4, 4, 2, 4
+};
+
+/*uint8_t mul_brightness[16][32] =
+{
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
+ { 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04 },
+ { 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06 },
+ { 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04,
+ 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08 },
+ { 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05,
+ 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a },
+ { 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06,
+ 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c },
+ { 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07,
+ 0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e },
+ { 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x08,
+ 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x11 },
+ { 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09,
+ 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x13 },
+ { 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x09, 0x0a,
+ 0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15 },
+ { 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b,
+ 0x0c, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17 },
+ { 0x00, 0x01, 0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19 },
+ { 0x00, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1b },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }
+};*/
+
+uint8_t S9xOpLengthsM0X0[256] =
+{
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 0
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1
+ 3, 2, 4, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 2
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3
+ 1, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 4
+ 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5
+ 1, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 6
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7
+ 2, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 8
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9
+ 3, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // A
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B
+ 3, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // C
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D
+ 3, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // E
+ 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F
+};
+
+uint8_t S9xOpLengthsM0X1[256] =
+{
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 0
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1
+ 3, 2, 4, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 2
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3
+ 1, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 4
+ 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5
+ 1, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 6
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7
+ 2, 2, 3, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 8
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // A
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // C
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // E
+ 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F
+};
+
+uint8_t S9xOpLengthsM1X0[256] =
+{
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 0
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1
+ 3, 2, 4, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 2
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3
+ 1, 2, 2, 2, 3, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 4
+ 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5
+ 1, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 6
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7
+ 2, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 8
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9
+ 3, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // A
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B
+ 3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // C
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D
+ 3, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // E
+ 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F
+};
+
+uint8_t S9xOpLengthsM1X1[256] =
+{
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 0
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 1
+ 3, 2, 4, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 2
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 3
+ 1, 2, 2, 2, 3, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 4
+ 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 4, 3, 3, 4, // 5
+ 1, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 6
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 7
+ 2, 2, 3, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // 8
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // 9
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // A
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // B
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // C
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4, // D
+ 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 4, // E
+ 2, 2, 2, 2, 3, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 4 // F
+};
+
--- /dev/null
+++ b/src/in_snsf/snes9x/memmap.cpp
@@ -1,1 +1,4327 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+#include <algorithm>
+#include <string>
+#include <numeric>
+#include <assert.h>
+
+#ifdef UNZIP_SUPPORT
+#include "unzip/unzip.h"
+#endif
+
+#ifdef JMA_SUPPORT
+#include "jma/s9x-jma.h"
+#endif
+
+#include "snes9x.h"
+#include "memmap.h"
+#include "apu/apu.h"
+//#include "fxemu.h"
+#include "sdd1.h"
+//#include "srtc.h"
+//#include "controls.h"
+//#include "cheats.h"
+//#include "movie.h"
+//#include "reader.h"
+//#include "display.h"
+
+/*#ifndef SET_UI_COLOR
+#define SET_UI_COLOR(r, g, b) ;
+#endif*/
+
+/*#ifndef max
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+#endif*/
+
+/*#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif*/
+
+//static bool stopMovie = true;
+//static char LastRomFilename[PATH_MAX + 1] = "";
+
+// from NSRT
+/*static const char *nintendo_licensees[] =
+{
+ "Unlicensed",
+ "Nintendo",
+ "Rocket Games/Ajinomoto",
+ "Imagineer-Zoom",
+ "Gray Matter",
+ "Zamuse",
+ "Falcom",
+ NULL,
+ "Capcom",
+ "Hot B Co.",
+ "Jaleco",
+ "Coconuts Japan",
+ "Coconuts Japan/G.X.Media",
+ "Micronet",
+ "Technos",
+ "Mebio Software",
+ "Shouei System",
+ "Starfish",
+ NULL,
+ "Mitsui Fudosan/Dentsu",
+ NULL,
+ "Warashi Inc.",
+ NULL,
+ "Nowpro",
+ NULL,
+ "Game Village",
+ "IE Institute",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Banarex",
+ "Starfish",
+ "Infocom",
+ "Electronic Arts Japan",
+ NULL,
+ "Cobra Team",
+ "Human/Field",
+ "KOEI",
+ "Hudson Soft",
+ "S.C.P./Game Village",
+ "Yanoman",
+ NULL,
+ "Tecmo Products",
+ "Japan Glary Business",
+ "Forum/OpenSystem",
+ "Virgin Games (Japan)",
+ "SMDE",
+ "Yojigen",
+ NULL,
+ "Daikokudenki",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Creatures Inc.",
+ "TDK Deep Impresion",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Destination Software/KSS",
+ "Sunsoft/Tokai Engineering",
+ "POW (Planning Office Wada)/VR 1 Japan",
+ "Micro World",
+ NULL,
+ "San-X",
+ "Enix",
+ "Loriciel/Electro Brain",
+ "Kemco Japan",
+ "Seta Co.,Ltd.",
+ "Culture Brain",
+ "Irem Corp.",
+ "Palsoft",
+ "Visit Co., Ltd.",
+ "Intec",
+ "System Sacom",
+ "Poppo",
+ "Ubisoft Japan",
+ NULL,
+ "Media Works",
+ "NEC InterChannel",
+ "Tam",
+ "Gajin/Jordan",
+ "Smilesoft",
+ NULL,
+ NULL,
+ "Mediakite",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Viacom",
+ "Carrozzeria",
+ "Dynamic",
+ NULL,
+ "Magifact",
+ "Hect",
+ "Codemasters",
+ "Taito/GAGA Communications",
+ "Laguna",
+ "Telstar Fun & Games/Event/Taito",
+ NULL,
+ "Arcade Zone Ltd.",
+ "Entertainment International/Empire Software",
+ "Loriciel",
+ "Gremlin Graphics",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Seika Corp.",
+ "UBI SOFT Entertainment Software",
+ "Sunsoft US",
+ NULL,
+ "Life Fitness",
+ NULL,
+ "System 3",
+ "Spectrum Holobyte",
+ NULL,
+ "Irem",
+ NULL,
+ "Raya Systems",
+ "Renovation Products",
+ "Malibu Games",
+ NULL,
+ "Eidos/U.S. Gold",
+ "Playmates Interactive",
+ NULL,
+ NULL,
+ "Fox Interactive",
+ "Time Warner Interactive",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Disney Interactive",
+ NULL,
+ "Black Pearl",
+ NULL,
+ "Advanced Productions",
+ NULL,
+ NULL,
+ "GT Interactive",
+ "RARE",
+ "Crave Entertainment",
+ "Absolute Entertainment",
+ "Acclaim",
+ "Activision",
+ "American Sammy",
+ "Take 2/GameTek",
+ "Hi Tech",
+ "LJN Ltd.",
+ NULL,
+ "Mattel",
+ NULL,
+ "Mindscape/Red Orb Entertainment",
+ "Romstar",
+ "Taxan",
+ "Midway/Tradewest",
+ NULL,
+ "American Softworks Corp.",
+ "Majesco Sales Inc.",
+ "3DO",
+ NULL,
+ NULL,
+ "Hasbro",
+ "NewKidCo",
+ "Telegames",
+ "Metro3D",
+ NULL,
+ "Vatical Entertainment",
+ "LEGO Media",
+ NULL,
+ "Xicat Interactive",
+ "Cryo Interactive",
+ NULL,
+ NULL,
+ "Red Storm Entertainment",
+ "Microids",
+ NULL,
+ "Conspiracy/Swing",
+ "Titus",
+ "Virgin Interactive",
+ "Maxis",
+ NULL,
+ "LucasArts Entertainment",
+ NULL,
+ NULL,
+ "Ocean",
+ NULL,
+ "Electronic Arts",
+ NULL,
+ "Laser Beam",
+ NULL,
+ NULL,
+ "Elite Systems",
+ "Electro Brain",
+ "The Learning Company",
+ "BBC",
+ NULL,
+ "Software 2000",
+ NULL,
+ "BAM! Entertainment",
+ "Studio 3",
+ NULL,
+ NULL,
+ NULL,
+ "Classified Games",
+ NULL,
+ "TDK Mediactive",
+ NULL,
+ "DreamCatcher",
+ "JoWood Produtions",
+ "SEGA",
+ "Wannado Edition",
+ "LSP (Light & Shadow Prod.)",
+ "ITE Media",
+ "Infogrames",
+ "Interplay",
+ "JVC (US)",
+ "Parker Brothers",
+ NULL,
+ "SCI (Sales Curve Interactive)/Storm",
+ NULL,
+ NULL,
+ "THQ Software",
+ "Accolade Inc.",
+ "Triffix Entertainment",
+ NULL,
+ "Microprose Software",
+ "Universal Interactive/Sierra/Simon & Schuster",
+ NULL,
+ "Kemco",
+ "Rage Software",
+ "Encore",
+ NULL,
+ "Zoo",
+ "Kiddinx",
+ "Simon & Schuster Interactive",
+ "Asmik Ace Entertainment Inc./AIA",
+ "Empire Interactive",
+ NULL,
+ NULL,
+ "Jester Interactive",
+ NULL,
+ "Rockstar Games",
+ "Scholastic",
+ "Ignition Entertainment",
+ "Summitsoft",
+ "Stadlbauer",
+ NULL,
+ NULL,
+ NULL,
+ "Misawa",
+ "Teichiku",
+ "Namco Ltd.",
+ "LOZC",
+ "KOEI",
+ NULL,
+ "Tokuma Shoten Intermedia",
+ "Tsukuda Original",
+ "DATAM-Polystar",
+ NULL,
+ NULL,
+ "Bullet-Proof Software",
+ "Vic Tokai Inc.",
+ NULL,
+ "Character Soft",
+ "I'Max",
+ "Saurus",
+ NULL,
+ NULL,
+ "General Entertainment",
+ NULL,
+ NULL,
+ "I'Max",
+ "Success",
+ NULL,
+ "SEGA Japan",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Takara",
+ "Chun Soft",
+ "Video System Co., Ltd./McO'River",
+ "BEC",
+ NULL,
+ "Varie",
+ "Yonezawa/S'pal",
+ "Kaneko",
+ NULL,
+ "Victor Interactive Software/Pack-in-Video",
+ "Nichibutsu/Nihon Bussan",
+ "Tecmo",
+ "Imagineer",
+ NULL,
+ NULL,
+ "Nova",
+ "Den'Z",
+ "Bottom Up",
+ NULL,
+ "TGL (Technical Group Laboratory)",
+ NULL,
+ "Hasbro Japan",
+ NULL,
+ "Marvelous Entertainment",
+ NULL,
+ "Keynet Inc.",
+ "Hands-On Entertainment",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Telenet",
+ "Hori",
+ NULL,
+ NULL,
+ "Konami",
+ "K.Amusement Leasing Co.",
+ "Kawada",
+ "Takara",
+ NULL,
+ "Technos Japan Corp.",
+ "JVC (Europe/Japan)/Victor Musical Industries",
+ NULL,
+ "Toei Animation",
+ "Toho",
+ NULL,
+ "Namco",
+ "Media Rings Corp.",
+ "J-Wing",
+ NULL,
+ "Pioneer LDC",
+ "KID",
+ "Mediafactory",
+ NULL,
+ NULL,
+ NULL,
+ "Infogrames Hudson",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Acclaim Japan",
+ "ASCII Co./Nexoft",
+ "Bandai",
+ NULL,
+ "Enix",
+ NULL,
+ "HAL Laboratory/Halken",
+ "SNK",
+ NULL,
+ "Pony Canyon Hanbai",
+ "Culture Brain",
+ "Sunsoft",
+ "Toshiba EMI",
+ "Sony Imagesoft",
+ NULL,
+ "Sammy",
+ "Magical",
+ "Visco",
+ NULL,
+ "Compile",
+ NULL,
+ "MTO Inc.",
+ NULL,
+ "Sunrise Interactive",
+ NULL,
+ "Global A Entertainment",
+ "Fuuki",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Taito",
+ NULL,
+ "Kemco",
+ "Square",
+ "Tokuma Shoten",
+ "Data East",
+ "Tonkin House",
+ NULL,
+ "KOEI",
+ NULL,
+ "Konami/Ultra/Palcom",
+ "NTVIC/VAP",
+ "Use Co., Ltd.",
+ "Meldac",
+ "Pony Canyon (Japan)/FCI (US)",
+ "Angel/Sotsu Agency/Sunrise",
+ "Yumedia/Aroma Co., Ltd.",
+ NULL,
+ NULL,
+ "Boss",
+ "Axela/Crea-Tech",
+ "Sekaibunka-Sha/Sumire kobo/Marigul Management Inc.",
+ "Konami Computer Entertainment Osaka",
+ NULL,
+ NULL,
+ "Enterbrain",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Taito/Disco",
+ "Sofel",
+ "Quest Corp.",
+ "Sigma",
+ "Ask Kodansha",
+ NULL,
+ "Naxat",
+ "Copya System",
+ "Capcom Co., Ltd.",
+ "Banpresto",
+ "TOMY",
+ "Acclaim/LJN Japan",
+ NULL,
+ "NCS",
+ "Human Entertainment",
+ "Altron",
+ "Jaleco",
+ "Gaps Inc.",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Elf",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Jaleco",
+ NULL,
+ "Yutaka",
+ "Varie",
+ "T&ESoft",
+ "Epoch Co., Ltd.",
+ NULL,
+ "Athena",
+ "Asmik",
+ "Natsume",
+ "King Records",
+ "Atlus",
+ "Epic/Sony Records (Japan)",
+ NULL,
+ "IGS (Information Global Service)",
+ NULL,
+ "Chatnoir",
+ "Right Stuff",
+ NULL,
+ "NTT COMWARE",
+ NULL,
+ "Spike",
+ "Konami Computer Entertainment Tokyo",
+ "Alphadream Corp.",
+ NULL,
+ "Sting",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "A Wave",
+ "Motown Software",
+ "Left Field Entertainment",
+ "Extreme Entertainment Group",
+ "TecMagik",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Cybersoft",
+ NULL,
+ "Psygnosis",
+ NULL,
+ NULL,
+ "Davidson/Western Tech.",
+ "Unlicensed",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "The Game Factory Europe",
+ "Hip Games",
+ "Aspyr",
+ NULL,
+ NULL,
+ "Mastiff",
+ "iQue",
+ "Digital Tainment Pool",
+ "XS Games",
+ "Daiwon",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "PCCW Japan",
+ NULL,
+ NULL,
+ "KiKi Co. Ltd.",
+ "Open Sesame Inc.",
+ "Sims",
+ "Broccoli",
+ "Avex",
+ "D3 Publisher",
+ NULL,
+ "Konami Computer Entertainment Japan",
+ NULL,
+ "Square-Enix",
+ "KSG",
+ "Micott & Basara Inc.",
+ NULL,
+ "Orbital Media",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "The Game Factory USA",
+ NULL,
+ NULL,
+ "Treasure",
+ "Aruze",
+ "Ertain",
+ "SNK Playmore",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Yojigen"
+};*/
+
+static const uint32_t crc32Table[256] =
+{
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+//static void S9xDeinterleaveType1 (int, uint8_t *);
+//static void S9xDeinterleaveType2 (int, uint8_t *);
+//static void S9xDeinterleaveGD24 (int, uint8_t *);
+//static bool allASCII (uint8_t *, int);
+//static bool is_SufamiTurbo_BIOS (uint8_t *, uint32_t);
+//static bool is_SufamiTurbo_Cart (uint8_t *, uint32_t);
+//static bool is_SameGame_BIOS (uint8_t *, uint32_t);
+//static bool is_SameGame_Add_On (uint8_t *, uint32_t);
+//static uint32_t caCRC32 (uint8_t *, uint32_t, uint32_t crc32 = 0xffffffff);
+/*static uint32_t ReadUPSPointer (const uint8_t *, unsigned &, unsigned);
+static bool ReadUPSPatch (Reader *, long, int32_t &);
+static long ReadInt (Reader *, unsigned);
+static bool ReadIPSPatch (Reader *, long, int32_t &);*/
+#ifdef UNZIP_SUPPORT
+static int unzFindExtension (unzFile &, const char *, bool restart = true, bool print = true);
+#endif
+
+// deinterleave
+
+static void S9xDeinterleaveType1 (int size, uint8_t *base)
+{
+ //Settings.DisplayColor = BUILD_PIXEL(0, 31, 0);
+ //SET_UI_COLOR(0, 255, 0);
+
+ uint8_t blocks[256];
+ int nblocks = size >> 16;
+
+ for (int i = 0; i < nblocks; i++)
+ {
+ blocks[i * 2] = i + nblocks;
+ blocks[i * 2 + 1] = i;
+ }
+
+ uint8_t *tmp = (uint8_t *) malloc(0x8000);
+ if (tmp)
+ {
+ for (int i = 0; i < nblocks * 2; i++)
+ {
+ for (int j = i; j < nblocks * 2; j++)
+ {
+ if (blocks[j] == i)
+ {
+ memmove(tmp, &base[blocks[j] * 0x8000], 0x8000);
+ memmove(&base[blocks[j] * 0x8000], &base[blocks[i] * 0x8000], 0x8000);
+ memmove(&base[blocks[i] * 0x8000], tmp, 0x8000);
+ uint8_t b = blocks[j];
+ blocks[j] = blocks[i];
+ blocks[i] = b;
+ break;
+ }
+ }
+ }
+
+ free(tmp);
+ }
+}
+
+static void S9xDeinterleaveType2 (int size, uint8_t *base)
+{
+ // for odd Super FX images
+ //Settings.DisplayColor = BUILD_PIXEL(31, 14, 6);
+ //SET_UI_COLOR(255, 119, 25);
+
+ uint8_t blocks[256];
+ int nblocks = size >> 16;
+ int step = 64;
+
+ while (nblocks <= step)
+ step >>= 1;
+ nblocks = step;
+
+ for (int i = 0; i < nblocks * 2; i++)
+ blocks[i] = (i & ~0xf) | ((i & 3) << 2) | ((i & 12) >> 2);
+
+ uint8_t *tmp = (uint8_t *) malloc(0x10000);
+ if (tmp)
+ {
+ for (int i = 0; i < nblocks * 2; i++)
+ {
+ for (int j = i; j < nblocks * 2; j++)
+ {
+ if (blocks[j] == i)
+ {
+ memmove(tmp, &base[blocks[j] * 0x10000], 0x10000);
+ memmove(&base[blocks[j] * 0x10000], &base[blocks[i] * 0x10000], 0x10000);
+ memmove(&base[blocks[i] * 0x10000], tmp, 0x10000);
+ uint8_t b = blocks[j];
+ blocks[j] = blocks[i];
+ blocks[i] = b;
+ break;
+ }
+ }
+ }
+
+ free(tmp);
+ }
+}
+
+static void S9xDeinterleaveGD24 (int size, uint8_t *base)
+{
+ // for 24Mb images dumped with Game Doctor
+ if (size != 0x300000)
+ return;
+
+ //Settings.DisplayColor = BUILD_PIXEL(0, 31, 31);
+ //SET_UI_COLOR(0, 255, 255);
+
+ uint8_t *tmp = (uint8_t *) malloc(0x80000);
+ if (tmp)
+ {
+ memmove(tmp, &base[0x180000], 0x80000);
+ memmove(&base[0x180000], &base[0x200000], 0x80000);
+ memmove(&base[0x200000], &base[0x280000], 0x80000);
+ memmove(&base[0x280000], tmp, 0x80000);
+
+ free(tmp);
+
+ S9xDeinterleaveType1(size, base);
+ }
+}
+
+// allocation and deallocation
+
+bool CMemory::Init()
+{
+ RAM = (uint8_t *) malloc(0x20000);
+ SRAM = (uint8_t *) malloc(0x20000);
+ VRAM = (uint8_t *) malloc(0x10000);
+ ROM = (uint8_t *) malloc(MAX_ROM_SIZE + 0x200 + 0x8000);
+
+ IPPU.TileCache[TILE_2BIT] = (uint8_t *) malloc(MAX_2BIT_TILES * 64);
+ IPPU.TileCache[TILE_4BIT] = (uint8_t *) malloc(MAX_4BIT_TILES * 64);
+ IPPU.TileCache[TILE_8BIT] = (uint8_t *) malloc(MAX_8BIT_TILES * 64);
+ IPPU.TileCache[TILE_2BIT_EVEN] = (uint8_t *) malloc(MAX_2BIT_TILES * 64);
+ IPPU.TileCache[TILE_2BIT_ODD] = (uint8_t *) malloc(MAX_2BIT_TILES * 64);
+ IPPU.TileCache[TILE_4BIT_EVEN] = (uint8_t *) malloc(MAX_4BIT_TILES * 64);
+ IPPU.TileCache[TILE_4BIT_ODD] = (uint8_t *) malloc(MAX_4BIT_TILES * 64);
+
+ IPPU.TileCached[TILE_2BIT] = (uint8_t *) malloc(MAX_2BIT_TILES);
+ IPPU.TileCached[TILE_4BIT] = (uint8_t *) malloc(MAX_4BIT_TILES);
+ IPPU.TileCached[TILE_8BIT] = (uint8_t *) malloc(MAX_8BIT_TILES);
+ IPPU.TileCached[TILE_2BIT_EVEN] = (uint8_t *) malloc(MAX_2BIT_TILES);
+ IPPU.TileCached[TILE_2BIT_ODD] = (uint8_t *) malloc(MAX_2BIT_TILES);
+ IPPU.TileCached[TILE_4BIT_EVEN] = (uint8_t *) malloc(MAX_4BIT_TILES);
+ IPPU.TileCached[TILE_4BIT_ODD] = (uint8_t *) malloc(MAX_4BIT_TILES);
+
+ if (!RAM || !SRAM || !VRAM || !ROM ||
+ !IPPU.TileCache[TILE_2BIT] ||
+ !IPPU.TileCache[TILE_4BIT] ||
+ !IPPU.TileCache[TILE_8BIT] ||
+ !IPPU.TileCache[TILE_2BIT_EVEN] ||
+ !IPPU.TileCache[TILE_2BIT_ODD] ||
+ !IPPU.TileCache[TILE_4BIT_EVEN] ||
+ !IPPU.TileCache[TILE_4BIT_ODD] ||
+ !IPPU.TileCached[TILE_2BIT] ||
+ !IPPU.TileCached[TILE_4BIT] ||
+ !IPPU.TileCached[TILE_8BIT] ||
+ !IPPU.TileCached[TILE_2BIT_EVEN] ||
+ !IPPU.TileCached[TILE_2BIT_ODD] ||
+ !IPPU.TileCached[TILE_4BIT_EVEN] ||
+ !IPPU.TileCached[TILE_4BIT_ODD])
+ {
+ Deinit();
+ return false;
+ }
+
+ ZeroMemory(RAM, 0x20000);
+ ZeroMemory(SRAM, 0x20000);
+ ZeroMemory(VRAM, 0x10000);
+ ZeroMemory(ROM, MAX_ROM_SIZE + 0x200 + 0x8000);
+
+ ZeroMemory(IPPU.TileCache[TILE_2BIT], MAX_2BIT_TILES * 64);
+ ZeroMemory(IPPU.TileCache[TILE_4BIT], MAX_4BIT_TILES * 64);
+ ZeroMemory(IPPU.TileCache[TILE_8BIT], MAX_8BIT_TILES * 64);
+ ZeroMemory(IPPU.TileCache[TILE_2BIT_EVEN], MAX_2BIT_TILES * 64);
+ ZeroMemory(IPPU.TileCache[TILE_2BIT_ODD], MAX_2BIT_TILES * 64);
+ ZeroMemory(IPPU.TileCache[TILE_4BIT_EVEN], MAX_4BIT_TILES * 64);
+ ZeroMemory(IPPU.TileCache[TILE_4BIT_ODD], MAX_4BIT_TILES * 64);
+
+ ZeroMemory(IPPU.TileCached[TILE_2BIT], MAX_2BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_4BIT], MAX_4BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_8BIT], MAX_8BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_2BIT_EVEN], MAX_2BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_2BIT_ODD], MAX_2BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_4BIT_EVEN], MAX_4BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_4BIT_ODD], MAX_4BIT_TILES);
+
+ // FillRAM uses first 32K of ROM image area, otherwise space just
+ // wasted. Might be read by the SuperFX code.
+
+ FillRAM = ROM;
+
+ // Add 0x8000 to ROM image pointer to stop SuperFX code accessing
+ // unallocated memory (can cause crash on some ports).
+
+ ROM += 0x8000;
+
+ C4RAM = ROM + 0x400000 + 8192 * 8; // C4
+ OBC1RAM = ROM + 0x400000; // OBC1
+ BIOSROM = ROM + 0x300000; // BS
+ BSRAM = ROM + 0x400000; // BS
+
+ /*SuperFX.pvRegisters = FillRAM + 0x3000;
+ SuperFX.nRamBanks = 2; // Most only use 1. 1=64KB=512Mb, 2=128KB=1024Mb
+ SuperFX.pvRam = SRAM;
+ SuperFX.nRomBanks = (2 * 1024 * 1024) / (32 * 1024);
+ SuperFX.pvRom = (uint8_t *) ROM;*/
+
+ PostRomInitFunc = NULL;
+
+ return true;
+}
+
+void CMemory::Deinit()
+{
+ if (RAM)
+ {
+ free(RAM);
+ RAM = NULL;
+ }
+
+ if (SRAM)
+ {
+ free(SRAM);
+ SRAM = NULL;
+ }
+
+ if (VRAM)
+ {
+ free(VRAM);
+ VRAM = NULL;
+ }
+
+ if (ROM)
+ {
+ ROM -= 0x8000;
+ free(ROM);
+ ROM = NULL;
+ }
+
+ for (int t = 0; t < 7; t++)
+ {
+ if (IPPU.TileCache[t])
+ {
+ free(IPPU.TileCache[t]);
+ IPPU.TileCache[t] = NULL;
+ }
+
+ if (IPPU.TileCached[t])
+ {
+ free(IPPU.TileCached[t]);
+ IPPU.TileCached[t] = NULL;
+ }
+ }
+
+ Safe(NULL);
+ SafeANK(NULL);
+}
+
+// file management and ROM detection
+
+static bool allASCII (uint8_t *b, int size)
+{
+ for (int i = 0; i < size; i++)
+ {
+ if (b[i] < 32 || b[i] > 126)
+ return false;
+ }
+
+ return true;
+}
+
+/*static bool is_SufamiTurbo_BIOS (uint8_t *data, uint32_t size)
+{
+ if (size == 0x40000 &&
+ strncmp((char *) data, "BANDAI SFC-ADX", 14) == 0 && strncmp((char * ) (data + 0x10), "SFC-ADX BACKUP", 14) == 0)
+ return true;
+ else
+ return false;
+}*/
+
+/*static bool is_SufamiTurbo_Cart (uint8_t *data, uint32_t size)
+{
+ if (size >= 0x80000 && size <= 0x100000 &&
+ strncmp((char *) data, "BANDAI SFC-ADX", 14) == 0 && strncmp((char * ) (data + 0x10), "SFC-ADX BACKUP", 14) != 0)
+ return true;
+ else
+ return false;
+}*/
+
+/*static bool is_SameGame_BIOS (uint8_t *data, uint32_t size)
+{
+ if (size == 0x100000 && strncmp((char *) (data + 0xffc0), "Same Game Tsume Game", 20) == 0)
+ return true;
+ else
+ return false;
+}*/
+
+/*static bool is_SameGame_Add_On (uint8_t *data, uint32_t size)
+{
+ if (size == 0x80000)
+ return true;
+ else
+ return false;
+}*/
+
+int CMemory::ScoreHiROM (bool skip_header, int32_t romoff)
+{
+ uint8_t *buf = ROM + 0xff00 + romoff + (skip_header ? 0x200 : 0);
+ int score = 0;
+
+ if (buf[0xd5] & 0x1)
+ score += 2;
+
+ // Mode23 is SA-1
+ if (buf[0xd5] == 0x23)
+ score -= 2;
+
+ if (buf[0xd4] == 0x20)
+ score += 2;
+
+ if ((buf[0xdc] + (buf[0xdd] << 8)) + (buf[0xde] + (buf[0xdf] << 8)) == 0xffff)
+ {
+ score += 2;
+ if (0 != (buf[0xde] + (buf[0xdf] << 8)))
+ score++;
+ }
+
+ if (buf[0xda] == 0x33)
+ score += 2;
+
+ if ((buf[0xd5] & 0xf) < 4)
+ score += 2;
+
+ if (!(buf[0xfd] & 0x80))
+ score -= 6;
+
+ if ((buf[0xfc] + (buf[0xfd] << 8)) > 0xffb0)
+ score -= 2; // reduced after looking at a scan by Cowering
+
+ if (CalculatedSize > 1024 * 1024 * 3)
+ score += 4;
+
+ if ((1 << (buf[0xd7] - 7)) > 48)
+ score -= 1;
+
+ if (!allASCII(&buf[0xb0], 6))
+ score -= 1;
+
+ if (!allASCII(&buf[0xc0], ROM_NAME_LEN - 1))
+ score -= 1;
+
+ return score;
+}
+
+int CMemory::ScoreLoROM (bool skip_header, int32_t romoff)
+{
+ uint8_t *buf = ROM + 0x7f00 + romoff + (skip_header ? 0x200 : 0);
+ int score = 0;
+
+ if (!(buf[0xd5] & 0x1))
+ score += 3;
+
+ // Mode23 is SA-1
+ if (buf[0xd5] == 0x23)
+ score += 2;
+
+ if ((buf[0xdc] + (buf[0xdd] << 8)) + (buf[0xde] + (buf[0xdf] << 8)) == 0xffff)
+ {
+ score += 2;
+ if (0 != (buf[0xde] + (buf[0xdf] << 8)))
+ score++;
+ }
+
+ if (buf[0xda] == 0x33)
+ score += 2;
+
+ if ((buf[0xd5] & 0xf) < 4)
+ score += 2;
+
+ if (!(buf[0xfd] & 0x80))
+ score -= 6;
+
+ if ((buf[0xfc] + (buf[0xfd] << 8)) > 0xffb0)
+ score -= 2; // reduced per Cowering suggestion
+
+ if (CalculatedSize <= 1024 * 1024 * 16)
+ score += 2;
+
+ if ((1 << (buf[0xd7] - 7)) > 48)
+ score -= 1;
+
+ if (!allASCII(&buf[0xb0], 6))
+ score -= 1;
+
+ if (!allASCII(&buf[0xc0], ROM_NAME_LEN - 1))
+ score -= 1;
+
+ return score;
+}
+
+/*uint32_t CMemory::HeaderRemove (uint32_t size, int32_t &headerCount, uint8_t *buf)
+{
+ uint32_t calc_size = (size / 0x2000) * 0x2000;
+
+ if ((size - calc_size == 512 && !Settings.ForceNoHeader) || Settings.ForceHeader)
+ {
+ uint8_t *NSRTHead = buf + 0x1D0; // NSRT Header Location
+
+ // detect NSRT header
+ if (!strncmp("NSRT", (char *) &NSRTHead[24], 4))
+ {
+ if (NSRTHead[28] == 22)
+ {
+ if (((std::accumulate(NSRTHead, NSRTHead + sizeof(NSRTHeader), 0) & 0xFF) == NSRTHead[30]) &&
+ (NSRTHead[30] + NSRTHead[31] == 255) && ((NSRTHead[0] & 0x0F) <= 13) &&
+ (((NSRTHead[0] & 0xF0) >> 4) <= 3) && ((NSRTHead[0] & 0xF0) >> 4))
+ memcpy(NSRTHeader, NSRTHead, sizeof(NSRTHeader));
+ }
+ }
+
+ memmove(buf, buf + 512, calc_size);
+ headerCount++;
+ size -= 512;
+ }
+
+ return size;
+}*/
+
+/*uint32_t CMemory::FileLoader (uint8_t *buffer, const char *filename, int32_t maxsize)
+{
+ // <- ROM size without header
+ // ** Memory.HeaderCount
+ // ** Memory.ROMFilename
+
+ int32_t totalSize = 0;
+ char fname[PATH_MAX + 1];
+ char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], name[_MAX_FNAME + 1], exts[_MAX_EXT + 1];
+ char *ext;
+
+#if defined(_WIN32) || defined(__MACOSX__)
+ ext = &exts[1];
+#else
+ ext = &exts[0];
+#endif
+
+ memset(NSRTHeader, 0, sizeof(NSRTHeader));
+ HeaderCount = 0;
+
+ _splitpath(filename, drive, dir, name, exts);
+ _makepath(fname, drive, dir, name, exts);
+
+ int nFormat = FILE_DEFAULT;
+ if (strcasecmp(ext, "zip") == 0)
+ nFormat = FILE_ZIP;
+ else
+ if (strcasecmp(ext, "jma") == 0)
+ nFormat = FILE_JMA;
+
+ switch (nFormat)
+ {
+ case FILE_ZIP:
+ {
+ #ifdef UNZIP_SUPPORT
+ if (!LoadZip(fname, &totalSize, &HeaderCount, buffer))
+ {
+ S9xMessage(S9X_ERROR, S9X_ROM_INFO, "Invalid Zip archive.");
+ return 0;
+ }
+
+ strcpy(ROMFilename, fname);
+ #else
+ //S9xMessage(S9X_ERROR, S9X_ROM_INFO, "This binary was not created with Zip support.");
+ return 0;
+ #endif
+ break;
+ }
+
+ case FILE_JMA:
+ {
+ #ifdef JMA_SUPPORT
+ size_t size = load_jma_file(fname, buffer);
+ if (!size)
+ {
+ S9xMessage(S9X_ERROR, S9X_ROM_INFO, "Invalid JMA archive.");
+ return 0;
+ }
+
+ totalSize = HeaderRemove(size, HeaderCount, buffer);
+
+ strcpy(ROMFilename, fname);
+ #else
+ //S9xMessage(S9X_ERROR, S9X_ROM_INFO, "This binary was not created with JMA support.");
+ return 0;
+ #endif
+ break;
+ }
+
+ case FILE_DEFAULT:
+ default:
+ {
+ STREAM fp = OPEN_STREAM(fname, "rb");
+ if (!fp)
+ return 0;
+
+ strcpy(ROMFilename, fname);
+
+ int len = 0;
+ uint32_t size = 0;
+ bool more = false;
+ uint8_t *ptr = buffer;
+
+ do
+ {
+ size = READ_STREAM(ptr, maxsize + 0x200 - (ptr - buffer), fp);
+ CLOSE_STREAM(fp);
+
+ size = HeaderRemove(size, HeaderCount, ptr);
+ totalSize += size;
+ ptr += size;
+
+ // check for multi file roms
+ if (ptr - buffer < maxsize + 0x200 &&
+ (isdigit(ext[0]) && ext[1] == 0 && ext[0] < '9'))
+ {
+ more = true;
+ ext[0]++;
+ _makepath(fname, drive, dir, name, exts);
+ }
+ else
+ if (ptr - buffer < maxsize + 0x200 &&
+ (((len = strlen(name)) == 7 || len == 8) &&
+ strncasecmp(name, "sf", 2) == 0 &&
+ isdigit(name[2]) && isdigit(name[3]) && isdigit(name[4]) && isdigit(name[5]) &&
+ isalpha(name[len - 1])))
+ {
+ more = true;
+ name[len - 1]++;
+ _makepath(fname, drive, dir, name, exts);
+ }
+ else
+ more = false;
+
+ } while (more && (fp = OPEN_STREAM(fname, "rb")) != NULL);
+
+ break;
+ }
+ }
+
+ if (HeaderCount == 0)
+ S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "No ROM file header found.");
+ else
+ if (HeaderCount == 1)
+ S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "Found ROM file header (and ignored it).");
+ else
+ S9xMessage(S9X_INFO, S9X_HEADERS_INFO, "Found multiple ROM file headers (and ignored them).");
+
+ return (uint32_t) totalSize;
+}*/
+
+//bool CMemory::LoadROM (const char *filename)
+bool CMemory::LoadROMSNSF(const unsigned char *lrombuf, int32_t lromsize, const unsigned char *srambuf, int32_t sramsize)
+{
+ int retry_count = 0;
+
+ /*if (!filename || !*filename)
+ return false;*/
+
+ ZeroMemory(ROM, MAX_ROM_SIZE);
+ ZeroMemory(&Multi, sizeof(Multi));
+
+again:
+ //Settings.DisplayColor = BUILD_PIXEL(31, 31, 31);
+ //SET_UI_COLOR(255, 255, 255);
+
+ CalculatedSize = 0;
+ ExtendedFormat = NOPE;
+
+ int32_t totalFileSize;
+
+ //totalFileSize = FileLoader(ROM, filename, MAX_ROM_SIZE);
+ totalFileSize = std::min<int32_t>(MAX_ROM_SIZE, lromsize);
+ if (!totalFileSize)
+ return false;
+ memcpy(ROM, lrombuf, totalFileSize);
+ SNESGameFixes.SRAMInitialValue = 0xff;
+ memset(SRAM, SNESGameFixes.SRAMInitialValue, 0x20000);
+ if (srambuf && sramsize)
+ memcpy(SRAM, srambuf, sramsize);
+
+ /*if (!Settings.NoPatch)
+ CheckForAnyPatch(filename, HeaderCount != 0, totalFileSize);*/
+
+ int hi_score, lo_score;
+
+ hi_score = ScoreHiROM(false);
+ lo_score = ScoreLoROM(false);
+
+ if (HeaderCount == 0 && !Settings.ForceNoHeader &&
+ ((hi_score > lo_score && ScoreHiROM(true) > hi_score) ||
+ (hi_score <= lo_score && ScoreLoROM(true) > lo_score)))
+ {
+ memmove(ROM, ROM + 512, totalFileSize - 512);
+ totalFileSize -= 512;
+ //S9xMessage(S9X_INFO, S9X_HEADER_WARNING, "Try 'force no-header' option if the game doesn't work");
+ // modifying ROM, so we need to rescore
+ hi_score = ScoreHiROM(false);
+ lo_score = ScoreLoROM(false);
+ }
+
+ CalculatedSize = (totalFileSize / 0x2000) * 0x2000;
+
+ if (CalculatedSize > 0x400000 &&
+ (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x4332 && // exclude S-DD1
+ (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x4532 &&
+ (ROM[0xffd5] + (ROM[0xffd6] << 8)) != 0xF93a && // exclude SPC7110
+ (ROM[0xffd5] + (ROM[0xffd6] << 8)) != 0xF53a)
+ ExtendedFormat = YEAH;
+
+ // if both vectors are invalid, it's type 1 interleaved LoROM
+ if (ExtendedFormat == NOPE &&
+ ((ROM[0x7ffc] + (ROM[0x7ffd] << 8)) < 0x8000) &&
+ ((ROM[0xfffc] + (ROM[0xfffd] << 8)) < 0x8000))
+ {
+ if (!Settings.ForceInterleaved && !Settings.ForceNotInterleaved)
+ S9xDeinterleaveType1(totalFileSize, ROM);
+ }
+
+ // CalculatedSize is now set, so rescore
+ hi_score = ScoreHiROM(false);
+ lo_score = ScoreLoROM(false);
+
+ uint8_t *RomHeader = ROM;
+
+ if (ExtendedFormat != NOPE)
+ {
+ int swappedhirom, swappedlorom;
+
+ swappedhirom = ScoreHiROM(false, 0x400000);
+ swappedlorom = ScoreLoROM(false, 0x400000);
+
+ // set swapped here
+ if (std::max(swappedlorom, swappedhirom) >= std::max(lo_score, hi_score))
+ {
+ ExtendedFormat = BIGFIRST;
+ hi_score = swappedhirom;
+ lo_score = swappedlorom;
+ RomHeader += 0x400000;
+ }
+ else
+ ExtendedFormat = SMALLFIRST;
+ }
+
+ bool interleaved, tales = false;
+
+ interleaved = Settings.ForceInterleaved || Settings.ForceInterleaved2 || Settings.ForceInterleaveGD24;
+
+ if (Settings.ForceLoROM || (!Settings.ForceHiROM && lo_score >= hi_score))
+ {
+ LoROM = true;
+ HiROM = false;
+
+ // ignore map type byte if not 0x2x or 0x3x
+ if ((RomHeader[0x7fd5] & 0xf0) == 0x20 || (RomHeader[0x7fd5] & 0xf0) == 0x30)
+ {
+ switch (RomHeader[0x7fd5] & 0xf)
+ {
+ case 1:
+ interleaved = true;
+ break;
+
+ case 5:
+ interleaved = true;
+ tales = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ LoROM = false;
+ HiROM = true;
+
+ if ((RomHeader[0xffd5] & 0xf0) == 0x20 || (RomHeader[0xffd5] & 0xf0) == 0x30)
+ {
+ switch (RomHeader[0xffd5] & 0xf)
+ {
+ case 0:
+ case 3:
+ interleaved = true;
+ break;
+ }
+ }
+ }
+
+ // this two games fail to be detected
+ if (!Settings.ForceHiROM && !Settings.ForceLoROM)
+ {
+ if (strncmp((char *) &ROM[0x7fc0], "YUYU NO QUIZ DE GO!GO!", 22) == 0 ||
+ (strncmp((char *) &ROM[0xffc0], "BATMAN--REVENGE JOKER", 21) == 0))
+ {
+ LoROM = true;
+ HiROM = false;
+ interleaved = false;
+ tales = false;
+ }
+ }
+
+ if (!Settings.ForceNotInterleaved && interleaved)
+ {
+ //S9xMessage(S9X_INFO, S9X_ROM_INTERLEAVED_INFO, "ROM image is in interleaved format - converting...");
+
+ if (tales)
+ {
+ if (ExtendedFormat == BIGFIRST)
+ {
+ S9xDeinterleaveType1(0x400000, ROM);
+ S9xDeinterleaveType1(CalculatedSize - 0x400000, ROM + 0x400000);
+ }
+ else
+ {
+ S9xDeinterleaveType1(CalculatedSize - 0x400000, ROM);
+ S9xDeinterleaveType1(0x400000, ROM + CalculatedSize - 0x400000);
+ }
+
+ LoROM = false;
+ HiROM = true;
+ }
+ else
+ if (Settings.ForceInterleaveGD24 && CalculatedSize == 0x300000)
+ {
+ bool t = LoROM;
+ LoROM = HiROM;
+ HiROM = t;
+ S9xDeinterleaveGD24(CalculatedSize, ROM);
+ }
+ else
+ if (Settings.ForceInterleaved2)
+ S9xDeinterleaveType2(CalculatedSize, ROM);
+ else
+ {
+ bool t = LoROM;
+ LoROM = HiROM;
+ HiROM = t;
+ S9xDeinterleaveType1(CalculatedSize, ROM);
+ }
+
+ hi_score = ScoreHiROM(false);
+ lo_score = ScoreLoROM(false);
+
+ if ((HiROM && (lo_score >= hi_score || hi_score < 0)) ||
+ (LoROM && (hi_score > lo_score || lo_score < 0)))
+ {
+ if (retry_count == 0)
+ {
+ //S9xMessage(S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO, "ROM lied about its type! Trying again.");
+ Settings.ForceNotInterleaved = true;
+ Settings.ForceInterleaved = false;
+ retry_count++;
+ goto again;
+ }
+ }
+ }
+
+ if (ExtendedFormat == SMALLFIRST)
+ tales = true;
+
+ if (tales)
+ {
+ uint8_t *tmp = (uint8_t *) malloc(CalculatedSize - 0x400000);
+ if (tmp)
+ {
+ //S9xMessage(S9X_INFO, S9X_ROM_INTERLEAVED_INFO, "Fixing swapped ExHiROM...");
+ memmove(tmp, ROM, CalculatedSize - 0x400000);
+ memmove(ROM, ROM + CalculatedSize - 0x400000, 0x400000);
+ memmove(ROM + 0x400000, tmp, CalculatedSize - 0x400000);
+ free(tmp);
+ }
+ }
+
+ /*if (strncmp(LastRomFilename, filename, PATH_MAX + 1))
+ {
+ strncpy(LastRomFilename, filename, PATH_MAX + 1);
+ LastRomFilename[PATH_MAX] = 0;
+ }*/
+
+ ZeroMemory(&SNESGameFixes, sizeof(SNESGameFixes));
+ SNESGameFixes.SRAMInitialValue = 0x60;
+
+ //S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
+
+ InitROM();
+
+ /*S9xInitCheatData();
+ S9xApplyCheats();*/
+
+ S9xReset();
+
+ return true;
+}
+
+/*bool CMemory::LoadMultiCart (const char *cartA, const char *cartB)
+{
+ bool r = true;
+
+ ZeroMemory(ROM, MAX_ROM_SIZE);
+ ZeroMemory(&Multi, sizeof(Multi));
+
+ Settings.DisplayColor = BUILD_PIXEL(31, 31, 31);
+ SET_UI_COLOR(255, 255, 255);
+
+ CalculatedSize = 0;
+ ExtendedFormat = NOPE;
+
+ if (cartA && cartA[0])
+ Multi.cartSizeA = FileLoader(ROM, cartA, MAX_ROM_SIZE);
+
+ if (Multi.cartSizeA == 0)
+ {
+ if (cartB && cartB[0])
+ Multi.cartSizeB = FileLoader(ROM, cartB, MAX_ROM_SIZE);
+ }
+
+ if (Multi.cartSizeA)
+ {
+ if (is_SufamiTurbo_Cart(ROM, Multi.cartSizeA))
+ Multi.cartType = 4;
+ else
+ if (is_SameGame_BIOS(ROM, Multi.cartSizeA))
+ Multi.cartType = 3;
+ }
+ else
+ if (Multi.cartSizeB)
+ {
+ if (is_SufamiTurbo_Cart(ROM, Multi.cartSizeB))
+ Multi.cartType = 4;
+ }
+ else
+ Multi.cartType = 4; // assuming BIOS only
+
+ switch (Multi.cartType)
+ {
+ case 4:
+ r = LoadSufamiTurbo(cartA, cartB);
+ break;
+
+ case 3:
+ r = LoadSameGame(cartA, cartB);
+ break;
+
+ default:
+ r = false;
+ }
+
+ if (!r)
+ {
+ ZeroMemory(&Multi, sizeof(Multi));
+ return false;
+ }
+
+ ZeroMemory(&SNESGameFixes, sizeof(SNESGameFixes));
+ SNESGameFixes.SRAMInitialValue = 0x60;
+
+ S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
+
+ InitROM();
+
+ S9xInitCheatData();
+ S9xApplyCheats();
+
+ S9xReset();
+
+ return true;
+}
+
+bool CMemory::LoadSufamiTurbo (const char *cartA, const char *cartB)
+{
+ Multi.cartOffsetA = 0x100000;
+ Multi.cartOffsetB = 0x200000;
+ Multi.sramA = SRAM;
+ Multi.sramB = SRAM + 0x10000;
+
+ if (Multi.cartSizeA)
+ {
+ Multi.sramSizeA = 4; // ROM[0x37]?
+ Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0;
+
+ if (!Settings.NoPatch)
+ CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA);
+
+ strcpy(Multi.fileNameA, cartA);
+ memcpy(ROM + Multi.cartOffsetA, ROM, Multi.cartSizeA);
+ }
+
+ if (Multi.cartSizeA && !Multi.cartSizeB)
+ {
+ if (cartB && cartB[0])
+ Multi.cartSizeB = FileLoader(ROM, cartB, MAX_ROM_SIZE);
+
+ if (Multi.cartSizeB)
+ {
+ if (!is_SufamiTurbo_Cart(ROM, Multi.cartSizeB))
+ Multi.cartSizeB = 0;
+ }
+ }
+
+ if (Multi.cartSizeB)
+ {
+ Multi.sramSizeB = 4; // ROM[0x37]?
+ Multi.sramMaskB = Multi.sramSizeB ? ((1 << (Multi.sramSizeB + 3)) * 128 - 1) : 0;
+
+ if (!Settings.NoPatch)
+ CheckForAnyPatch(cartB, HeaderCount != 0, Multi.cartSizeB);
+
+ strcpy(Multi.fileNameB, cartB);
+ memcpy(ROM + Multi.cartOffsetB, ROM, Multi.cartSizeB);
+ }
+
+ FILE *fp;
+ size_t size;
+ char path[PATH_MAX + 1];
+
+ strcpy(path, S9xGetDirectory(BIOS_DIR));
+ strcat(path, SLASH_STR);
+ strcat(path, "STBIOS.bin");
+
+ fp = fopen(path, "rb");
+ if (fp)
+ {
+ size = fread((void *) ROM, 1, 0x40000, fp);
+ fclose(fp);
+ if (!is_SufamiTurbo_BIOS(ROM, size))
+ return false;
+ }
+ else
+ return false;
+
+ if (Multi.cartSizeA)
+ strcpy(ROMFilename, Multi.fileNameA);
+ else
+ if (Multi.cartSizeB)
+ strcpy(ROMFilename, Multi.fileNameB);
+ else
+ strcpy(ROMFilename, path);
+
+ LoROM = true;
+ HiROM = false;
+ CalculatedSize = 0x40000;
+
+ return true;
+}
+
+bool CMemory::LoadSameGame (const char *cartA, const char *cartB)
+{
+ Multi.cartOffsetA = 0;
+ Multi.cartOffsetB = 0x200000;
+ Multi.sramA = SRAM;
+ Multi.sramB = NULL;
+
+ Multi.sramSizeA = ROM[0xffd8];
+ Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0;
+ Multi.sramSizeB = 0;
+ Multi.sramMaskB = 0;
+
+ if (!Settings.NoPatch)
+ CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA);
+
+ strcpy(Multi.fileNameA, cartA);
+
+ if (cartB && cartB[0])
+ Multi.cartSizeB = FileLoader(ROM + Multi.cartOffsetB, cartB, MAX_ROM_SIZE - Multi.cartOffsetB);
+
+ if (Multi.cartSizeB)
+ {
+ if (!is_SameGame_Add_On(ROM + Multi.cartOffsetB, Multi.cartSizeB))
+ Multi.cartSizeB = 0;
+ else
+ strcpy(Multi.fileNameB, cartB);
+ }
+
+ strcpy(ROMFilename, Multi.fileNameA);
+
+ LoROM = false;
+ HiROM = true;
+ CalculatedSize = Multi.cartSizeA;
+
+ return true;
+}
+
+bool CMemory::LoadSRTC()
+{
+ FILE *fp;
+ size_t ignore;
+
+ fp = fopen(S9xGetFilename(".rtc", SRAM_DIR), "rb");
+ if (!fp)
+ return false;
+
+ ignore = fread(RTCData.reg, 1, 20, fp);
+ fclose(fp);
+
+ return true;
+}
+
+bool CMemory::SaveSRTC()
+{
+ FILE *fp;
+ size_t ignore;
+
+ fp = fopen(S9xGetFilename(".rtc", SRAM_DIR), "wb");
+ if (!fp)
+ return false;
+
+ ignore = fwrite(RTCData.reg, 1, 20, fp);
+ fclose(fp);
+
+ return true;
+}
+
+void CMemory::ClearSRAM (bool onlyNonSavedSRAM)
+{
+ if (onlyNonSavedSRAM)
+ if (!(Settings.SuperFX && ROMType < 0x15) && !(Settings.SA1 && ROMType == 0x34)) // can have SRAM
+ return;
+
+ memset(SRAM, SNESGameFixes.SRAMInitialValue, 0x20000);
+}
+
+bool CMemory::LoadSRAM (const char *filename)
+{
+ FILE *file;
+ int size, len;
+ char sramName[PATH_MAX + 1];
+
+ strcpy(sramName, filename);
+
+ ClearSRAM();
+
+ if (Multi.cartType && Multi.sramSizeB)
+ {
+ char temp[PATH_MAX + 1];
+
+ strcpy(temp, ROMFilename);
+ strcpy(ROMFilename, Multi.fileNameB);
+
+ size = (1 << (Multi.sramSizeB + 3)) * 128;
+
+ file = fopen(S9xGetFilename(".srm", SRAM_DIR), "rb");
+ if (file)
+ {
+ len = fread((char *) Multi.sramB, 1, 0x10000, file);
+ fclose(file);
+ if (len - size == 512)
+ memmove(Multi.sramB, Multi.sramB + 512, size);
+ }
+
+ strcpy(ROMFilename, temp);
+ }
+
+ size = SRAMSize ? (1 << (SRAMSize + 3)) * 128 : 0;
+ if (size > 0x20000)
+ size = 0x20000;
+
+ if (size)
+ {
+ file = fopen(sramName, "rb");
+ if (file)
+ {
+ len = fread((char *) SRAM, 1, 0x20000, file);
+ fclose(file);
+ if (len - size == 512)
+ memmove(SRAM, SRAM + 512, size);
+
+ if (Settings.SRTC || Settings.SPC7110RTC)
+ LoadSRTC();
+
+ return true;
+ }
+ else
+ if (Settings.BS && !Settings.BSXItself)
+ {
+ // The BS game's SRAM was not found
+ // Try to read BS-X.srm instead
+ char path[PATH_MAX + 1];
+
+ strcpy(path, S9xGetDirectory(SRAM_DIR));
+ strcat(path, SLASH_STR);
+ strcat(path, "BS-X.srm");
+
+ file = fopen(path, "rb");
+ if (file)
+ {
+ len = fread((char *) SRAM, 1, 0x20000, file);
+ fclose(file);
+ if (len - size == 512)
+ memmove(SRAM, SRAM + 512, size);
+
+ S9xMessage(S9X_INFO, S9X_ROM_INFO, "The SRAM file wasn't found: BS-X.srm was read instead.");
+ return true;
+ }
+ else
+ {
+ S9xMessage(S9X_INFO, S9X_ROM_INFO, "The SRAM file wasn't found, BS-X.srm wasn't found either.");
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+bool CMemory::SaveSRAM (const char *filename)
+{
+ if (Settings.SuperFX && ROMType < 0x15) // doesn't have SRAM
+ return true;
+
+ if (Settings.SA1 && ROMType == 0x34) // doesn't have SRAM
+ return true;
+
+ FILE *file;
+ int size;
+ char sramName[PATH_MAX + 1];
+
+ strcpy(sramName, filename);
+
+ if (Multi.cartType && Multi.sramSizeB)
+ {
+ char name[PATH_MAX + 1], temp[PATH_MAX + 1];
+
+ strcpy(temp, ROMFilename);
+ strcpy(ROMFilename, Multi.fileNameB);
+ strcpy(name, S9xGetFilename(".srm", SRAM_DIR));
+
+ size = (1 << (Multi.sramSizeB + 3)) * 128;
+
+ file = fopen(name, "wb");
+ if (file)
+ {
+ size_t ignore;
+ ignore = fwrite((char *) Multi.sramB, size, 1, file);
+ fclose(file);
+ #ifdef __linux
+ ignore = chown(name, getuid(), getgid());
+ #endif
+ }
+
+ strcpy(ROMFilename, temp);
+ }
+
+ size = SRAMSize ? (1 << (SRAMSize + 3)) * 128 : 0;
+ if (size > 0x20000)
+ size = 0x20000;
+
+ if (size)
+ {
+ file = fopen(sramName, "wb");
+ if (file)
+ {
+ size_t ignore;
+ ignore = fwrite((char *) SRAM, size, 1, file);
+ fclose(file);
+ #ifdef __linux
+ ignore = chown(sramName, getuid(), getgid());
+ #endif
+
+ if (Settings.SRTC || Settings.SPC7110RTC)
+ SaveSRTC();
+
+ return true;
+ }
+ }
+
+ return false;
+}*/
+
+// initialization
+
+static uint32_t caCRC32 (uint8_t *array, uint32_t size, uint32_t crc32 = 0xffffffff)
+{
+ for (uint32_t i = 0; i < size; i++)
+ crc32 = ((crc32 >> 8) & 0x00FFFFFF) ^ crc32Table[(crc32 ^ array[i]) & 0xFF];
+
+ return ~crc32;
+}
+
+char * CMemory::Safe (const char *s)
+{
+ static char *safe = NULL;
+ static int safe_len = 0;
+
+ if (s == NULL)
+ {
+ if (safe)
+ {
+ free(safe);
+ safe = NULL;
+ }
+
+ return NULL;
+ }
+
+ int len = strlen(s);
+ if (!safe || len + 1 > safe_len)
+ {
+ if (safe)
+ free(safe);
+
+ safe_len = len + 1;
+ safe = (char *) malloc(safe_len);
+ }
+
+ for (int i = 0; i < len; i++)
+ {
+ if (s[i] >= 32 && s[i] < 127)
+ safe[i] = s[i];
+ else
+ safe[i] = '_';
+ }
+
+ safe[len] = 0;
+
+ return safe;
+}
+
+char * CMemory::SafeANK (const char *s)
+{
+ static char *safe = NULL;
+ static int safe_len = 0;
+
+ if (s == NULL)
+ {
+ if (safe)
+ {
+ free(safe);
+ safe = NULL;
+ }
+
+ return NULL;
+ }
+
+ int len = strlen(s);
+ if (!safe || len + 1 > safe_len)
+ {
+ if (safe)
+ free(safe);
+
+ safe_len = len + 1;
+ safe = (char *) malloc(safe_len);
+ }
+
+ for (int i = 0; i < len; i++)
+ {
+ if (s[i] >= 32 && s[i] < 127) // ASCII
+ safe [i] = s[i];
+ else
+ if (ROMRegion == 0 && ((uint8_t) s[i] >= 0xa0 && (uint8_t) s[i] < 0xe0)) // JIS X 201 - Katakana
+ safe [i] = s[i];
+ else
+ safe [i] = '_';
+ }
+
+ safe [len] = 0;
+
+ return safe;
+}
+
+void CMemory::ParseSNESHeader (uint8_t *RomHeader)
+{
+ bool bs = Settings.BS & !Settings.BSXItself;
+
+ strncpy(ROMName, (char *) &RomHeader[0x10], ROM_NAME_LEN - 1);
+ if (bs)
+ memset(ROMName + 16, 0x20, ROM_NAME_LEN - 17);
+
+ if (bs)
+ {
+ if (!(((RomHeader[0x29] & 0x20) && CalculatedSize < 0x100000) ||
+ (!(RomHeader[0x29] & 0x20) && CalculatedSize == 0x100000)))
+ printf("BS: Size mismatch\n");
+
+ // FIXME
+ int p = 0;
+ while ((1 << p) < (int) CalculatedSize)
+ p++;
+ ROMSize = p - 10;
+ }
+ else
+ ROMSize = RomHeader[0x27];
+
+ SRAMSize = bs ? 5 /* BS-X */ : RomHeader[0x28];
+ ROMSpeed = bs ? RomHeader[0x28] : RomHeader[0x25];
+ ROMType = bs ? 0xE5 /* BS-X */ : RomHeader[0x26];
+ ROMRegion = bs ? 0 : RomHeader[0x29];
+
+ ROMChecksum = RomHeader[0x2E] + (RomHeader[0x2F] << 8);
+ ROMComplementChecksum = RomHeader[0x2C] + (RomHeader[0x2D] << 8);
+
+ memmove(ROMId, &RomHeader[0x02], 4);
+
+ if (RomHeader[0x2A] != 0x33)
+ CompanyId = ((RomHeader[0x2A] >> 4) & 0x0F) * 36 + (RomHeader[0x2A] & 0x0F);
+ else
+ if (isalnum(RomHeader[0x00]) && isalnum(RomHeader[0x01]))
+ {
+ int l, r, l2, r2;
+ l = toupper(RomHeader[0x00]);
+ r = toupper(RomHeader[0x01]);
+ l2 = (l > '9') ? l - '7' : l - '0';
+ r2 = (r > '9') ? r - '7' : r - '0';
+ CompanyId = l2 * 36 + r2;
+ }
+}
+
+void CMemory::InitROM()
+{
+ Settings.SuperFX = false;
+ Settings.DSP = 0;
+ Settings.SA1 = false;
+ Settings.C4 = false;
+ Settings.SDD1 = false;
+ Settings.SPC7110 = false;
+ Settings.SPC7110RTC = false;
+ Settings.OBC1 = false;
+ Settings.SETA = 0;
+ Settings.SRTC = false;
+ Settings.BS = false;
+
+ //SuperFX.nRomBanks = CalculatedSize >> 15;
+
+ //// Parse ROM header and read ROM informatoin
+
+ CompanyId = -1;
+ memset(ROMId, 0, 5);
+
+ uint8_t *RomHeader = ROM + 0x7FB0;
+ if (ExtendedFormat == BIGFIRST)
+ RomHeader += 0x400000;
+ if (HiROM)
+ RomHeader += 0x8000;
+
+ //S9xInitBSX(); // Set BS header before parsing
+
+ ParseSNESHeader(RomHeader);
+
+ //// Detect and initialize chips
+ //// detection codes are compatible with NSRT
+
+ // DSP1/2/3/4
+ if (ROMType == 0x03)
+ {
+ if (ROMSpeed == 0x30)
+ Settings.DSP = 4; // DSP4
+ else
+ Settings.DSP = 1; // DSP1
+ }
+ else
+ if (ROMType == 0x05)
+ {
+ if (ROMSpeed == 0x20)
+ Settings.DSP = 2; // DSP2
+ else
+ if (ROMSpeed == 0x30 && RomHeader[0x2a] == 0xb2)
+ Settings.DSP = 3; // DSP3
+ else
+ Settings.DSP = 1; // DSP1
+ }
+
+ /*switch (Settings.DSP)
+ {
+ case 1: // DSP1
+ if (HiROM)
+ {
+ DSP0.boundary = 0x7000;
+ DSP0.maptype = M_DSP1_HIROM;
+ }
+ else
+ if (CalculatedSize > 0x100000)
+ {
+ DSP0.boundary = 0x4000;
+ DSP0.maptype = M_DSP1_LOROM_L;
+ }
+ else
+ {
+ DSP0.boundary = 0xc000;
+ DSP0.maptype = M_DSP1_LOROM_S;
+ }
+
+ SetDSP = &DSP1SetByte;
+ GetDSP = &DSP1GetByte;
+ break;
+
+ case 2: // DSP2
+ DSP0.boundary = 0x10000;
+ DSP0.maptype = M_DSP2_LOROM;
+ SetDSP = &DSP2SetByte;
+ GetDSP = &DSP2GetByte;
+ break;
+
+ case 3: // DSP3
+ DSP0.boundary = 0xc000;
+ DSP0.maptype = M_DSP3_LOROM;
+ SetDSP = &DSP3SetByte;
+ GetDSP = &DSP3GetByte;
+ break;
+
+ case 4: // DSP4
+ DSP0.boundary = 0xc000;
+ DSP0.maptype = M_DSP4_LOROM;
+ SetDSP = &DSP4SetByte;
+ GetDSP = &DSP4GetByte;
+ break;
+
+ default:
+ SetDSP = NULL;
+ GetDSP = NULL;
+ break;
+ }*/
+
+ uint32_t identifier = ((ROMType & 0xff) << 8) + (ROMSpeed & 0xff);
+
+ switch (identifier)
+ {
+ // SRTC
+ /*case 0x5535:
+ Settings.SRTC = true;
+ S9xInitSRTC();
+ break;
+
+ // SPC7110
+ case 0xF93A:
+ Settings.SPC7110RTC = true;
+ case 0xF53A:
+ Settings.SPC7110 = true;
+ S9xInitSPC7110();
+ break;
+
+ // OBC1
+ case 0x2530:
+ Settings.OBC1 = true;
+ break;
+
+ // SA1
+ case 0x3423:
+ case 0x3523:
+ Settings.SA1 = true;
+ break;
+
+ // SuperFX
+ case 0x1320:
+ case 0x1420:
+ case 0x1520:
+ case 0x1A20:
+ Settings.SuperFX = true;
+ S9xInitSuperFX();
+ if (ROM[0x7FDA] == 0x33)
+ SRAMSize = ROM[0x7FBD];
+ else
+ SRAMSize = 5;
+ break;*/
+
+ // SDD1
+ case 0x4332:
+ case 0x4532:
+ Settings.SDD1 = true;
+ break;
+
+ // ST018
+ /*case 0xF530:
+ Settings.SETA = ST_018;
+ SetSETA = NULL;
+ GetSETA = NULL;
+ SRAMSize = 2;
+ SNESGameFixes.SRAMInitialValue = 0x00;
+ break;
+
+ // ST010/011
+ case 0xF630:
+ if (ROM[0x7FD7] == 0x09)
+ {
+ Settings.SETA = ST_011;
+ SetSETA = &S9xSetST011;
+ GetSETA = &S9xGetST011;
+ }
+ else
+ {
+ Settings.SETA = ST_010;
+ SetSETA = &S9xSetST010;
+ GetSETA = &S9xGetST010;
+ }
+
+ SRAMSize = 2;
+ SNESGameFixes.SRAMInitialValue = 0x00;
+ break;
+
+ // C4
+ case 0xF320:
+ Settings.C4 = true;
+ break;*/
+ }
+
+ //// Map memory and calculate checksum
+
+ Map_Initialize();
+ CalculatedChecksum = 0;
+
+ if (HiROM)
+ {
+ if (Settings.BS)
+ /* Do nothing */;
+ else
+ /*if (Settings.SPC7110)
+ Map_SPC7110HiROMMap();
+ else*/
+ if (ExtendedFormat != NOPE)
+ Map_ExtendedHiROMMap();
+ /*else
+ if (Multi.cartType == 3)
+ Map_SameGameHiROMMap();*/
+ else
+ Map_HiROMMap();
+ }
+ else
+ {
+ if (Settings.BS)
+ /* Do nothing */;
+ else
+ /*if (Settings.SETA && Settings.SETA != ST_018)
+ Map_SetaDSPLoROMMap();
+ else
+ if (Settings.SuperFX)
+ Map_SuperFXLoROMMap();
+ else
+ if (Settings.SA1)
+ Map_SA1LoROMMap();
+ else*/
+ if (Settings.SDD1)
+ Map_SDD1LoROMMap();
+ else
+ if (ExtendedFormat != NOPE)
+ Map_JumboLoROMMap();
+ else
+ if (strncmp(ROMName, "WANDERERS FROM YS", 17) == 0)
+ Map_NoMAD1LoROMMap();
+ else
+ if (strncmp(ROMName, "SOUND NOVEL-TCOOL", 17) == 0 ||
+ strncmp(ROMName, "DERBY STALLION 96", 17) == 0)
+ Map_ROM24MBSLoROMMap();
+ else
+ if (strncmp(ROMName, "THOROUGHBRED BREEDER3", 21) == 0 ||
+ strncmp(ROMName, "RPG-TCOOL 2", 11) == 0)
+ Map_SRAM512KLoROMMap();
+ /*else
+ if (strncmp(ROMName, "ADD-ON BASE CASSETE", 19) == 0)
+ {
+ if (Multi.cartType == 4)
+ {
+ SRAMSize = Multi.sramSizeA;
+ Map_SufamiTurboLoROMMap();
+ }
+ else
+ {
+ SRAMSize = 5;
+ Map_SufamiTurboPseudoLoROMMap();
+ }
+ }*/
+ else
+ Map_LoROMMap();
+ }
+
+ Checksum_Calculate();
+
+ bool isChecksumOK = (ROMChecksum + ROMComplementChecksum == 0xffff) &
+ (ROMChecksum == CalculatedChecksum);
+
+ //// Build more ROM information
+
+ // CRC32
+ if (!Settings.BS || Settings.BSXItself) // Not BS Dump
+ ROMCRC32 = caCRC32(ROM, CalculatedSize);
+ else // Convert to correct format before scan
+ {
+ int offset = HiROM ? 0xffc0 : 0x7fc0;
+ // Backup
+ uint8_t BSMagic0 = ROM[offset + 22],
+ BSMagic1 = ROM[offset + 23];
+ // uCONSRT standard
+ ROM[offset + 22] = 0x42;
+ ROM[offset + 23] = 0x00;
+ // Calc
+ ROMCRC32 = caCRC32(ROM, CalculatedSize);
+ // Convert back
+ ROM[offset + 22] = BSMagic0;
+ ROM[offset + 23] = BSMagic1;
+ }
+
+ // NTSC/PAL
+ if (Settings.ForceNTSC)
+ Settings.PAL = false;
+ else
+ if (Settings.ForcePAL)
+ Settings.PAL = true;
+ else
+ if (!Settings.BS && (ROMRegion >= 2) && (ROMRegion <= 12))
+ Settings.PAL = true;
+ else
+ Settings.PAL = false;
+
+ if (Settings.PAL)
+ {
+ Settings.FrameTime = Settings.FrameTimePAL;
+ ROMFramesPerSecond = 50;
+ }
+ else
+ {
+ Settings.FrameTime = Settings.FrameTimeNTSC;
+ ROMFramesPerSecond = 60;
+ }
+
+ // truncate cart name
+ ROMName[ROM_NAME_LEN - 1] = 0;
+ if (strlen(ROMName))
+ {
+ char *p = ROMName + strlen(ROMName);
+ if (p > ROMName + 21 && ROMName[20] == ' ')
+ p = ROMName + 21;
+ while (p > ROMName && *(p - 1) == ' ')
+ p--;
+ *p = 0;
+ }
+
+ // SRAM size
+ SRAMMask = SRAMSize ? ((1 << (SRAMSize + 3)) * 128) - 1 : 0;
+
+ // checksum
+ /*if (!isChecksumOK || ((uint32_t) CalculatedSize > (uint32_t) (((1 << (ROMSize - 7)) * 128) * 1024)))
+ {
+ Settings.DisplayColor = BUILD_PIXEL(31, 31, 0);
+ SET_UI_COLOR(255, 255, 0);
+ }*/
+
+ /*if (Multi.cartType == 4)
+ {
+ Settings.DisplayColor = BUILD_PIXEL(0, 16, 31);
+ SET_UI_COLOR(0, 128, 255);
+ }*/
+
+ //// Initialize emulation
+
+ Timings.H_Max_Master = SNES_CYCLES_PER_SCANLINE;
+ Timings.H_Max = Timings.H_Max_Master;
+ Timings.HBlankStart = SNES_HBLANK_START_HC;
+ Timings.HBlankEnd = SNES_HBLANK_END_HC;
+ Timings.HDMAInit = SNES_HDMA_INIT_HC;
+ Timings.HDMAStart = SNES_HDMA_START_HC;
+ Timings.RenderPos = SNES_RENDER_START_HC;
+ Timings.V_Max_Master = Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER;
+ Timings.V_Max = Timings.V_Max_Master;
+ /* From byuu: The total delay time for both the initial (H)DMA sync (to the DMA clock),
+ and the end (H)DMA sync (back to the last CPU cycle's mcycle rate (6, 8, or 12)) always takes between 12-24 mcycles.
+ Possible delays: { 12, 14, 16, 18, 20, 22, 24 }
+ XXX: Snes9x can't emulate this timing :( so let's use the average value... */
+ Timings.DMACPUSync = 18;
+ /* If the CPU is halted (i.e. for DMA) while /NMI goes low, the NMI will trigger
+ after the DMA completes (even if /NMI goes high again before the DMA
+ completes). In this case, there is a 24-30 cycle delay between the end of DMA
+ 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;
+
+ IPPU.TotalEmulatedFrames = 0;
+
+ //// Hack games
+
+ ApplyROMFixes();
+
+ //// Show ROM information
+ //char displayName[ROM_NAME_LEN];
+
+ strcpy(RawROMName, ROMName);
+ //sprintf(displayName, "%s", SafeANK(ROMName));
+ sprintf(ROMName, "%s", Safe(ROMName));
+ sprintf(ROMId, "%s", Safe(ROMId));
+
+ /*sprintf(String, "\"%s\" [%s] %s, %s, %s, %s, SRAM:%s, ID:%s, CRC32:%08X",
+ displayName, isChecksumOK ? "checksum ok" : ((Multi.cartType == 4) ? "no checksum" : "bad checksum"),
+ MapType(), Size(), KartContents(), Settings.PAL ? "PAL" : "NTSC", StaticRAMSize(), ROMId, ROMCRC32);*/
+ //S9xMessage(S9X_INFO, S9X_ROM_INFO, String);
+
+ Settings.ForceLoROM = false;
+ Settings.ForceHiROM = false;
+ Settings.ForceHeader = false;
+ Settings.ForceNoHeader = false;
+ Settings.ForceInterleaved = false;
+ Settings.ForceInterleaved2 = false;
+ Settings.ForceInterleaveGD24 = false;
+ Settings.ForceNotInterleaved = false;
+ Settings.ForcePAL = false;
+ Settings.ForceNTSC = false;
+
+ Settings.TakeScreenshot = false;
+
+ /*if (stopMovie)
+ S9xMovieStop(true);*/
+
+ if (PostRomInitFunc)
+ PostRomInitFunc();
+
+ //S9xVerifyControllers();
+}
+
+// memory map
+
+uint32_t CMemory::map_mirror (uint32_t size, uint32_t pos)
+{
+ // from bsnes
+ if (size == 0)
+ return 0;
+ if (pos < size)
+ return pos;
+
+ uint32_t mask = 1 << 31;
+ while (!(pos & mask))
+ mask >>= 1;
+
+ if (size <= (pos & mask))
+ return map_mirror(size, pos - mask);
+ else
+ return mask + map_mirror(size - mask, pos - mask);
+}
+
+void CMemory::map_lorom (uint32_t bank_s, uint32_t bank_e, uint32_t addr_s, uint32_t addr_e, uint32_t size)
+{
+ uint32_t c, i, p, addr;
+
+ for (c = bank_s; c <= bank_e; c++)
+ {
+ for (i = addr_s; i <= addr_e; i += 0x1000)
+ {
+ p = (c << 4) | (i >> 12);
+ addr = (c & 0x7f) * 0x8000;
+ Map[p] = ROM + map_mirror(size, addr) - (i & 0x8000);
+ BlockIsROM[p] = true;
+ BlockIsRAM[p] = false;
+ }
+ }
+}
+
+void CMemory::map_hirom (uint32_t bank_s, uint32_t bank_e, uint32_t addr_s, uint32_t addr_e, uint32_t size)
+{
+ uint32_t c, i, p, addr;
+
+ for (c = bank_s; c <= bank_e; c++)
+ {
+ for (i = addr_s; i <= addr_e; i += 0x1000)
+ {
+ p = (c << 4) | (i >> 12);
+ addr = c << 16;
+ Map[p] = ROM + map_mirror(size, addr);
+ BlockIsROM[p] = true;
+ BlockIsRAM[p] = false;
+ }
+ }
+}
+
+void CMemory::map_lorom_offset (uint32_t bank_s, uint32_t bank_e, uint32_t addr_s, uint32_t addr_e, uint32_t size, uint32_t offset)
+{
+ uint32_t c, i, p, addr;
+
+ for (c = bank_s; c <= bank_e; c++)
+ {
+ for (i = addr_s; i <= addr_e; i += 0x1000)
+ {
+ p = (c << 4) | (i >> 12);
+ addr = ((c - bank_s) & 0x7f) * 0x8000;
+ Map[p] = ROM + offset + map_mirror(size, addr) - (i & 0x8000);
+ BlockIsROM[p] = true;
+ BlockIsRAM[p] = false;
+ }
+ }
+}
+
+void CMemory::map_hirom_offset (uint32_t bank_s, uint32_t bank_e, uint32_t addr_s, uint32_t addr_e, uint32_t size, uint32_t offset)
+{
+ uint32_t c, i, p, addr;
+
+ for (c = bank_s; c <= bank_e; c++)
+ {
+ for (i = addr_s; i <= addr_e; i += 0x1000)
+ {
+ p = (c << 4) | (i >> 12);
+ addr = (c - bank_s) << 16;
+ Map[p] = ROM + offset + map_mirror(size, addr);
+ BlockIsROM[p] = true;
+ BlockIsRAM[p] = false;
+ }
+ }
+}
+
+void CMemory::map_space (uint32_t bank_s, uint32_t bank_e, uint32_t addr_s, uint32_t addr_e, uint8_t *data)
+{
+ uint32_t c, i, p;
+
+ for (c = bank_s; c <= bank_e; c++)
+ {
+ for (i = addr_s; i <= addr_e; i += 0x1000)
+ {
+ p = (c << 4) | (i >> 12);
+ Map[p] = data;
+ BlockIsROM[p] = false;
+ BlockIsRAM[p] = true;
+ }
+ }
+}
+
+void CMemory::map_index (uint32_t bank_s, uint32_t bank_e, uint32_t addr_s, uint32_t addr_e, int index, int type)
+{
+ uint32_t c, i, p;
+ bool isROM, isRAM;
+
+ isROM = ((type == MAP_TYPE_I_O) || (type == MAP_TYPE_RAM)) ? false : true;
+ isRAM = ((type == MAP_TYPE_I_O) || (type == MAP_TYPE_ROM)) ? false : true;
+
+ for (c = bank_s; c <= bank_e; c++)
+ {
+ for (i = addr_s; i <= addr_e; i += 0x1000)
+ {
+ p = (c << 4) | (i >> 12);
+ Map[p] = (uint8_t *) index;
+ BlockIsROM[p] = isROM;
+ BlockIsRAM[p] = isRAM;
+ }
+ }
+}
+
+void CMemory::map_System()
+{
+ // will be overwritten
+ map_space(0x00, 0x3f, 0x0000, 0x1fff, RAM);
+ map_index(0x00, 0x3f, 0x2000, 0x3fff, MAP_PPU, MAP_TYPE_I_O);
+ map_index(0x00, 0x3f, 0x4000, 0x5fff, MAP_CPU, MAP_TYPE_I_O);
+ map_space(0x80, 0xbf, 0x0000, 0x1fff, RAM);
+ map_index(0x80, 0xbf, 0x2000, 0x3fff, MAP_PPU, MAP_TYPE_I_O);
+ map_index(0x80, 0xbf, 0x4000, 0x5fff, MAP_CPU, MAP_TYPE_I_O);
+}
+
+void CMemory::map_WRAM()
+{
+ // will overwrite others
+ map_space(0x7e, 0x7e, 0x0000, 0xffff, RAM);
+ map_space(0x7f, 0x7f, 0x0000, 0xffff, RAM + 0x10000);
+}
+
+void CMemory::map_LoROMSRAM()
+{
+ map_index(0x70, 0x7f, 0x0000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
+ map_index(0xf0, 0xff, 0x0000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
+}
+
+void CMemory::map_HiROMSRAM()
+{
+ map_index(0x20, 0x3f, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM);
+ map_index(0xa0, 0xbf, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM);
+}
+
+/*void CMemory::map_DSP()
+{
+ switch (DSP0.maptype)
+ {
+ case M_DSP1_LOROM_S:
+ map_index(0x20, 0x3f, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
+ map_index(0xa0, 0xbf, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
+ break;
+
+ case M_DSP1_LOROM_L:
+ map_index(0x60, 0x6f, 0x0000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
+ map_index(0xe0, 0xef, 0x0000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
+ break;
+
+ case M_DSP1_HIROM:
+ map_index(0x00, 0x1f, 0x6000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
+ map_index(0x80, 0x9f, 0x6000, 0x7fff, MAP_DSP, MAP_TYPE_I_O);
+ break;
+
+ case M_DSP2_LOROM:
+ map_index(0x20, 0x3f, 0x6000, 0x6fff, MAP_DSP, MAP_TYPE_I_O);
+ map_index(0x20, 0x3f, 0x8000, 0xbfff, MAP_DSP, MAP_TYPE_I_O);
+ map_index(0xa0, 0xbf, 0x6000, 0x6fff, MAP_DSP, MAP_TYPE_I_O);
+ map_index(0xa0, 0xbf, 0x8000, 0xbfff, MAP_DSP, MAP_TYPE_I_O);
+ break;
+
+ case M_DSP3_LOROM:
+ map_index(0x20, 0x3f, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
+ map_index(0xa0, 0xbf, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
+ break;
+
+ case M_DSP4_LOROM:
+ map_index(0x30, 0x3f, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
+ map_index(0xb0, 0xbf, 0x8000, 0xffff, MAP_DSP, MAP_TYPE_I_O);
+ break;
+ }
+}*/
+
+/*void CMemory::map_C4()
+{
+ map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_C4, MAP_TYPE_I_O);
+ map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_C4, MAP_TYPE_I_O);
+}*/
+
+/*void CMemory::map_OBC1()
+{
+ map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_OBC_RAM, MAP_TYPE_I_O);
+ map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_OBC_RAM, MAP_TYPE_I_O);
+}*/
+
+/*void CMemory::map_SetaRISC()
+{
+ map_index(0x00, 0x3f, 0x3000, 0x3fff, MAP_SETA_RISC, MAP_TYPE_I_O);
+ map_index(0x80, 0xbf, 0x3000, 0x3fff, MAP_SETA_RISC, MAP_TYPE_I_O);
+}*/
+
+/*void CMemory::map_SetaDSP()
+{
+ // where does the SETA chip access, anyway?
+ // please confirm this?
+ map_index(0x68, 0x6f, 0x0000, 0x7fff, MAP_SETA_DSP, MAP_TYPE_RAM);
+ // and this!
+ map_index(0x60, 0x67, 0x0000, 0x3fff, MAP_SETA_DSP, MAP_TYPE_I_O);
+
+ // ST-0010:
+ // map_index(0x68, 0x6f, 0x0000, 0x0fff, MAP_SETA_DSP, ?);
+}*/
+
+void CMemory::map_WriteProtectROM()
+{
+ memmove((void *) WriteMap, (void *) Map, sizeof(Map));
+
+ for (int c = 0; c < 0x1000; c++)
+ {
+ if (BlockIsROM[c])
+ WriteMap[c] = (uint8_t *) MAP_NONE;
+ }
+}
+
+void CMemory::Map_Initialize()
+{
+ for (int c = 0; c < 0x1000; c++)
+ {
+ Map[c] = (uint8_t *) MAP_NONE;
+ WriteMap[c] = (uint8_t *) MAP_NONE;
+ BlockIsROM[c] = false;
+ BlockIsRAM[c] = false;
+ }
+}
+
+void CMemory::Map_LoROMMap()
+{
+ printf("Map_LoROMMap\n");
+ map_System();
+
+ map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize);
+ map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize);
+
+ /*if (Settings.DSP)
+ map_DSP();
+ else
+ if (Settings.C4)
+ map_C4();
+ else
+ if (Settings.OBC1)
+ map_OBC1();
+ else
+ if (Settings.SETA == ST_018)
+ map_SetaRISC();*/
+
+ map_LoROMSRAM();
+ map_WRAM();
+
+ map_WriteProtectROM();
+}
+
+void CMemory::Map_NoMAD1LoROMMap()
+{
+ printf("Map_NoMAD1LoROMMap\n");
+ map_System();
+
+ map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize);
+ map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize);
+
+ map_index(0x70, 0x7f, 0x0000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
+ map_index(0xf0, 0xff, 0x0000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
+
+ map_WRAM();
+
+ map_WriteProtectROM();
+}
+
+void CMemory::Map_JumboLoROMMap()
+{
+ // XXX: Which game uses this?
+ printf("Map_JumboLoROMMap\n");
+ map_System();
+
+ map_lorom_offset(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize - 0x400000, 0x400000);
+ map_lorom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize - 0x400000, 0x400000);
+ map_lorom_offset(0x80, 0xbf, 0x8000, 0xffff, 0x400000, 0);
+ map_lorom_offset(0xc0, 0xff, 0x0000, 0xffff, 0x400000, 0x200000);
+
+ map_LoROMSRAM();
+ map_WRAM();
+
+ map_WriteProtectROM();
+}
+
+void CMemory::Map_ROM24MBSLoROMMap()
+{
+ // PCB: BSC-1A5M-01, BSC-1A7M-10
+ printf("Map_ROM24MBSLoROMMap\n");
+ map_System();
+
+ map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x100000, 0);
+ map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, 0x100000, 0x100000);
+ map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x100000, 0x200000);
+ map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, 0x100000, 0x100000);
+
+ map_LoROMSRAM();
+ map_WRAM();
+
+ map_WriteProtectROM();
+}
+
+void CMemory::Map_SRAM512KLoROMMap()
+{
+ printf("Map_SRAM512KLoROMMap\n");
+ map_System();
+
+ map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize);
+ map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize);
+
+ map_space(0x70, 0x70, 0x0000, 0xffff, SRAM);
+ map_space(0x71, 0x71, 0x0000, 0xffff, SRAM + 0x8000);
+ map_space(0x72, 0x72, 0x0000, 0xffff, SRAM + 0x10000);
+ map_space(0x73, 0x73, 0x0000, 0xffff, SRAM + 0x18000);
+
+ map_WRAM();
+
+ map_WriteProtectROM();
+}
+
+/*void CMemory::Map_SufamiTurboLoROMMap()
+{
+ printf("Map_SufamiTurboLoROMMap\n");
+ map_System();
+
+ map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x40000, 0);
+ map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
+ map_lorom_offset(0x40, 0x5f, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
+ map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x40000, 0);
+ map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
+ map_lorom_offset(0xc0, 0xdf, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
+
+ if (Multi.sramSizeA)
+ {
+ map_index(0x60, 0x63, 0x8000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
+ map_index(0xe0, 0xe3, 0x8000, 0xffff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
+ }
+
+ if (Multi.sramSizeB)
+ {
+ map_index(0x70, 0x73, 0x8000, 0xffff, MAP_LOROM_SRAM_B, MAP_TYPE_RAM);
+ map_index(0xf0, 0xf3, 0x8000, 0xffff, MAP_LOROM_SRAM_B, MAP_TYPE_RAM);
+ }
+
+ map_WRAM();
+
+ map_WriteProtectROM();
+}*/
+
+/*void CMemory::Map_SufamiTurboPseudoLoROMMap()
+{
+ // for combined images
+ printf("Map_SufamiTurboPseudoLoROMMap\n");
+ map_System();
+
+ map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x40000, 0);
+ map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, 0x100000, 0x100000);
+ map_lorom_offset(0x40, 0x5f, 0x8000, 0xffff, 0x100000, 0x200000);
+ map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x40000, 0);
+ map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, 0x100000, 0x100000);
+ map_lorom_offset(0xc0, 0xdf, 0x8000, 0xffff, 0x100000, 0x200000);
+
+ // I don't care :P
+ map_space(0x60, 0x63, 0x8000, 0xffff, SRAM - 0x8000);
+ map_space(0xe0, 0xe3, 0x8000, 0xffff, SRAM - 0x8000);
+ map_space(0x70, 0x73, 0x8000, 0xffff, SRAM + 0x4000 - 0x8000);
+ map_space(0xf0, 0xf3, 0x8000, 0xffff, SRAM + 0x4000 - 0x8000);
+
+ map_WRAM();
+
+ map_WriteProtectROM();
+}*/
+
+/*void CMemory::Map_SuperFXLoROMMap()
+{
+ printf("Map_SuperFXLoROMMap\n");
+ map_System();
+
+ // Replicate the first 2Mb of the ROM at ROM + 2MB such that each 32K
+ // block is repeated twice in each 64K block.
+ for (int c = 0; c < 64; c++)
+ {
+ memmove(&ROM[0x200000 + c * 0x10000], &ROM[c * 0x8000], 0x8000);
+ memmove(&ROM[0x208000 + c * 0x10000], &ROM[c * 0x8000], 0x8000);
+ }
+
+ map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
+
+ map_hirom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize, 0);
+ map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize, 0);
+
+ map_space(0x00, 0x3f, 0x6000, 0x7fff, SRAM - 0x6000);
+ map_space(0x80, 0xbf, 0x6000, 0x7fff, SRAM - 0x6000);
+ map_space(0x70, 0x70, 0x0000, 0xffff, SRAM);
+ map_space(0x71, 0x71, 0x0000, 0xffff, SRAM + 0x10000);
+
+ map_WRAM();
+
+ map_WriteProtectROM();
+}*/
+
+/*void CMemory::Map_SetaDSPLoROMMap()
+{
+ printf("Map_SetaDSPLoROMMap\n");
+ map_System();
+
+ map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0x40, 0x7f, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0xc0, 0xff, 0x8000, 0xffff, CalculatedSize);
+
+ map_SetaDSP();
+
+ map_LoROMSRAM();
+ map_WRAM();
+
+ map_WriteProtectROM();
+}*/
+
+void CMemory::Map_SDD1LoROMMap()
+{
+ printf("Map_SDD1LoROMMap\n");
+ map_System();
+
+ map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
+
+ map_hirom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize, 0);
+ map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize, 0); // will be overwritten dynamically
+
+ map_index(0x70, 0x7f, 0x0000, 0x7fff, MAP_LOROM_SRAM, MAP_TYPE_RAM);
+
+ map_WRAM();
+
+ map_WriteProtectROM();
+}
+
+/*void CMemory::Map_SA1LoROMMap()
+{
+ printf("Map_SA1LoROMMap\n");
+ map_System();
+
+ map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
+ map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
+
+ map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize, 0);
+
+ map_space(0x00, 0x3f, 0x3000, 0x3fff, FillRAM);
+ map_space(0x80, 0xbf, 0x3000, 0x3fff, FillRAM);
+ map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O);
+ map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O);
+
+ for (int c = 0x40; c < 0x80; c++)
+ map_space(c, c, 0x0000, 0xffff, SRAM + (c & 1) * 0x10000);
+
+ map_WRAM();
+
+ map_WriteProtectROM();
+
+ // Now copy the map and correct it for the SA1 CPU.
+ memmove((void *) SA1.Map, (void *) Map, sizeof(Map));
+ memmove((void *) SA1.WriteMap, (void *) WriteMap, sizeof(WriteMap));
+
+ // SA-1 Banks 00->3f and 80->bf
+ for (int c = 0x000; c < 0x400; c += 0x10)
+ {
+ SA1.Map[c + 0] = SA1.Map[c + 0x800] = FillRAM + 0x3000;
+ SA1.Map[c + 1] = SA1.Map[c + 0x801] = (uint8_t *) MAP_NONE;
+ SA1.WriteMap[c + 0] = SA1.WriteMap[c + 0x800] = FillRAM + 0x3000;
+ SA1.WriteMap[c + 1] = SA1.WriteMap[c + 0x801] = (uint8_t *) MAP_NONE;
+ }
+
+ // SA-1 Banks 60->6f
+ for (int c = 0x600; c < 0x700; c++)
+ SA1.Map[c] = SA1.WriteMap[c] = (uint8_t *) MAP_BWRAM_BITMAP;
+
+ BWRAM = SRAM;
+}*/
+
+void CMemory::Map_HiROMMap()
+{
+ printf("Map_HiROMMap\n");
+ map_System();
+
+ map_hirom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
+ map_hirom(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize);
+ map_hirom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
+ map_hirom(0xc0, 0xff, 0x0000, 0xffff, CalculatedSize);
+
+ /*if (Settings.DSP)
+ map_DSP();*/
+
+ map_HiROMSRAM();
+ map_WRAM();
+
+ map_WriteProtectROM();
+}
+
+void CMemory::Map_ExtendedHiROMMap()
+{
+ printf("Map_ExtendedHiROMMap\n");
+ map_System();
+
+ map_hirom_offset(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize - 0x400000, 0x400000);
+ map_hirom_offset(0x40, 0x7f, 0x0000, 0xffff, CalculatedSize - 0x400000, 0x400000);
+ map_hirom_offset(0x80, 0xbf, 0x8000, 0xffff, 0x400000, 0);
+ map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, 0x400000, 0);
+
+ map_HiROMSRAM();
+ map_WRAM();
+
+ map_WriteProtectROM();
+}
+
+/*void CMemory::Map_SameGameHiROMMap()
+{
+ printf("Map_SameGameHiROMMap\n");
+ map_System();
+
+ map_hirom_offset(0x00, 0x1f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
+ map_hirom_offset(0x20, 0x3f, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
+ map_hirom_offset(0x40, 0x5f, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
+ map_hirom_offset(0x60, 0x7f, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
+ map_hirom_offset(0x80, 0x9f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
+ map_hirom_offset(0xa0, 0xbf, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
+ map_hirom_offset(0xc0, 0xdf, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
+ map_hirom_offset(0xe0, 0xff, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
+
+ map_HiROMSRAM();
+ map_WRAM();
+
+ map_WriteProtectROM();
+}*/
+
+/*void CMemory::Map_SPC7110HiROMMap()
+{
+ printf("Map_SPC7110HiROMMap\n");
+ map_System();
+
+ map_index(0x00, 0x00, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM);
+ map_hirom(0x00, 0x0f, 0x8000, 0xffff, CalculatedSize);
+ map_index(0x30, 0x30, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM);
+ map_index(0x50, 0x50, 0x0000, 0xffff, MAP_SPC7110_DRAM, MAP_TYPE_ROM);
+ map_hirom(0x80, 0x8f, 0x8000, 0xffff, CalculatedSize);
+ map_hirom_offset(0xc0, 0xcf, 0x0000, 0xffff, CalculatedSize, 0);
+ map_index(0xd0, 0xff, 0x0000, 0xffff, MAP_SPC7110_ROM, MAP_TYPE_ROM);
+
+ map_WRAM();
+
+ map_WriteProtectROM();
+}*/
+
+// checksum
+
+uint16_t CMemory::checksum_calc_sum (uint8_t *data, uint32_t length)
+{
+ uint16_t sum = 0;
+
+ for (uint32_t i = 0; i < length; i++)
+ sum += data[i];
+
+ return sum;
+}
+
+uint16_t CMemory::checksum_mirror_sum (uint8_t *start, uint32_t &length, uint32_t mask)
+{
+ // from NSRT
+ while (!(length & mask))
+ mask >>= 1;
+
+ uint16_t part1 = checksum_calc_sum(start, mask);
+ uint16_t part2 = 0;
+
+ uint32_t next_length = length - mask;
+ if (next_length)
+ {
+ part2 = checksum_mirror_sum(start + mask, next_length, mask >> 1);
+
+ while (next_length < mask)
+ {
+ next_length += next_length;
+ part2 += part2;
+ }
+
+ length = mask + mask;
+ }
+
+ return part1 + part2;
+}
+
+void CMemory::Checksum_Calculate()
+{
+ // from NSRT
+ uint16_t sum = 0;
+
+ if (Settings.BS && !Settings.BSXItself)
+ sum = checksum_calc_sum(ROM, CalculatedSize) - checksum_calc_sum(ROM + (HiROM ? 0xffb0 : 0x7fb0), 48);
+ else
+ if (Settings.SPC7110)
+ {
+ sum = checksum_calc_sum(ROM, CalculatedSize);
+ if (CalculatedSize == 0x300000)
+ sum += sum;
+ }
+ else
+ {
+ if (CalculatedSize & 0x7fff)
+ sum = checksum_calc_sum(ROM, CalculatedSize);
+ else
+ {
+ uint32_t length = CalculatedSize;
+ sum = checksum_mirror_sum(ROM, length);
+ }
+ }
+
+ CalculatedChecksum = sum;
+}
+
+// information
+
+/*const char * CMemory::MapType()
+{
+ return HiROM ? ((ExtendedFormat != NOPE) ? "ExHiROM": "HiROM") : "LoROM";
+}*/
+
+/*const char * CMemory::StaticRAMSize()
+{
+ static char str[20];
+
+ if (SRAMSize > 16)
+ strcpy(str, "Corrupt");
+ else
+ sprintf(str, "%dKbits", 8 * (SRAMMask + 1) / 1024);
+
+ return str;
+}*/
+
+/*const char * CMemory::Size()
+{
+ static char str[20];
+
+ if (Multi.cartType == 4)
+ strcpy(str, "N/A");
+ else
+ if (ROMSize < 7 || ROMSize - 7 > 23)
+ strcpy(str, "Corrupt");
+ else
+ sprintf(str, "%dMbits", 1 << (ROMSize - 7));
+
+ return str;
+}*/
+
+/*const char * CMemory::Revision()
+{
+ static char str[20];
+
+ sprintf(str, "1.%d", HiROM ? ((ExtendedFormat != NOPE) ? ROM[0x40ffdb] : ROM[0xffdb]) : ROM[0x7fdb]);
+
+ return str;
+}*/
+
+/*const char * CMemory::KartContents()
+{
+ static char str[64];
+ static const char *contents[3] = { "ROM", "ROM+RAM", "ROM+RAM+BAT" };
+
+ char chip[16];
+
+ if (ROMType == 0 && !Settings.BS)
+ return "ROM";
+
+ if (Settings.BS)
+ strcpy(chip, "+BS");
+ else
+ if (Settings.SuperFX)
+ strcpy(chip, "+Super FX");
+ else
+ if (Settings.SDD1)
+ strcpy(chip, "+S-DD1");
+ else
+ if (Settings.OBC1)
+ strcpy(chip, "+OBC1");
+ else
+ if (Settings.SA1)
+ strcpy(chip, "+SA-1");
+ else
+ if (Settings.SPC7110RTC)
+ strcpy(chip, "+SPC7110+RTC");
+ else
+ if (Settings.SPC7110)
+ strcpy(chip, "+SPC7110");
+ else
+ if (Settings.SRTC)
+ strcpy(chip, "+S-RTC");
+ else
+ if (Settings.C4)
+ strcpy(chip, "+C4");
+ else
+ if (Settings.SETA == ST_010)
+ strcpy(chip, "+ST-010");
+ else
+ if (Settings.SETA == ST_011)
+ strcpy(chip, "+ST-011");
+ else
+ if (Settings.SETA == ST_018)
+ strcpy(chip, "+ST-018");
+ else
+ if (Settings.DSP)
+ sprintf(chip, "+DSP-%d", Settings.DSP);
+ else
+ strcpy(chip, "");
+
+ sprintf(str, "%s%s", contents[(ROMType & 0xf) % 3], chip);
+
+ return str;
+}*/
+
+/*const char * CMemory::Country()
+{
+ switch (ROMRegion)
+ {
+ case 0: return "Japan";
+ case 1: return "USA and Canada";
+ case 2: return "Oceania, Europe and Asia";
+ case 3: return "Sweden";
+ case 4: return "Finland";
+ case 5: return "Denmark";
+ case 6: return "France";
+ case 7: return "Holland";
+ case 8: return "Spain";
+ case 9: return "Germany, Austria and Switzerland";
+ case 10: return "Italy";
+ case 11: return "Hong Kong and China";
+ case 12: return "Indonesia";
+ case 13: return "South Korea";
+ default: return "Unknown";
+ }
+}*/
+
+/*const char * CMemory::PublishingCompany()
+{
+ if (CompanyId >= (int) (sizeof(nintendo_licensees) / sizeof(nintendo_licensees[0])) || CompanyId < 0)
+ return "Unknown";
+
+ if (nintendo_licensees[CompanyId] == NULL)
+ return "Unknown";
+
+ return nintendo_licensees[CompanyId];
+}*/
+
+/*void CMemory::MakeRomInfoText (char *romtext)
+{
+ char temp[256];
+
+ romtext[0] = 0;
+
+ sprintf(temp, " Cart Name: %s", ROMName);
+ strcat(romtext, temp);
+ sprintf(temp, "\n Game Code: %s", ROMId);
+ strcat(romtext, temp);
+ sprintf(temp, "\n Contents: %s", KartContents());
+ strcat(romtext, temp);
+ sprintf(temp, "\n Map: %s", MapType());
+ strcat(romtext, temp);
+ sprintf(temp, "\n Speed: 0x%02X (%s)", ROMSpeed, (ROMSpeed & 0x10) ? "FastROM" : "SlowROM");
+ strcat(romtext, temp);
+ sprintf(temp, "\n Type: 0x%02X", ROMType);
+ strcat(romtext, temp);
+ sprintf(temp, "\n Size (calculated): %dMbits", CalculatedSize / 0x20000);
+ strcat(romtext, temp);
+ sprintf(temp, "\n Size (header): %s", Size());
+ strcat(romtext, temp);
+ sprintf(temp, "\n SRAM size: %s", StaticRAMSize());
+ strcat(romtext, temp);
+ sprintf(temp, "\nChecksum (calculated): 0x%04X", CalculatedChecksum);
+ strcat(romtext, temp);
+ sprintf(temp, "\n Checksum (header): 0x%04X", ROMChecksum);
+ strcat(romtext, temp);
+ sprintf(temp, "\n Complement (header): 0x%04X", ROMComplementChecksum);
+ strcat(romtext, temp);
+ sprintf(temp, "\n Video Output: %s", (ROMRegion > 12 || ROMRegion < 2) ? "NTSC 60Hz" : "PAL 50Hz");
+ strcat(romtext, temp);
+ sprintf(temp, "\n Revision: %s", Revision());
+ strcat(romtext, temp);
+ sprintf(temp, "\n Licensee: %s", PublishingCompany());
+ strcat(romtext, temp);
+ sprintf(temp, "\n Region: %s", Country());
+ strcat(romtext, temp);
+ sprintf(temp, "\n CRC32: 0x%08X", ROMCRC32);
+ strcat(romtext, temp);
+}*/
+
+// hack
+
+bool CMemory::match_na (const char *str)
+{
+ return strcmp(ROMName, str) == 0;
+}
+
+bool CMemory::match_nn (const char *str)
+{
+ return strncmp(ROMName, str, strlen(str)) == 0;
+}
+
+/*bool CMemory::match_nc (const char *str)
+{
+ return strncasecmp(ROMName, str, strlen(str)) == 0;
+}*/
+
+bool CMemory::match_id (const char *str)
+{
+ return strncmp(ROMId, str, strlen(str)) == 0;
+}
+
+void CMemory::ApplyROMFixes()
+{
+ Settings.BlockInvalidVRAMAccess = Settings.BlockInvalidVRAMAccessMaster;
+
+ //// Warnings
+
+ // Reject strange hacked games
+ /*if ((ROMCRC32 == 0x6810aa95) ||
+ (ROMCRC32 == 0x340f23e5) ||
+ (ROMCRC32 == 0x77fd806a) ||
+ (match_nn("HIGHWAY BATTLE 2")) ||
+ (match_na("FX SKIING NINTENDO 96") && (ROM[0x7fda] == 0)) ||
+ (match_nn("HONKAKUHA IGO GOSEI") && (ROM[0xffd5] != 0x31)))
+ {
+ Settings.DisplayColor = BUILD_PIXEL(31, 0, 0);
+ SET_UI_COLOR(255, 0, 0);
+ }*/
+
+ //// APU timing hacks :(
+
+ Timings.APUSpeedup = 0;
+ Timings.APUAllowTimeOverflow = false;
+
+ if (!Settings.DisableGameSpecificHacks)
+ {
+ if (match_id("AVCJ")) // Rendering Ranger R2
+ Timings.APUSpeedup = 4;
+
+ if (match_na("GAIA GENSOUKI 1 JPN") || // Gaia Gensouki
+ match_id("JG ") || // Illusion of Gaia
+ match_id("CQ ") || // Stunt Race FX
+ match_na("SOULBLADER - 1") || // Soul Blader
+ match_na("SOULBLAZER - 1 USA") || // Soul Blazer
+ match_na("SLAP STICK 1 JPN") || // Slap Stick
+ match_id("E9 ") || // Robotrek
+ match_nn("ACTRAISER") || // Actraiser
+ match_nn("ActRaiser-2") || // Actraiser 2
+ match_id("AQT") || // Tenchi Souzou, Terranigma
+ match_id("ATV") || // Tales of Phantasia
+ match_id("ARF") || // Star Ocean
+ match_id("APR") || // Zen-Nippon Pro Wrestling 2 - 3-4 Budoukan
+ match_id("A4B") || // Super Bomberman 4
+ match_id("Y7 ") || // U.F.O. Kamen Yakisoban - Present Ban
+ match_id("Y9 ") || // U.F.O. Kamen Yakisoban - Shihan Ban
+ match_id("APB") || // Super Bomberman - Panic Bomber W
+ match_na("DARK KINGDOM") || // Dark Kingdom
+ match_na("ZAN3 SFC") || // Zan III Spirits
+ match_na("HIOUDEN") || // Hiouden - Mamono-tachi Tono Chikai
+ match_na("\xC3\xDD\xBC\xC9\xB3\xC0") || // Tenshi no Uta
+ match_na("FORTUNE QUEST") || // Fortune Quest - Dice wo Korogase
+ match_na("FISHING TO BASSING") || // Shimono Masaki no Fishing To Bassing
+ match_na("OHMONO BLACKBASS") || // Oomono Black Bass Fishing - Jinzouko Hen
+ match_na("MASTERS") || // Harukanaru Augusta 2 - Masters
+ match_na("SFC \xB6\xD2\xDD\xD7\xB2\xC0\xDE\xB0") || // Kamen Rider
+ match_na("ZENKI TENCHIMEIDOU") || // Kishin Douji Zenki - Tenchi Meidou
+ match_nn("TokyoDome '95Battle 7") || // Shin Nippon Pro Wrestling Kounin '95 - Tokyo Dome Battle 7
+ match_nn("SWORD WORLD SFC") || // Sword World SFC/2
+ match_nn("LETs PACHINKO(") || // BS Lets Pachinko Nante Gindama 1/2/3/4
+ match_nn("THE FISHING MASTER") || // Mark Davis The Fishing Master
+ match_nn("Parlor") || // Parlor mini/2/3/4/5/6/7, Parlor Parlor!/2/3/4/5
+ match_na("HEIWA Parlor!Mini8") || // Parlor mini 8
+ match_nn("SANKYO Fever! \xCC\xA8\xB0\xCA\xDE\xB0!")) // SANKYO Fever! Fever!
+ Timings.APUSpeedup = 1;
+
+ if (match_na ("EARTHWORM JIM 2") || // Earthworm Jim 2
+ match_na ("NBA Hangtime") || // NBA Hang Time
+ match_na ("MSPACMAN") || // Ms Pacman
+ match_na ("THE MASK") || // The Mask
+ match_na ("PRIMAL RAGE") || // Primal Rage
+ match_na ("DOOM TROOPERS")) // Doom Troopers
+ Timings.APUAllowTimeOverflow = true;
+ }
+
+ 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;
+
+ if (!Settings.DisableGameSpecificHacks)
+ {
+ // The delay to sync CPU and DMA which Snes9x cannot emulate.
+ // Some games need really severe delay timing...
+ if (match_na("BATTLE GRANDPRIX")) // Battle Grandprix
+ {
+ Timings.DMACPUSync = 20;
+ printf("DMA sync: %d\n", Timings.DMACPUSync);
+ }
+ }
+
+ if (!Settings.DisableGameSpecificHacks)
+ {
+ // 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 (match_na("Aero the AcroBat 2"))
+ {
+ Timings.IRQPendCount = 2;
+ printf("IRQ count hack: %d\n", Timings.IRQPendCount);
+ }
+ }
+
+ if (!Settings.DisableGameSpecificHacks)
+ {
+ // XXX: What's happening?
+ if (match_na("X-MEN")) // Spider-Man and the X-Men
+ {
+ Settings.BlockInvalidVRAMAccess = false;
+ printf("Invalid VRAM access hack\n");
+ }
+ }
+
+ //// SRAM initial value
+
+ if (!Settings.DisableGameSpecificHacks)
+ {
+ if (match_na("HITOMI3"))
+ {
+ SRAMSize = 1;
+ SRAMMask = ((1 << (SRAMSize + 3)) * 128) - 1;
+ }
+
+ // SRAM value fixes
+ if (match_na("SUPER DRIFT OUT") || // Super Drift Out
+ match_na("SATAN IS OUR FATHER!") ||
+ match_na("goemon 4")) // Ganbare Goemon Kirakira Douchuu
+ SNESGameFixes.SRAMInitialValue = 0x00;
+
+ // Additional game fixes by sanmaiwashi ...
+ // XXX: unnecessary?
+ if (match_na("SFX \xC5\xB2\xC4\xB6\xDE\xDD\xC0\xDE\xD1\xD3\xC9\xB6\xDE\xC0\xD8 1")) // SD Gundam Gaiden - Knight Gundam Monogatari
+ SNESGameFixes.SRAMInitialValue = 0x6b;
+
+ // others: BS and ST-01x games are 0x00.
+ }
+
+ //// OAM hacks :(
+
+ if (!Settings.DisableGameSpecificHacks)
+ {
+ // OAM hacks because we don't fully understand the behavior of the SNES.
+ // Totally wacky display in 2P mode...
+ // seems to need a disproven behavior, so we're definitely overlooking some other bug?
+ if (match_nn("UNIRACERS")) // Uniracers
+ {
+ SNESGameFixes.Uniracers = true;
+ printf("Applied Uniracers hack.\n");
+ }
+ }
+}
+
+// UPS % IPS
+
+/*static uint32_t ReadUPSPointer (const uint8_t *data, unsigned &addr, unsigned size)
+{
+ uint32_t offset = 0, shift = 1;
+ while(addr < size) {
+ uint8_t x = data[addr++];
+ offset += (x & 0x7f) * shift;
+ if(x & 0x80) break;
+ shift <<= 7;
+ offset += shift;
+ }
+ return offset;
+}
+
+//NOTE: UPS patches are *never* created against a headered ROM!
+//this is per the UPS file specification. however, do note that it is
+//technically possible for a non-compliant patcher to ignore this requirement.
+//therefore, it is *imperative* that no emulator support such patches.
+//thusly, we ignore the "long offset" parameter below. failure to do so would
+//completely invalidate the purpose of UPS; which is to avoid header vs
+//no-header patching errors that result in IPS patches having a 50/50 chance of
+//being applied correctly.
+
+static bool ReadUPSPatch (Reader *r, long, int32_t &rom_size)
+{
+ //Reader lacks size() and rewind(), so we need to read in the file to get its size
+ uint8_t *data = new uint8_t[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ...
+ uint32_t size = 0;
+ while(true) {
+ int value = r->get_char();
+ if(value == EOF) break;
+ data[size++] = value;
+ if(size >= 8 * 1024 * 1024) {
+ //prevent buffer overflow: SNES-made UPS patches should never be this big anyway ...
+ delete[] data;
+ return false;
+ }
+ }
+
+ //4-byte header + 1-byte input size + 1-byte output size + 4-byte patch CRC32 + 4-byte unpatched CRC32 + 4-byte patched CRC32
+ if(size < 18) { delete[] data; return false; } //patch is too small
+
+ uint32_t addr = 0;
+ if(data[addr++] != 'U') { delete[] data; return false; } //patch has an invalid header
+ if(data[addr++] != 'P') { delete[] data; return false; } //...
+ if(data[addr++] != 'S') { delete[] data; return false; } //...
+ if(data[addr++] != '1') { delete[] data; return false; } //...
+
+ uint32_t patch_crc32 = caCRC32(data, size - 4); //don't include patch CRC32 itself in CRC32 calculation
+ uint32_t rom_crc32 = caCRC32(Memory.ROM, rom_size);
+ uint32_t px_crc32 = (data[size - 12] << 0) + (data[size - 11] << 8) + (data[size - 10] << 16) + (data[size - 9] << 24);
+ uint32_t py_crc32 = (data[size - 8] << 0) + (data[size - 7] << 8) + (data[size - 6] << 16) + (data[size - 5] << 24);
+ uint32_t pp_crc32 = (data[size - 4] << 0) + (data[size - 3] << 8) + (data[size - 2] << 16) + (data[size - 1] << 24);
+ if(patch_crc32 != pp_crc32) { delete[] data; return false; } //patch is corrupted
+ if((rom_crc32 != px_crc32) && (rom_crc32 != py_crc32)) { delete[] data; return false; } //patch is for a different ROM
+
+ uint32_t px_size = ReadUPSPointer(data, addr, size);
+ uint32_t py_size = ReadUPSPointer(data, addr, size);
+ uint32_t out_size = ((uint32_t) rom_size == px_size) ? py_size : px_size;
+ if(out_size > CMemory::MAX_ROM_SIZE) { delete[] data; return false; } //applying this patch will overflow Memory.ROM buffer
+
+ //fill expanded area with 0x00s; so that XORing works as expected below.
+ //note that this is needed (and works) whether output ROM is larger or smaller than pre-patched ROM
+ for(unsigned i = min((uint32_t) rom_size, out_size); i < max((uint32_t) rom_size, out_size); i++) {
+ Memory.ROM[i] = 0x00;
+ }
+
+ uint32_t relative = 0;
+ while(addr < size - 12) {
+ relative += ReadUPSPointer(data, addr, size);
+ while(addr < size - 12) {
+ uint8_t x = data[addr++];
+ Memory.ROM[relative++] ^= x;
+ if(!x) break;
+ }
+ }
+
+ rom_size = out_size;
+ delete[] data;
+
+ uint32_t out_crc32 = caCRC32(Memory.ROM, rom_size);
+ if(((rom_crc32 == px_crc32) && (out_crc32 == py_crc32))
+ || ((rom_crc32 == py_crc32) && (out_crc32 == px_crc32))
+ ) {
+ return true;
+ } else {
+ //technically, reaching here means that patching has failed.
+ //we should return false, but unfortunately Memory.ROM has already
+ //been modified above and cannot be undone. to do this properly, we
+ //would need to make a copy of Memory.ROM, apply the patch, and then
+ //copy that back to Memory.ROM.
+ //
+ //however, the only way for this case to happen is if the UPS patch file
+ //itself is corrupted, which should be detected by the patch CRC32 check
+ //above anyway. errors due to the wrong ROM or patch file being used are
+ //already caught above.
+ fprintf(stderr, "WARNING: UPS patching appears to have failed.\nGame may not be playable.\n");
+ return true;
+ }
+}
+
+static long ReadInt (Reader *r, unsigned nbytes)
+{
+ long v = 0;
+
+ while (nbytes--)
+ {
+ int c = r->get_char();
+ if (c == EOF)
+ return -1;
+ v = (v << 8) | (c & 0xFF);
+ }
+
+ return v;
+}
+
+static bool ReadIPSPatch (Reader *r, long offset, int32_t &rom_size)
+{
+ const int32_t IPS_EOF = 0x00454F46l;
+ int32_t ofs;
+ char fname[6];
+
+ fname[5] = 0;
+ for (int i = 0; i < 5; i++)
+ {
+ int c = r->get_char();
+ if (c == EOF)
+ return 0;
+ fname[i] = (char) c;
+ }
+
+ if (strncmp(fname, "PATCH", 5))
+ return 0;
+
+ for (;;)
+ {
+ long len, rlen;
+ int rchar;
+
+ ofs = ReadInt(r, 3);
+ if (ofs == -1)
+ return 0;
+
+ if (ofs == IPS_EOF)
+ break;
+
+ ofs -= offset;
+
+ len = ReadInt(r, 2);
+ if (len == -1)
+ return 0;
+
+ if (len)
+ {
+ if (ofs + len > CMemory::MAX_ROM_SIZE)
+ return 0;
+
+ while (len--)
+ {
+ rchar = r->get_char();
+ if (rchar == EOF)
+ return 0;
+ Memory.ROM[ofs++] = (uint8_t) rchar;
+ }
+
+ if (ofs > rom_size)
+ rom_size = ofs;
+ }
+ else
+ {
+ rlen = ReadInt(r, 2);
+ if (rlen == -1)
+ return 0;
+
+ rchar = r->get_char();
+ if (rchar == EOF)
+ return 0;
+
+ if (ofs + rlen > CMemory::MAX_ROM_SIZE)
+ return 0;
+
+ while (rlen--)
+ Memory.ROM[ofs++] = (uint8_t) rchar;
+
+ if (ofs > rom_size)
+ rom_size = ofs;
+ }
+ }
+
+ ofs = ReadInt(r, 3);
+ if (ofs != -1 && ofs - offset < rom_size)
+ rom_size = ofs - offset;
+
+ return 1;
+}*/
+
+#ifdef UNZIP_SUPPORT
+static int unzFindExtension (unzFile &file, const char *ext, bool restart, bool print)
+{
+ unz_file_info info;
+ int port, l = strlen(ext);
+
+ if (restart)
+ port = unzGoToFirstFile(file);
+ else
+ port = unzGoToNextFile(file);
+
+ while (port == UNZ_OK)
+ {
+ int len;
+ char name[132];
+
+ unzGetCurrentFileInfo(file, &info, name, 128, NULL, 0, NULL, 0);
+ len = strlen(name);
+
+ if (len >= l + 1 && name[len - l - 1] == '.' && strcasecmp(name + len - l, ext) == 0 && unzOpenCurrentFile(file) == UNZ_OK)
+ {
+ if (print)
+ printf("Using IPS or UPS patch %s", name);
+
+ return port;
+ }
+
+ port = unzGoToNextFile(file);
+ }
+
+ return port;
+}
+#endif
+
+/*void CMemory::CheckForAnyPatch (const char *rom_filename, bool header, int32_t &rom_size)
+{
+ if (Settings.NoPatch)
+ return;
+
+ STREAM patch_file = NULL;
+ uint32_t i;
+ long offset = header ? 512 : 0;
+ int ret;
+ bool flag;
+ char dir[_MAX_DIR + 1], drive[_MAX_DRIVE + 1], name[_MAX_FNAME + 1], ext[_MAX_EXT + 1], ips[_MAX_EXT + 3], fname[PATH_MAX + 1];
+ const char *n;
+
+ // UPS
+
+ _splitpath(rom_filename, drive, dir, name, ext);
+ _makepath(fname, drive, dir, name, "ups");
+
+ if ((patch_file = OPEN_STREAM(fname, "rb")) != NULL)
+ {
+ printf("Using UPS patch %s", fname);
+
+ ret = ReadUPSPatch(new fReader(patch_file), 0, rom_size);
+ CLOSE_STREAM(patch_file);
+
+ if (ret)
+ {
+ printf("!\n");
+ return;
+ }
+ else
+ printf(" failed!\n");
+ }
+
+#ifdef UNZIP_SUPPORT
+ if (!strcasecmp(ext, "zip") || !strcasecmp(ext, ".zip"))
+ {
+ unzFile file = unzOpen(rom_filename);
+ if (file)
+ {
+ int port = unzFindExtension(file, "ups");
+ if (port == UNZ_OK)
+ {
+ printf(" in %s", rom_filename);
+
+ ret = ReadUPSPatch(new unzReader(file), offset, rom_size);
+ unzCloseCurrentFile(file);
+
+ if (ret)
+ printf("!\n");
+ else
+ printf(" failed!\n");
+ }
+ }
+ }
+#endif
+
+ n = S9xGetFilename(".ups", IPS_DIR);
+
+ if ((patch_file = OPEN_STREAM(n, "rb")) != NULL)
+ {
+ printf("Using UPS patch %s", n);
+
+ ret = ReadUPSPatch(new fReader(patch_file), 0, rom_size);
+ CLOSE_STREAM(patch_file);
+
+ if (ret)
+ {
+ printf("!\n");
+ return;
+ }
+ else
+ printf(" failed!\n");
+ }
+
+ // IPS
+
+ _splitpath(rom_filename, drive, dir, name, ext);
+ _makepath(fname, drive, dir, name, "ips");
+
+ if ((patch_file = OPEN_STREAM(fname, "rb")) != NULL)
+ {
+ printf("Using IPS patch %s", fname);
+
+ ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
+ CLOSE_STREAM(patch_file);
+
+ if (ret)
+ {
+ printf("!\n");
+ return;
+ }
+ else
+ printf(" failed!\n");
+ }
+
+ if (_MAX_EXT > 6)
+ {
+ i = 0;
+ flag = false;
+
+ do
+ {
+ snprintf(ips, 8, "%03d.ips", i);
+ _makepath(fname, drive, dir, name, ips);
+
+ if (!(patch_file = OPEN_STREAM(fname, "rb")))
+ break;
+
+ printf("Using IPS patch %s", fname);
+
+ ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
+ CLOSE_STREAM(patch_file);
+
+ if (ret)
+ {
+ printf("!\n");
+ flag = true;
+ }
+ else
+ {
+ printf(" failed!\n");
+ break;
+ }
+ } while (++i < 1000);
+
+ if (flag)
+ return;
+ }
+
+ if (_MAX_EXT > 3)
+ {
+ i = 0;
+ flag = false;
+
+ do
+ {
+ snprintf(ips, _MAX_EXT + 2, "ips%d", i);
+ if (strlen(ips) > _MAX_EXT)
+ break;
+ _makepath(fname, drive, dir, name, ips);
+
+ if (!(patch_file = OPEN_STREAM(fname, "rb")))
+ break;
+
+ printf("Using IPS patch %s", fname);
+
+ ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
+ CLOSE_STREAM(patch_file);
+
+ if (ret)
+ {
+ printf("!\n");
+ flag = true;
+ }
+ else
+ {
+ printf(" failed!\n");
+ break;
+ }
+ } while (++i != 0);
+
+ if (flag)
+ return;
+ }
+
+ if (_MAX_EXT > 2)
+ {
+ i = 0;
+ flag = false;
+
+ do
+ {
+ snprintf(ips, 4, "ip%d", i);
+ _makepath(fname, drive, dir, name, ips);
+
+ if (!(patch_file = OPEN_STREAM(fname, "rb")))
+ break;
+
+ printf("Using IPS patch %s", fname);
+
+ ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
+ CLOSE_STREAM(patch_file);
+
+ if (ret)
+ {
+ printf("!\n");
+ flag = true;
+ }
+ else
+ {
+ printf(" failed!\n");
+ break;
+ }
+ } while (++i < 10);
+
+ if (flag)
+ return;
+ }
+
+#ifdef UNZIP_SUPPORT
+ if (!strcasecmp(ext, "zip") || !strcasecmp(ext, ".zip"))
+ {
+ unzFile file = unzOpen(rom_filename);
+ if (file)
+ {
+ int port = unzFindExtension(file, "ips");
+ while (port == UNZ_OK)
+ {
+ printf(" in %s", rom_filename);
+
+ ret = ReadIPSPatch(new unzReader(file), offset, rom_size);
+ unzCloseCurrentFile(file);
+
+ if (ret)
+ {
+ printf("!\n");
+ flag = true;
+ }
+ else
+ printf(" failed!\n");
+
+ port = unzFindExtension(file, "ips", false);
+ }
+
+ if (!flag)
+ {
+ i = 0;
+
+ do
+ {
+ snprintf(ips, 8, "%03d.ips", i);
+
+ if (unzFindExtension(file, ips) != UNZ_OK)
+ break;
+
+ printf(" in %s", rom_filename);
+
+ ret = ReadIPSPatch(new unzReader(file), offset, rom_size);
+ unzCloseCurrentFile(file);
+
+ if (ret)
+ {
+ printf("!\n");
+ flag = true;
+ }
+ else
+ {
+ printf(" failed!\n");
+ break;
+ }
+
+ if (unzFindExtension(file, ips, false, false) == UNZ_OK)
+ printf("WARNING: Ignoring extra .%s files!\n", ips);
+ } while (++i < 1000);
+ }
+
+ if (!flag)
+ {
+ i = 0;
+
+ do
+ {
+ snprintf(ips, _MAX_EXT + 2, "ips%d", i);
+ if (strlen(ips) > _MAX_EXT)
+ break;
+
+ if (unzFindExtension(file, ips) != UNZ_OK)
+ break;
+
+ printf(" in %s", rom_filename);
+
+ ret = ReadIPSPatch(new unzReader(file), offset, rom_size);
+ unzCloseCurrentFile(file);
+
+ if (ret)
+ {
+ printf("!\n");
+ flag = true;
+ }
+ else
+ {
+ printf(" failed!\n");
+ break;
+ }
+
+ if (unzFindExtension(file, ips, false, false) == UNZ_OK)
+ printf("WARNING: Ignoring extra .%s files!\n", ips);
+ } while (++i != 0);
+ }
+
+ if (!flag)
+ {
+ i = 0;
+
+ do
+ {
+ snprintf(ips, 4, "ip%d", i);
+
+ if (unzFindExtension(file, ips) != UNZ_OK)
+ break;
+
+ printf(" in %s", rom_filename);
+
+ ret = ReadIPSPatch(new unzReader(file), offset, rom_size);
+ unzCloseCurrentFile(file);
+
+ if (ret)
+ {
+ printf("!\n");
+ flag = true;
+ }
+ else
+ {
+ printf(" failed!\n");
+ break;
+ }
+
+ if (unzFindExtension(file, ips, false, false) == UNZ_OK)
+ printf("WARNING: Ignoring extra .%s files!\n", ips);
+ } while (++i < 10);
+ }
+
+ assert(unzClose(file) == UNZ_OK);
+
+ if (flag)
+ return;
+ }
+ }
+#endif
+
+ n = S9xGetFilename(".ips", IPS_DIR);
+
+ if ((patch_file = OPEN_STREAM(n, "rb")) != NULL)
+ {
+ printf("Using IPS patch %s", n);
+
+ ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
+ CLOSE_STREAM(patch_file);
+
+ if (ret)
+ {
+ printf("!\n");
+ return;
+ }
+ else
+ printf(" failed!\n");
+ }
+
+ if (_MAX_EXT > 6)
+ {
+ i = 0;
+ flag = false;
+
+ do
+ {
+ snprintf(ips, 9, ".%03d.ips", i);
+ n = S9xGetFilename(ips, IPS_DIR);
+
+ if (!(patch_file = OPEN_STREAM(n, "rb")))
+ break;
+
+ printf("Using IPS patch %s", n);
+
+ ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
+ CLOSE_STREAM(patch_file);
+
+ if (ret)
+ {
+ printf("!\n");
+ flag = true;
+ }
+ else
+ {
+ printf(" failed!\n");
+ break;
+ }
+ } while (++i < 1000);
+
+ if (flag)
+ return;
+ }
+
+ if (_MAX_EXT > 3)
+ {
+ i = 0;
+ flag = false;
+
+ do
+ {
+ snprintf(ips, _MAX_EXT + 3, ".ips%d", i);
+ if (strlen(ips) > _MAX_EXT + 1)
+ break;
+ n = S9xGetFilename(ips, IPS_DIR);
+
+ if (!(patch_file = OPEN_STREAM(n, "rb")))
+ break;
+
+ printf("Using IPS patch %s", n);
+
+ ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
+ CLOSE_STREAM(patch_file);
+
+ if (ret)
+ {
+ printf("!\n");
+ flag = true;
+ }
+ else
+ {
+ printf(" failed!\n");
+ break;
+ }
+ } while (++i != 0);
+
+ if (flag)
+ return;
+ }
+
+ if (_MAX_EXT > 2)
+ {
+ i = 0;
+ flag = false;
+
+ do
+ {
+ snprintf(ips, 5, ".ip%d", i);
+ n = S9xGetFilename(ips, IPS_DIR);
+
+ if (!(patch_file = OPEN_STREAM(n, "rb")))
+ break;
+
+ printf("Using IPS patch %s", n);
+
+ ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size);
+ CLOSE_STREAM(patch_file);
+
+ if (ret)
+ {
+ printf("!\n");
+ flag = true;
+ }
+ else
+ {
+ printf(" failed!\n");
+ break;
+ }
+ } while (++i < 10);
+
+ if (flag)
+ return;
+ }
+}*/
+
--- /dev/null
+++ b/src/in_snsf/snes9x/memmap.h
@@ -1,1 +1,381 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _MEMMAP_H_
+#define _MEMMAP_H_
+
+#define MEMMAP_BLOCK_SIZE (0x1000)
+#define MEMMAP_NUM_BLOCKS (0x1000000 / MEMMAP_BLOCK_SIZE)
+#define MEMMAP_SHIFT (12)
+#define MEMMAP_MASK (MEMMAP_BLOCK_SIZE - 1)
+
+struct CMemory
+{
+ enum
+ { MAX_ROM_SIZE = 0x800000 };
+
+ enum file_formats
+ { FILE_ZIP, FILE_JMA, FILE_DEFAULT };
+
+ enum
+ { NOPE, YEAH, BIGFIRST, SMALLFIRST };
+
+ enum
+ { MAP_TYPE_I_O, MAP_TYPE_ROM, MAP_TYPE_RAM };
+
+ enum
+ {
+ MAP_CPU,
+ MAP_PPU,
+ MAP_LOROM_SRAM,
+ MAP_LOROM_SRAM_B,
+ MAP_HIROM_SRAM,
+ MAP_DSP,
+ MAP_SA1RAM,
+ MAP_BWRAM,
+ MAP_BWRAM_BITMAP,
+ MAP_BWRAM_BITMAP2,
+ MAP_SPC7110_ROM,
+ MAP_SPC7110_DRAM,
+ MAP_RONLY_SRAM,
+ MAP_C4,
+ MAP_OBC_RAM,
+ MAP_SETA_DSP,
+ MAP_SETA_RISC,
+ MAP_BSX,
+ MAP_NONE,
+ MAP_LAST
+ };
+
+ uint8_t NSRTHeader[32];
+ int32_t HeaderCount;
+
+ uint8_t *RAM;
+ uint8_t *ROM;
+ uint8_t *SRAM;
+ uint8_t *VRAM;
+ uint8_t *FillRAM;
+ uint8_t *BWRAM;
+ uint8_t *C4RAM;
+ uint8_t *OBC1RAM;
+ uint8_t *BSRAM;
+ uint8_t *BIOSROM;
+
+ uint8_t *Map[MEMMAP_NUM_BLOCKS];
+ uint8_t *WriteMap[MEMMAP_NUM_BLOCKS];
+ uint8_t BlockIsRAM[MEMMAP_NUM_BLOCKS];
+ uint8_t BlockIsROM[MEMMAP_NUM_BLOCKS];
+ uint8_t ExtendedFormat;
+
+ char ROMFilename[PATH_MAX + 1];
+ char ROMName[ROM_NAME_LEN];
+ char RawROMName[ROM_NAME_LEN];
+ char ROMId[5];
+ int32_t CompanyId;
+ uint8_t ROMRegion;
+ uint8_t ROMSpeed;
+ uint8_t ROMType;
+ uint8_t ROMSize;
+ uint32_t ROMChecksum;
+ uint32_t ROMComplementChecksum;
+ uint32_t ROMCRC32;
+ int32_t ROMFramesPerSecond;
+
+ bool HiROM;
+ bool LoROM;
+ uint8_t SRAMSize;
+ uint32_t SRAMMask;
+ uint32_t CalculatedSize;
+ uint32_t CalculatedChecksum;
+
+ // ports can assign this to perform some custom action upon loading a ROM (such as adjusting controls)
+ void (*PostRomInitFunc)();
+
+ bool Init();
+ void Deinit();
+
+ int ScoreHiROM (bool, int32_t romoff = 0);
+ int ScoreLoROM (bool, int32_t romoff = 0);
+ //uint32_t HeaderRemove (uint32_t, int32_t &, uint8_t *);
+ //uint32_t FileLoader (uint8_t *, const char *, int32_t);
+ /*bool LoadROM (const char *);
+ bool LoadMultiCart (const char *, const char *);
+ bool LoadSufamiTurbo (const char *, const char *);
+ bool LoadSameGame (const char *, const char *);
+ bool LoadSRAM (const char *);
+ bool SaveSRAM (const char *);
+ void ClearSRAM (bool onlyNonSavedSRAM = 0);
+ bool LoadSRTC();
+ bool SaveSRTC();*/
+ bool LoadROMSNSF(const unsigned char *, int32_t, const unsigned char *, int32_t);
+
+ char * Safe (const char *);
+ char * SafeANK (const char *);
+ void ParseSNESHeader (uint8_t *);
+ void InitROM();
+
+ uint32_t map_mirror (uint32_t, uint32_t);
+ void map_lorom (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+ void map_hirom (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+ void map_lorom_offset (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+ void map_hirom_offset (uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+ void map_space (uint32_t, uint32_t, uint32_t, uint32_t, uint8_t *);
+ void map_index (uint32_t, uint32_t, uint32_t, uint32_t, int, int);
+ void map_System();
+ void map_WRAM();
+ void map_LoROMSRAM();
+ void map_HiROMSRAM();
+ //void map_DSP();
+ //void map_C4();
+ //void map_OBC1();
+ //void map_SetaRISC();
+ //void map_SetaDSP();
+ void map_WriteProtectROM();
+ void Map_Initialize();
+ void Map_LoROMMap();
+ void Map_NoMAD1LoROMMap();
+ void Map_JumboLoROMMap();
+ void Map_ROM24MBSLoROMMap();
+ void Map_SRAM512KLoROMMap();
+ //void Map_SufamiTurboLoROMMap();
+ //void Map_SufamiTurboPseudoLoROMMap();
+ //void Map_SuperFXLoROMMap();
+ //void Map_SetaDSPLoROMMap();
+ void Map_SDD1LoROMMap();
+ //void Map_SA1LoROMMap();
+ void Map_HiROMMap();
+ void Map_ExtendedHiROMMap();
+ //void Map_SameGameHiROMMap();
+ //void Map_SPC7110HiROMMap();
+
+ uint16_t checksum_calc_sum (uint8_t *, uint32_t);
+ uint16_t checksum_mirror_sum (uint8_t *, uint32_t &, uint32_t mask = 0x800000);
+ void Checksum_Calculate();
+
+ bool match_na (const char *);
+ bool match_nn (const char *);
+ //bool match_nc (const char *);
+ bool match_id (const char *);
+ void ApplyROMFixes();
+ //void CheckForAnyPatch (const char *, bool, int32_t &);
+
+ //void MakeRomInfoText (char *);
+
+ //const char * MapType();
+ //const char * StaticRAMSize();
+ //const char * Size();
+ //const char * Revision();
+ //const char * KartContents();
+ //const char * Country();
+ //const char * PublishingCompany();
+};
+
+struct SMulti
+{
+ int cartType;
+ int32_t cartSizeA, cartSizeB;
+ int32_t sramSizeA, sramSizeB;
+ uint32_t sramMaskA, sramMaskB;
+ uint32_t cartOffsetA, cartOffsetB;
+ uint8_t *sramA, *sramB;
+ char fileNameA[PATH_MAX + 1], fileNameB[PATH_MAX + 1];
+};
+
+extern CMemory Memory;
+extern SMulti Multi;
+
+void S9xAutoSaveSRAM();
+bool LoadZip(const char *, int32_t *, int32_t *, uint8_t *);
+
+enum s9xwrap_t
+{
+ WRAP_NONE,
+ WRAP_BANK,
+ WRAP_PAGE
+};
+
+enum s9xwriteorder_t
+{
+ WRITE_01,
+ WRITE_10
+};
+
+#include "getset.h"
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/port.h
@@ -1,1 +1,371 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _PORT_H_
+#define _PORT_H_
+
+#include <cstdio>
+#include <cstdlib>
+#include <climits>
+//#include <memory.h>
+#include <ctime>
+#include <cstring>
+/*#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif*/
+#include <sys/types.h>
+
+#ifdef _WIN32
+//#define NOMINMAX
+//#include <windows.h>
+#include "windowsh_wrapper.h"
+#endif
+
+//#define GFX_MULTI_FORMAT
+
+/*#ifdef _WIN32
+//#define RIGHTSHIFT_IS_SAR
+#define RIGHTSHIFT_int8_IS_SAR
+#define RIGHTSHIFT_int16_IS_SAR
+#define RIGHTSHIFT_int32_IS_SAR
+//#define SNES_JOY_READ_CALLBACKS
+#endif*/
+
+#ifdef __MACOSX__
+#undef GFX_MULTI_FORMAT
+#define PIXEL_FORMAT RGB555
+#endif
+
+#include "pstdint.h"
+/*#ifndef snes9x_types_defined
+#define snes9x_types_defined
+typedef unsigned char bool8;
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+typedef intptr_t pint;
+typedef int8_t int8;
+typedef uint8_t uint8;
+typedef int16_t int16;
+typedef uint16_t uint16;
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+#else // HAVE_STDINT_H
+#ifdef _WIN32
+typedef intptr_t pint;
+#else // __WIN32__
+#ifdef PTR_NOT_INT
+typedef long pint;
+#else
+typedef int pint;
+#endif
+#endif // __WIN32__
+#ifdef _WIN32
+#ifdef __BORLANDC__
+#include <systypes.h>
+#else
+typedef signed char int8;
+typedef unsigned char uint8;
+typedef signed short int16;
+typedef unsigned short uint16;
+#ifndef WSAAP
+// winsock2.h typedefs int32 as well
+typedef signed int int32;
+#endif
+typedef unsigned int uint32;
+#endif
+typedef unsigned char uint8_t;
+typedef signed char int8_t;
+typedef signed __int64 int64;
+typedef unsigned __int64 uint64;
+typedef int socklen_t;
+#else // __WIN32__
+typedef signed char int8;
+typedef unsigned char uint8;
+typedef signed short int16;
+typedef unsigned short uint16;
+typedef signed int int32;
+typedef unsigned int uint32;
+#ifdef __GNUC__
+// long long is not part of ISO C++
+__extension__
+#endif
+typedef long long int64;
+typedef unsigned long long uint64;
+#endif // __WIN32__
+#endif // HAVE_STDINT_H
+#endif // snes9x_types_defined
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif*/
+
+/*#define START_EXTERN_C extern "C" {
+#define END_EXTERN_C }*/
+
+#ifndef _WIN32
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+#define _MAX_DRIVE 1
+#define _MAX_DIR PATH_MAX
+#define _MAX_FNAME PATH_MAX
+#define _MAX_EXT PATH_MAX
+#define _MAX_PATH PATH_MAX
+#else
+#ifndef PATH_MAX
+#define PATH_MAX _MAX_PATH
+#endif
+#endif
+
+#ifndef _WIN32
+#define ZeroMemory(a, b) memset((a), 0, (b))
+void _splitpath (const char *, char *, char *, char *, char *);
+void _makepath (char *, const char *, const char *, const char *, const char *);
+//#define S9xDisplayString DisplayStringFromBottom
+#else
+#define snprintf _snprintf
+#define strcasecmp stricmp
+#define strncasecmp _strnicmp
+//void WinDisplayStringFromBottom(const char *string, int linesFromBottom, int pixelsFromLeft, bool allowWrap);
+//#define S9xDisplayString WinDisplayStringFromBottom
+//void SetInfoDlgColor(unsigned char, unsigned char, unsigned char);
+//#define SET_UI_COLOR(r,g,b) SetInfoDlgColor(r,g,b)
+#endif
+
+/*#ifdef __DJGPP
+#define SLASH_STR "\\"
+#define SLASH_CHAR '\\'
+#else
+#define SLASH_STR "/"
+#define SLASH_CHAR '/'
+#endif*/
+
+/*#ifndef SIG_PF
+#define SIG_PF void (*) (int)
+#endif*/
+
+/*#ifdef __linux
+#define TITLE "Snes9x: Linux"
+#define SYS_CONFIG_FILE "/etc/snes9x/snes9x.conf"
+#endif
+
+#ifndef TITLE
+#define TITLE "Snes9x"
+#endif*/
+
+#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) || defined(__alpha__) || defined(__MIPSEL__) || defined(_M_IX86) || defined(_M_X64)
+#define LSB_FIRST
+#define FAST_LSB_WORD_ACCESS
+#else
+#define MSB_FIRST
+#endif
+
+#ifdef FAST_LSB_WORD_ACCESS
+//#define READ_WORD(s) (*(uint16_t *) (s))
+static inline uint16_t READ_WORD(uint8_t *s) { return *reinterpret_cast<uint16_t *>(s); }
+//#define READ_3WORD(s) (*(uint32_t *) (s) & 0x00ffffff)
+static inline uint32_t READ_3WORD(uint8_t *s) { return *reinterpret_cast<uint32_t *>(s) & 0x00FFFFFF; }
+//#define READ_DWORD(s) (*(uint32_t *) (s))
+//#define WRITE_WORD(s, d) *(uint16_t *) (s) = (d)
+static inline void WRITE_WORD(uint8_t *s, uint16_t d) { *reinterpret_cast<uint16_t *>(s) = d; }
+//#define WRITE_3WORD(s, d) *(uint16_t *) (s) = (uint16_t) (d), *((uint8_t *) (s) + 2) = (uint8_t) ((d) >> 16)
+//#define WRITE_DWORD(s, d) *(uint32_t *) (s) = (d)
+#else
+//#define READ_WORD(s) (*(uint8_t *) (s) | (*((uint8_t *) (s) + 1) << 8))
+static inline uint16_t READ_WORD(uint8_t *s) { return s | ((s + 1) << 8); }
+//#define READ_3WORD(s) (*(uint8_t *) (s) | (*((uint8_t *) (s) + 1) << 8) | (*((uint8_t *) (s) + 2) << 16))
+static inline uint32-t READ_3WORD(uint8_t *s) { return s | ((s + 1) << 8) | ((s + 2) << 16); }
+//#define READ_DWORD(s) (*(uint8_t *) (s) | (*((uint8_t *) (s) + 1) << 8) | (*((uint8_t *) (s) + 2) << 16) | (*((uint8_t *) (s) + 3) << 24))
+//#define WRITE_WORD(s, d) *(uint8_t *) (s) = (uint8_t) (d), *((uint8_t *) (s) + 1) = (uint8_t) ((d) >> 8)
+static inline void WRITE_WORD(uint8_t *s, uint16_t) { *s = static_cast<uint8_t>(d); *(s + 1) = static_cast<uint8_t>(d >> 8); }
+//#define WRITE_3WORD(s, d) *(uint8_t *) (s) = (uint8_t) (d), *((uint8_t *) (s) + 1) = (uint8_t) ((d) >> 8), *((uint8_t *) (s) + 2) = (uint8_t) ((d) >> 16)
+//#define WRITE_DWORD(s, d) *(uint8_t *) (s) = (uint8_t) (d), *((uint8_t *) (s) + 1) = (uint8_t) ((d) >> 8), *((uint8_t *) (s) + 2) = (uint8_t) ((d) >> 16), *((uint8_t *) (s) + 3) = (uint8_t) ((d) >> 24)
+#endif
+
+//#define SWAP_WORD(s) (s) = (((s) & 0xff) << 8) | (((s) & 0xff00) >> 8)
+//#define SWAP_DWORD(s) (s) = (((s) & 0xff) << 24) | (((s) & 0xff00) << 8) | (((s) & 0xff0000) >> 8) | (((s) & 0xff000000) >> 24)
+
+//#include "pixform.h"
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/ppu.cpp
@@ -1,1 +1,1987 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+#include "snes9x.h"
+#include "memmap.h"
+#include "dma.h"
+#include "apu/apu.h"
+//#include "fxemu.h"
+#include "sdd1.h"
+//#include "srtc.h"
+//#include "controls.h"
+//#include "movie.h"
+//#include "display.h"
+#ifdef NETPLAY_SUPPORT
+#include "netplay.h"
+#endif
+#ifdef DEBUGGER
+#include "debug.h"
+#include "missing.h"
+#endif
+
+extern uint8_t *HDMAMemPointers[8];
+
+static inline void S9xLatchCounters (bool force)
+{
+ if (force || (Memory.FillRAM[0x4213] & 0x80))
+ {
+ // Latch h and v counters, like the gun
+ #ifdef DEBUGGER
+ missing.h_v_latch = 1;
+ #endif
+
+ PPU.HVBeamCounterLatched = 1;
+ PPU.VBeamPosLatched = (uint16_t) CPU.V_Counter;
+
+ // From byuu:
+ // All dots are 4 cycles long, except dots 322 and 326. dots 322 and 326 are 6 cycles long.
+ // This holds true for all scanlines except scanline 240 on non-interlace odd frames.
+ // The reason for this is because this scanline is only 1360 cycles long,
+ // instead of 1364 like all other scanlines.
+ // This makes the effective range of hscan_pos 0-339 at all times.
+ int32_t hc = CPU.Cycles;
+
+ if (Timings.H_Max == Timings.H_Max_Master) // 1364
+ {
+ if (hc >= 1292)
+ hc -= (ONE_DOT_CYCLE / 2);
+ if (hc >= 1308)
+ hc -= (ONE_DOT_CYCLE / 2);
+ }
+
+ PPU.HBeamPosLatched = (uint16_t) (hc / ONE_DOT_CYCLE);
+
+ Memory.FillRAM[0x213f] |= 0x40;
+ }
+
+ if (CPU.V_Counter > PPU.GunVLatch || (CPU.V_Counter == PPU.GunVLatch && CPU.Cycles >= PPU.GunHLatch * ONE_DOT_CYCLE))
+ PPU.GunVLatch = 1000;
+}
+
+static inline void S9xTryGunLatch (bool force)
+{
+ if (CPU.V_Counter > PPU.GunVLatch || (CPU.V_Counter == PPU.GunVLatch && CPU.Cycles >= PPU.GunHLatch * ONE_DOT_CYCLE))
+ {
+ if (force || (Memory.FillRAM[0x4213] & 0x80))
+ {
+ #ifdef DEBUGGER
+ missing.h_v_latch = 1;
+ #endif
+
+ PPU.HVBeamCounterLatched = 1;
+ PPU.VBeamPosLatched = (uint16_t) PPU.GunVLatch;
+ PPU.HBeamPosLatched = (uint16_t) PPU.GunHLatch;
+
+ Memory.FillRAM[0x213f] |= 0x40;
+ }
+
+ PPU.GunVLatch = 1000;
+ }
+}
+
+void S9xUpdateHVTimerPosition()
+{
+ 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.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;
+ }
+
+#ifdef DEBUGGER
+ S9xTraceFormattedMessage("--- IRQ Timer set HTimer:%d Pos:%04d VTimer:%d Pos:%03d",
+ PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition);
+#endif
+}
+
+/*void S9xFixColourBrightness()
+{
+ IPPU.XB = mul_brightness[PPU.Brightness];
+
+ for (int i = 0; i < 256; i++)
+ {
+ IPPU.Red[i] = IPPU.XB[(PPU.CGDATA[i]) & 0x1f];
+ IPPU.Green[i] = IPPU.XB[(PPU.CGDATA[i] >> 5) & 0x1f];
+ IPPU.Blue[i] = IPPU.XB[(PPU.CGDATA[i] >> 10) & 0x1f];
+ IPPU.ScreenColors[i] = BUILD_PIXEL(IPPU.Red[i], IPPU.Green[i], IPPU.Blue[i]);
+ }
+}*/
+
+void S9xSetPPU (uint8_t Byte, uint16_t Address)
+{
+ // MAP_PPU: $2000-$3FFF
+
+ if (CPU.InDMAorHDMA)
+ {
+ if (CPU.CurrentDMAorHDMAChannel >= 0 && DMA[CPU.CurrentDMAorHDMAChannel].ReverseTransfer)
+ {
+ // S9xSetPPU() is called to write to DMA[].AAddress
+ if ((Address & 0xff00) == 0x2100)
+ {
+ // Cannot access to Address Bus B ($2100-$21ff) via (H)DMA
+ return;
+ }
+ else
+ {
+ // 0x2000-0x3FFF is connected to Address Bus A
+ // SA1, SuperFX and SRTC are mapped here
+ // I don't bother for now...
+ return;
+ }
+ }
+ else
+ {
+ // S9xSetPPU() is called to read from $21xx
+ // Take care of DMA wrapping
+ if (Address > 0x21ff)
+ Address = 0x2100 + (Address & 0xff);
+ }
+ }
+
+#ifdef DEBUGGER
+ if (CPU.InHDMA)
+ S9xTraceFormattedMessage("--- HDMA PPU %04X -> %02X", Address, Byte);
+#endif
+
+ if ((Address & 0xffc0) == 0x2140) // APUIO0, APUIO1, APUIO2, APUIO3
+ // write_port will run the APU until given clock before writing value
+ S9xAPUWritePort(Address & 3, Byte);
+ else
+ if (Address <= 0x2183)
+ {
+ switch (Address)
+ {
+ case 0x2100: // INIDISP
+ if (Byte != Memory.FillRAM[0x2100])
+ {
+ //FLUSH_REDRAW();
+
+ if (PPU.Brightness != (Byte & 0xf))
+ {
+ IPPU.ColorsChanged = true;
+ IPPU.DirectColourMapsNeedRebuild = true;
+ PPU.Brightness = Byte & 0xf;
+ //S9xFixColourBrightness();
+ if (PPU.Brightness > IPPU.MaxBrightness)
+ IPPU.MaxBrightness = PPU.Brightness;
+ }
+
+ if ((Memory.FillRAM[0x2100] & 0x80) != (Byte & 0x80))
+ {
+ IPPU.ColorsChanged = true;
+ PPU.ForcedBlanking = (Byte >> 7) & 1;
+ }
+ }
+
+ if ((Memory.FillRAM[0x2100] & 0x80) && CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE)
+ {
+ PPU.OAMAddr = PPU.SavedOAMAddr;
+
+ uint8_t tmp = 0;
+ if (PPU.OAMPriorityRotation)
+ tmp = (PPU.OAMAddr & 0xfe) >> 1;
+ if ((PPU.OAMFlip & 1) || PPU.FirstSprite != tmp)
+ {
+ PPU.FirstSprite = tmp;
+ IPPU.OBJChanged = true;
+ }
+
+ PPU.OAMFlip = 0;
+ }
+
+ break;
+
+ case 0x2101: // OBSEL
+ if (Byte != Memory.FillRAM[0x2101])
+ {
+ //FLUSH_REDRAW();
+ PPU.OBJNameBase = (Byte & 3) << 14;
+ PPU.OBJNameSelect = ((Byte >> 3) & 3) << 13;
+ PPU.OBJSizeSelect = (Byte >> 5) & 7;
+ IPPU.OBJChanged = true;
+ }
+
+ break;
+
+ case 0x2102: // OAMADDL
+ PPU.OAMAddr = ((Memory.FillRAM[0x2103] & 1) << 8) | Byte;
+ PPU.OAMFlip = 2;
+ PPU.OAMReadFlip = 0;
+ PPU.SavedOAMAddr = PPU.OAMAddr;
+ if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1))
+ {
+ PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1;
+ IPPU.OBJChanged = true;
+ #ifdef DEBUGGER
+ missing.sprite_priority_rotation = 1;
+ #endif
+ }
+
+ break;
+
+ case 0x2103: // OAMADDH
+ PPU.OAMAddr = ((Byte & 1) << 8) | Memory.FillRAM[0x2102];
+ PPU.OAMPriorityRotation = (Byte & 0x80) ? 1 : 0;
+ if (PPU.OAMPriorityRotation)
+ {
+ if (PPU.FirstSprite != (PPU.OAMAddr >> 1))
+ {
+ PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1;
+ IPPU.OBJChanged = true;
+ #ifdef DEBUGGER
+ missing.sprite_priority_rotation = 1;
+ #endif
+ }
+ }
+ else
+ {
+ if (PPU.FirstSprite != 0)
+ {
+ PPU.FirstSprite = 0;
+ IPPU.OBJChanged = true;
+ #ifdef DEBUGGER
+ missing.sprite_priority_rotation = 1;
+ #endif
+ }
+ }
+
+ PPU.OAMFlip = 0;
+ PPU.OAMReadFlip = 0;
+ PPU.SavedOAMAddr = PPU.OAMAddr;
+
+ break;
+
+ case 0x2104: // OAMDATA
+ REGISTER_2104(Byte);
+ break;
+
+ case 0x2105: // BGMODE
+ if (Byte != Memory.FillRAM[0x2105])
+ {
+ //FLUSH_REDRAW();
+ PPU.BG[0].BGSize = (Byte >> 4) & 1;
+ PPU.BG[1].BGSize = (Byte >> 5) & 1;
+ PPU.BG[2].BGSize = (Byte >> 6) & 1;
+ PPU.BG[3].BGSize = (Byte >> 7) & 1;
+ PPU.BGMode = Byte & 7;
+ // BJ: BG3Priority only takes effect if BGMode == 1 and the bit is set
+ PPU.BG3Priority = ((Byte & 0x0f) == 0x09);
+ IPPU.Interlace = Memory.FillRAM[0x2133] & 1;
+ #ifdef DEBUGGER
+ missing.modes[PPU.BGMode] = 1;
+ #endif
+ }
+
+ break;
+
+ case 0x2106: // MOSAIC
+ if (Byte != Memory.FillRAM[0x2106])
+ {
+ //FLUSH_REDRAW();
+ PPU.MosaicStart = CPU.V_Counter;
+ if (PPU.MosaicStart > PPU.ScreenHeight)
+ PPU.MosaicStart = 0;
+ PPU.Mosaic = (Byte >> 4) + 1;
+ PPU.BGMosaic[0] = (Byte & 1);
+ PPU.BGMosaic[1] = !!(Byte & 2);
+ PPU.BGMosaic[2] = !!(Byte & 4);
+ PPU.BGMosaic[3] = !!(Byte & 8);
+ #ifdef DEBUGGER
+ if ((Byte & 0xf0) && (Byte & 0x0f))
+ missing.mosaic = 1;
+ #endif
+ }
+
+ break;
+
+ case 0x2107: // BG1SC
+ if (Byte != Memory.FillRAM[0x2107])
+ {
+ //FLUSH_REDRAW();
+ PPU.BG[0].SCSize = Byte & 3;
+ PPU.BG[0].SCBase = (Byte & 0x7c) << 8;
+ }
+
+ break;
+
+ case 0x2108: // BG2SC
+ if (Byte != Memory.FillRAM[0x2108])
+ {
+ //FLUSH_REDRAW();
+ PPU.BG[1].SCSize = Byte & 3;
+ PPU.BG[1].SCBase = (Byte & 0x7c) << 8;
+ }
+
+ break;
+
+ case 0x2109: // BG3SC
+ if (Byte != Memory.FillRAM[0x2109])
+ {
+ //FLUSH_REDRAW();
+ PPU.BG[2].SCSize = Byte & 3;
+ PPU.BG[2].SCBase = (Byte & 0x7c) << 8;
+ }
+
+ break;
+
+ case 0x210a: // BG4SC
+ if (Byte != Memory.FillRAM[0x210a])
+ {
+ //FLUSH_REDRAW();
+ PPU.BG[3].SCSize = Byte & 3;
+ PPU.BG[3].SCBase = (Byte & 0x7c) << 8;
+ }
+
+ break;
+
+ case 0x210b: // BG12NBA
+ if (Byte != Memory.FillRAM[0x210b])
+ {
+ //FLUSH_REDRAW();
+ PPU.BG[0].NameBase = (Byte & 7) << 12;
+ PPU.BG[1].NameBase = ((Byte >> 4) & 7) << 12;
+ }
+
+ break;
+
+ case 0x210c: // BG34NBA
+ if (Byte != Memory.FillRAM[0x210c])
+ {
+ //FLUSH_REDRAW();
+ PPU.BG[2].NameBase = (Byte & 7) << 12;
+ PPU.BG[3].NameBase = ((Byte >> 4) & 7) << 12;
+ }
+
+ break;
+
+ case 0x210d: // BG1HOFS, M7HOFS
+ PPU.BG[0].HOffset = (Byte << 8) | (PPU.BGnxOFSbyte & ~7) | ((PPU.BG[0].HOffset >> 8) & 7);
+ PPU.M7HOFS = (Byte << 8) | PPU.M7byte;
+ PPU.BGnxOFSbyte = Byte;
+ PPU.M7byte = Byte;
+ break;
+
+ case 0x210e: // BG1VOFS, M7VOFS
+ PPU.BG[0].VOffset = (Byte << 8) | PPU.BGnxOFSbyte;
+ PPU.M7VOFS = (Byte << 8) | PPU.M7byte;
+ PPU.BGnxOFSbyte = Byte;
+ PPU.M7byte = Byte;
+ break;
+
+ case 0x210f: // BG2HOFS
+ PPU.BG[1].HOffset = (Byte << 8) | (PPU.BGnxOFSbyte & ~7) | ((PPU.BG[1].HOffset >> 8) & 7);
+ PPU.BGnxOFSbyte = Byte;
+ break;
+
+ case 0x2110: // BG2VOFS
+ PPU.BG[1].VOffset = (Byte << 8) | PPU.BGnxOFSbyte;
+ PPU.BGnxOFSbyte = Byte;
+ break;
+
+ case 0x2111: // BG3HOFS
+ PPU.BG[2].HOffset = (Byte << 8) | (PPU.BGnxOFSbyte & ~7) | ((PPU.BG[2].HOffset >> 8) & 7);
+ PPU.BGnxOFSbyte = Byte;
+ break;
+
+ case 0x2112: // BG3VOFS
+ PPU.BG[2].VOffset = (Byte << 8) | PPU.BGnxOFSbyte;
+ PPU.BGnxOFSbyte = Byte;
+ break;
+
+ case 0x2113: // BG4HOFS
+ PPU.BG[3].HOffset = (Byte << 8) | (PPU.BGnxOFSbyte & ~7) | ((PPU.BG[3].HOffset >> 8) & 7);
+ PPU.BGnxOFSbyte = Byte;
+ break;
+
+ case 0x2114: // BG4VOFS
+ PPU.BG[3].VOffset = (Byte << 8) | PPU.BGnxOFSbyte;
+ PPU.BGnxOFSbyte = Byte;
+ break;
+
+ case 0x2115: // VMAIN
+ PPU.VMA.High = (Byte & 0x80) == 0 ? false : true;
+ switch (Byte & 3)
+ {
+ case 0: PPU.VMA.Increment = 1; break;
+ case 1: PPU.VMA.Increment = 32; break;
+ case 2: PPU.VMA.Increment = 128; break;
+ case 3: PPU.VMA.Increment = 128; break;
+ }
+
+ if (Byte & 0x0c)
+ {
+ static uint16_t Shift[4] = { 0, 5, 6, 7 };
+ static uint16_t IncCount[4] = { 0, 32, 64, 128 };
+
+ uint8_t i = (Byte & 0x0c) >> 2;
+ PPU.VMA.FullGraphicCount = IncCount[i];
+ PPU.VMA.Mask1 = IncCount[i] * 8 - 1;
+ PPU.VMA.Shift = Shift[i];
+ #ifdef DEBUGGER
+ missing.vram_full_graphic_inc = (Byte & 0x0c) >> 2;
+ #endif
+ }
+ else
+ PPU.VMA.FullGraphicCount = 0;
+ #ifdef DEBUGGER
+ if (Byte & 3)
+ missing.vram_inc = Byte & 3;
+ #endif
+ break;
+
+ case 0x2116: // VMADDL
+ 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));
+
+ break;
+
+ case 0x2117: // VMADDH
+ 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));
+
+ break;
+
+ case 0x2118: // VMDATAL
+ REGISTER_2118(Byte);
+ break;
+
+ case 0x2119: // VMDATAH
+ REGISTER_2119(Byte);
+ break;
+
+ case 0x211a: // M7SEL
+ if (Byte != Memory.FillRAM[0x211a])
+ {
+ //FLUSH_REDRAW();
+ PPU.Mode7Repeat = Byte >> 6;
+ if (PPU.Mode7Repeat == 1)
+ PPU.Mode7Repeat = 0;
+ PPU.Mode7VFlip = !!((Byte & 2) >> 1);
+ PPU.Mode7HFlip = Byte & 1;
+ }
+
+ break;
+
+ case 0x211b: // M7A
+ PPU.MatrixA = PPU.M7byte | (Byte << 8);
+ PPU.Need16x8Mulitply = true;
+ PPU.M7byte = Byte;
+ break;
+
+ case 0x211c: // M7B
+ PPU.MatrixB = PPU.M7byte | (Byte << 8);
+ PPU.Need16x8Mulitply = true;
+ PPU.M7byte = Byte;
+ break;
+
+ case 0x211d: // M7C
+ PPU.MatrixC = PPU.M7byte | (Byte << 8);
+ PPU.M7byte = Byte;
+ break;
+
+ case 0x211e: // M7D
+ PPU.MatrixD = PPU.M7byte | (Byte << 8);
+ PPU.M7byte = Byte;
+ break;
+
+ case 0x211f: // M7X
+ PPU.CentreX = PPU.M7byte | (Byte << 8);
+ PPU.M7byte = Byte;
+ break;
+
+ case 0x2120: // M7Y
+ PPU.CentreY = PPU.M7byte | (Byte << 8);
+ PPU.M7byte = Byte;
+ break;
+
+ case 0x2121: // CGADD
+ PPU.CGFLIP = 0;
+ PPU.CGFLIPRead = 0;
+ PPU.CGADD = Byte;
+ break;
+
+ /*case 0x2122: // CGDATA
+ REGISTER_2122(Byte);
+ break;*/
+
+ case 0x2123: // W12SEL
+ if (Byte != Memory.FillRAM[0x2123])
+ {
+ //FLUSH_REDRAW();
+ PPU.ClipWindow1Enable[0] = !!(Byte & 0x02);
+ PPU.ClipWindow1Enable[1] = !!(Byte & 0x20);
+ PPU.ClipWindow2Enable[0] = !!(Byte & 0x08);
+ PPU.ClipWindow2Enable[1] = !!(Byte & 0x80);
+ PPU.ClipWindow1Inside[0] = !(Byte & 0x01);
+ PPU.ClipWindow1Inside[1] = !(Byte & 0x10);
+ PPU.ClipWindow2Inside[0] = !(Byte & 0x04);
+ PPU.ClipWindow2Inside[1] = !(Byte & 0x40);
+ PPU.RecomputeClipWindows = true;
+ #ifdef DEBUGGER
+ if (Byte & 0x80)
+ missing.window2[1] = 1;
+ if (Byte & 0x20)
+ missing.window1[1] = 1;
+ if (Byte & 0x08)
+ missing.window2[0] = 1;
+ if (Byte & 0x02)
+ missing.window1[0] = 1;
+ #endif
+ }
+
+ break;
+
+ case 0x2124: // W34SEL
+ if (Byte != Memory.FillRAM[0x2124])
+ {
+ //FLUSH_REDRAW();
+ PPU.ClipWindow1Enable[2] = !!(Byte & 0x02);
+ PPU.ClipWindow1Enable[3] = !!(Byte & 0x20);
+ PPU.ClipWindow2Enable[2] = !!(Byte & 0x08);
+ PPU.ClipWindow2Enable[3] = !!(Byte & 0x80);
+ PPU.ClipWindow1Inside[2] = !(Byte & 0x01);
+ PPU.ClipWindow1Inside[3] = !(Byte & 0x10);
+ PPU.ClipWindow2Inside[2] = !(Byte & 0x04);
+ PPU.ClipWindow2Inside[3] = !(Byte & 0x40);
+ PPU.RecomputeClipWindows = true;
+ #ifdef DEBUGGER
+ if (Byte & 0x80)
+ missing.window2[3] = 1;
+ if (Byte & 0x20)
+ missing.window1[3] = 1;
+ if (Byte & 0x08)
+ missing.window2[2] = 1;
+ if (Byte & 0x02)
+ missing.window1[2] = 1;
+ #endif
+ }
+
+ break;
+
+ case 0x2125: // WOBJSEL
+ if (Byte != Memory.FillRAM[0x2125])
+ {
+ //FLUSH_REDRAW();
+ PPU.ClipWindow1Enable[4] = !!(Byte & 0x02);
+ PPU.ClipWindow1Enable[5] = !!(Byte & 0x20);
+ PPU.ClipWindow2Enable[4] = !!(Byte & 0x08);
+ PPU.ClipWindow2Enable[5] = !!(Byte & 0x80);
+ PPU.ClipWindow1Inside[4] = !(Byte & 0x01);
+ PPU.ClipWindow1Inside[5] = !(Byte & 0x10);
+ PPU.ClipWindow2Inside[4] = !(Byte & 0x04);
+ PPU.ClipWindow2Inside[5] = !(Byte & 0x40);
+ PPU.RecomputeClipWindows = true;
+ #ifdef DEBUGGER
+ if (Byte & 0x80)
+ missing.window2[5] = 1;
+ if (Byte & 0x20)
+ missing.window1[5] = 1;
+ if (Byte & 0x08)
+ missing.window2[4] = 1;
+ if (Byte & 0x02)
+ missing.window1[4] = 1;
+ #endif
+ }
+
+ break;
+
+ case 0x2126: // WH0
+ if (Byte != Memory.FillRAM[0x2126])
+ {
+ //FLUSH_REDRAW();
+ PPU.Window1Left = Byte;
+ PPU.RecomputeClipWindows = true;
+ }
+
+ break;
+
+ case 0x2127: // WH1
+ if (Byte != Memory.FillRAM[0x2127])
+ {
+ //FLUSH_REDRAW();
+ PPU.Window1Right = Byte;
+ PPU.RecomputeClipWindows = true;
+ }
+
+ break;
+
+ case 0x2128: // WH2
+ if (Byte != Memory.FillRAM[0x2128])
+ {
+ //FLUSH_REDRAW();
+ PPU.Window2Left = Byte;
+ PPU.RecomputeClipWindows = true;
+ }
+
+ break;
+
+ case 0x2129: // WH3
+ if (Byte != Memory.FillRAM[0x2129])
+ {
+ //FLUSH_REDRAW();
+ PPU.Window2Right = Byte;
+ PPU.RecomputeClipWindows = true;
+ }
+
+ break;
+
+ case 0x212a: // WBGLOG
+ if (Byte != Memory.FillRAM[0x212a])
+ {
+ //FLUSH_REDRAW();
+ PPU.ClipWindowOverlapLogic[0] = (Byte & 0x03);
+ PPU.ClipWindowOverlapLogic[1] = (Byte & 0x0c) >> 2;
+ PPU.ClipWindowOverlapLogic[2] = (Byte & 0x30) >> 4;
+ PPU.ClipWindowOverlapLogic[3] = (Byte & 0xc0) >> 6;
+ PPU.RecomputeClipWindows = true;
+ }
+
+ break;
+
+ case 0x212b: // WOBJLOG
+ if (Byte != Memory.FillRAM[0x212b])
+ {
+ //FLUSH_REDRAW();
+ PPU.ClipWindowOverlapLogic[4] = (Byte & 0x03);
+ PPU.ClipWindowOverlapLogic[5] = (Byte & 0x0c) >> 2;
+ PPU.RecomputeClipWindows = true;
+ }
+
+ break;
+
+ case 0x212c: // TM
+ if (Byte != Memory.FillRAM[0x212c])
+ {
+ //FLUSH_REDRAW();
+ PPU.RecomputeClipWindows = true;
+ }
+
+ break;
+
+ case 0x212d: // TS
+ if (Byte != Memory.FillRAM[0x212d])
+ {
+ //FLUSH_REDRAW();
+ PPU.RecomputeClipWindows = true;
+ #ifdef DEBUGGER
+ if (Byte & 0x1f)
+ missing.subscreen = 1;
+ #endif
+ }
+
+ break;
+
+ case 0x212e: // TMW
+ if (Byte != Memory.FillRAM[0x212e])
+ {
+ //FLUSH_REDRAW();
+ PPU.RecomputeClipWindows = true;
+ }
+
+ break;
+
+ case 0x212f: // TSW
+ if (Byte != Memory.FillRAM[0x212f])
+ {
+ //FLUSH_REDRAW();
+ PPU.RecomputeClipWindows = true;
+ }
+
+ break;
+
+ case 0x2130: // CGWSEL
+ if (Byte != Memory.FillRAM[0x2130])
+ {
+ //FLUSH_REDRAW();
+ PPU.RecomputeClipWindows = true;
+ #ifdef DEBUGGER
+ if ((Byte & 1) && (PPU.BGMode == 3 || PPU.BGMode == 4 || PPU.BGMode == 7))
+ missing.direct = 1;
+ #endif
+ }
+
+ break;
+
+ case 0x2131: // CGADSUB
+ if (Byte != Memory.FillRAM[0x2131])
+ {
+ //FLUSH_REDRAW();
+ #ifdef DEBUGGER
+ if (Byte & 0x80)
+ {
+ if (Memory.FillRAM[0x2130] & 0x02)
+ missing.subscreen_sub = 1;
+ else
+ missing.fixed_colour_sub = 1;
+ }
+ else
+ {
+ if (Memory.FillRAM[0x2130] & 0x02)
+ missing.subscreen_add = 1;
+ else
+ missing.fixed_colour_add = 1;
+ }
+ #endif
+ }
+
+ break;
+
+ case 0x2132: // COLDATA
+ if (Byte != Memory.FillRAM[0x2132])
+ {
+ //FLUSH_REDRAW();
+ if (Byte & 0x80)
+ PPU.FixedColourBlue = Byte & 0x1f;
+ if (Byte & 0x40)
+ PPU.FixedColourGreen = Byte & 0x1f;
+ if (Byte & 0x20)
+ PPU.FixedColourRed = Byte & 0x1f;
+ }
+
+ break;
+
+ case 0x2133: // SETINI
+ if (Byte != Memory.FillRAM[0x2133])
+ {
+ if ((Memory.FillRAM[0x2133] ^ Byte) & 8)
+ {
+ //FLUSH_REDRAW();
+ IPPU.PseudoHires = !!(Byte & 8);
+ }
+
+ if (Byte & 0x04)
+ {
+ PPU.ScreenHeight = SNES_HEIGHT_EXTENDED;
+ if (IPPU.DoubleHeightPixels)
+ IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
+ else
+ IPPU.RenderedScreenHeight = PPU.ScreenHeight;
+ #ifdef DEBUGGER
+ missing.lines_239 = 1;
+ #endif
+ }
+ else
+ PPU.ScreenHeight = SNES_HEIGHT;
+
+ if ((Memory.FillRAM[0x2133] ^ Byte) & 3)
+ {
+ //FLUSH_REDRAW();
+ if ((Memory.FillRAM[0x2133] ^ Byte) & 2)
+ IPPU.OBJChanged = true;
+ IPPU.Interlace = Byte & 1;
+ IPPU.InterlaceOBJ = !!(Byte & 2);
+ }
+ #ifdef DEBUGGER
+ if (Byte & 0x40)
+ missing.mode7_bgmode = 1;
+ if (Byte & 0x08)
+ missing.pseudo_512 = 1;
+ if (Byte & 0x02)
+ missing.sprite_double_height = 1;
+ if (Byte & 0x01)
+ missing.interlace = 1;
+ #endif
+ }
+
+ break;
+
+ case 0x2134: // MPYL
+ case 0x2135: // MPYM
+ case 0x2136: // MPYH
+ case 0x2137: // SLHV
+ case 0x2138: // OAMDATAREAD
+ case 0x2139: // VMDATALREAD
+ case 0x213a: // VMDATAHREAD
+ case 0x213b: // CGDATAREAD
+ case 0x213c: // OPHCT
+ case 0x213d: // OPVCT
+ case 0x213e: // STAT77
+ case 0x213f: // STAT78
+ return;
+
+ case 0x2180: // WMDATA
+ if (!CPU.InWRAMDMAorHDMA)
+ REGISTER_2180(Byte);
+ break;
+
+ case 0x2181: // WMADDL
+ if (!CPU.InWRAMDMAorHDMA)
+ {
+ PPU.WRAM &= 0x1ff00;
+ PPU.WRAM |= Byte;
+ }
+
+ break;
+
+ case 0x2182: // WMADDM
+ if (!CPU.InWRAMDMAorHDMA)
+ {
+ PPU.WRAM &= 0x100ff;
+ PPU.WRAM |= Byte << 8;
+ }
+
+ break;
+
+ case 0x2183: // WMADDH
+ if (!CPU.InWRAMDMAorHDMA)
+ {
+ PPU.WRAM &= 0x0ffff;
+ PPU.WRAM |= Byte << 16;
+ PPU.WRAM &= 0x1ffff;
+ }
+
+ break;
+ }
+ }
+ /*else
+ {
+ if (Settings.SuperFX && Address >= 0x3000 && Address <= 0x32ff)
+ {
+ S9xSetSuperFX(Byte, Address);
+ return;
+ }
+ else
+ if (Settings.SA1 && Address >= 0x2200)
+ {
+ if (Address <= 0x23ff)
+ S9xSetSA1(Byte, Address);
+ else
+ Memory.FillRAM[Address] = Byte;
+ return;
+ }
+ else
+ if (Settings.BS && Address >= 0x2188 && Address <= 0x219f)
+ S9xSetBSXPPU(Byte, Address);
+ else
+ if (Settings.SRTC && Address == 0x2801)
+ S9xSetSRTC(Byte, Address);
+ #ifdef DEBUGGER
+ else
+ {
+ missing.unknownppu_write = Address;
+ if (Settings.TraceUnknownRegisters)
+ {
+ sprintf(String, "Unknown register write: $%02X->$%04X\n", Byte, Address);
+ S9xMessage(S9X_TRACE, S9X_PPU_TRACE, String);
+ }
+ }
+ #endif
+ }*/
+
+ Memory.FillRAM[Address] = Byte;
+}
+
+uint8_t S9xGetPPU (uint16_t Address)
+{
+ // MAP_PPU: $2000-$3FFF
+
+ if (Address < 0x2100)
+ return OpenBus;
+
+ if (CPU.InDMAorHDMA)
+ {
+ if (CPU.CurrentDMAorHDMAChannel >= 0 && !DMA[CPU.CurrentDMAorHDMAChannel].ReverseTransfer)
+ {
+ // S9xGetPPU() is called to read from DMA[].AAddress
+ if ((Address & 0xff00) == 0x2100)
+ // Cannot access to Address Bus B ($2100-$21FF) via (H)DMA
+ return OpenBus;
+ else
+ // $2200-$3FFF are connected to Address Bus A
+ // SA1, SuperFX and SRTC are mapped here
+ // I don't bother for now...
+ return OpenBus;
+ }
+ else
+ {
+ // S9xGetPPU() is called to write to $21xx
+ // Take care of DMA wrapping
+ if (Address > 0x21ff)
+ Address = 0x2100 + (Address & 0xff);
+ }
+ }
+
+ if ((Address & 0xffc0) == 0x2140) // APUIO0, APUIO1, APUIO2, APUIO3
+ // read_port will run the APU until given APU time before reading value
+ return S9xAPUReadPort(Address & 3);
+ else
+ if (Address <= 0x2183)
+ {
+ uint8_t byte;
+
+ switch (Address)
+ {
+ case 0x2104: // OAMDATA
+ case 0x2105: // BGMODE
+ case 0x2106: // MOSAIC
+ case 0x2108: // BG2SC
+ case 0x2109: // BG3SC
+ case 0x210a: // BG4SC
+ case 0x2114: // BG4VOFS
+ case 0x2115: // VMAIN
+ case 0x2116: // VMADDL
+ case 0x2118: // VMDATAL
+ case 0x2119: // VMDATAH
+ case 0x211a: // M7SEL
+ case 0x2124: // W34SEL
+ case 0x2125: // WOBJSEL
+ case 0x2126: // WH0
+ case 0x2128: // WH2
+ case 0x2129: // WH3
+ case 0x212a: // WBGLOG
+ return PPU.OpenBus1;
+
+ case 0x2134: // MPYL
+ case 0x2135: // MPYM
+ case 0x2136: // MPYH
+ if (PPU.Need16x8Mulitply)
+ {
+ int32_t r = (int32_t) PPU.MatrixA * (int32_t) (PPU.MatrixB >> 8);
+ Memory.FillRAM[0x2134] = (uint8_t) r;
+ Memory.FillRAM[0x2135] = (uint8_t) (r >> 8);
+ Memory.FillRAM[0x2136] = (uint8_t) (r >> 16);
+ PPU.Need16x8Mulitply = false;
+ }
+ #ifdef DEBUGGER
+ missing.matrix_multiply = 1;
+ #endif
+ return (PPU.OpenBus1 = Memory.FillRAM[Address]);
+
+ case 0x2137: // SLHV
+ S9xLatchCounters(0);
+ return OpenBus;
+
+ case 0x2138: // OAMDATAREAD
+ if (PPU.OAMAddr & 0x100)
+ {
+ if (!(PPU.OAMFlip & 1))
+ byte = PPU.OAMData[(PPU.OAMAddr & 0x10f) << 1];
+ else
+ {
+ byte = PPU.OAMData[((PPU.OAMAddr & 0x10f) << 1) + 1];
+ PPU.OAMAddr = (PPU.OAMAddr + 1) & 0x1ff;
+ if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1))
+ {
+ PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1;
+ IPPU.OBJChanged = true;
+ #ifdef DEBUGGER
+ missing.sprite_priority_rotation = 1;
+ #endif
+ }
+ }
+ }
+ else
+ {
+ if (!(PPU.OAMFlip & 1))
+ byte = PPU.OAMData[PPU.OAMAddr << 1];
+ else
+ {
+ byte = PPU.OAMData[(PPU.OAMAddr << 1) + 1];
+ ++PPU.OAMAddr;
+ if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1))
+ {
+ PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1;
+ IPPU.OBJChanged = true;
+ #ifdef DEBUGGER
+ missing.sprite_priority_rotation = 1;
+ #endif
+ }
+ }
+ }
+
+ PPU.OAMFlip ^= 1;
+ #ifdef DEBUGGER
+ missing.oam_read = 1;
+ #endif
+ return (PPU.OpenBus1 = byte);
+
+ case 0x2139: // VMDATALREAD
+ byte = IPPU.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));
+
+ PPU.VMA.Address += PPU.VMA.Increment;
+ }
+
+ #ifdef DEBUGGER
+ missing.vram_read = 1;
+ #endif
+ return (PPU.OpenBus1 = byte);
+
+ case 0x213a: // VMDATAHREAD
+ byte = (IPPU.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));
+
+ PPU.VMA.Address += PPU.VMA.Increment;
+ }
+ #ifdef DEBUGGER
+ missing.vram_read = 1;
+ #endif
+ return (PPU.OpenBus1 = byte);
+
+ case 0x213b: // CGDATAREAD
+ if (PPU.CGFLIPRead)
+ byte = (PPU.OpenBus2 & 0x80) | ((PPU.CGDATA[PPU.CGADD++] >> 8) & 0x7f);
+ else
+ byte = PPU.CGDATA[PPU.CGADD] & 0xff;
+ PPU.CGFLIPRead ^= 1;
+ #ifdef DEBUGGER
+ missing.cgram_read = 1;
+ #endif
+ return (PPU.OpenBus2 = byte);
+
+ case 0x213c: // OPHCT
+ S9xTryGunLatch(false);
+ if (PPU.HBeamFlip)
+ byte = (PPU.OpenBus2 & 0xfe) | ((PPU.HBeamPosLatched >> 8) & 0x01);
+ else
+ byte = (uint8_t) PPU.HBeamPosLatched;
+ PPU.HBeamFlip ^= 1;
+ #ifdef DEBUGGER
+ missing.h_counter_read = 1;
+ #endif
+ return (PPU.OpenBus2 = byte);
+
+ case 0x213d: // OPVCT
+ S9xTryGunLatch(false);
+ if (PPU.VBeamFlip)
+ byte = (PPU.OpenBus2 & 0xfe) | ((PPU.VBeamPosLatched >> 8) & 0x01);
+ else
+ byte = (uint8_t) PPU.VBeamPosLatched;
+ PPU.VBeamFlip ^= 1;
+ #ifdef DEBUGGER
+ missing.v_counter_read = 1;
+ #endif
+ return (PPU.OpenBus2 = byte);
+
+ case 0x213e: // STAT77
+ //FLUSH_REDRAW();
+ byte = (PPU.OpenBus1 & 0x10) | PPU.RangeTimeOver | Model->_5C77;
+ return (PPU.OpenBus1 = byte);
+
+ case 0x213f: // STAT78
+ S9xTryGunLatch(false);
+ PPU.VBeamFlip = PPU.HBeamFlip = 0;
+ byte = (PPU.OpenBus2 & 0x20) | (Memory.FillRAM[0x213f] & 0xc0) | (Settings.PAL ? 0x10 : 0) | Model->_5C78;
+ Memory.FillRAM[0x213f] &= ~0x40;
+ return (PPU.OpenBus2 = byte);
+
+ case 0x2180: // WMDATA
+ if (!CPU.InWRAMDMAorHDMA)
+ {
+ byte = Memory.RAM[PPU.WRAM++];
+ PPU.WRAM &= 0x1ffff;
+ }
+ else
+ byte = OpenBus;
+ #ifdef DEBUGGER
+ missing.wram_read = 1;
+ #endif
+ return byte;
+
+ default:
+ return OpenBus;
+ }
+ }
+ else
+ {
+ /*if (Settings.SuperFX && Address >= 0x3000 && Address <= 0x32ff)
+ return S9xGetSuperFX(Address);
+ else
+ if (Settings.SA1 && Address >= 0x2200)
+ return S9xGetSA1(Address);
+ else
+ if (Settings.BS && Address >= 0x2188 && Address <= 0x219f)
+ return S9xGetBSXPPU(Address);
+ else
+ if (Settings.SRTC && Address == 0x2800)
+ return S9xGetSRTC(Address);
+ else*/
+ switch (Address)
+ {
+ case 0x21c2:
+ if (Model->_5C77 == 2)
+ return 0x20;
+ return OpenBus;
+
+ case 0x21c3:
+ if (Model->_5C77 == 2)
+ return 0;
+ return OpenBus;
+
+ default:
+ return OpenBus;
+ }
+ }
+}
+
+void S9xSetCPU (uint8_t Byte, uint16_t Address)
+{
+ if (Address < 0x4200)
+ {
+ /*switch (Address)
+ {
+ case 0x4016: // JOYSER0
+ S9xSetJoypadLatch(Byte & 1);
+ break;
+
+ case 0x4017: // JOYSER1
+ return;
+
+ default:
+ break;
+ }*/
+ }
+ else
+ if ((Address & 0xff80) == 0x4300)
+ {
+ if (CPU.InDMAorHDMA)
+ return;
+
+ int d = (Address >> 4) & 0x7;
+
+ switch (Address & 0xf)
+ {
+ case 0x0: // 0x43x0: DMAPx
+ DMA[d].ReverseTransfer = (Byte & 0x80) ? true : false;
+ DMA[d].HDMAIndirectAddressing = (Byte & 0x40) ? true : false;
+ DMA[d].UnusedBit43x0 = (Byte & 0x20) ? true : false;
+ DMA[d].AAddressDecrement = (Byte & 0x10) ? true : false;
+ DMA[d].AAddressFixed = (Byte & 0x08) ? true : false;
+ DMA[d].TransferMode = (Byte & 7);
+ return;
+
+ case 0x1: // 0x43x1: BBADx
+ DMA[d].BAddress = Byte;
+ return;
+
+ case 0x2: // 0x43x2: A1TxL
+ DMA[d].AAddress &= 0xff00;
+ DMA[d].AAddress |= Byte;
+ return;
+
+ case 0x3: // 0x43x3: A1TxH
+ DMA[d].AAddress &= 0xff;
+ DMA[d].AAddress |= Byte << 8;
+ return;
+
+ case 0x4: // 0x43x4: A1Bx
+ DMA[d].ABank = Byte;
+ HDMAMemPointers[d] = NULL;
+ return;
+
+ case 0x5: // 0x43x5: DASxL
+ DMA[d].DMACount_Or_HDMAIndirectAddress &= 0xff00;
+ DMA[d].DMACount_Or_HDMAIndirectAddress |= Byte;
+ HDMAMemPointers[d] = NULL;
+ return;
+
+ case 0x6: // 0x43x6: DASxH
+ DMA[d].DMACount_Or_HDMAIndirectAddress &= 0xff;
+ DMA[d].DMACount_Or_HDMAIndirectAddress |= Byte << 8;
+ HDMAMemPointers[d] = NULL;
+ return;
+
+ case 0x7: // 0x43x7: DASBx
+ DMA[d].IndirectBank = Byte;
+ HDMAMemPointers[d] = NULL;
+ return;
+
+ case 0x8: // 0x43x8: A2AxL
+ DMA[d].Address &= 0xff00;
+ DMA[d].Address |= Byte;
+ HDMAMemPointers[d] = NULL;
+ return;
+
+ case 0x9: // 0x43x9: A2AxH
+ DMA[d].Address &= 0xff;
+ DMA[d].Address |= Byte << 8;
+ HDMAMemPointers[d] = NULL;
+ return;
+
+ case 0xa: // 0x43xa: NLTRx
+ if (Byte & 0x7f)
+ {
+ DMA[d].LineCount = Byte & 0x7f;
+ DMA[d].Repeat = !(Byte & 0x80);
+ }
+ else
+ {
+ DMA[d].LineCount = 128;
+ DMA[d].Repeat = !!(Byte & 0x80);
+ }
+
+ return;
+
+ case 0xb: // 0x43xb: ????x
+ case 0xf: // 0x43xf: mirror of 0x43xb
+ DMA[d].UnknownByte = Byte;
+ return;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ uint16_t pos;
+
+ switch (Address)
+ {
+ case 0x4200: // NMITIMEN
+ if (Byte & 0x20)
+ {
+ PPU.VTimerEnabled = true;
+ #ifdef DEBUGGER
+ missing.virq = 1;
+ missing.virq_pos = PPU.IRQVBeamPos;
+ #endif
+ }
+ else
+ PPU.VTimerEnabled = false;
+
+ if (Byte & 0x10)
+ {
+ PPU.HTimerEnabled = true;
+ #ifdef DEBUGGER
+ missing.hirq = 1;
+ missing.hirq_pos = PPU.IRQHBeamPos;
+ #endif
+ }
+ else
+ PPU.HTimerEnabled = false;
+
+ if (CPU.IRQLine && !PPU.HTimerEnabled && PPU.VTimerEnabled)
+ CPU.IRQTransition = true;
+
+ if (!PPU.HTimerEnabled && !PPU.VTimerEnabled)
+ {
+ CPU.IRQLine = false;
+ CPU.IRQTransition = false;
+ }
+
+ // 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 + 6 + 6;
+ }
+
+ break;
+
+ case 0x4201: // WRIO
+ if ((Byte & 0x80) == 0 && (Memory.FillRAM[0x4213] & 0x80) == 0x80)
+ S9xLatchCounters(1);
+ else
+ S9xTryGunLatch((Byte & 0x80) ? true : false);
+ Memory.FillRAM[0x4201] = Memory.FillRAM[0x4213] = Byte;
+ break;
+
+ case 0x4202: // WRMPYA
+ break;
+
+ case 0x4203: // WRMPYB
+ {
+ uint32_t res = Memory.FillRAM[0x4202] * Byte;
+ // FIXME: The update occurs 8 machine cycles after $4203 is set.
+ Memory.FillRAM[0x4216] = (uint8_t) res;
+ Memory.FillRAM[0x4217] = (uint8_t) (res >> 8);
+ break;
+ }
+
+ case 0x4204: // WRDIVL
+ case 0x4205: // WRDIVH
+ break;
+
+ case 0x4206: // WRDIVB
+ {
+ uint16_t a = Memory.FillRAM[0x4204] + (Memory.FillRAM[0x4205] << 8);
+ uint16_t div = Byte ? a / Byte : 0xffff;
+ uint16_t rem = Byte ? a % Byte : a;
+ // FIXME: The update occurs 16 machine cycles after $4206 is set.
+ Memory.FillRAM[0x4214] = (uint8_t) div;
+ Memory.FillRAM[0x4215] = div >> 8;
+ Memory.FillRAM[0x4216] = (uint8_t) rem;
+ Memory.FillRAM[0x4217] = rem >> 8;
+ break;
+ }
+
+ case 0x4207: // HTIMEL
+ pos = PPU.IRQHBeamPos;
+ PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff00) | Byte;
+ if (PPU.IRQHBeamPos != pos)
+ S9xUpdateHVTimerPosition();
+ #ifdef DEBUGGER
+ missing.hirq_pos = PPU.IRQHBeamPos;
+ #endif
+ break;
+
+ case 0x4208: // HTIMEH
+ pos = PPU.IRQHBeamPos;
+ PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff) | ((Byte & 1) << 8);
+ if (PPU.IRQHBeamPos != pos)
+ S9xUpdateHVTimerPosition();
+ #ifdef DEBUGGER
+ missing.hirq_pos = PPU.IRQHBeamPos;
+ #endif
+ break;
+
+ case 0x4209: // VTIMEL
+ pos = PPU.IRQVBeamPos;
+ PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff00) | Byte;
+ if (PPU.IRQVBeamPos != pos)
+ S9xUpdateHVTimerPosition();
+ #ifdef DEBUGGER
+ missing.virq_pos = PPU.IRQVBeamPos;
+ #endif
+ break;
+
+ case 0x420a: // VTIMEH
+ pos = PPU.IRQVBeamPos;
+ PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff) | ((Byte & 1) << 8);
+ if (PPU.IRQVBeamPos != pos)
+ S9xUpdateHVTimerPosition();
+ #ifdef DEBUGGER
+ missing.virq_pos = PPU.IRQVBeamPos;
+ #endif
+ break;
+
+ case 0x420b: // MDMAEN
+ if (CPU.InDMAorHDMA)
+ return;
+ // XXX: Not quite right...
+ if (Byte)
+ CPU.Cycles += Timings.DMACPUSync;
+ if (Byte & 0x01)
+ S9xDoDMA(0);
+ if (Byte & 0x02)
+ S9xDoDMA(1);
+ if (Byte & 0x04)
+ S9xDoDMA(2);
+ if (Byte & 0x08)
+ S9xDoDMA(3);
+ if (Byte & 0x10)
+ S9xDoDMA(4);
+ if (Byte & 0x20)
+ S9xDoDMA(5);
+ if (Byte & 0x40)
+ S9xDoDMA(6);
+ if (Byte & 0x80)
+ S9xDoDMA(7);
+ #ifdef DEBUGGER
+ missing.dma_this_frame = Byte;
+ missing.dma_channels = Byte;
+ #endif
+ break;
+
+ case 0x420c: // HDMAEN
+ if (CPU.InDMAorHDMA)
+ return;
+ Memory.FillRAM[0x420c] = Byte;
+ // Yoshi's Island, Genjyu Ryodan, Mortal Kombat, Tales of Phantasia
+ PPU.HDMA = Byte & ~PPU.HDMAEnded;
+ #ifdef DEBUGGER
+ missing.hdma_this_frame |= Byte;
+ missing.hdma_channels |= Byte;
+ #endif
+ break;
+
+ case 0x420d: // MEMSEL
+ if ((Byte & 1) != (Memory.FillRAM[0x420d] & 1))
+ {
+ if (Byte & 1)
+ {
+ CPU.FastROMSpeed = ONE_CYCLE;
+ #ifdef DEBUGGER
+ missing.fast_rom = 1;
+ #endif
+ }
+ else
+ CPU.FastROMSpeed = SLOW_ONE_CYCLE;
+ }
+
+ break;
+
+ case 0x4210: // RDNMI
+ case 0x4211: // TIMEUP
+ case 0x4212: // HVBJOY
+ case 0x4213: // RDIO
+ case 0x4214: // RDDIVL
+ case 0x4215: // RDDIVH
+ case 0x4216: // RDMPYL
+ case 0x4217: // RDMPYH
+ case 0x4218: // JOY1L
+ case 0x4219: // JOY1H
+ case 0x421a: // JOY2L
+ case 0x421b: // JOY2H
+ case 0x421c: // JOY3L
+ case 0x421d: // JOY3H
+ case 0x421e: // JOY4L
+ case 0x421f: // JOY4H
+ return;
+
+ default:
+ /*if (Settings.SPC7110 && Address >= 0x4800)
+ S9xSetSPC7110(Byte, Address);
+ else*/
+ if (Settings.SDD1 && Address >= 0x4804 && Address <= 0x4807)
+ S9xSetSDD1MemoryMap(Address - 0x4804, Byte & 7);
+ break;
+ }
+ }
+
+ Memory.FillRAM[Address] = Byte;
+}
+
+uint8_t S9xGetCPU (uint16_t Address)
+{
+ if (Address < 0x4200)
+ {
+ #ifdef SNES_JOY_READ_CALLBACKS
+ extern bool pad_read;
+ if (Address == 0x4016 || Address == 0x4017)
+ {
+ S9xOnSNESPadRead();
+ pad_read = true;
+ }
+ #endif
+
+ /*switch (Address)
+ {
+ case 0x4016: // JOYSER0
+ case 0x4017: // JOYSER1
+ return S9xReadJOYSERn(Address);
+
+ default:*/
+ return OpenBus;
+ //}
+ }
+ else
+ if ((Address & 0xff80) == 0x4300)
+ {
+ if (CPU.InDMAorHDMA)
+ return OpenBus;
+
+ int d = (Address >> 4) & 0x7;
+
+ switch (Address & 0xf)
+ {
+ case 0x0: // 0x43x0: DMAPx
+ return (DMA[d].ReverseTransfer ? 0x80 : 0) |
+ (DMA[d].HDMAIndirectAddressing ? 0x40 : 0) |
+ (DMA[d].UnusedBit43x0 ? 0x20 : 0) |
+ (DMA[d].AAddressDecrement ? 0x10 : 0) |
+ (DMA[d].AAddressFixed ? 0x08 : 0) |
+ (DMA[d].TransferMode & 7);
+
+ case 0x1: // 0x43x1: BBADx
+ return DMA[d].BAddress;
+
+ case 0x2: // 0x43x2: A1TxL
+ return DMA[d].AAddress & 0xff;
+
+ case 0x3: // 0x43x3: A1TxH
+ return DMA[d].AAddress >> 8;
+
+ case 0x4: // 0x43x4: A1Bx
+ return DMA[d].ABank;
+
+ case 0x5: // 0x43x5: DASxL
+ return DMA[d].DMACount_Or_HDMAIndirectAddress & 0xff;
+
+ case 0x6: // 0x43x6: DASxH
+ return DMA[d].DMACount_Or_HDMAIndirectAddress >> 8;
+
+ case 0x7: // 0x43x7: DASBx
+ return DMA[d].IndirectBank;
+
+ case 0x8: // 0x43x8: A2AxL
+ return DMA[d].Address & 0xff;
+
+ case 0x9: // 0x43x9: A2AxH
+ return DMA[d].Address >> 8;
+
+ case 0xa: // 0x43xa: NLTRx
+ return DMA[d].LineCount ^ (DMA[d].Repeat ? 0x00 : 0x80);
+
+ case 0xb: // 0x43xb: ????x
+ case 0xf: // 0x43xf: mirror of 0x43xb
+ return DMA[d].UnknownByte;
+
+ default:
+ return OpenBus;
+ }
+ }
+ else
+ {
+ uint8_t byte;
+
+ switch (Address)
+ {
+ case 0x4210: // RDNMI
+ byte = Memory.FillRAM[0x4210];
+ Memory.FillRAM[0x4210] = Model->_5A22;
+ return (byte & 0x80) | (OpenBus & 0x70) | Model->_5A22;
+
+ case 0x4211: // TIMEUP
+ byte = CPU.IRQLine ? 0x80 : 0;
+ CPU.IRQLine = false;
+ CPU.IRQTransition = false;
+ return byte | (OpenBus & 0x7f);
+
+ case 0x4212: // HVBJOY
+ return REGISTER_4212() | (OpenBus & 0x3e);
+
+ case 0x4213: // RDIO
+ return Memory.FillRAM[0x4213];
+
+ case 0x4214: // RDDIVL
+ case 0x4215: // RDDIVH
+ case 0x4216: // RDMPYL
+ case 0x4217: // RDMPYH
+ return Memory.FillRAM[Address];
+
+ case 0x4218: // JOY1L
+ case 0x4219: // JOY1H
+ case 0x421a: // JOY2L
+ case 0x421b: // JOY2H
+ case 0x421c: // JOY3L
+ case 0x421d: // JOY3H
+ case 0x421e: // JOY4L
+ case 0x421f: // JOY4H
+ #ifdef SNES_JOY_READ_CALLBACKS
+ extern bool pad_read;
+ if (Memory.FillRAM[0x4200] & 1)
+ {
+ S9xOnSNESPadRead();
+ pad_read = true;
+ }
+ #endif
+ return Memory.FillRAM[Address];
+
+ default:
+ /*if (Settings.SPC7110 && Address >= 0x4800)
+ return S9xGetSPC7110(Address);*/
+ if (Settings.SDD1 && Address >= 0x4800 && Address <= 0x4807)
+ return Memory.FillRAM[Address];
+ return OpenBus;
+ }
+ }
+}
+
+void S9xResetPPU()
+{
+ S9xSoftResetPPU();
+ //S9xControlsReset();
+ PPU.M7HOFS = 0;
+ PPU.M7VOFS = 0;
+ PPU.M7byte = 0;
+}
+
+void S9xSoftResetPPU()
+{
+ //S9xControlsSoftReset();
+
+ PPU.VMA.High = 0;
+ PPU.VMA.Increment = 1;
+ PPU.VMA.Address = 0;
+ PPU.VMA.FullGraphicCount = 0;
+ PPU.VMA.Shift = 0;
+
+ PPU.WRAM = 0;
+
+ for (int c = 0; c < 4; c++)
+ {
+ PPU.BG[c].SCBase = 0;
+ PPU.BG[c].HOffset = 0;
+ PPU.BG[c].VOffset = 0;
+ PPU.BG[c].BGSize = 0;
+ PPU.BG[c].NameBase = 0;
+ PPU.BG[c].SCSize = 0;
+ }
+
+ PPU.BGMode = 0;
+ PPU.BG3Priority = 0;
+
+ PPU.CGFLIP = 0;
+ PPU.CGFLIPRead = 0;
+ PPU.CGADD = 0;
+
+ for (int c = 0; c < 256; c++)
+ {
+ IPPU.Red[c] = (c & 7) << 2;
+ IPPU.Green[c] = ((c >> 3) & 7) << 2;
+ IPPU.Blue[c] = ((c >> 6) & 2) << 3;
+ PPU.CGDATA[c] = IPPU.Red[c] | (IPPU.Green[c] << 5) | (IPPU.Blue[c] << 10);
+ }
+
+ for (int c = 0; c < 128; c++)
+ {
+ PPU.OBJ[c].HPos = 0;
+ PPU.OBJ[c].VPos = 0;
+ PPU.OBJ[c].HFlip = 0;
+ PPU.OBJ[c].VFlip = 0;
+ PPU.OBJ[c].Name = 0;
+ PPU.OBJ[c].Priority = 0;
+ PPU.OBJ[c].Palette = 0;
+ PPU.OBJ[c].Size = 0;
+ }
+
+ PPU.OBJThroughMain = false;
+ PPU.OBJThroughSub = false;
+ PPU.OBJAddition = false;
+ PPU.OBJNameBase = 0;
+ PPU.OBJNameSelect = 0;
+ PPU.OBJSizeSelect = 0;
+
+ PPU.OAMAddr = 0;
+ PPU.SavedOAMAddr = 0;
+ PPU.OAMPriorityRotation = 0;
+ PPU.OAMFlip = 0;
+ PPU.OAMReadFlip = 0;
+ PPU.OAMTileAddress = 0;
+ PPU.OAMWriteRegister = 0;
+ ZeroMemory(PPU.OAMData, 512 + 32);
+
+ PPU.FirstSprite = 0;
+ PPU.LastSprite = 127;
+ PPU.RangeTimeOver = 0;
+
+ PPU.HTimerEnabled = false;
+ PPU.VTimerEnabled = false;
+ PPU.HTimerPosition = Timings.H_Max + 1;
+ PPU.VTimerPosition = Timings.V_Max + 1;
+ PPU.IRQHBeamPos = 0x1ff;
+ PPU.IRQVBeamPos = 0x1ff;
+
+ PPU.HBeamFlip = 0;
+ PPU.VBeamFlip = 0;
+ PPU.HBeamPosLatched = 0;
+ PPU.VBeamPosLatched = 0;
+ PPU.GunHLatch = 0;
+ PPU.GunVLatch = 1000;
+ PPU.HVBeamCounterLatched = 0;
+
+ PPU.Mode7HFlip = false;
+ PPU.Mode7VFlip = false;
+ PPU.Mode7Repeat = 0;
+ PPU.MatrixA = 0;
+ PPU.MatrixB = 0;
+ PPU.MatrixC = 0;
+ PPU.MatrixD = 0;
+ PPU.CentreX = 0;
+ PPU.CentreY = 0;
+
+ PPU.Mosaic = 0;
+ PPU.BGMosaic[0] = false;
+ PPU.BGMosaic[1] = false;
+ PPU.BGMosaic[2] = false;
+ PPU.BGMosaic[3] = false;
+
+ PPU.Window1Left = 1;
+ PPU.Window1Right = 0;
+ PPU.Window2Left = 1;
+ PPU.Window2Right = 0;
+ PPU.RecomputeClipWindows = true;
+
+ for (int c = 0; c < 6; c++)
+ {
+ PPU.ClipCounts[c] = 0;
+ PPU.ClipWindowOverlapLogic[c] = CLIP_OR;
+ PPU.ClipWindow1Enable[c] = false;
+ PPU.ClipWindow2Enable[c] = false;
+ PPU.ClipWindow1Inside[c] = true;
+ PPU.ClipWindow2Inside[c] = true;
+ }
+
+ PPU.ForcedBlanking = true;
+
+ PPU.FixedColourRed = 0;
+ PPU.FixedColourGreen = 0;
+ PPU.FixedColourBlue = 0;
+ PPU.Brightness = 0;
+ PPU.ScreenHeight = SNES_HEIGHT;
+
+ PPU.Need16x8Mulitply = false;
+ PPU.BGnxOFSbyte = 0;
+
+ PPU.HDMA = 0;
+ PPU.HDMAEnded = 0;
+
+ PPU.OpenBus1 = 0;
+ PPU.OpenBus2 = 0;
+
+ for (int c = 0; c < 2; c++)
+ memset(&IPPU.Clip[c], 0, sizeof(struct ClipData));
+ IPPU.ColorsChanged = true;
+ IPPU.OBJChanged = true;
+ IPPU.DirectColourMapsNeedRebuild = true;
+ ZeroMemory(IPPU.TileCached[TILE_2BIT], MAX_2BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_4BIT], MAX_4BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_8BIT], MAX_8BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_2BIT_EVEN], MAX_2BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_2BIT_ODD], MAX_2BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_4BIT_EVEN], MAX_4BIT_TILES);
+ ZeroMemory(IPPU.TileCached[TILE_4BIT_ODD], MAX_4BIT_TILES);
+ IPPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better?
+ IPPU.Interlace = false;
+ IPPU.InterlaceOBJ = false;
+ IPPU.DoubleWidthPixels = false;
+ IPPU.DoubleHeightPixels = false;
+ IPPU.CurrentLine = 0;
+ IPPU.PreviousLine = 0;
+ IPPU.XB = NULL;
+ for (int c = 0; c < 256; c++)
+ IPPU.ScreenColors[c] = c;
+ IPPU.MaxBrightness = 0;
+ IPPU.RenderThisFrame = true;
+ IPPU.RenderedScreenWidth = SNES_WIDTH;
+ IPPU.RenderedScreenHeight = SNES_HEIGHT;
+ IPPU.FrameCount = 0;
+ IPPU.RenderedFramesCount = 0;
+ IPPU.DisplayedRenderedFrameCount = 0;
+ IPPU.SkippedFrames = 0;
+ IPPU.FrameSkip = 0;
+
+ //S9xFixColourBrightness();
+
+ for (int c = 0; c < 0x8000; c += 0x100)
+ memset(&Memory.FillRAM[c], c >> 8, 0x100);
+ ZeroMemory(&Memory.FillRAM[0x2100], 0x100);
+ ZeroMemory(&Memory.FillRAM[0x4200], 0x100);
+ ZeroMemory(&Memory.FillRAM[0x4000], 0x100);
+ // For BS Suttehakkun 2...
+ ZeroMemory(&Memory.FillRAM[0x1000], 0x1000);
+
+ Memory.FillRAM[0x4201] = Memory.FillRAM[0x4213] = 0xff;
+}
+
--- /dev/null
+++ b/src/in_snsf/snes9x/ppu.h
@@ -1,1 +1,742 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _PPU_H_
+#define _PPU_H_
+
+#define FIRST_VISIBLE_LINE 1
+
+#define TILE_2BIT 0
+#define TILE_4BIT 1
+#define TILE_8BIT 2
+#define TILE_2BIT_EVEN 3
+#define TILE_2BIT_ODD 4
+#define TILE_4BIT_EVEN 5
+#define TILE_4BIT_ODD 6
+
+#define MAX_2BIT_TILES 4096
+#define MAX_4BIT_TILES 2048
+#define MAX_8BIT_TILES 1024
+
+#define CLIP_OR 0
+#define CLIP_AND 1
+#define CLIP_XOR 2
+#define CLIP_XNOR 3
+
+struct ClipData
+{
+ uint8_t Count;
+ uint8_t DrawMode[6];
+ uint16_t Left[6];
+ uint16_t Right[6];
+};
+
+struct InternalPPU
+{
+ struct ClipData Clip[2][6];
+ bool ColorsChanged;
+ bool OBJChanged;
+ bool DirectColourMapsNeedRebuild;
+ uint8_t *TileCache[7];
+ uint8_t *TileCached[7];
+ uint16_t VRAMReadBuffer;
+ bool Interlace;
+ bool InterlaceOBJ;
+ bool PseudoHires;
+ bool DoubleWidthPixels;
+ bool DoubleHeightPixels;
+ int CurrentLine;
+ int PreviousLine;
+ uint8_t *XB;
+ uint32_t Red[256];
+ uint32_t Green[256];
+ uint32_t Blue[256];
+ uint16_t ScreenColors[256];
+ uint8_t MaxBrightness;
+ bool RenderThisFrame;
+ int RenderedScreenWidth;
+ int RenderedScreenHeight;
+ uint32_t FrameCount;
+ uint32_t RenderedFramesCount;
+ uint32_t DisplayedRenderedFrameCount;
+ uint32_t TotalEmulatedFrames;
+ uint32_t SkippedFrames;
+ uint32_t FrameSkip;
+};
+
+struct SOBJ
+{
+ int16_t HPos;
+ uint16_t VPos;
+ uint8_t HFlip;
+ uint8_t VFlip;
+ uint16_t Name;
+ uint8_t Priority;
+ uint8_t Palette;
+ uint8_t Size;
+};
+
+struct SPPU
+{
+ struct
+ {
+ bool High;
+ uint8_t Increment;
+ uint16_t Address;
+ uint16_t Mask1;
+ uint16_t FullGraphicCount;
+ uint16_t Shift;
+ } VMA;
+
+ uint32_t WRAM;
+
+ struct
+ {
+ uint16_t SCBase;
+ uint16_t HOffset;
+ uint16_t VOffset;
+ uint8_t BGSize;
+ uint16_t NameBase;
+ uint16_t SCSize;
+ } BG[4];
+
+ uint8_t BGMode;
+ uint8_t BG3Priority;
+
+ bool CGFLIP;
+ uint8_t CGFLIPRead;
+ uint8_t CGADD;
+ uint16_t CGDATA[256];
+
+ struct SOBJ OBJ[128];
+ bool OBJThroughMain;
+ bool OBJThroughSub;
+ bool OBJAddition;
+ uint16_t OBJNameBase;
+ uint16_t OBJNameSelect;
+ uint8_t OBJSizeSelect;
+
+ uint16_t OAMAddr;
+ uint16_t SavedOAMAddr;
+ uint8_t OAMPriorityRotation;
+ uint8_t OAMFlip;
+ uint8_t OAMReadFlip;
+ uint16_t OAMTileAddress;
+ uint16_t OAMWriteRegister;
+ uint8_t OAMData[512 + 32];
+
+ uint8_t FirstSprite;
+ uint8_t LastSprite;
+ uint8_t RangeTimeOver;
+
+ bool HTimerEnabled;
+ bool VTimerEnabled;
+ short HTimerPosition;
+ short VTimerPosition;
+ uint16_t IRQHBeamPos;
+ uint16_t IRQVBeamPos;
+
+ uint8_t HBeamFlip;
+ uint8_t VBeamFlip;
+ uint16_t HBeamPosLatched;
+ uint16_t VBeamPosLatched;
+ uint16_t GunHLatch;
+ uint16_t GunVLatch;
+ uint8_t HVBeamCounterLatched;
+
+ bool Mode7HFlip;
+ bool Mode7VFlip;
+ uint8_t Mode7Repeat;
+ short MatrixA;
+ short MatrixB;
+ short MatrixC;
+ short MatrixD;
+ short CentreX;
+ short CentreY;
+ short M7HOFS;
+ short M7VOFS;
+
+ uint8_t Mosaic;
+ uint8_t MosaicStart;
+ bool BGMosaic[4];
+
+ uint8_t Window1Left;
+ uint8_t Window1Right;
+ uint8_t Window2Left;
+ uint8_t Window2Right;
+ bool RecomputeClipWindows;
+ uint8_t ClipCounts[6];
+ uint8_t ClipWindowOverlapLogic[6];
+ uint8_t ClipWindow1Enable[6];
+ uint8_t ClipWindow2Enable[6];
+ bool ClipWindow1Inside[6];
+ bool ClipWindow2Inside[6];
+
+ bool ForcedBlanking;
+
+ uint8_t FixedColourRed;
+ uint8_t FixedColourGreen;
+ uint8_t FixedColourBlue;
+ uint8_t Brightness;
+ uint16_t ScreenHeight;
+
+ bool Need16x8Mulitply;
+ uint8_t BGnxOFSbyte;
+ uint8_t M7byte;
+
+ uint8_t HDMA;
+ uint8_t HDMAEnded;
+
+ uint8_t OpenBus1;
+ uint8_t OpenBus2;
+};
+
+extern uint16_t SignExtend[2];
+extern struct SPPU PPU;
+extern struct InternalPPU IPPU;
+
+void S9xResetPPU();
+void S9xSoftResetPPU();
+void S9xSetPPU (uint8_t, uint16_t);
+uint8_t S9xGetPPU (uint16_t);
+void S9xSetCPU (uint8_t, uint16_t);
+uint8_t S9xGetCPU (uint16_t);
+void S9xUpdateHVTimerPosition();
+//void S9xFixColourBrightness();
+//void S9xDoAutoJoypad();
+
+//#include "gfx.h"
+#include "memmap.h"
+
+typedef struct
+{
+ uint8_t _5C77;
+ uint8_t _5C78;
+ uint8_t _5A22;
+} SnesModel;
+
+extern SnesModel *Model;
+extern SnesModel M1SNES;
+//extern SnesModel M2SNES;
+
+#define MAX_5C77_VERSION 0x01
+#define MAX_5C78_VERSION 0x03
+#define MAX_5A22_VERSION 0x02
+
+/*static inline void FLUSH_REDRAW()
+{
+ if (IPPU.PreviousLine != IPPU.CurrentLine)
+ S9xUpdateScreen();
+}*/
+
+static inline void REGISTER_2104 (uint8_t Byte)
+{
+ if (PPU.OAMAddr & 0x100)
+ {
+ int addr = ((PPU.OAMAddr & 0x10f) << 1) + (PPU.OAMFlip & 1);
+ if (Byte != PPU.OAMData[addr])
+ {
+ //FLUSH_REDRAW();
+ PPU.OAMData[addr] = Byte;
+ IPPU.OBJChanged = true;
+
+ // X position high bit, and sprite size (x4)
+ struct SOBJ *pObj = &PPU.OBJ[(addr & 0x1f) * 4];
+ pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(Byte >> 0) & 1];
+ pObj++->Size = Byte & 2;
+ pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(Byte >> 2) & 1];
+ pObj++->Size = Byte & 8;
+ pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(Byte >> 4) & 1];
+ pObj++->Size = Byte & 32;
+ pObj->HPos = (pObj->HPos & 0xFF) | SignExtend[(Byte >> 6) & 1];
+ pObj->Size = Byte & 128;
+ }
+
+ 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;
+ IPPU.OBJChanged = true;
+ }
+ }
+ else
+ {
+ if (PPU.OAMPriorityRotation && (PPU.OAMAddr & 1))
+ IPPU.OBJChanged = true;
+ }
+ }
+ else
+ if (!(PPU.OAMFlip & 1))
+ {
+ PPU.OAMWriteRegister &= 0xff00;
+ PPU.OAMWriteRegister |= Byte;
+ PPU.OAMFlip |= 1;
+ if (PPU.OAMPriorityRotation && (PPU.OAMAddr & 1))
+ IPPU.OBJChanged = true;
+ }
+ else
+ {
+ PPU.OAMWriteRegister &= 0x00ff;
+ uint8_t lowbyte = (uint8_t) (PPU.OAMWriteRegister);
+ uint8_t highbyte = Byte;
+ PPU.OAMWriteRegister |= Byte << 8;
+
+ int addr = (PPU.OAMAddr << 1);
+ if (lowbyte != PPU.OAMData[addr] || highbyte != PPU.OAMData[addr + 1])
+ {
+ //FLUSH_REDRAW();
+ PPU.OAMData[addr] = lowbyte;
+ PPU.OAMData[addr + 1] = highbyte;
+ IPPU.OBJChanged = true;
+ if (addr & 2)
+ {
+ // Tile
+ PPU.OBJ[addr = PPU.OAMAddr >> 1].Name = PPU.OAMWriteRegister & 0x1ff;
+ // priority, h and v flip.
+ PPU.OBJ[addr].Palette = (highbyte >> 1) & 7;
+ PPU.OBJ[addr].Priority = (highbyte >> 4) & 3;
+ PPU.OBJ[addr].HFlip = (highbyte >> 6) & 1;
+ PPU.OBJ[addr].VFlip = (highbyte >> 7) & 1;
+ }
+ else
+ {
+ // X position (low)
+ PPU.OBJ[addr = PPU.OAMAddr >> 1].HPos &= 0xff00;
+ PPU.OBJ[addr].HPos |= lowbyte;
+ // Sprite Y position
+ PPU.OBJ[addr].VPos = highbyte;
+ }
+ }
+
+ PPU.OAMFlip &= ~1;
+ ++PPU.OAMAddr;
+ if (PPU.OAMPriorityRotation && PPU.FirstSprite != (PPU.OAMAddr >> 1))
+ {
+ PPU.FirstSprite = (PPU.OAMAddr & 0xfe) >> 1;
+ IPPU.OBJChanged = true;
+ }
+ }
+}
+
+// This code is correct, however due to Snes9x's inaccurate timings, some games might be broken by this chage. :(
+#ifdef DEBUGGER
+#define CHECK_INBLANK() \
+ if (!PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) \
+ { \
+ printf("Invalid VRAM acess at (%04d, %04d) blank:%d\n", CPU.Cycles, CPU.V_Counter, PPU.ForcedBlanking); \
+ if (Settings.BlockInvalidVRAMAccess) \
+ return; \
+ }
+#else
+#define CHECK_INBLANK() \
+ if (Settings.BlockInvalidVRAMAccess && !PPU.ForcedBlanking && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) \
+ return;
+#endif
+
+static inline void REGISTER_2118 (uint8_t Byte)
+{
+ CHECK_INBLANK();
+
+ uint32_t address;
+
+ if (PPU.VMA.FullGraphicCount)
+ {
+ uint32_t rem = PPU.VMA.Address & PPU.VMA.Mask1;
+ address = (((PPU.VMA.Address & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) & 0xffff;
+ Memory.VRAM[address] = Byte;
+ }
+ else
+ Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xffff] = Byte;
+
+ IPPU.TileCached[TILE_2BIT][address >> 4] = false;
+ IPPU.TileCached[TILE_4BIT][address >> 5] = false;
+ IPPU.TileCached[TILE_8BIT][address >> 6] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+
+ if (!PPU.VMA.High)
+ {
+ #ifdef DEBUGGER
+ if (Settings.TraceVRAM && !CPU.InDMAorHDMA)
+ printf("VRAM write byte: $%04X (%d, %d)\n", PPU.VMA.Address, Memory.FillRAM[0x2115] & 3, (Memory.FillRAM[0x2115] & 0x0c) >> 2);
+ #endif
+ PPU.VMA.Address += PPU.VMA.Increment;
+ }
+}
+
+static inline void REGISTER_2119 (uint8_t Byte)
+{
+ CHECK_INBLANK();
+
+ uint32_t address;
+
+ if (PPU.VMA.FullGraphicCount)
+ {
+ uint32_t rem = PPU.VMA.Address & PPU.VMA.Mask1;
+ address = ((((PPU.VMA.Address & ~PPU.VMA.Mask1) + (rem >> PPU.VMA.Shift) + ((rem & (PPU.VMA.FullGraphicCount - 1)) << 3)) << 1) + 1) & 0xffff;
+ Memory.VRAM[address] = Byte;
+ }
+ else
+ Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xffff] = Byte;
+
+ IPPU.TileCached[TILE_2BIT][address >> 4] = false;
+ IPPU.TileCached[TILE_4BIT][address >> 5] = false;
+ IPPU.TileCached[TILE_8BIT][address >> 6] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+
+ if (PPU.VMA.High)
+ {
+ #ifdef DEBUGGER
+ if (Settings.TraceVRAM && !CPU.InDMAorHDMA)
+ printf("VRAM write word: $%04X (%d, %d)\n", PPU.VMA.Address, Memory.FillRAM[0x2115] & 3, (Memory.FillRAM[0x2115] & 0x0c) >> 2);
+ #endif
+ PPU.VMA.Address += PPU.VMA.Increment;
+ }
+}
+
+static inline void REGISTER_2118_tile (uint8_t Byte)
+{
+ CHECK_INBLANK();
+
+ 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] = Byte;
+
+ IPPU.TileCached[TILE_2BIT][address >> 4] = false;
+ IPPU.TileCached[TILE_4BIT][address >> 5] = false;
+ IPPU.TileCached[TILE_8BIT][address >> 6] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+
+ if (!PPU.VMA.High)
+ PPU.VMA.Address += PPU.VMA.Increment;
+}
+
+static inline void REGISTER_2119_tile (uint8_t Byte)
+{
+ CHECK_INBLANK();
+
+ 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) + 1) & 0xffff;
+
+ Memory.VRAM[address] = Byte;
+
+ IPPU.TileCached[TILE_2BIT][address >> 4] = false;
+ IPPU.TileCached[TILE_4BIT][address >> 5] = false;
+ IPPU.TileCached[TILE_8BIT][address >> 6] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+
+ if (PPU.VMA.High)
+ PPU.VMA.Address += PPU.VMA.Increment;
+}
+
+static inline void REGISTER_2118_linear (uint8_t Byte)
+{
+ CHECK_INBLANK();
+
+ uint32_t address;
+
+ Memory.VRAM[address = (PPU.VMA.Address << 1) & 0xffff] = Byte;
+
+ IPPU.TileCached[TILE_2BIT][address >> 4] = false;
+ IPPU.TileCached[TILE_4BIT][address >> 5] = false;
+ IPPU.TileCached[TILE_8BIT][address >> 6] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+
+ if (!PPU.VMA.High)
+ PPU.VMA.Address += PPU.VMA.Increment;
+}
+
+static inline void REGISTER_2119_linear (uint8_t Byte)
+{
+ CHECK_INBLANK();
+
+ uint32_t address;
+
+ Memory.VRAM[address = ((PPU.VMA.Address << 1) + 1) & 0xffff] = Byte;
+
+ IPPU.TileCached[TILE_2BIT][address >> 4] = false;
+ IPPU.TileCached[TILE_4BIT][address >> 5] = false;
+ IPPU.TileCached[TILE_8BIT][address >> 6] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_EVEN][((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [address >> 4] = false;
+ IPPU.TileCached[TILE_2BIT_ODD] [((address >> 4) - 1) & (MAX_2BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_EVEN][((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [address >> 5] = false;
+ IPPU.TileCached[TILE_4BIT_ODD] [((address >> 5) - 1) & (MAX_4BIT_TILES - 1)] = false;
+
+ if (PPU.VMA.High)
+ PPU.VMA.Address += PPU.VMA.Increment;
+}
+
+/*static inline void REGISTER_2122 (uint8_t Byte)
+{
+ if (PPU.CGFLIP)
+ {
+ if ((Byte & 0x7f) != (PPU.CGDATA[PPU.CGADD] >> 8))
+ {
+ FLUSH_REDRAW();
+ PPU.CGDATA[PPU.CGADD] &= 0x00ff;
+ PPU.CGDATA[PPU.CGADD] |= (Byte & 0x7f) << 8;
+ IPPU.ColorsChanged = true;
+ IPPU.Blue[PPU.CGADD] = IPPU.XB[(Byte >> 2) & 0x1f];
+ IPPU.Green[PPU.CGADD] = IPPU.XB[(PPU.CGDATA[PPU.CGADD] >> 5) & 0x1f];
+ IPPU.ScreenColors[PPU.CGADD] = (uint16_t) BUILD_PIXEL(IPPU.Red[PPU.CGADD], IPPU.Green[PPU.CGADD], IPPU.Blue[PPU.CGADD]);
+ }
+
+ PPU.CGADD++;
+ }
+ else
+ {
+ if (Byte != (uint8_t) (PPU.CGDATA[PPU.CGADD] & 0xff))
+ {
+ FLUSH_REDRAW();
+ PPU.CGDATA[PPU.CGADD] &= 0x7f00;
+ PPU.CGDATA[PPU.CGADD] |= Byte;
+ IPPU.ColorsChanged = true;
+ IPPU.Red[PPU.CGADD] = IPPU.XB[Byte & 0x1f];
+ IPPU.Green[PPU.CGADD] = IPPU.XB[(PPU.CGDATA[PPU.CGADD] >> 5) & 0x1f];
+ IPPU.ScreenColors[PPU.CGADD] = (uint16_t) BUILD_PIXEL(IPPU.Red[PPU.CGADD], IPPU.Green[PPU.CGADD], IPPU.Blue[PPU.CGADD]);
+ }
+ }
+
+ PPU.CGFLIP ^= 1;
+}*/
+
+static inline void REGISTER_2180 (uint8_t Byte)
+{
+ Memory.RAM[PPU.WRAM++] = Byte;
+ PPU.WRAM &= 0x1ffff;
+}
+
+static inline uint8_t REGISTER_4212()
+{
+ uint8_t byte = 0;
+
+ if ((CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE) && (CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE + 3))
+ byte = 1;
+ if ((CPU.Cycles < Timings.HBlankEnd) || (CPU.Cycles >= Timings.HBlankStart))
+ byte |= 0x40;
+ if (CPU.V_Counter >= PPU.ScreenHeight + FIRST_VISIBLE_LINE)
+ byte |= 0x80;
+
+ return byte;
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/sdd1.cpp
@@ -1,1 +1,211 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+#include "snes9x.h"
+#include "memmap.h"
+#include "sdd1.h"
+//#include "display.h"
+
+void S9xSetSDD1MemoryMap(uint32_t bank, uint32_t value)
+{
+ bank = 0xc00 + bank * 0x100;
+ value = value * 1024 * 1024;
+
+ for (int c = 0; c < 0x100; c += 16)
+ {
+ uint8_t *block = &Memory.ROM[value + (c << 12)];
+ for (int i = c; i < c + 16; ++i)
+ Memory.Map[i + bank] = block;
+ }
+}
+
+void S9xResetSDD1()
+{
+ memset(&Memory.FillRAM[0x4800], 0, 4);
+ for (int i = 0; i < 4; ++i)
+ {
+ Memory.FillRAM[0x4804 + i] = i;
+ S9xSetSDD1MemoryMap(i, i);
+ }
+}
+
+/*void S9xSDD1PostLoadState()
+{
+ for (int i = 0; i < 4; ++i)
+ S9xSetSDD1MemoryMap(i, Memory.FillRAM[0x4804 + i]);
+}*/
+
--- /dev/null
+++ b/src/in_snsf/snes9x/sdd1.h
@@ -1,1 +1,187 @@
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _SDD1_H_
+#define _SDD1_H_
+
+void S9xSetSDD1MemoryMap (uint32_t, uint32_t);
+void S9xResetSDD1();
+//void S9xSDD1PostLoadState();
+
+#endif
+
--- /dev/null
+++ b/src/in_snsf/snes9x/snes9x.h
@@ -1,1 +1,470 @@
-
+/***********************************************************************************
+ 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.
+ ***********************************************************************************/
+
+
+#ifndef _SNES9X_H_
+#define _SNES9X_H_
+
+#ifndef VERSION
+#define VERSION "1.53"
+#endif
+
+#include "port.h"
+#include "65c816.h"
+//#include "messages.h"
+
+#ifdef ZLIB
+#include <zlib.h>
+#define STREAM gzFile
+#define READ_STREAM(p, l, s) gzread(s, p, l)
+#define WRITE_STREAM(p, l, s) gzwrite(s, p, l)
+#define GETS_STREAM(p, l, s) gzgets(s, p, l)
+#define GETC_STREAM(s) gzgetc(s)
+#define OPEN_STREAM(f, m) gzopen(f, m)
+#define REOPEN_STREAM(f, m) gzdopen(f, m)
+#define FIND_STREAM(f) gztell(f)
+#define REVERT_STREAM(f, o, s) gzseek(f, o, s)
+#define CLOSE_STREAM(s) gzclose(s)
+#else
+#define STREAM FILE *
+#define READ_STREAM(p, l, s) fread(p, 1, l, s)
+#define WRITE_STREAM(p, l, s) fwrite(p, 1, l, s)
+#define GETS_STREAM(p, l, s) fgets(p, l, s)
+#define GETC_STREAM(s) fgetc(s)
+#define OPEN_STREAM(f, m) fopen(f, m)
+#define REOPEN_STREAM(f, m) fdopen(f, m)
+#define FIND_STREAM(f) ftell(f)
+#define REVERT_STREAM(f, o, s) fseek(f, o, s)
+#define CLOSE_STREAM(s) fclose(s)
+#endif
+
+#define SNES_WIDTH 256
+#define SNES_HEIGHT 224
+#define SNES_HEIGHT_EXTENDED 239
+#define MAX_SNES_WIDTH (SNES_WIDTH * 2)
+#define MAX_SNES_HEIGHT (SNES_HEIGHT_EXTENDED * 2)
+#define IMAGE_WIDTH (Settings.SupportHiRes ? MAX_SNES_WIDTH : SNES_WIDTH)
+#define IMAGE_HEIGHT (Settings.SupportHiRes ? MAX_SNES_HEIGHT : SNES_HEIGHT_EXTENDED)
+
+#define NTSC_MASTER_CLOCK 21477272.0
+#define PAL_MASTER_CLOCK 21281370.0
+
+#define SNES_MAX_NTSC_VCOUNTER 262
+#define SNES_MAX_PAL_VCOUNTER 312
+#define SNES_HCOUNTER_MAX 341
+
+#define ONE_CYCLE 6
+#define SLOW_ONE_CYCLE 8
+#define TWO_CYCLES 12
+#define ONE_DOT_CYCLE 4
+
+#define SNES_CYCLES_PER_SCANLINE (SNES_HCOUNTER_MAX * ONE_DOT_CYCLE)
+#define SNES_SCANLINE_TIME (SNES_CYCLES_PER_SCANLINE / NTSC_MASTER_CLOCK)
+
+#define SNES_WRAM_REFRESH_HC_v1 530
+#define SNES_WRAM_REFRESH_HC_v2 538
+#define SNES_WRAM_REFRESH_CYCLES 40
+
+#define SNES_HBLANK_START_HC 1096 // H=274
+#define SNES_HDMA_START_HC 1106 // FIXME: not true
+#define SNES_HBLANK_END_HC 4 // H=1
+#define SNES_HDMA_INIT_HC 20 // FIXME: not true
+#define SNES_RENDER_START_HC (48 * ONE_DOT_CYCLE) // FIXME: Snes9x renders a line at a time.
+
+#define SNES_TR_MASK (1 << 4)
+#define SNES_TL_MASK (1 << 5)
+#define SNES_X_MASK (1 << 6)
+#define SNES_A_MASK (1 << 7)
+#define SNES_RIGHT_MASK (1 << 8)
+#define SNES_LEFT_MASK (1 << 9)
+#define SNES_DOWN_MASK (1 << 10)
+#define SNES_UP_MASK (1 << 11)
+#define SNES_START_MASK (1 << 12)
+#define SNES_SELECT_MASK (1 << 13)
+#define SNES_Y_MASK (1 << 14)
+#define SNES_B_MASK (1 << 15)
+
+#define DEBUG_MODE_FLAG (1 << 0) // debugger
+#define TRACE_FLAG (1 << 1) // debugger
+#define SINGLE_STEP_FLAG (1 << 2) // debugger
+#define BREAK_FLAG (1 << 3) // debugger
+#define SCAN_KEYS_FLAG (1 << 4) // CPU
+#define HALTED_FLAG (1 << 12) // APU
+#define FRAME_ADVANCE_FLAG (1 << 9)
+
+#define ROM_NAME_LEN 23
+#define AUTO_FRAMERATE 200
+
+struct SCPUState
+{
+ uint32_t Flags;
+ int32_t Cycles;
+ int32_t PrevCycles;
+ int32_t V_Counter;
+ uint8_t *PCBase;
+ bool NMILine;
+ bool IRQLine;
+ bool IRQTransition;
+ bool IRQLastState;
+ bool IRQExternal;
+ int32_t IRQPending;
+ int32_t MemSpeed;
+ int32_t MemSpeedx2;
+ int32_t FastROMSpeed;
+ bool InDMA;
+ bool InHDMA;
+ bool InDMAorHDMA;
+ bool InWRAMDMAorHDMA;
+ uint8_t HDMARanInDMA;
+ int32_t CurrentDMAorHDMAChannel;
+ uint8_t WhichEvent;
+ int32_t NextEvent;
+ bool WaitingForInterrupt;
+ uint32_t AutoSaveTimer;
+ bool SRAMModified;
+};
+
+enum
+{
+ HC_HBLANK_START_EVENT = 1,
+ HC_HDMA_START_EVENT = 2,
+ HC_HCOUNTER_MAX_EVENT = 3,
+ HC_HDMA_INIT_EVENT = 4,
+ HC_RENDER_EVENT = 5,
+ HC_WRAM_REFRESH_EVENT = 6
+};
+
+struct STimings
+{
+ int32_t H_Max_Master;
+ int32_t H_Max;
+ int32_t V_Max_Master;
+ int32_t V_Max;
+ int32_t HBlankStart;
+ int32_t HBlankEnd;
+ int32_t HDMAInit;
+ int32_t HDMAStart;
+ int32_t NMITriggerPos;
+ 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 APUSpeedup;
+ bool APUAllowTimeOverflow;
+};
+
+struct SSettings
+{
+ bool TraceDMA;
+ bool TraceHDMA;
+ bool TraceVRAM;
+ bool TraceUnknownRegisters;
+ bool TraceDSP;
+ bool TraceHCEvent;
+
+ bool SuperFX;
+ uint8_t DSP;
+ bool SA1;
+ bool C4;
+ bool SDD1;
+ bool SPC7110;
+ bool SPC7110RTC;
+ bool OBC1;
+ uint8_t SETA;
+ bool SRTC;
+ bool BS;
+ bool BSXItself;
+ bool BSXBootup;
+ bool MouseMaster;
+ bool SuperScopeMaster;
+ bool JustifierMaster;
+ bool MultiPlayer5Master;
+
+ bool ForceLoROM;
+ bool ForceHiROM;
+ bool ForceHeader;
+ bool ForceNoHeader;
+ bool ForceInterleaved;
+ bool ForceInterleaved2;
+ bool ForceInterleaveGD24;
+ bool ForceNotInterleaved;
+ bool ForcePAL;
+ bool ForceNTSC;
+ bool PAL;
+ uint32_t FrameTimePAL;
+ uint32_t FrameTimeNTSC;
+ uint32_t FrameTime;
+
+ bool SoundSync;
+ bool SixteenBitSound;
+ uint32_t SoundPlaybackRate;
+ uint32_t SoundInputRate;
+ bool Stereo;
+ bool ReverseStereo;
+ bool Mute;
+
+ bool SupportHiRes;
+ bool Transparency;
+ uint8_t BG_Forced;
+ bool DisableGraphicWindows;
+
+ bool DisplayFrameRate;
+ bool DisplayWatchedAddresses;
+ bool DisplayPressedKeys;
+ bool DisplayMovieFrame;
+ bool AutoDisplayMessages;
+ uint32_t InitialInfoStringTimeout;
+ uint16_t DisplayColor;
+
+ bool Multi;
+ char CartAName[PATH_MAX + 1];
+ char CartBName[PATH_MAX + 1];
+
+ bool DisableGameSpecificHacks;
+ bool BlockInvalidVRAMAccessMaster;
+ bool BlockInvalidVRAMAccess;
+ int32_t HDMATimingHack;
+
+ bool ForcedPause;
+ bool Paused;
+ bool StopEmulation;
+
+ uint32_t SkipFrames;
+ uint32_t TurboSkipFrames;
+ uint32_t AutoMaxSkipFrames;
+ bool TurboMode;
+ uint32_t HighSpeedSeek;
+ bool FrameAdvance;
+
+ bool NetPlay;
+ bool NetPlayServer;
+ char ServerName[128];
+ int Port;
+
+ bool MovieTruncate;
+ bool MovieNotifyIgnored;
+ bool WrongMovieStateProtection;
+ bool DumpStreams;
+ int DumpStreamsMaxFrames;
+
+ bool TakeScreenshot;
+ int8_t StretchScreenshots;
+ bool SnapshotScreenshots;
+
+ bool ApplyCheats;
+ bool NoPatch;
+ int32_t AutoSaveDelay;
+ bool DontSaveOopsSnapshot;
+ bool UpAndDown;
+
+ bool OpenGLEnable;
+};
+
+struct SSNESGameFixes
+{
+ uint8_t SRAMInitialValue;
+ uint8_t Uniracers;
+};
+
+enum
+{
+ PAUSE_NETPLAY_CONNECT = (1 << 0),
+ PAUSE_TOGGLE_FULL_SCREEN = (1 << 1),
+ PAUSE_EXIT = (1 << 2),
+ PAUSE_MENU = (1 << 3),
+ PAUSE_INACTIVE_WINDOW = (1 << 4),
+ PAUSE_WINDOW_ICONISED = (1 << 5),
+ PAUSE_RESTORE_GUI = (1 << 6),
+ PAUSE_FREEZE_FILE = (1 << 7)
+};
+
+void S9xSetPause(uint32_t);
+void S9xClearPause(uint32_t);
+void S9xExi();
+void S9xMessage(int, int, const char *);
+
+extern struct SSettings Settings;
+extern struct SCPUState CPU;
+extern struct STimings Timings;
+extern struct SSNESGameFixes SNESGameFixes;
+//extern char String[513];
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/BigSString.h
@@ -1,1 +1,221 @@
-
+/*
+ * String class in ANSI (or rather, current Windows code page), UTF-8, and UTF-16
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ */
+
+#ifndef BIGSSTRING_H
+#define BIGSSTRING_H
+
+#include <string>
+#include <cstring>
+#include <cwchar>
+#include "UtfConverter.h"
+#include "UTFEncodeDecode.h"
+
+class String
+{
+public:
+ String(const std::locale &L = std::locale::classic()) : ansi(""), utf8(""), utf16(L""), loc(L) { }
+ String(const char *new_str, bool is_utf8 = false, const std::locale &L = std::locale::classic()) : ansi(is_utf8 ? DecodeFromUTF8(new_str, L) : new_str), utf8(is_utf8 ? new_str : EncodeToUTF8(new_str, L)),
+ utf16(UtfConverter::FromUtf8(utf8)), loc(L) { }
+ String(const std::string &new_str, bool is_utf8 = false, const std::locale &L = std::locale::classic()) : ansi(is_utf8 ? DecodeFromUTF8(new_str, L) : new_str), utf8(is_utf8 ? new_str : EncodeToUTF8(new_str, L)),
+ utf16(UtfConverter::FromUtf8(utf8)), loc(L) { }
+ String(const wchar_t *new_wstr, const std::locale &L = std::locale::classic()) : ansi(DecodeFromUTF8(UtfConverter::ToUtf8(new_wstr), L)), utf8(UtfConverter::ToUtf8(new_wstr)), utf16(new_wstr), loc(L) { }
+ String(const std::wstring &new_wstr, const std::locale &L = std::locale::classic()) : ansi(DecodeFromUTF8(UtfConverter::ToUtf8(new_wstr), L)), utf8(UtfConverter::ToUtf8(new_wstr)), utf16(new_wstr), loc(L) { }
+ bool empty() const { return this->utf8.empty(); }
+ std::string GetAnsi() const { return this->ansi; }
+ const char *GetAnsiC() const { return this->ansi.c_str(); }
+ std::string GetStr() const { return this->utf8; }
+ const char *GetStrC() const { return this->utf8.c_str(); }
+ std::wstring GetWStr() const { return this->utf16; }
+ const wchar_t *GetWStrC() const { return this->utf16.c_str(); }
+ bool operator==(const String &str2) const
+ {
+ return this->utf8 == str2.utf8;
+ }
+ String &operator=(const std::string &new_str)
+ {
+ this->ansi = DecodeFromUTF8(new_str, this->loc);
+ this->utf8 = new_str;
+ this->utf16 = UtfConverter::FromUtf8(new_str);
+ return *this;
+ }
+ String &operator=(const std::wstring &new_wstr)
+ {
+ this->utf8 = UtfConverter::ToUtf8(new_wstr);
+ this->ansi = DecodeFromUTF8(this->utf8, this->loc);
+ this->utf16 = new_wstr;
+ return *this;
+ }
+ String &operator=(const String &new_string)
+ {
+ if (this != &new_string)
+ {
+ this->ansi = new_string.ansi;
+ this->utf8 = new_string.utf8;
+ this->utf16 = new_string.utf16;
+ }
+ return *this;
+ }
+ String &SetISO8859_1(const std::string &new_str)
+ {
+ this->ansi = new_str;
+ this->utf8 = EncodeToUTF8(new_str, this->loc);
+ this->utf16 = UtfConverter::FromUtf8(this->utf8);
+ return *this;
+ }
+ String operator+(const String &str2) const
+ {
+ String new_string = String(*this);
+ new_string.ansi.append(str2.ansi);
+ new_string.utf8.append(str2.utf8);
+ new_string.utf16.append(str2.utf16);
+ return new_string;
+ }
+ String operator+(char chr) const
+ {
+ String new_string = String(*this);
+ char str2[] = { chr, 0 };
+ new_string.ansi.append(str2);
+ std::string new_utf8 = EncodeToUTF8(str2, this->loc);
+ new_string.utf8.append(new_utf8);
+ new_string.utf16.append(UtfConverter::FromUtf8(new_utf8));
+ return new_string;
+ }
+ String operator+(wchar_t wchr) const
+ {
+ String new_string = String(*this);
+ wchar_t wstr2[] = { wchr, 0 };
+ std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
+ new_string.ansi.append(DecodeFromUTF8(new_utf8, this->loc));
+ new_string.utf8.append(new_utf8);
+ new_string.utf16.append(wstr2);
+ return new_string;
+ }
+ String operator+(const char *str2) const
+ {
+ String new_string = String(*this);
+ new_string.ansi.append(DecodeFromUTF8(str2, this->loc));
+ new_string.utf8.append(str2);
+ new_string.utf16.append(UtfConverter::FromUtf8(str2));
+ return new_string;
+ }
+ String operator+(const std::string &str2) const
+ {
+ String new_string = String(*this);
+ new_string.ansi.append(DecodeFromUTF8(str2, this->loc));
+ new_string.utf8.append(str2);
+ new_string.utf16.append(UtfConverter::FromUtf8(str2));
+ return new_string;
+ }
+ String operator+(const wchar_t *wstr2) const
+ {
+ String new_string = String(*this);
+ std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
+ new_string.ansi.append(DecodeFromUTF8(new_utf8, this->loc));
+ new_string.utf8.append(new_utf8);
+ new_string.utf16.append(wstr2);
+ return new_string;
+ }
+ String operator+(const std::wstring &wstr2) const
+ {
+ String new_string = String(*this);
+ std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
+ new_string.ansi.append(DecodeFromUTF8(new_utf8, this->loc));
+ new_string.utf8.append(new_utf8);
+ new_string.utf16.append(wstr2);
+ return new_string;
+ }
+ String &operator+=(const String &str2)
+ {
+ if (this != &str2)
+ {
+ this->ansi.append(str2.ansi);
+ this->utf8.append(str2.utf8);
+ this->utf16.append(str2.utf16);
+ }
+ return *this;
+ }
+ String &operator+=(char chr)
+ {
+ char str2[] = { chr, 0 };
+ this->ansi.append(str2);
+ std::string new_utf8 = EncodeToUTF8(str2, this->loc);
+ this->utf8.append(new_utf8);
+ this->utf16.append(UtfConverter::FromUtf8(new_utf8));
+ return *this;
+ }
+ String &operator+=(wchar_t wchr)
+ {
+ wchar_t wstr2[] = { wchr, 0 };
+ std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
+ this->ansi.append(DecodeFromUTF8(new_utf8, this->loc));
+ this->utf8.append(new_utf8);
+ this->utf16.append(wstr2);
+ return *this;
+ }
+ String &operator+=(const char *str2)
+ {
+ this->ansi.append(DecodeFromUTF8(str2, this->loc));
+ this->utf8.append(str2);
+ this->utf16.append(UtfConverter::FromUtf8(str2));
+ return *this;
+ }
+ String &operator+=(const std::string &str2)
+ {
+ this->ansi.append(DecodeFromUTF8(str2, this->loc));
+ this->utf8.append(str2);
+ this->utf16.append(UtfConverter::FromUtf8(str2));
+ return *this;
+ }
+ String &operator+=(const wchar_t *wstr2)
+ {
+ std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
+ this->ansi.append(DecodeFromUTF8(new_utf8, this->loc));
+ this->utf8.append(new_utf8);
+ this->utf16.append(wstr2);
+ return *this;
+ }
+ String &operator+=(const std::wstring &wstr2)
+ {
+ std::string new_utf8 = UtfConverter::ToUtf8(wstr2);
+ this->ansi.append(DecodeFromUTF8(new_utf8, this->loc));
+ this->utf8.append(new_utf8);
+ this->utf16.append(wstr2);
+ return *this;
+ }
+ String &AppendISO8859_1(const std::string &str2)
+ {
+ this->ansi.append(str2);
+ std::string new_utf8 = EncodeToUTF8(str2, this->loc);
+ this->utf8.append(new_utf8);
+ this->utf16.append(UtfConverter::FromUtf8(new_utf8));
+ return *this;
+ }
+ String Substring(size_t pos = 0, size_t n = std::string::npos) const
+ {
+ String new_string = String(*this);
+ new_string.ansi.substr(pos, n);
+ new_string.utf8.substr(pos, n);
+ if (n == std::string::npos)
+ n = std::wstring::npos;
+ new_string.utf16.substr(pos, n);
+ return new_string;
+ }
+ void CopyToString(wchar_t *str, bool = false) const
+ {
+ wcscpy(str, utf16.c_str());
+ }
+ void CopyToString(char *str, bool use_utf8 = false) const
+ {
+ strcpy(str, (use_utf8 ? utf8 : ansi).c_str());
+ }
+protected:
+ std::string ansi, utf8;
+ std::wstring utf16;
+ std::locale loc;
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/ConvertUTF.cpp
@@ -1,1 +1,603 @@
-
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Source code file.
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Sept 2001: fixed const & error conditions per
+ mods suggested by S. Parent & A. Lillich.
+ June 2002: Tim Dodd added detection and handling of incomplete
+ source sequences, enhanced error detection, added casts
+ to eliminate compiler warnings.
+ July 2003: slight mods to back out aggressive FFFE detection.
+ Jan 2004: updated switches in from-UTF8 conversions.
+ Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
+
+ See the header file "ConvertUTF.h" for complete documentation.
+
+------------------------------------------------------------------------ */
+
+#include "ConvertUTF.h"
+
+static const int halfShift = 10; /* used for shifting by 10 bits */
+
+static const UTF32 halfBase = 0x0010000UL;
+static const UTF32 halfMask = 0x3FFUL;
+
+static const UTF32 UNI_SUR_HIGH_START = 0xD800;
+static const UTF32 UNI_SUR_HIGH_END = 0xDBFF;
+static const UTF32 UNI_SUR_LOW_START = 0xDC00;
+static const UTF32 UNI_SUR_LOW_END = 0xDFFF;
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd, UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF32 *source = *sourceStart;
+ UTF16 *target = *targetStart;
+ while (source < sourceEnd)
+ {
+ if (target >= targetEnd)
+ {
+ result = targetExhausted;
+ break;
+ }
+ UTF32 ch = *source++;
+ if (ch <= UNI_MAX_BMP) /* Target is a character <= 0xFFFF */
+ {
+ /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
+ {
+ if (flags == strictConversion)
+ {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ else
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ else
+ *target++ = static_cast<UTF16>(ch); /* normal case */
+ }
+ else if (ch > UNI_MAX_LEGAL_UTF32)
+ {
+ if (flags == strictConversion)
+ result = sourceIllegal;
+ else
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ else
+ {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd)
+ {
+ --source; /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ ch -= halfBase;
+ *target++ = static_cast<UTF16>((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = static_cast<UTF16>((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd, UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF16 *source = *sourceStart;
+ UTF32 *target = *targetStart;
+ while (source < sourceEnd)
+ {
+ const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */
+ UTF32 ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END)
+ {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd)
+ {
+ UTF32 ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END)
+ {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ }
+ else if (flags == strictConversion) /* it's an unpaired high surrogate */
+ {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ else /* We don't have the 16 bits following the high surrogate. */
+ {
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ }
+ else if (flags == strictConversion)
+ {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)
+ {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ if (target >= targetEnd)
+ {
+ source = oldSource; /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ *target++ = ch;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Index into the table below with the first byte of a UTF-8 sequence to
+ * get the number of trailing bytes that are supposed to follow it.
+ * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+ * left as-is for anyone who may want to do such conversion, which was
+ * allowed in earlier algorithms.
+ */
+static const char trailingBytesForUTF8[256] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 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,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+/*
+ * Magic values subtracted from a buffer value during UTF8 conversion.
+ * This table contains as many values as there might be trailing bytes
+ * in a UTF-8 sequence.
+ */
+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+
+/*
+ * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+ * into the first byte, depending on how many bytes follow. There are
+ * as many entries in this table as there are UTF-8 sequence types.
+ * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
+ * for *legal* UTF-8 will be 4 or fewer bytes total.
+ */
+static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+/* --------------------------------------------------------------------- */
+
+/* The interface converts a whole buffer to avoid function-call overhead.
+ * Constants have been gathered. Loops & conditionals have been removed as
+ * much as possible for efficiency, in favor of drop-through switches.
+ * (See "Note A" at the bottom of the file for equivalent code.)
+ * If your compiler supports it, the "isLegalUTF8" call can be turned
+ * into an inline function.
+ */
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF16 *source = *sourceStart;
+ UTF8 *target = *targetStart;
+ while (source < sourceEnd)
+ {
+ const UTF32 byteMask = 0xBF, byteMark = 0x80;
+ const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */
+ UTF32 ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END)
+ {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd)
+ {
+ UTF32 ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END)
+ {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase;
+ ++source;
+ }
+ else if (flags == strictConversion) /* it's an unpaired high surrogate */
+ {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ else /* We don't have the 16 bits following the high surrogate. */
+ {
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ }
+ else if (flags == strictConversion)
+ {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)
+ {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /* Figure out how many bytes the result will require */
+ unsigned short bytesToWrite = 0;
+ if (ch < 0x80)
+ bytesToWrite = 1;
+ else if (ch < 0x800)
+ bytesToWrite = 2;
+ else if (ch < 0x10000)
+ bytesToWrite = 3;
+ else if (ch < 0x110000)
+ bytesToWrite = 4;
+ else
+ {
+ bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ }
+ target += bytesToWrite;
+ if (target > targetEnd)
+ {
+ source = oldSource; /* Back up source pointer! */
+ target -= bytesToWrite;
+ result = targetExhausted;
+ break;
+ }
+ switch (bytesToWrite) /* note: everything falls through. */
+ {
+ case 4: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = static_cast<UTF8>(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+ * This must be called with the length pre-determined by the first byte.
+ * If not calling this from ConvertUTF8to*, then the length can be set by:
+ * length = trailingBytesForUTF8[*source]+1;
+ * and the sequence is illegal right away if there aren't that many bytes
+ * available.
+ * If presented with a length > 4, this returns false. The Unicode
+ * definition of UTF-8 goes up to 4-byte sequences.
+ */
+
+static bool isLegalUTF8(const UTF8 *source, int length)
+{
+ const UTF8 *srcptr = source + length;
+ UTF8 a;
+ switch (length)
+ {
+ default: return false;
+ /* Everything else falls through when "true"... */
+ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+ case 2: if ((a = (*--srcptr)) > 0xBF) return false;
+
+ switch (*source)
+ {
+ /* no fall-through in this inner switch */
+ case 0xE0: if (a < 0xA0) return false; break;
+ case 0xED: if (a > 0x9F) return false; break;
+ case 0xF0: if (a < 0x90) return false; break;
+ case 0xF4: if (a > 0x8F) return false; break;
+ default: if (a < 0x80) return false;
+ }
+
+ case 1: if (*source >= 0x80 && *source < 0xC2) return false;
+ }
+ if (*source > 0xF4)
+ return false;
+ return true;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Exported function to return whether a UTF-8 sequence is legal or not.
+ * This is not used here; it's just exported.
+ */
+bool isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
+{
+ int length = trailingBytesForUTF8[*source] + 1;
+ if (source + length > sourceEnd)
+ return false;
+ return isLegalUTF8(source, length);
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF8 *source = *sourceStart;
+ UTF16 *target = *targetStart;
+ while (source < sourceEnd)
+ {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd)
+ {
+ result = sourceExhausted;
+ break;
+ }
+ /* Do this check whether lenient or strict */
+ if (!isLegalUTF8(source, extraBytesToRead + 1))
+ {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead)
+ {
+ case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+ case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd)
+ {
+ source -= extraBytesToRead + 1; /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ if (ch <= UNI_MAX_BMP) /* Target is a character <= 0xFFFF */
+ {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
+ {
+ if (flags == strictConversion)
+ {
+ source -= extraBytesToRead + 1; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ else
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ else
+ *target++ = static_cast<UTF16>(ch); /* normal case */
+ }
+ else if (ch > UNI_MAX_UTF16)
+ {
+ if (flags == strictConversion)
+ {
+ result = sourceIllegal;
+ source -= extraBytesToRead + 1; /* return to the start */
+ break; /* Bail out; shouldn't continue */
+ }
+ else
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ else
+ {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd)
+ {
+ source -= extraBytesToRead + 1; /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ ch -= halfBase;
+ *target++ = static_cast<UTF16>((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = static_cast<UTF16>((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF32 *source = *sourceStart;
+ UTF8 *target = *targetStart;
+ while (source < sourceEnd)
+ {
+ const UTF32 byteMask = 0xBF, byteMark = 0x80;
+ UTF32 ch = *source++;
+ if (flags == strictConversion)
+ {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
+ {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /*
+ * Figure out how many bytes the result will require. Turn any
+ * illegally large UTF32 things (> Plane 17) into replacement chars.
+ */
+ unsigned short bytesToWrite = 0;
+ if (ch < 0x80)
+ bytesToWrite = 1;
+ else if (ch < 0x800)
+ bytesToWrite = 2;
+ else if (ch < 0x10000)
+ bytesToWrite = 3;
+ else if (ch <= UNI_MAX_LEGAL_UTF32)
+ bytesToWrite = 4;
+ else
+ {
+ bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ result = sourceIllegal;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd)
+ {
+ --source; /* Back up source pointer! */
+ target -= bytesToWrite;
+ result = targetExhausted;
+ break;
+ }
+ switch (bytesToWrite) /* note: everything falls through. */
+ {
+ case 4: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
+ case 3: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
+ case 2: *--target = static_cast<UTF8>((ch | byteMark) & byteMask); ch >>= 6;
+ case 1: *--target = static_cast<UTF8>(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF8 *source = *sourceStart;
+ UTF32 *target = *targetStart;
+ while (source < sourceEnd)
+ {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd)
+ {
+ result = sourceExhausted;
+ break;
+ }
+ /* Do this check whether lenient or strict */
+ if (!isLegalUTF8(source, extraBytesToRead + 1))
+ {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead)
+ {
+ case 5: ch += *source++; ch <<= 6;
+ case 4: ch += *source++; ch <<= 6;
+ case 3: ch += *source++; ch <<= 6;
+ case 2: ch += *source++; ch <<= 6;
+ case 1: ch += *source++; ch <<= 6;
+ case 0: ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd)
+ {
+ source -= extraBytesToRead + 1; /* Back up the source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ if (ch <= UNI_MAX_LEGAL_UTF32)
+ {
+ /*
+ * UTF-16 surrogate values are illegal in UTF-32, and anything
+ * over Plane 17 (> 0x10FFFF) is illegal.
+ */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
+ {
+ if (flags == strictConversion)
+ {
+ source -= extraBytesToRead + 1; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ else
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ else
+ *target++ = ch;
+ }
+ else /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+ {
+ result = sourceIllegal;
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* ---------------------------------------------------------------------
+
+ Note A.
+ The fall-through switches in UTF-8 reading code save a
+ temp variable, some decrements & conditionals. The switches
+ are equivalent to the following loop:
+ {
+ int tmpBytesToRead = extraBytesToRead+1;
+ do {
+ ch += *source++;
+ --tmpBytesToRead;
+ if (tmpBytesToRead) ch <<= 6;
+ } while (tmpBytesToRead > 0);
+ }
+ In UTF-8 writing code, the switches on "bytesToWrite" are
+ similarly unrolled loops.
+
+ --------------------------------------------------------------------- */
+
--- /dev/null
+++ b/src/in_xsf_framework/ConvertUTF.h
@@ -1,1 +1,135 @@
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Header file.
+
+ Several funtions are included here, forming a complete set of
+ conversions between the three formats. UTF-7 is not included
+ here, but is handled in a separate source file.
+
+ Each of these routines takes pointers to input buffers and output
+ buffers. The input buffers are const.
+
+ Each routine converts the text between *sourceStart and sourceEnd,
+ putting the result into the buffer between *targetStart and
+ targetEnd. Note: the end pointers are *after* the last item: e.g.
+ *(sourceEnd - 1) is the last item.
+
+ The return result indicates whether the conversion was successful,
+ and if not, whether the problem was in the source or target buffers.
+ (Only the first encountered problem is indicated.)
+
+ After the conversion, *sourceStart and *targetStart are both
+ updated to point to the end of last text successfully converted in
+ the respective buffers.
+
+ Input parameters:
+ sourceStart - pointer to a pointer to the source buffer.
+ The contents of this are modified on return so that
+ it points at the next thing to be converted.
+ targetStart - similarly, pointer to pointer to the target buffer.
+ sourceEnd, targetEnd - respectively pointers to the ends of the
+ two buffers, for overflow checking only.
+
+ These conversion functions take a ConversionFlags argument. When this
+ flag is set to strict, both irregular sequences and isolated surrogates
+ will cause an error. When the flag is set to lenient, both irregular
+ sequences and isolated surrogates are converted.
+
+ Whether the flag is strict or lenient, all illegal sequences will cause
+ an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
+ or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
+ must check for illegal sequences.
+
+ When the flag is set to lenient, characters over 0x10FFFF are converted
+ to the replacement character; otherwise (when the flag is set to strict)
+ they constitute an error.
+
+ Output parameters:
+ The value "sourceIllegal" is returned from some routines if the input
+ sequence is malformed. When "sourceIllegal" is returned, the source
+ value will point to the illegal value that caused the problem. E.g.,
+ in UTF-8 when a sequence is malformed, it points to the start of the
+ malformed sequence.
+
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Fixes & updates, Sept 2001.
+
+------------------------------------------------------------------------ */
+
+#ifndef _CONVERTUTF_H_
+#define _CONVERTUTF_H_
+
+/* ---------------------------------------------------------------------
+ The following 4 definitions are compiler-specific.
+ The C standard does not guarantee that wchar_t has at least
+ 16 bits, so wchar_t is no less portable than unsigned short!
+ All should be unsigned values to avoid sign extension during
+ bit mask & shift operations.
+------------------------------------------------------------------------ */
+
+typedef unsigned long UTF32; /* at least 32 bits */
+typedef unsigned short UTF16; /* at least 16 bits */
+typedef unsigned char UTF8; /* typically 8 bits */
+
+/* Some fundamental constants */
+static const UTF32 UNI_REPLACEMENT_CHAR = 0x0000FFFD;
+static const UTF32 UNI_MAX_BMP = 0x0000FFFF;
+static const UTF32 UNI_MAX_UTF16 = 0x0010FFFF;
+static const UTF32 UNI_MAX_UTF32 = 0x7FFFFFFF;
+static const UTF32 UNI_MAX_LEGAL_UTF32 = 0x0010FFFF;
+
+enum ConversionResult
+{
+ conversionOK, /* conversion successful */
+ sourceExhausted, /* partial character in source, but hit end */
+ targetExhausted, /* insuff. room in target for conversion */
+ sourceIllegal /* source sequence is illegal/malformed */
+};
+
+enum ConversionFlags
+{
+ strictConversion,
+ lenientConversion
+};
+
+ConversionResult ConvertUTF8toUTF16(const UTF8 **, const UTF8 *, UTF16 **, UTF16 *, ConversionFlags);
+
+ConversionResult ConvertUTF16toUTF8(const UTF16 **, const UTF16 *, UTF8 **, UTF8 *, ConversionFlags);
+
+ConversionResult ConvertUTF8toUTF32(const UTF8 **, const UTF8 *, UTF32 **, UTF32 *, ConversionFlags);
+
+ConversionResult ConvertUTF32toUTF8(const UTF32 **, const UTF32 *, UTF8 **, UTF8 *, ConversionFlags);
+
+ConversionResult ConvertUTF16toUTF32(const UTF16 **, const UTF16 *, UTF32 **, UTF32 *, ConversionFlags);
+
+ConversionResult ConvertUTF32toUTF16(const UTF32 **, const UTF32 *, UTF16 **, UTF16 *, ConversionFlags);
+
+bool isLegalUTF8Sequence(const UTF8 *, const UTF8 *);
+
+/* --------------------------------------------------------------------- */
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/DialogBuilder.cpp
@@ -1,1 +1,348 @@
-
+/*
+ * Windows Dynamic Dialog Builder framework
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ */
+
+#include "DialogBuilder.h"
+
+// Code modified from the following answer on Stack Overflow:
+// http://stackoverflow.com/a/3407254
+static inline uint32_t getNextMultipleOf4(uint32_t origNum)
+{
+ uint32_t remainder = origNum % 4;
+ if (!remainder)
+ return origNum;
+ return origNum + 4 - remainder;
+}
+
+void DialogTemplate::DialogGroup::CalculatePositions(bool doRightAndBottom)
+{
+ short x = 0, num = this->controls.empty() ? 0 : this->controls.size();
+ for (; x < num; ++x)
+ {
+ DialogControl *control = this->controls[x];
+ if (control->relativePosition.get())
+ {
+ bool valid = true;
+ if (!doRightAndBottom && control->relativePosition->type == RelativePosition::TO_PARENT)
+ {
+ switch (control->relativePosition->positionType)
+ {
+ case RelativePosition::FROM_BOTTOM:
+ case RelativePosition::FROM_BOTTOMLEFT:
+ case RelativePosition::FROM_BOTTOMRIGHT:
+ case RelativePosition::FROM_RIGHT:
+ case RelativePosition::FROM_TOPRIGHT:
+ valid = false;
+ break;
+ default:
+ break;
+ }
+ }
+ if (valid)
+ {
+ Rect<short> other = this->rect;
+ if (control->relativePosition->type == RelativePosition::TO_SIBLING)
+ {
+ short siblingsBack = dynamic_cast<const RelativePositionToSibling *>(control->relativePosition.get())->siblingsBack;
+ if (x - siblingsBack >= 0)
+ other = this->controls[x - siblingsBack]->rect;
+ }
+ control->rect.position = control->relativePosition->CalculatePosition(control->rect, other);
+ }
+ }
+ }
+}
+
+void DialogTemplate::DialogGroup::CalculateSize()
+{
+ short maxX = 0, maxY = 0, maxOtherWidth = 0, maxOtherHeight = 0;
+ for (DialogTemplate::Controls::const_iterator curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr)
+ {
+ DialogControl *control = *curr;
+
+ bool usePosition = true;
+ if (control->relativePosition.get())
+ {
+ if (control->relativePosition->type == RelativePosition::TO_PARENT)
+ {
+ switch (control->relativePosition->positionType)
+ {
+ case RelativePosition::FROM_BOTTOM:
+ case RelativePosition::FROM_BOTTOMLEFT:
+ case RelativePosition::FROM_BOTTOMRIGHT:
+ case RelativePosition::FROM_RIGHT:
+ case RelativePosition::FROM_TOPRIGHT:
+ usePosition = false;
+ /*if (control->relativePosition->relativePosition.x != -1 && control->rect.size.width + control->relativePosition->relativePosition.x > maxOtherWidth)
+ maxOtherWidth = control->rect.size.width + control->relativePosition->relativePosition.x;
+ if (control->relativePosition->relativePosition.y != -1 && control->GetControlHeight() + control->relativePosition->relativePosition.y > maxOtherHeight)
+ maxOtherHeight = control->GetControlHeight() + control->relativePosition->relativePosition.y;*/
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (usePosition)
+ {
+ if (control->rect.position.x + control->rect.size.width > maxX)
+ maxX = control->rect.position.x + control->rect.size.width;
+ if (control->rect.position.y + control->GetControlHeight() > maxY)
+ maxY = control->rect.position.y + control->GetControlHeight();
+ }
+ }
+ this->rect.size.width = (maxX - this->rect.position.x) + maxOtherWidth + 4;
+ this->rect.size.height = (maxY - this->rect.position.y) + maxOtherHeight + 7;
+}
+
+uint16_t DialogTemplate::DialogGroup::GetControlCount() const
+{
+ uint16_t count = 1;
+ for (auto curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr)
+ count += (*curr)->GetControlCount();
+ return count;
+}
+
+std::vector<uint8_t> DialogTemplate::DialogGroup::GenerateControlTemplate() const
+{
+ auto data = std::vector<uint8_t>(getNextMultipleOf4(24 + sizeof(wchar_t) * (this->groupName.length() + 1)), 0);
+
+ *reinterpret_cast<uint32_t *>(&data[0]) = WS_CHILD | WS_VISIBLE | BS_GROUPBOX | this->style;
+ *reinterpret_cast<uint32_t *>(&data[4]) = this->exstyle;
+ *reinterpret_cast<uint16_t *>(&data[8]) = this->rect.position.x;
+ *reinterpret_cast<uint16_t *>(&data[10]) = this->rect.position.y;
+ *reinterpret_cast<uint16_t *>(&data[12]) = this->rect.size.width;
+ *reinterpret_cast<uint16_t *>(&data[14]) = this->rect.size.height;
+ *reinterpret_cast<uint16_t *>(&data[16]) = static_cast<uint16_t>(this->id);
+ *reinterpret_cast<uint16_t *>(&data[18]) = 0xFFFF;
+ *reinterpret_cast<uint16_t *>(&data[20]) = 0x0080;
+ memcpy(reinterpret_cast<wchar_t *>(&data[22]), this->groupName.c_str(), this->groupName.length() * sizeof(wchar_t));
+
+ for (auto curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr)
+ {
+ auto controlData = (*curr)->GenerateControlTemplate();
+ data.insert(data.end(), controlData.begin(), controlData.end());
+ }
+
+ return data;
+}
+
+std::vector<uint8_t> DialogTemplate::DialogControlWithoutLabel::GenerateControlTemplate() const
+{
+ auto data = std::vector<uint8_t>(getNextMultipleOf4(24 + sizeof(wchar_t)), 0);
+ *reinterpret_cast<uint32_t *>(&data[0]) = WS_CHILD | WS_VISIBLE | this->style;
+ *reinterpret_cast<uint32_t *>(&data[4]) = this->exstyle;
+ *reinterpret_cast<uint16_t *>(&data[8]) = this->rect.position.x;
+ *reinterpret_cast<uint16_t *>(&data[10]) = this->rect.position.y;
+ *reinterpret_cast<uint16_t *>(&data[12]) = this->rect.size.width;
+ *reinterpret_cast<uint16_t *>(&data[14]) = this->rect.size.height;
+ *reinterpret_cast<uint16_t *>(&data[16]) = static_cast<uint16_t>(this->id);
+ *reinterpret_cast<uint16_t *>(&data[18]) = 0xFFFF;
+ *reinterpret_cast<uint16_t *>(&data[20]) = this->type;
+
+ return data;
+}
+
+std::vector<uint8_t> DialogTemplate::DialogControlWithLabel::GenerateControlTemplate() const
+{
+ auto data = std::vector<uint8_t>(getNextMultipleOf4(24 + sizeof(wchar_t) * (this->label.length() + 1)), 0);
+ *reinterpret_cast<uint32_t *>(&data[0]) = WS_CHILD | WS_VISIBLE | this->style;
+ *reinterpret_cast<uint32_t *>(&data[4]) = this->exstyle;
+ *reinterpret_cast<uint16_t *>(&data[8]) = this->rect.position.x;
+ *reinterpret_cast<uint16_t *>(&data[10]) = this->rect.position.y;
+ *reinterpret_cast<uint16_t *>(&data[12]) = this->rect.size.width;
+ *reinterpret_cast<uint16_t *>(&data[14]) = this->rect.size.height;
+ *reinterpret_cast<uint16_t *>(&data[16]) = static_cast<uint16_t>(this->id);
+ *reinterpret_cast<uint16_t *>(&data[18]) = 0xFFFF;
+ *reinterpret_cast<uint16_t *>(&data[20]) = this->type;
+ memcpy(reinterpret_cast<wchar_t *>(&data[22]), this->label.c_str(), this->label.length() * sizeof(wchar_t));
+
+ return data;
+}
+
+uint16_t DialogTemplate::GetTotalControlCount() const
+{
+ uint16_t count = 0;
+ for (auto curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr)
+ count += (*curr)->GetControlCount();
+ return count;
+}
+
+void DialogTemplate::AddGroupControl(const DialogControlBuilder<DialogGroupBuilder> &builder)
+{
+ DialogGroup *newGroup = DialogGroup::CreateControl(builder);
+ if (builder.index == -1)
+ this->controls.push_back(newGroup);
+ else
+ this->controls.insert(this->controls.begin() + builder.index, newGroup);
+}
+
+void DialogTemplate::AddEditBoxControl(const DialogControlBuilder<DialogEditBoxBuilder> &builder)
+{
+ this->AddControlToGroup(DialogEditBox::CreateControl(builder), builder);
+}
+
+void DialogTemplate::AddLabelControl(const DialogControlBuilder<DialogLabelBuilder> &builder)
+{
+ this->AddControlToGroup(DialogLabel::CreateControl(builder), builder);
+}
+
+void DialogTemplate::AddCheckBoxControl(const DialogControlBuilder<DialogCheckBoxBuilder> &builder)
+{
+ this->AddControlToGroup(DialogButton::CreateControl(builder), builder);
+}
+
+void DialogTemplate::AddButtonControl(const DialogControlBuilder<DialogButtonBuilder> &builder)
+{
+ this->AddControlToGroup(DialogButton::CreateControl(builder), builder);
+}
+
+void DialogTemplate::AddListBoxControl(const DialogControlBuilder<DialogListBoxBuilder> &builder)
+{
+ this->AddControlToGroup(DialogListBox::CreateControl(builder), builder);
+}
+
+void DialogTemplate::AddComboBoxControl(const DialogControlBuilder<DialogComboBoxBuilder> &builder)
+{
+ this->AddControlToGroup(DialogComboBox::CreateControl(builder), builder);
+}
+
+bool DialogTemplate::CalculateControlPosition(short index, bool doRightAndBottom)
+{
+ DialogControl *control = this->controls[index];
+ bool valid = true;
+ if (control->relativePosition.get())
+ {
+ if (!doRightAndBottom && control->relativePosition->type == RelativePosition::TO_PARENT)
+ {
+ switch (control->relativePosition->positionType)
+ {
+ case RelativePosition::FROM_BOTTOM:
+ case RelativePosition::FROM_BOTTOMLEFT:
+ case RelativePosition::FROM_BOTTOMRIGHT:
+ case RelativePosition::FROM_RIGHT:
+ case RelativePosition::FROM_TOPRIGHT:
+ valid = false;
+ break;
+ default:
+ break;
+ }
+ }
+ if (valid)
+ {
+ Rect<short> other = Rect<short>(Point<short>(), this->size);
+ if (control->relativePosition->type == RelativePosition::TO_SIBLING)
+ {
+ short siblingsBack = dynamic_cast<const RelativePositionToSibling *>(control->relativePosition.get())->siblingsBack;
+ if (index - siblingsBack >= 0)
+ other = this->controls[index - siblingsBack]->rect;
+ }
+ control->rect.position = control->relativePosition->CalculatePosition(control->rect, other);
+ }
+ }
+ return valid;
+}
+
+void DialogTemplate::CalculateSize()
+{
+ short maxX = 0, maxY = 0, maxOtherWidth = 0, maxOtherHeight = 0;
+ for (auto curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr)
+ {
+ DialogControl *control = *curr;
+
+ bool usePosition = true;
+ if (control->relativePosition.get())
+ {
+ if (control->relativePosition->type == RelativePosition::TO_PARENT)
+ {
+ switch (control->relativePosition->positionType)
+ {
+ case RelativePosition::FROM_BOTTOM:
+ case RelativePosition::FROM_BOTTOMLEFT:
+ case RelativePosition::FROM_BOTTOMRIGHT:
+ case RelativePosition::FROM_RIGHT:
+ case RelativePosition::FROM_TOPRIGHT:
+ usePosition = false;
+ /*if (control->relativePosition->relativePosition.x != -1 && control->rect.size.width + control->relativePosition->relativePosition.x > maxOtherWidth)
+ maxOtherWidth = control->rect.size.width + control->relativePosition->relativePosition.x;
+ if (control->relativePosition->relativePosition.y != -1 && control->GetControlHeight() + control->relativePosition->relativePosition.y > maxOtherHeight)
+ maxOtherHeight = control->GetControlHeight() + control->relativePosition->relativePosition.y;*/
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (usePosition)
+ {
+ if (control->rect.position.x + control->rect.size.width > maxX)
+ maxX = control->rect.position.x + control->rect.size.width;
+ if (control->rect.position.y + control->GetControlHeight() > maxY)
+ maxY = control->rect.position.y + control->GetControlHeight();
+ }
+ }
+ this->size.width = maxX + maxOtherWidth + 7;
+ this->size.height = maxY + maxOtherHeight + 7;
+}
+
+void DialogTemplate::AutoSize()
+{
+ // Step 1: Calculate positions of dialog controls (only if the controls's position is relative to a sibling or if it's relativeness to the parent is from the top, left, or top left)
+ short x = 0, num = this->controls.empty() ? 0 : this->controls.size(), maxGroupWidth = 0;
+ for (; x < num; ++x)
+ {
+ DialogControl *control = this->controls[x];
+ bool valid = this->CalculateControlPosition(x, false);
+ if (valid && control->controlType == GROUP_CONTROL)
+ {
+ dynamic_cast<DialogGroup *>(control)->CalculatePositions(false);
+ // Techically step 2, but calculate the size of the group
+ dynamic_cast<DialogGroup *>(control)->CalculateSize();
+ if (control->rect.size.width > maxGroupWidth)
+ maxGroupWidth = control->rect.size.width;
+ }
+ }
+ // Step 2: Resize all group controls to be the same width, and then within the group, recalculate positions for all controls
+ for (x = 0; x < num; ++x)
+ {
+ DialogControl *control = this->controls[x];
+ if (control->controlType != GROUP_CONTROL)
+ continue;
+ control->rect.size.width = maxGroupWidth;
+ dynamic_cast<DialogGroup *>(control)->CalculatePositions(true);
+ }
+ // Step 3: Resize the dialog box itself
+ this->CalculateSize();
+ // Step 4: Calculate position of all dialog controls
+ for (x = 0; x < num; ++x)
+ this->CalculateControlPosition(x, true);
+}
+
+const DLGTEMPLATE *DialogTemplate::GenerateTemplate()
+{
+ this->templateData.clear();
+ uint16_t controlCount = this->GetTotalControlCount();
+ this->templateData.resize(getNextMultipleOf4(24 + sizeof(wchar_t) * (this->title.length() + 1 + (this->fontName.empty() ? 0 : this->fontName.length() + 1))), 0);
+ *reinterpret_cast<uint32_t *>(&this->templateData[0]) = this->style | (this->fontName.empty() ? 0 : DS_SETFONT);
+ *reinterpret_cast<uint32_t *>(&this->templateData[4]) = this->exstyle;
+ *reinterpret_cast<uint16_t *>(&this->templateData[8]) = controlCount;
+ *reinterpret_cast<uint16_t *>(&this->templateData[14]) = this->size.width;
+ *reinterpret_cast<uint16_t *>(&this->templateData[16]) = this->size.height;
+ memcpy(reinterpret_cast<wchar_t *>(&this->templateData[22]), this->title.c_str(), this->title.length() * sizeof(wchar_t));
+ if (!this->fontName.empty())
+ {
+ *reinterpret_cast<uint16_t *>(&this->templateData[22 + sizeof(wchar_t) * (this->title.length() + 1)]) = this->fontSizeInPts;
+ memcpy(reinterpret_cast<wchar_t *>(&this->templateData[24 + sizeof(wchar_t) * (this->title.length() + 1)]), this->fontName.c_str(), this->fontName.length() * sizeof(wchar_t));
+ }
+
+ for (auto curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr)
+ {
+ auto controlData = (*curr)->GenerateControlTemplate();
+ this->templateData.insert(this->templateData.end(), controlData.begin(), controlData.end());
+ }
+
+ return reinterpret_cast<const DLGTEMPLATE *>(&this->templateData[0]);
+}
+
--- /dev/null
+++ b/src/in_xsf_framework/DialogBuilder.h
@@ -1,1 +1,711 @@
-
+/*
+ * Windows Dynamic Dialog Builder framework
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ */
+
+#ifndef DIALOG_BUILDER_H
+#define DIALOG_BUILDER_H
+
+#include <string>
+#include <memory>
+#include <vector>
+#include <stdexcept>
+#include "pstdint.h"
+#include "windowsh_wrapper.h"
+#include "UtfConverter.h"
+
+template<typename T> struct Point
+{
+ T x, y;
+
+ Point() : x(), y() { }
+ Point(T X, T Y) : x(X), y(Y) { }
+};
+
+template<typename T> struct Size
+{
+ T width, height;
+
+ Size() : width(), height() { }
+ Size(T Width, T Height) : width(Width), height(Height) { }
+};
+
+template<typename T> struct Rect
+{
+ Point<T> position;
+ Size<T> size;
+
+ Rect() : position(), size() { }
+ Rect(Point<T> Position, Size<T> Sz) : position(Position), size(Sz) { }
+ Rect(T X, T Y, T Width, T Height) : position(X, Y), size(Width, Height) { }
+};
+
+class RelativePosition
+{
+public:
+ Point<short> relativePosition;
+ enum BaseType
+ {
+ TO_PARENT,
+ TO_SIBLING
+ } type;
+ enum PositionType
+ {
+ FROM_TOP,
+ FROM_BOTTOM,
+ FROM_LEFT,
+ FROM_RIGHT,
+ FROM_TOPLEFT,
+ FROM_BOTTOMLEFT,
+ FROM_TOPRIGHT,
+ FROM_BOTTOMRIGHT
+ } positionType;
+
+ RelativePosition(Point<short> RelPosition, BaseType Type, PositionType PosType) : relativePosition(RelPosition), type(Type), positionType(PosType) { }
+ virtual ~RelativePosition() { }
+ virtual RelativePosition *Clone() const = 0;
+ Point<short> CalculatePosition(Rect<short> child, Rect<short> other)
+ {
+ Point<short> newPosition = child.position;
+ if (this->relativePosition.y != -1)
+ {
+ if (this->positionType == FROM_TOP || this->positionType == FROM_TOPLEFT || this->positionType == FROM_TOPRIGHT)
+ newPosition.y = other.position.y + this->relativePosition.y;
+ if (this->positionType == FROM_BOTTOM || this->positionType == FROM_BOTTOMLEFT || this->positionType == FROM_BOTTOMRIGHT)
+ newPosition.y = other.position.y + other.size.height + this->relativePosition.y;
+ }
+ if (this->relativePosition.x != -1)
+ {
+ if (this->positionType == FROM_LEFT || this->positionType == FROM_TOPLEFT || this->positionType == FROM_BOTTOMLEFT)
+ newPosition.x = other.position.x + this->relativePosition.x;
+ if (this->positionType == FROM_RIGHT || this->positionType == FROM_TOPRIGHT || this->positionType == FROM_BOTTOMRIGHT)
+ newPosition.x = other.position.x + other.size.width + this->relativePosition.x;
+ }
+ return newPosition;
+ }
+};
+
+class RelativePositionToParent : public RelativePosition
+{
+public:
+ RelativePositionToParent(Point<short> RelPosition, PositionType PosType) : RelativePosition(RelPosition, TO_PARENT, PosType) { }
+ RelativePositionToParent *Clone() const { return new RelativePositionToParent(this->relativePosition, this->positionType); }
+};
+
+class RelativePositionToSibling : public RelativePosition
+{
+public:
+ short siblingsBack;
+
+ RelativePositionToSibling(Point<short> RelPosition, PositionType PosType, short SiblingsBack = 1) : RelativePosition(RelPosition, TO_SIBLING, PosType), siblingsBack(SiblingsBack) { }
+ RelativePositionToSibling *Clone() const { return new RelativePositionToSibling(this->relativePosition, this->positionType, this->siblingsBack); }
+};
+
+enum DialogControlType
+{
+ NO_CONTROL,
+ GROUP_CONTROL,
+ EDITBOX_CONTROL,
+ LABEL_CONTROL,
+ CHECKBOX_CONTROL,
+ BUTTON_CONTROL,
+ LISTBOX_CONTROL,
+ COMBOBOX_CONTROL
+};
+
+class DialogTemplate;
+
+class DialogBuilder
+{
+protected:
+ friend class DialogTemplate;
+ std::wstring title, fontName;
+ uint32_t style, exstyle;
+ uint16_t fontSizeInPts;
+ Size<short> size;
+ bool resetControls;
+public:
+ DialogBuilder() : title(L""), fontName(L""), style(0), exstyle(0), fontSizeInPts(0), size(), resetControls(false) { }
+ DialogBuilder &WithTitle(const std::wstring &Title) { this->title = Title; return *this; }
+ DialogBuilder &WithFont(const std::wstring &FontName, uint16_t FontSizeInPts) { this->fontName = FontName; this->fontSizeInPts = FontSizeInPts; return *this; }
+ DialogBuilder &WithSize(short Width, short Height) { this->size.width = Width; this->size.height = Height; return *this; }
+ DialogBuilder &WithSize(Size<short> Sz) { this->size = Sz; return *this; }
+ DialogBuilder &ResetControls(bool Reset = true) { this->resetControls = Reset; return *this; }
+ DialogBuilder &IsOverlapped() { this->style &= ~(WS_OVERLAPPED | WS_POPUP | WS_CHILD); this->style |= WS_OVERLAPPED; return *this; }
+ DialogBuilder &IsPopup() { this->style &= ~(WS_OVERLAPPED | WS_POPUP | WS_CHILD); this->style |= WS_POPUP; return *this; }
+ DialogBuilder &IsChild() { this->style &= ~(WS_OVERLAPPED | WS_POPUP | WS_CHILD); this->style |= WS_CHILD; return *this; }
+ DialogBuilder &WithBorder(bool Border = true) { if (Border) this->style |= WS_BORDER; else this->style &= ~WS_BORDER; return *this; }
+ DialogBuilder &WithDialogFrame(bool DialogFrame = true) { if (DialogFrame) this->style |= WS_DLGFRAME; else this->style &= ~WS_DLGFRAME; return *this; }
+ DialogBuilder &WithVerticalScrollbar(bool VerticalScrollbar = true) { if (VerticalScrollbar) this->style |= WS_VSCROLL; else this->style &= ~WS_VSCROLL; return *this; }
+ DialogBuilder &WithHorizontalScrollbar(bool HorizontalScrollbar = true) { if (HorizontalScrollbar) this->style |= WS_HSCROLL; else this->style &= ~WS_HSCROLL; return *this; }
+ DialogBuilder &WithSystemMenu(bool SystemMenu = true) { if (SystemMenu) this->style |= WS_SYSMENU; else this->style &= ~WS_SYSMENU; return *this; }
+ DialogBuilder &WithSizingBorder(bool SizingBorder = true) { if (SizingBorder) this->style |= WS_THICKFRAME; else this->style &= ~WS_THICKFRAME; return *this; }
+ DialogBuilder &WithMinimizeBox(bool MinimizeBox = true) { if (MinimizeBox) this->style |= WS_MINIMIZEBOX; else this->style &= ~WS_MINIMIZEBOX; return *this; }
+ DialogBuilder &WithMaximizeBox(bool MaximizeBox = true) { if (MaximizeBox) this->style |= WS_MAXIMIZEBOX; else this->style &= ~WS_MAXIMIZEBOX; return *this; }
+ DialogBuilder &WithDialogModalFrame(bool DialogModalFrame = true) { if (DialogModalFrame) this->exstyle |= WS_EX_DLGMODALFRAME; else this->exstyle &= ~WS_EX_DLGMODALFRAME; return *this; }
+#if WINVER >= 0x0400
+ DialogBuilder &WithRaisedEdge(bool RaisedEdge = true) { if (RaisedEdge) this->exstyle |= WS_EX_WINDOWEDGE; else this->exstyle &= ~WS_EX_WINDOWEDGE; return *this; }
+ DialogBuilder &WithSunkenEdge(bool SunkenEdge = true) { if (SunkenEdge) this->exstyle |= WS_EX_CLIENTEDGE; else this->exstyle &= ~WS_EX_CLIENTEDGE; return *this; }
+ DialogBuilder &WithContextHelp(bool ContextHelp = true) { if (ContextHelp) this->exstyle |= WS_EX_CONTEXTHELP; else this->exstyle &= ~WS_EX_CONTEXTHELP; return *this; }
+ DialogBuilder &IsControlWindow(bool ControlWindow = true) { if (ControlWindow) this->style |= DS_CONTROL; else this->style &= ~DS_CONTROL; return *this; }
+ DialogBuilder &IsCentered(bool Centered = true) { if (Centered) this->style |= DS_CENTER; else this->style &= ~DS_CENTER; return *this; }
+#endif
+};
+
+template<class T> class DialogControlBuilder
+{
+protected:
+ friend class DialogTemplate;
+ DialogControlType controlType;
+ uint32_t style, exstyle;
+ Rect<short> rect;
+ short id;
+ int index;
+ std::auto_ptr<RelativePosition> relativePosition;
+
+ T &me() { return dynamic_cast<T &>(*this); }
+public:
+ DialogControlBuilder(DialogControlType Type = NO_CONTROL) : controlType(Type), style(0), exstyle(0), rect(), id(-1), index(-1), relativePosition() { }
+ virtual ~DialogControlBuilder() { }
+ T &WithPosition(short X, short Y) { this->rect.position.x = X; this->rect.position.y = Y; return this->me(); }
+ T &WithPosition(Point<short> Position) { this->rect.position = Position; return this->me(); }
+ T &WithRelativePositionToParent(RelativePosition::PositionType PosType, Point<short> RelativePosition)
+ {
+ this->relativePosition.reset(new RelativePositionToParent(RelativePosition, PosType));
+ return this->me();
+ }
+ T &WithRelativePositionToSibling(RelativePosition::PositionType PosType, Point<short> RelativePosition, short SiblingsBack = 1)
+ {
+ this->relativePosition.reset(new RelativePositionToSibling(RelativePosition, PosType, SiblingsBack));
+ return this->me();
+ }
+ T &WithSize(short Width, short Height) { this->rect.size.width = Width; this->rect.size.height = Height; return this->me(); }
+ T &WithSize(Size<short> Sz) { this->rect.size = Sz; return this->me(); }
+ T &WithID(short ID) { this->id = ID; return this->me(); }
+ T &AtIndex(int Index) { this->index = Index; return this->me(); }
+ T &IsDisabled(bool Disabled = true) { if (Disabled) this->style |= WS_DISABLED; else this->style &= ~WS_DISABLED; return this->me(); }
+ T &WithBorder(bool ThinBorder = true) { if (ThinBorder) this->style |= WS_BORDER; else this->style &= ~WS_BORDER; return this->me(); }
+ T &WithVerticalScrollbar(bool VerticalScrollbar = true) { if (VerticalScrollbar) this->style |= WS_VSCROLL; else this->style &= ~WS_VSCROLL; return this->me(); }
+ T &WithHorizontalScrollbar(bool HorizontalScrollbar = true) { if (HorizontalScrollbar) this->style |= WS_HSCROLL; else this->style &= ~WS_HSCROLL; return this->me(); }
+ T &WithTabStop(bool TabStop = true) { if (TabStop) this->style |= WS_TABSTOP; else this->style &= ~WS_TABSTOP; return this->me(); }
+#if WINVER >= 0x0400
+ T &WithRaisedEdge(bool RaisedEdge = true) { if (RaisedEdge) this->exstyle |= WS_EX_WINDOWEDGE; else this->exstyle &= ~WS_EX_WINDOWEDGE; return this->me(); }
+ T &WithSunkenEdge(bool SunkenEdge = true) { if (SunkenEdge) this->exstyle |= WS_EX_CLIENTEDGE; else this->exstyle &= ~WS_EX_CLIENTEDGE; return this->me(); }
+#endif
+};
+
+class DialogGroupBuilder : public DialogControlBuilder<DialogGroupBuilder>
+{
+protected:
+ friend class DialogTemplate;
+ std::wstring groupName;
+public:
+ DialogGroupBuilder(const std::wstring &newGroupName) : DialogControlBuilder(GROUP_CONTROL), groupName(newGroupName) { }
+};
+
+template<class T> class DialogInGroupBuilder : public DialogControlBuilder<T>
+{
+protected:
+ friend class DialogTemplate;
+ std::wstring groupName;
+public:
+ DialogInGroupBuilder(DialogControlType Type) : DialogControlBuilder<T>(Type), groupName(L"") { }
+ T &InGroup(const std::wstring &GroupName) { this->groupName = GroupName; return this->me(); }
+};
+
+class DialogEditBoxBuilder : public DialogInGroupBuilder<DialogEditBoxBuilder>
+{
+protected:
+ friend class DialogTemplate;
+public:
+ DialogEditBoxBuilder() : DialogInGroupBuilder(EDITBOX_CONTROL) { }
+ DialogEditBoxBuilder &IsLeftJustified() { this->style &= ~(ES_LEFT | ES_CENTER | ES_RIGHT); this->style |= ES_LEFT; return this->me(); }
+ DialogEditBoxBuilder &IsCenterJustified() { this->style &= ~(ES_LEFT | ES_CENTER | ES_RIGHT); this->style |= ES_CENTER; return this->me(); }
+ DialogEditBoxBuilder &IsRightJustified() { this->style &= ~(ES_LEFT | ES_CENTER | ES_RIGHT); this->style |= ES_RIGHT; return this->me(); }
+ DialogEditBoxBuilder &IsMultiline(bool Multiline = true) { if (Multiline) this->style |= ES_MULTILINE; else this->style &= ~ES_MULTILINE; return this->me(); }
+ DialogEditBoxBuilder &WithAllUppercase(bool AllUppercase = true) { if (AllUppercase) this->style |= ES_UPPERCASE; else this->style &= ~ES_UPPERCASE; return this->me(); }
+ DialogEditBoxBuilder &WithAllLowercase(bool AllLowercase = true) { if (AllLowercase) this->style |= ES_LOWERCASE; else this->style &= ~ES_LOWERCASE; return this->me(); }
+ DialogEditBoxBuilder &IsPasswordInput(bool PasswordInput = true) { if (PasswordInput) this->style |= ES_PASSWORD; else this->style &= ~ES_PASSWORD; return this->me(); }
+ DialogEditBoxBuilder &WithAutoVScroll(bool AutoVScroll = true) { if (AutoVScroll) this->style |= ES_AUTOVSCROLL; else this->style &= ~ES_AUTOVSCROLL; return this->me(); }
+ DialogEditBoxBuilder &WithAutoHScroll(bool AutoHScroll = true) { if (AutoHScroll) this->style |= ES_AUTOHSCROLL; else this->style &= ~ES_AUTOHSCROLL; return this->me(); }
+ DialogEditBoxBuilder &WithDontHideSelection(bool DontHideSelection = true) { if (DontHideSelection) this->style |= ES_NOHIDESEL; else this->style &= ~ES_NOHIDESEL; return this->me(); }
+ DialogEditBoxBuilder &IsReadOnly(bool ReadOnly = true) { if (ReadOnly) this->style |= ES_READONLY; else this->style &= ~ES_READONLY; return this->me(); }
+ DialogEditBoxBuilder &WithWantReturn(bool WantReturn = true) { if (WantReturn) this->style |= ES_WANTRETURN; else this->style &= ~ES_WANTRETURN; return this->me(); }
+};
+
+template<class T> class DialogControlWithLabelBuilder : public DialogInGroupBuilder<T>
+{
+protected:
+ friend class DialogTemplate;
+ std::wstring label;
+public:
+ DialogControlWithLabelBuilder(DialogControlType Type, const std::wstring &Label) : DialogInGroupBuilder<T>(Type), label(Label) { }
+};
+
+class DialogLabelBuilder : public DialogControlWithLabelBuilder<DialogLabelBuilder>
+{
+protected:
+ friend class DialogTemplate;
+public:
+ DialogLabelBuilder(const std::wstring &Label) : DialogControlWithLabelBuilder(LABEL_CONTROL, Label) { }
+ DialogLabelBuilder &IsLeftJustified(bool WithWordWrap = false)
+ {
+ this->style &= ~(SS_LEFT | SS_CENTER | SS_RIGHT | SS_LEFTNOWORDWRAP);
+ if (WithWordWrap)
+ this->style |= SS_LEFTNOWORDWRAP;
+ else
+ this->style |= SS_LEFT;
+ return this->me();
+ }
+ DialogLabelBuilder &IsCenterJustified() { this->style &= ~(SS_LEFT | SS_CENTER | SS_RIGHT | SS_LEFTNOWORDWRAP); this->style |= SS_CENTER; return this->me(); }
+ DialogLabelBuilder &IsRightJustified() { this->style &= ~(SS_LEFT | SS_CENTER | SS_RIGHT | SS_LEFTNOWORDWRAP); this->style |= SS_RIGHT; return this->me(); }
+ DialogLabelBuilder &WithAmpsNotTranslated(bool AmpsNotTranslated = true) { if (AmpsNotTranslated) this->style |= SS_NOPREFIX; else this->style &= ~SS_NOPREFIX; return this->me(); }
+#if WINVER >= 0x0400
+ DialogLabelBuilder &WithNotify(bool Notify = true) { if (Notify) this->style |= SS_NOTIFY; else this->style &= ~SS_NOTIFY; return this->me(); }
+#endif
+};
+
+template<class T> class DialogButtonBaseBuilder : public DialogControlWithLabelBuilder<T>
+{
+protected:
+ friend class DialogTemplate;
+public:
+ DialogButtonBaseBuilder(DialogControlType Type, const std::wstring &Label) : DialogControlWithLabelBuilder<T>(Type, Label) { }
+#if WINVER >= 0x0400
+ T &IsLeftJustified(bool LeftJustified = true)
+ {
+ if (LeftJustified)
+ {
+ this->style |= BS_LEFT;
+ this->style &= ~BS_RIGHT;
+ }
+ else
+ this->style &= ~BS_LEFT;
+ return this->me();
+ }
+ T &IsRightJustified(bool RightJustified = true)
+ {
+ if (RightJustified)
+ {
+ this->style |= BS_RIGHT;
+ this->style &= ~BS_LEFT;
+ }
+ else
+ this->style &= ~BS_RIGHT;
+ return this->me();
+ }
+ T &IsCenterJustified(bool CenterJustified = true) { if (CenterJustified) this->style |= BS_CENTER; else this->style &= ~BS_CENTER; return this->me(); }
+ T &WithVerticalTop(bool VerticalTop = true)
+ {
+ if (VerticalTop)
+ {
+ this->style |= BS_TOP;
+ this->style &= ~BS_BOTTOM;
+ }
+ else
+ this->style &= ~BS_TOP;
+ return this->me();
+ }
+ T &WithVerticalBottom(bool VerticalBottom = true)
+ {
+ if (VerticalBottom)
+ {
+ this->style |= BS_BOTTOM;
+ this->style &= ~BS_TOP;
+ }
+ else
+ this->style &= ~BS_BOTTOM;
+ return this->me();
+ }
+ T &WithVerticalCenter(bool VerticalCenter = true) { if (VerticalCenter) this->style |= BS_VCENTER; else this->style &= ~BS_VCENTER; return this->me(); }
+ T &IsMultiline(bool Multiline = true) { if (Multiline) this->style |= BS_MULTILINE; else this->style &= ~BS_MULTILINE; return this->me(); }
+ T &WithNotify(bool Notify = true) { if (Notify) this->style |= BS_NOTIFY; else this->style &= ~BS_NOTIFY; return this->me(); }
+ T &IsFlat(bool Flat = true) { if (Flat) this->style |= BS_FLAT; else this->style &= ~BS_FLAT; return this->me(); }
+#endif
+};
+
+class DialogButtonBuilder : public DialogButtonBaseBuilder<DialogButtonBuilder>
+{
+protected:
+ friend class DialogTemplate;
+public:
+ DialogButtonBuilder(const std::wstring &Label) : DialogButtonBaseBuilder(BUTTON_CONTROL, Label) { }
+ DialogButtonBuilder &IsDefault(bool Default = true) { if (Default) this->style |= BS_DEFPUSHBUTTON; else this->style &= ~BS_DEFPUSHBUTTON; return this->me(); }
+};
+
+class DialogCheckBoxBuilder : public DialogButtonBaseBuilder<DialogCheckBoxBuilder>
+{
+protected:
+ friend class DialogTemplate;
+public:
+ DialogCheckBoxBuilder(const std::wstring &Label) : DialogButtonBaseBuilder(CHECKBOX_CONTROL, Label) { this->style |= BS_AUTOCHECKBOX; }
+ DialogCheckBoxBuilder &WithTextOnLeft(bool TextOnLeft = true) { if (TextOnLeft) this->style |= BS_LEFTTEXT; else this->style &= ~BS_LEFTTEXT; return this->me(); }
+ DialogCheckBoxBuilder &LikePushButton(bool PushButton = true) { if (PushButton) this->style |= BS_PUSHLIKE; else this->style &= ~BS_PUSHLIKE; return this->me(); }
+};
+
+class DialogListBoxBuilder : public DialogInGroupBuilder<DialogListBoxBuilder>
+{
+protected:
+ friend class DialogTemplate;
+public:
+ DialogListBoxBuilder() : DialogInGroupBuilder(LISTBOX_CONTROL) { }
+ DialogListBoxBuilder &WithNotify(bool Notify = true) { if (Notify) this->style |= LBS_NOTIFY; else this->style &= ~LBS_NOTIFY; return this->me(); }
+ DialogListBoxBuilder &WithSort(bool Sort = true) { if (Sort) this->style |= LBS_SORT; else this->style &= ~LBS_SORT; return this->me(); }
+ DialogListBoxBuilder &WithMultipleSelect(bool MultipleSelect = true) { if (MultipleSelect) this->style |= LBS_MULTIPLESEL; else this->style &= ~LBS_MULTIPLESEL; return this->me(); }
+ DialogListBoxBuilder &WithExactHeight(bool ExactHeight = true) { if (ExactHeight) this->style |= LBS_NOINTEGRALHEIGHT; else this->style &= ~LBS_NOINTEGRALHEIGHT; return this->me(); }
+ DialogListBoxBuilder &WithMultipleColumns(bool MultipleColumns = true) { if (MultipleColumns) this->style |= LBS_MULTICOLUMN; else this->style &= ~LBS_MULTICOLUMN; return this->me(); }
+ DialogListBoxBuilder &WithExtendedSelect(bool ExtendedSelect = true) { if (ExtendedSelect) this->style |= LBS_EXTENDEDSEL; else this->style &= ~LBS_EXTENDEDSEL; return this->me(); }
+ DialogListBoxBuilder &WithDisabledNoScroll(bool DisabledNoScroll = true) { if (DisabledNoScroll) this->style |= LBS_DISABLENOSCROLL; else this->style &= ~LBS_DISABLENOSCROLL; return this->me(); }
+#if WINVER >= 0x0400
+ DialogListBoxBuilder &WithNoSelect(bool NoSelect = true) { if (NoSelect) this->style |= LBS_NOSEL; else this->style &= ~LBS_NOSEL; return this->me(); }
+#endif
+};
+
+class DialogComboBoxBuilder : public DialogInGroupBuilder<DialogComboBoxBuilder>
+{
+protected:
+ friend class DialogTemplate;
+public:
+ DialogComboBoxBuilder() : DialogInGroupBuilder(COMBOBOX_CONTROL) { }
+ DialogComboBoxBuilder &IsSimple() { this->style &= ~(CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST); this->style |= CBS_SIMPLE; return this->me(); }
+ DialogComboBoxBuilder &IsDropDown() { this->style &= ~(CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST); this->style |= CBS_DROPDOWN; return this->me(); }
+ DialogComboBoxBuilder &IsDropDownList() { this->style &= ~(CBS_SIMPLE | CBS_DROPDOWN | CBS_DROPDOWNLIST); this->style |= CBS_DROPDOWNLIST; return this->me(); }
+ DialogComboBoxBuilder &WithAutoHScroll(bool AutoHScroll = true) { if (AutoHScroll) this->style |= CBS_AUTOHSCROLL; else this->style &= ~CBS_AUTOHSCROLL; return this->me(); }
+ DialogComboBoxBuilder &WithSort(bool Sort = true) { if (Sort) this->style |= CBS_SORT; else this->style &= ~CBS_SORT; return this->me(); }
+ DialogComboBoxBuilder &WithExactHeight(bool ExactHeight = true) { if (ExactHeight) this->style |= CBS_NOINTEGRALHEIGHT; else this->style &= ~CBS_NOINTEGRALHEIGHT; return this->me(); }
+ DialogComboBoxBuilder &WithDisabledNoScroll(bool DisabledNoScroll = true) { if (DisabledNoScroll) this->style |= CBS_DISABLENOSCROLL; else this->style &= ~CBS_DISABLENOSCROLL; return this->me(); }
+#if WINVER >= 0x0400
+ DialogComboBoxBuilder &WithAllLowercase(bool AllLowercase = true) { if (AllLowercase) this->style |= CBS_LOWERCASE; else this->style &= ~CBS_LOWERCASE; return this->me(); }
+ DialogComboBoxBuilder &WithAllUppercase(bool AllUppercase = true) { if (AllUppercase) this->style |= CBS_UPPERCASE; else this->style &= ~CBS_UPPERCASE; return this->me(); }
+#endif
+};
+
+class DialogTemplate
+{
+ class DialogControl;
+
+ typedef std::vector<DialogControl *> Controls;
+
+ class DialogControl
+ {
+ protected:
+ DialogControlType controlType;
+ uint32_t style, exstyle;
+ Rect<short> rect;
+ short id;
+ std::auto_ptr<RelativePosition> relativePosition;
+
+ friend class DialogTemplate;
+ DialogControl() : controlType(NO_CONTROL), style(0), exstyle(0), rect(), id(-1), relativePosition() { }
+ DialogControl(const DialogControl &control) : controlType(control.controlType), style(control.style), exstyle(control.exstyle), rect(control.rect), id(control.id),
+ relativePosition(control.relativePosition.get() ? control.relativePosition->Clone() : NULL) { }
+ DialogControl &operator=(const DialogControl &control)
+ {
+ this->controlType = control.controlType;
+ this->style = control.style;
+ this->exstyle = control.exstyle;
+ this->rect = control.rect;
+ this->id = control.id;
+ if (control.relativePosition.get())
+ this->relativePosition.reset(control.relativePosition->Clone());
+ else
+ this->relativePosition.reset();
+
+ return *this;
+ }
+ public:
+ virtual ~DialogControl() { }
+ template<typename Control, typename Builder> static Control *CreateControl(const DialogControlBuilder<Builder> &builder)
+ {
+ Control *control = new Control();
+
+ control->controlType = builder.controlType;
+ control->style = builder.style;
+ control->exstyle = builder.exstyle;
+ control->rect = builder.rect;
+ control->id = builder.id;
+ if (builder.relativePosition.get())
+ control->relativePosition.reset(builder.relativePosition->Clone());
+
+ return control;
+ }
+ virtual uint16_t GetControlCount() const { return 1; }
+ virtual short GetControlHeight() const { return this->rect.size.height; }
+ virtual std::vector<uint8_t> GenerateControlTemplate() const = 0;
+ virtual DialogControl *Clone() const = 0;
+ };
+
+ class DialogGroup : public DialogControl
+ {
+ protected:
+ DialogTemplate::Controls controls;
+ std::wstring groupName;
+
+ friend class DialogTemplate;
+ friend class DialogControl;
+ DialogGroup() : DialogControl(), controls(), groupName(L"") { }
+ DialogGroup(const DialogGroup &control) : DialogControl(control), controls(), groupName(control.groupName)
+ {
+ for (auto curr = control.controls.begin(), end = control.controls.end(); curr != end; ++curr)
+ this->controls.push_back((*curr)->Clone());
+ }
+ DialogGroup &operator=(const DialogGroup &control)
+ {
+ DialogControl::operator=(control);
+
+ if (!this->controls.empty())
+ this->ClearControls();
+ for (auto curr = control.controls.begin(), end = control.controls.end(); curr != end; ++curr)
+ this->controls.push_back((*curr)->Clone());
+
+ return *this;
+ }
+ void ClearControls()
+ {
+ for (auto curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr)
+ delete *curr;
+ }
+ public:
+ ~DialogGroup() { this->ClearControls(); }
+ static DialogGroup *CreateControl(const DialogControlBuilder<DialogGroupBuilder> &builder)
+ {
+ DialogGroup *control = DialogControl::CreateControl<DialogGroup>(builder);
+
+ control->groupName = dynamic_cast<const DialogGroupBuilder &>(builder).groupName;
+
+ return control;
+ }
+ void CalculatePositions(bool doRightAndBottom = false);
+ void CalculateSize();
+ uint16_t GetControlCount() const;
+ std::vector<uint8_t> GenerateControlTemplate() const;
+ DialogGroup *Clone() const { return new DialogGroup(*this); }
+ };
+
+ class DialogControlWithoutLabel : public DialogControl
+ {
+ protected:
+ uint16_t type;
+
+ friend class DialogTemplate;
+ friend class DialogControl;
+ DialogControlWithoutLabel() : DialogControl(), type(0) { }
+ DialogControlWithoutLabel(const DialogControlWithoutLabel &control) : DialogControl(control), type(control.type) { }
+ DialogControlWithoutLabel &operator=(const DialogControlWithoutLabel &control)
+ {
+ DialogControl::operator=(control);
+
+ this->type = control.type;
+
+ return *this;
+ }
+ public:
+ template<typename Control, typename Builder> static Control *CreateControl(const DialogControlBuilder<Builder> &builder, uint16_t Type)
+ {
+ Control *control = DialogControl::CreateControl<Control>(builder);
+
+ control->type = Type;
+
+ return control;
+ }
+ virtual std::vector<uint8_t> GenerateControlTemplate() const;
+ virtual DialogControlWithoutLabel *Clone() const { return new DialogControlWithoutLabel(*this); }
+ };
+
+ class DialogControlWithLabel : public DialogControl
+ {
+ protected:
+ uint16_t type;
+ std::wstring label;
+
+ friend class DialogTemplate;
+ friend class DialogControl;
+ DialogControlWithLabel() : DialogControl(), type(0), label(L"") { }
+ DialogControlWithLabel(const DialogControlWithLabel &control) : DialogControl(control), type(control.type), label(control.label) { }
+ DialogControlWithLabel &operator=(const DialogControlWithLabel &control)
+ {
+ DialogControl::operator=(control);
+
+ this->type = control.type;
+ this->label = control.label;
+
+ return *this;
+ }
+ public:
+ template<typename Control, typename Builder> static Control *CreateControl(const DialogControlBuilder<Builder> &builder, uint16_t Type)
+ {
+ Control *control = DialogControl::CreateControl<Control>(builder);
+
+ control->type = Type;
+ control->label = dynamic_cast<const DialogControlWithLabelBuilder<Builder> &>(builder).label;
+
+ return control;
+ }
+ virtual std::vector<uint8_t> GenerateControlTemplate() const;
+ virtual DialogControlWithLabel *Clone() const { return new DialogControlWithLabel(*this); }
+ };
+
+ class DialogEditBox : public DialogControlWithoutLabel
+ {
+ protected:
+ friend class DialogTemplate;
+ friend class DialogControl;
+ DialogEditBox() : DialogControlWithoutLabel() { }
+ public:
+ static DialogEditBox *CreateControl(const DialogControlBuilder<DialogEditBoxBuilder> &builder)
+ {
+ return DialogControlWithoutLabel::CreateControl<DialogEditBox>(builder, 0x0081);
+ }
+ };
+
+ class DialogLabel : public DialogControlWithLabel
+ {
+ protected:
+ friend class DialogTemplate;
+ friend class DialogControl;
+ DialogLabel() : DialogControlWithLabel() { }
+ public:
+ static DialogLabel *CreateControl(const DialogControlBuilder<DialogLabelBuilder> &builder)
+ {
+ return DialogControlWithLabel::CreateControl<DialogLabel>(builder, 0x0082);
+ }
+ };
+
+ class DialogButton : public DialogControlWithLabel
+ {
+ protected:
+ friend class DialogTemplate;
+ friend class DialogControl;
+ DialogButton() : DialogControlWithLabel() { }
+ public:
+ template<typename Builder> static DialogButton *CreateControl(const DialogControlBuilder<Builder> &builder)
+ {
+ return DialogControlWithLabel::CreateControl<DialogButton>(builder, 0x0080);
+ }
+ };
+
+ class DialogListBox : public DialogControlWithoutLabel
+ {
+ protected:
+ friend class DialogTemplate;
+ friend class DialogControl;
+ DialogListBox() : DialogControlWithoutLabel() { }
+ public:
+ static DialogListBox *CreateControl(const DialogControlBuilder<DialogListBoxBuilder> &builder)
+ {
+ return DialogControlWithoutLabel::CreateControl<DialogListBox>(builder, 0x0083);
+ }
+ };
+
+ class DialogComboBox : public DialogControlWithoutLabel
+ {
+ protected:
+ friend class DialogTemplate;
+ friend class DialogControl;
+ DialogComboBox() : DialogControlWithoutLabel() { }
+ public:
+ static DialogComboBox *CreateControl(const DialogControlBuilder<DialogComboBoxBuilder> &builder)
+ {
+ return DialogControlWithoutLabel::CreateControl<DialogComboBox>(builder, 0x0085);
+ }
+ short GetControlHeight() const { return (this->style & CBS_SIMPLE && !(this->style & CBS_DROPDOWNLIST)) ? this->rect.size.height : 14; }
+ };
+
+ std::wstring title;
+ uint32_t style, exstyle;
+ std::wstring fontName;
+ uint16_t fontSizeInPts;
+ Size<short> size;
+ Controls controls;
+ std::vector<uint8_t> templateData;
+
+ template<typename Builder> void AddControlToGroup(DialogControl *control, const DialogControlBuilder<Builder> &builder)
+ {
+ const DialogInGroupBuilder<Builder> &groupBuilder = dynamic_cast<const DialogInGroupBuilder<Builder> &>(builder);
+ if (groupBuilder.groupName.empty())
+ {
+ if (builder.index == -1)
+ this->controls.push_back(control);
+ else
+ this->controls.insert(this->controls.begin() + builder.index, control);
+ }
+ else
+ {
+ for (DialogTemplate::Controls::iterator curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr)
+ {
+ if ((*curr)->controlType != GROUP_CONTROL)
+ continue;
+ DialogGroup *group = dynamic_cast<DialogGroup *>(*curr);
+ if (group->groupName == groupBuilder.groupName)
+ {
+ if (builder.index == -1)
+ group->controls.push_back(control);
+ else
+ group->controls.insert(group->controls.begin() + builder.index, control);
+ return;
+ }
+ }
+ throw std::runtime_error("Group " + UtfConverter::ToUtf8(groupBuilder.groupName) + " was not found.");
+ }
+ }
+ uint16_t GetTotalControlCount() const;
+ bool CalculateControlPosition(short index, bool doRightAndBottom = false);
+ void CalculateSize();
+ void ClearControls()
+ {
+ for (auto curr = this->controls.begin(), end = this->controls.end(); curr != end; ++curr)
+ delete *curr;
+ }
+public:
+ DialogTemplate() : title(L""), style(0), exstyle(0), fontName(L""), fontSizeInPts(0), size(), controls(), templateData() { }
+ DialogTemplate(const DialogBuilder &builder) : title(builder.title), style(builder.style), exstyle(builder.exstyle), fontName(builder.fontName), fontSizeInPts(builder.fontSizeInPts),
+ size(builder.size), controls(), templateData() { }
+ DialogTemplate(const DialogTemplate &dlg) : title(dlg.title), style(dlg.style), exstyle(dlg.style), fontName(dlg.fontName), fontSizeInPts(dlg.fontSizeInPts), size(dlg.size),
+ controls(), templateData()
+ {
+ for (auto curr = dlg.controls.begin(), end = dlg.controls.end(); curr != end; ++curr)
+ this->controls.push_back((*curr)->Clone());
+ }
+ DialogTemplate &operator=(const DialogBuilder &builder)
+ {
+ this->title = builder.title;
+ this->style = builder.style;
+ this->exstyle = builder.exstyle;
+ this->fontName = builder.fontName;
+ this->fontSizeInPts = builder.fontSizeInPts;
+ this->size = builder.size;
+ if (builder.resetControls && !this->controls.empty())
+ this->ClearControls();
+
+ return *this;
+ }
+ DialogTemplate &operator=(const DialogTemplate &dlg)
+ {
+ this->title = dlg.title;
+ this->style = dlg.style;
+ this->exstyle = dlg.exstyle;
+ this->fontName = dlg.fontName;
+ this->fontSizeInPts = dlg.fontSizeInPts;
+ this->size = dlg.size;
+ if (!this->controls.empty())
+ this->ClearControls();
+ for (auto curr = dlg.controls.begin(), end = dlg.controls.end(); curr != end; ++curr)
+ this->controls.push_back((*curr)->Clone());
+
+ return *this;
+ }
+ ~DialogTemplate() { this->ClearControls(); }
+ void AddGroupControl(const DialogControlBuilder<DialogGroupBuilder> &builder);
+ void AddEditBoxControl(const DialogControlBuilder<DialogEditBoxBuilder> &builder);
+ void AddLabelControl(const DialogControlBuilder<DialogLabelBuilder> &builder);
+ void AddCheckBoxControl(const DialogControlBuilder<DialogCheckBoxBuilder> &builder);
+ void AddButtonControl(const DialogControlBuilder<DialogButtonBuilder> &builder);
+ void AddListBoxControl(const DialogControlBuilder<DialogListBoxBuilder> &builder);
+ void AddComboBoxControl(const DialogControlBuilder<DialogComboBoxBuilder> &builder);
+ void AutoSize();
+ const DLGTEMPLATE *GenerateTemplate();
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/TagList.cpp
@@ -1,1 +1,66 @@
+/*
+ * xSF Tag List
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Storage of tags from PSF-style files, specifications found at
+ * http://wiki.neillcorlett.com/PSFTagFormat
+ */
+#include <algorithm>
+#include "TagList.h"
+
+eq_str TagList::eqstr;
+
+auto TagList::GetKeys() const -> const TagsList &
+{
+ return this->tagsOrder;
+}
+
+auto TagList::GetTags() const -> TagsList
+{
+ TagsList allTags;
+ for (auto curr = this->tagsOrder.begin(), end = this->tagsOrder.end(); curr != end; ++curr)
+ allTags.push_back(*curr + "=" + this->tags.find(*curr)->second);
+ return allTags;
+}
+
+bool TagList::Exists(const std::string &name) const
+{
+ return std::find_if(this->tagsOrder.begin(), this->tagsOrder.end(), std::bind2nd(TagList::eqstr, name)) != this->tagsOrder.end();
+}
+
+std::string TagList::operator[](const std::string &name) const
+{
+ auto tag = this->tags.find(name);
+ if (tag == this->tags.end())
+ return "";
+ return tag->second;
+}
+
+std::string &TagList::operator[](const std::string &name)
+{
+ auto tag = std::find_if(this->tagsOrder.begin(), this->tagsOrder.end(), std::bind2nd(TagList::eqstr, name));
+ if (tag == this->tagsOrder.end())
+ {
+ this->tagsOrder.push_back(name);
+ this->tags[name] = "";
+ }
+ return this->tags[name];
+}
+
+void TagList::Remove(const std::string &name)
+{
+ auto tagOrder = std::find_if(this->tagsOrder.begin(), this->tagsOrder.end(), std::bind2nd(TagList::eqstr, name));
+ if (tagOrder != this->tagsOrder.end())
+ this->tagsOrder.erase(tagOrder);
+ if (this->tags.count(name))
+ this->tags.erase(name);
+}
+
+void TagList::Clear()
+{
+ this->tagsOrder.clear();
+ this->tags.clear();
+}
+
--- /dev/null
+++ b/src/in_xsf_framework/TagList.h
@@ -1,1 +1,40 @@
+/*
+ * xSF Tag List
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Storage of tags from PSF-style files, specifications found at
+ * http://wiki.neillcorlett.com/PSFTagFormat
+ */
+#ifndef TAGLIST_H
+#define TAGLIST_H
+
+#include <map>
+#include <vector>
+#include "eqstr.h"
+#include "ltstr.h"
+
+class TagList
+{
+public:
+ typedef std::map<std::string, std::string, lt_str> Tags;
+ typedef std::vector<std::string> TagsList;
+private:
+ static eq_str eqstr;
+
+ Tags tags;
+ TagsList tagsOrder;
+public:
+ TagList() : tags(), tagsOrder() { }
+ const TagsList &GetKeys() const;
+ TagsList GetTags() const;
+ bool Exists(const std::string &name) const;
+ std::string operator[](const std::string &name) const;
+ std::string &operator[](const std::string &name);
+ void Remove(const std::string &name);
+ void Clear();
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/UTFEncodeDecode.cpp
@@ -1,1 +1,30 @@
+// original code is from here: http://www.codeproject.com/Tips/197097/Converting-ANSI-to-Unicode-and-back
+// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx
+#include "UTFEncodeDecode.h"
+#include "UtfConverter.h"
+
+std::string EncodeToUTF8(const std::string &source, const std::locale &L)
+{
+ try
+ {
+ return UtfConverter::ToUtf8(cp_converter<>(L).widen(source));
+ }
+ catch (const std::runtime_error &)
+ {
+ return "";
+ }
+}
+
+std::string DecodeFromUTF8(const std::string &source, const std::locale &L)
+{
+ try
+ {
+ return cp_converter<>(L).narrow(UtfConverter::FromUtf8(source));
+ }
+ catch (const std::runtime_error &)
+ {
+ return "";
+ }
+}
+
--- /dev/null
+++ b/src/in_xsf_framework/UTFEncodeDecode.h
@@ -1,1 +1,64 @@
+// original code is from here: http://www.codeproject.com/Tips/197097/Converting-ANSI-to-Unicode-and-back
+// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx
+#ifndef UTFENCODEDECODE_H
+#define UTFENCODEDECODE_H
+
+#include <string>
+#include <locale>
+#include <sstream>
+#include <stdexcept>
+
+std::string EncodeToUTF8(const std::string &, const std::locale & = std::locale::classic());
+std::string DecodeFromUTF8(const std::string &, const std::locale & = std::locale::classic());
+
+template<size_t buf_size = 100> class cp_converter
+{
+ const std::locale loc;
+public:
+ cp_converter(const std::locale &L = std::locale::classic()) : loc(L) { }
+ inline std::wstring widen(const std::string &in)
+ {
+ return this->convert<char, wchar_t>(in);
+ }
+ inline std::string narrow(const std::wstring &in)
+ {
+ return this->convert<wchar_t, char>(in);
+ }
+private:
+ typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_facet;
+
+ // widen
+ inline codecvt_facet::result cv(const codecvt_facet &facet, mbstate_t &s, const char *f1, const char *l1, const char *&n1, wchar_t *f2, wchar_t *l2, wchar_t *&n2) const
+ {
+ return facet.in(s, f1, l1, n1, f2, l2, n2);
+ }
+
+ // narrow
+ inline codecvt_facet::result cv(const codecvt_facet &facet, mbstate_t &s, const wchar_t *f1, const wchar_t *l1, const wchar_t *&n1, char *f2, char *l2, char *&n2) const
+ {
+ return facet.out(s, f1, l1, n1, f2, l2, n2);
+ }
+
+ template<class ct_in, class ct_out> std::basic_string<ct_out> convert(const std::basic_string<ct_in> &in)
+ {
+ auto &facet = std::use_facet<codecvt_facet>(this->loc);
+ std::basic_stringstream<ct_out> os;
+ ct_out buf[buf_size];
+ mbstate_t state = {0};
+ codecvt_facet::result result;
+ const ct_in *ipc = &in[0];
+ do
+ {
+ ct_out *opc = NULL;
+ result = this->cv(facet, state, ipc, &in[0] + in.length(), ipc, buf, buf + buf_size, opc);
+ os << std::basic_string<ct_out>(buf, opc - buf);
+ } while (ipc < &in[0] + in.length() && result != codecvt_facet::error);
+ if (result != codecvt_facet::ok)
+ throw std::runtime_error("result is not ok!");
+ return os.str();
+ }
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/UtfConverter.cpp
@@ -1,1 +1,70 @@
+// original code is from here: http://www.codeproject.com/Articles/17573/Convert-Between-std-string-and-std-wstring-UTF-8-a
+// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include "ConvertUTF.h"
+
+namespace UtfConverter
+{
+ std::wstring FromUtf8(const std::string &utf8string)
+ {
+ auto widesize = utf8string.length();
+ auto result = std::vector<wchar_t>(widesize + 1, L'\0');
+ auto orig = std::vector<char>(widesize + 1, '\0');
+ std::copy(utf8string.begin(), utf8string.end(), orig.begin());
+ auto *sourcestart = reinterpret_cast<const UTF8 *>(&orig[0]), *sourceend = sourcestart + widesize;
+ ConversionResult res;
+ if (sizeof(wchar_t) == 2)
+ {
+ auto *targetstart = reinterpret_cast<UTF16 *>(&result[0]), *targetend = targetstart + widesize;
+ res = ConvertUTF8toUTF16(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
+ *targetstart = 0;
+ unsigned end = targetstart - reinterpret_cast<UTF16 *>(&result[0]);
+ result.erase(result.begin() + end, result.end());
+ }
+ else if (sizeof(wchar_t) == 4)
+ {
+ auto *targetstart = reinterpret_cast<UTF32 *>(&result[0]), *targetend = targetstart + widesize;
+ res = ConvertUTF8toUTF32(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
+ *targetstart = 0;
+ unsigned end = targetstart - reinterpret_cast<UTF32 *>(&result[0]);
+ result.erase(result.begin() + end, result.end());
+ }
+ else
+ throw std::runtime_error("UtfConverter::FromUtf8: sizeof(wchar_t) is not 2 or 4.");
+ if (res != conversionOK)
+ throw std::runtime_error("UtfConverter::FromUtf8: Conversion failed.");
+ return std::wstring(result.begin(), result.end());
+ }
+
+ std::string ToUtf8(const std::wstring &widestring)
+ {
+ auto widesize = widestring.length(), utf8size = (sizeof(wchar_t) == 2 ? 3 : 4) * widesize + 1;
+ auto result = std::vector<char>(utf8size, '\0');
+ auto orig = std::vector<wchar_t>(widesize + 1, L'\0');
+ std::copy(widestring.begin(), widestring.end(), orig.begin());
+ auto *targetstart = reinterpret_cast<UTF8 *>(&result[0]), *targetend = targetstart + utf8size;
+ ConversionResult res;
+ if (sizeof(wchar_t) == 2)
+ {
+ auto *sourcestart = reinterpret_cast<const UTF16 *>(&orig[0]), *sourceend = sourcestart + widesize;
+ res = ConvertUTF16toUTF8(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
+ }
+ else if (sizeof(wchar_t) == 4)
+ {
+ auto *sourcestart = reinterpret_cast<const UTF32 *>(&orig[0]), *sourceend = sourcestart + widesize;
+ res = ConvertUTF32toUTF8(&sourcestart, sourceend, &targetstart, targetend, strictConversion);
+ }
+ else
+ throw std::runtime_error("UtfConverter::ToUtf8: sizeof(wchar_t) is not 2 or 4.");
+ if (res != conversionOK)
+ throw std::runtime_error("UtfConverter::ToUtf8: Conversion failed.");
+ *targetstart = 0;
+ auto end = targetstart - reinterpret_cast<UTF8 *>(&result[0]);
+ result.erase(result.begin() + end, result.end());
+ return std::string(result.begin(), result.end());
+ }
+}
+
--- /dev/null
+++ b/src/in_xsf_framework/UtfConverter.h
@@ -1,1 +1,16 @@
+// original code is from here: http://www.codeproject.com/Articles/17573/Convert-Between-std-string-and-std-wstring-UTF-8-a
+// License: The Code Project Open License (CPOL) http://www.codeproject.com/info/cpol10.aspx
+#ifndef UTFCONVERTER_H
+#define UTFCONVERTER_H
+
+#include <string>
+
+namespace UtfConverter
+{
+ std::wstring FromUtf8(const std::string &);
+ std::string ToUtf8(const std::wstring &);
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/XSFCommon.h
@@ -1,1 +1,75 @@
+/*
+ * xSF - Common functions
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Partially based on the vio*sf framework
+ */
+#ifndef XSFCOMMON_H
+#define XSFCOMMON_H
+
+#include <limits>
+#include <fstream>
+#include <string>
+#define _USE_MATH_DEFINES
+#include <cmath>
+#include "pstdint.h"
+
+// Code from http://learningcppisfun.blogspot.com/2010/04/comparing-floating-point-numbers.html
+template<typename T> inline bool fEqual(T x, T y, int N = 1)
+{
+ T diff = std::abs(x - y);
+ T tolerance = N * std::numeric_limits<T>::epsilon();
+ return diff <= tolerance * std::abs(x) && diff <= tolerance * std::abs(y);
+}
+
+inline uint32_t Get32BitsLE(const uint8_t *input)
+{
+ return input[0] | (input[1] << 8) | (input[2] << 16) | (input[3] << 24);
+}
+
+inline uint32_t Get32BitsLE(std::ifstream &input)
+{
+ uint8_t bytes[4];
+ input.read(reinterpret_cast<char *>(bytes), 4);
+ return Get32BitsLE(bytes);
+}
+
+// This gets the directory for the path, including the final forward/backward slash
+template<typename T> inline std::basic_string<T> ExtractDirectoryFromPath(const std::basic_string<T> &fullPath)
+{
+ size_t lastSlash = fullPath.rfind('\\');
+ if (lastSlash == std::basic_string<T>::npos)
+ lastSlash = fullPath.rfind('/');
+ return lastSlash != std::basic_string<T>::npos ? fullPath.substr(0, lastSlash + 1) : std::basic_string<T>();
+}
+
+// Code from the following answer on Stack Overflow:
+// http://stackoverflow.com/a/15479212
+template<typename T> static inline T NextHighestPowerOf2(T value)
+{
+ if (value < 1)
+ return 1;
+ --value;
+ for (size_t i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1)
+ value |= value >> i;
+ return value + 1;
+}
+
+inline bool FileExists(const std::string &filename)
+{
+ std::ifstream file((filename.c_str()));
+ return !!file;
+}
+
+#ifdef _WIN32
+inline bool FileExists(const std::wstring &filename)
+{
+ std::ifstream file((filename.c_str()));
+ return !!file;
+}
+#endif
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/XSFConfig.cpp
@@ -1,1 +1,412 @@
-
+/*
+ * xSF - Core configuration handler
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Partially based on the vio*sf framework
+ */
+
+#include "XSFConfig.h"
+#include "XSFPlayer.h"
+#include "convert.h"
+#include "BigSString.h"
+
+enum
+{
+ idPlayInfinitely = 500,
+ idDefaultLength,
+ idDefaultFade,
+ idSkipSilenceOnStartSec,
+ idDetectSilenceSec,
+ idVolume,
+ idReplayGain,
+ idClipProtect,
+ idSampleRate,
+ idTitleFormat,
+ idResetDefaults,
+ idInfoTitle = 600,
+ idInfoArtist,
+ idInfoGame,
+ idInfoYear,
+ idInfoGenre,
+ idInfoCopyright,
+ idInfoComment
+};
+
+bool XSFConfig::initPlayInfinitely = false;
+std::wstring XSFConfig::initSkipSilenceOnStartSec = L"5";
+std::wstring XSFConfig::initDetectSilenceSec = L"5";
+std::wstring XSFConfig::initDefaultLength = L"1:55";
+std::wstring XSFConfig::initDefaultFade = L"5";
+std::wstring XSFConfig::initTitleFormat = L"%game%[ - [%disc%.]%track%] - %title%";
+double XSFConfig::initVolume = 1.0;
+VolumeType XSFConfig::initVolumeType = VOLUMETYPE_REPLAYGAIN_ALBUM;
+PeakType XSFConfig::initPeakType = PEAKTYPE_REPLAYGAIN_TRACK;
+
+XSFConfig::XSFConfig() : playInfinitely(false), skipSilenceOnStartSec(0), detectSilenceSec(0), defaultLength(0), defaultFade(0), volume(0.0), volumeType(VOLUMETYPE_NONE), peakType(PEAKTYPE_NONE),
+ sampleRate(0), titleFormat(L""), configDialog(), configDialogProperty(), infoDialog(), supportedSampleRates(), configIO(XSFConfigIO::Create())
+{
+}
+
+std::wstring XSFConfig::GetTextFromWindow(HWND hwnd)
+{
+ LRESULT length = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
+ std::vector<wchar_t> value(length + 1);
+ length = SendMessageW(hwnd, WM_GETTEXT, length + 1, reinterpret_cast<LPARAM>(&value[0]));
+ return std::wstring(value.begin(), value.begin() + length);
+}
+
+void XSFConfig::LoadConfig()
+{
+ this->playInfinitely = this->configIO->GetValue(L"PlayInfinitely", XSFConfig::initPlayInfinitely);
+ this->skipSilenceOnStartSec = ConvertFuncs::StringToMS(this->configIO->GetValue(L"SkipSilenceOnStartSec", XSFConfig::initSkipSilenceOnStartSec));
+ this->detectSilenceSec = ConvertFuncs::StringToMS(this->configIO->GetValue(L"DetectSilenceSec", XSFConfig::initDetectSilenceSec));
+ this->defaultLength = ConvertFuncs::StringToMS(this->configIO->GetValue(L"DefaultLength", XSFConfig::initDefaultLength));
+ this->defaultFade = ConvertFuncs::StringToMS(this->configIO->GetValue(L"DefaultFade", XSFConfig::initDefaultFade));
+ this->volume = this->configIO->GetValue(L"Volume", XSFConfig::initVolume);
+ this->volumeType = static_cast<VolumeType>(this->configIO->GetValue(L"VolumeType", static_cast<int>(XSFConfig::initVolumeType)));
+ this->peakType = static_cast<PeakType>(this->configIO->GetValue(L"PeakType", static_cast<int>(XSFConfig::initPeakType)));
+ this->sampleRate = this->configIO->GetValue(L"SampleRate", XSFConfig::initSampleRate);
+ this->titleFormat = this->configIO->GetValue(L"TitleFormat", XSFConfig::initTitleFormat);
+
+ this->LoadSpecificConfig();
+}
+
+void XSFConfig::SaveConfig()
+{
+ this->configIO->SetValue(L"PlayInfinitely", this->playInfinitely);
+ this->configIO->SetValue(L"SkipSilenceOnStartSec", ConvertFuncs::MSToWString(this->skipSilenceOnStartSec));
+ this->configIO->SetValue(L"DetectSilenceSec", ConvertFuncs::MSToWString(this->detectSilenceSec));
+ this->configIO->SetValue(L"DefaultLength", ConvertFuncs::MSToWString(this->defaultLength));
+ this->configIO->SetValue(L"DefaultFade", ConvertFuncs::MSToWString(this->defaultFade));
+ this->configIO->SetValue(L"Volume", this->volume);
+ this->configIO->SetValue(L"VolumeType", this->volumeType);
+ this->configIO->SetValue(L"PeakType", this->peakType);
+ this->configIO->SetValue(L"SampleRate", this->sampleRate);
+ this->configIO->SetValue(L"TitleFormat", this->titleFormat);
+
+ this->SaveSpecificConfig();
+}
+
+void XSFConfig::GenerateDialogs()
+{
+ this->infoDialog = DialogBuilder().IsPopup().WithBorder().WithDialogFrame().WithDialogModalFrame().WithSystemMenu().WithFont(L"MS Shell Dlg", 8);
+ this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Title:").WithSize(50, 8).WithRelativePositionToParent(RelativePosition::FROM_TOPLEFT, Point<short>(7, 10)).IsRightJustified());
+ this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(200, 14).WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder().
+ WithTabStop().WithID(idInfoTitle));
+ this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Artist:").WithSize(50, 8).WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsRightJustified());
+ this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(200, 14).WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder().
+ WithTabStop().WithID(idInfoArtist));
+ this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Game:").WithSize(50, 8).WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsRightJustified());
+ this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(200, 14).WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder().
+ WithTabStop().WithID(idInfoGame));
+ this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Year:").WithSize(50, 8).WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsRightJustified());
+ this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(25, 14).WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder().
+ WithTabStop().WithID(idInfoYear));
+ this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Genre:").WithSize(25, 8).WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, 3)).IsRightJustified());
+ this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(140, 14).WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder().
+ WithTabStop().WithID(idInfoGenre));
+ this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Copyright:").WithSize(50, 8).WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 4).IsRightJustified());
+ this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(200, 14).WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder().
+ WithTabStop().WithID(idInfoCopyright));
+ this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Comment:").WithSize(50, 8).WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsRightJustified());
+ this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(200, 54).WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().WithAutoVScroll().WithBorder().
+ WithTabStop().WithID(idInfoComment).WithVerticalScrollbar().WithWantReturn().IsMultiline());
+
+ this->configDialog = DialogBuilder().WithTitle(XSFConfig::commonName + L" v" + XSFConfig::versionNumber).IsPopup().WithBorder().WithDialogFrame().WithDialogModalFrame().WithSystemMenu().WithFont(L"MS Shell Dlg", 8);
+ this->configDialog.AddGroupControl(DialogGroupBuilder(L"General").WithRelativePositionToParent(RelativePositionToParent::FROM_TOPLEFT, Point<short>(7, 7)));
+ this->configDialog.AddCheckBoxControl(DialogCheckBoxBuilder(L"Play infinitely").WithSize(60, 10).InGroup(L"General").WithRelativePositionToParent(RelativePosition::FROM_TOPLEFT, Point<short>(6, 11)).WithTabStop().
+ WithID(idPlayInfinitely));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Default play length (m:s)").WithSize(85, 8).InGroup(L"General").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 7)).
+ IsLeftJustified());
+ this->configDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(25, 14).InGroup(L"General").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().
+ WithAutoHScroll().WithBorder().WithTabStop().WithID(idDefaultLength));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Default fadeout length (m:s)").WithSize(85, 8).InGroup(L"General").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).
+ IsLeftJustified());
+ this->configDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(25, 14).InGroup(L"General").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().
+ WithAutoHScroll().WithBorder().WithTabStop().WithID(idDefaultFade));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Skip silence on start (sec)").WithSize(85, 8).InGroup(L"General").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).
+ IsLeftJustified());
+ this->configDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(25, 14).InGroup(L"General").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().
+ WithAutoHScroll().WithBorder().WithTabStop().WithID(idSkipSilenceOnStartSec));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Detect silence (sec)").WithSize(85, 8).InGroup(L"General").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).
+ IsLeftJustified());
+ this->configDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(25, 14).InGroup(L"General").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().
+ WithAutoHScroll().WithBorder().WithTabStop().WithID(idDetectSilenceSec));
+ this->configDialog.AddGroupControl(DialogGroupBuilder(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 7)));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Volume").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToParent(RelativePosition::FROM_TOPLEFT, Point<short>(6, 14)).IsLeftJustified());
+ this->configDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(25, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).IsLeftJustified().
+ WithAutoHScroll().WithBorder().WithTabStop().WithID(idVolume));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"ReplayGain").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
+ this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(78, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idReplayGain).
+ IsDropDownList().WithTabStop());
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Clip Protect").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
+ this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(78, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idClipProtect).
+ IsDropDownList().WithTabStop());
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Sample Rate").WithSize(50, 8).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 10), 2).IsLeftJustified());
+ this->configDialog.AddComboBoxControl(DialogComboBoxBuilder().WithSize(50, 14).InGroup(L"Output").WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(5, -3)).WithID(idSampleRate).
+ IsDropDownList().WithTabStop());
+ this->configDialog.AddGroupControl(DialogGroupBuilder(L"Title Format").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 7)));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"NOTE: This is only used if Advanced Title Formatting is disabled in Winamp.").WithSize(150, 16).InGroup(L"Title Format").
+ WithRelativePositionToParent(RelativePosition::FROM_TOPLEFT, Point<short>(6, 11)).IsLeftJustified());
+ this->configDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(150, 14).InGroup(L"Title Format").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 4)).IsLeftJustified().
+ WithAutoHScroll().WithBorder().WithTabStop().WithID(idTitleFormat));
+ this->configDialog.AddLabelControl(DialogLabelBuilder(L"Names between percent symbols (e.g. %game%, %title%) will be replaced with the respective value from the file's tags. Using square brackets around any "
+ L"items will cause them to only be displayed if there was a replacement done (e.g. [%disc%.] will display 01. if disc was in the tags as 01, but will display nothing if disc was not in the tags). Square "
+ L"bracket blocks can be nested.").WithSize(150, 72).InGroup(L"Title Format").WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMLEFT, Point<short>(0, 4)).IsLeftJustified());
+
+ this->GenerateSpecificDialogs();
+
+ this->infoDialog.AddButtonControl(DialogButtonBuilder(L"OK").WithSize(50, 14).WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMRIGHT, Point<short>(-104, 7)).WithID(IDOK).IsDefault().WithTabStop());
+ this->infoDialog.AddButtonControl(DialogButtonBuilder(L"Cancel").WithSize(50, 14).WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(4, 0)).WithID(IDCANCEL).WithTabStop());
+ this->infoDialog.AutoSize();
+
+ this->configDialogProperty = this->configDialog;
+ this->configDialogProperty = DialogBuilder().IsChild().IsControlWindow().WithFont(L"MS Shell Dlg", 8);
+ this->configDialogProperty.AutoSize();
+
+ this->configDialog.AddButtonControl(DialogButtonBuilder(L"Reset Defaults").WithSize(50, 14).WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMRIGHT, Point<short>(-50, 7)).WithID(idResetDefaults).
+ WithTabStop());
+ this->configDialog.AddButtonControl(DialogButtonBuilder(L"OK").WithSize(50, 14).WithRelativePositionToSibling(RelativePosition::FROM_BOTTOMRIGHT, Point<short>(-104, 7)).WithID(IDOK).IsDefault().WithTabStop());
+ this->configDialog.AddButtonControl(DialogButtonBuilder(L"Cancel").WithSize(50, 14).WithRelativePositionToSibling(RelativePosition::FROM_TOPRIGHT, Point<short>(4, 0)).WithID(IDCANCEL).WithTabStop());
+ this->configDialog.AutoSize();
+}
+
+INT_PTR CALLBACK XSFConfig::ConfigDialogProcStatic(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ XSFConfig *thisPtr = NULL;
+
+ if (uMsg == WM_INITDIALOG)
+ {
+ thisPtr = reinterpret_cast<XSFConfig *>(lParam);
+
+ SetWindowLongPtr(hwndDlg, DWLP_USER, reinterpret_cast<LONG_PTR>(thisPtr));
+ }
+ else
+ thisPtr = reinterpret_cast<XSFConfig *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
+
+ if (thisPtr)
+ return thisPtr->ConfigDialogProc(hwndDlg, uMsg, wParam, lParam);
+ else
+ return false;
+}
+
+INT_PTR CALLBACK XSFConfig::InfoDialogProcStatic(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ XSFConfig *thisPtr = NULL;
+
+ if (uMsg == WM_INITDIALOG)
+ {
+ thisPtr = reinterpret_cast<XSFConfig *>(lParam);
+
+ SetWindowLongPtr(hwndDlg, DWLP_USER, reinterpret_cast<LONG_PTR>(thisPtr));
+ }
+ else
+ thisPtr = reinterpret_cast<XSFConfig *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
+
+ if (thisPtr)
+ return thisPtr->InfoDialogProc(hwndDlg, uMsg, wParam, lParam);
+ else
+ return false;
+}
+
+INT_PTR CALLBACK XSFConfig::ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_CLOSE:
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ case WM_INITDIALOG:
+ if (this->playInfinitely)
+ SendMessageW(GetDlgItem(hwndDlg, idPlayInfinitely), BM_SETCHECK, BST_CHECKED, 0);
+ SetWindowTextW(GetDlgItem(hwndDlg, idDefaultLength), ConvertFuncs::MSToWString(this->defaultLength).c_str());
+ SetWindowTextW(GetDlgItem(hwndDlg, idDefaultFade), ConvertFuncs::MSToWString(this->defaultFade).c_str());
+ SetWindowTextW(GetDlgItem(hwndDlg, idSkipSilenceOnStartSec), ConvertFuncs::MSToWString(this->skipSilenceOnStartSec).c_str());
+ SetWindowTextW(GetDlgItem(hwndDlg, idDetectSilenceSec), ConvertFuncs::MSToWString(this->detectSilenceSec).c_str());
+ SetWindowTextW(GetDlgItem(hwndDlg, idVolume), wstringify(this->volume).c_str());
+ SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Disabled"));
+ SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Use Volume Tag"));
+ SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Track"));
+ SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Album"));
+ SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_SETCURSEL, this->volumeType, 0);
+ SendMessageW(GetDlgItem(hwndDlg, idClipProtect), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Disabled"));
+ SendMessageW(GetDlgItem(hwndDlg, idClipProtect), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Track"));
+ SendMessageW(GetDlgItem(hwndDlg, idClipProtect), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Album"));
+ SendMessageW(GetDlgItem(hwndDlg, idClipProtect), CB_SETCURSEL, this->peakType, 0);
+ for (unsigned x = 0, rates = this->supportedSampleRates.size(); x < rates; ++x)
+ {
+ unsigned rate = this->supportedSampleRates[x];
+ SendMessageW(GetDlgItem(hwndDlg, idSampleRate), CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(wstringify(rate).c_str()));
+ if (this->sampleRate == rate)
+ SendMessageW(GetDlgItem(hwndDlg, idSampleRate), CB_SETCURSEL, x, 0);
+ }
+ SetWindowTextW(GetDlgItem(hwndDlg, idTitleFormat), this->titleFormat.c_str());
+ break;
+ case WM_COMMAND:
+ switch (GET_WM_COMMAND_ID(wParam, lParam))
+ {
+ case IDOK:
+ this->SaveConfigDialog(hwndDlg);
+ this->SaveConfig();
+ EndDialog(hwndDlg, IDOK);
+ break;
+ case IDCANCEL:
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ case idResetDefaults:
+ this->ResetConfigDefaults(hwndDlg);
+ break;
+ default:
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+extern XSFFile *xSFFileInInfo;
+
+INT_PTR CALLBACK XSFConfig::InfoDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_CLOSE:
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ case WM_INITDIALOG:
+ SetWindowTextW(hwndDlg, xSFFileInInfo->GetFilename().GetWStrC());
+ SetWindowTextW(GetDlgItem(hwndDlg, idInfoTitle), xSFFileInInfo->GetTagValue("title").GetWStrC());
+ SetWindowTextW(GetDlgItem(hwndDlg, idInfoArtist), xSFFileInInfo->GetTagValue("artist").GetWStrC());
+ SetWindowTextW(GetDlgItem(hwndDlg, idInfoGame), xSFFileInInfo->GetTagValue("game").GetWStrC());
+ SetWindowTextW(GetDlgItem(hwndDlg, idInfoYear), xSFFileInInfo->GetTagValue("year").GetWStrC());
+ SetWindowTextW(GetDlgItem(hwndDlg, idInfoGenre), xSFFileInInfo->GetTagValue("genre").GetWStrC());
+ SetWindowTextW(GetDlgItem(hwndDlg, idInfoCopyright), xSFFileInInfo->GetTagValue("copyright").GetWStrC());
+ SetWindowTextW(GetDlgItem(hwndDlg, idInfoComment), xSFFileInInfo->GetTagValue("comment").GetWStrC());
+ break;
+ case WM_COMMAND:
+ switch (GET_WM_COMMAND_ID(wParam, lParam))
+ {
+ case IDOK:
+ xSFFileInInfo->SetTag("title", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoTitle)));
+ xSFFileInInfo->SetTag("artist", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoArtist)));
+ xSFFileInInfo->SetTag("game", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoGame)));
+ xSFFileInInfo->SetTag("year", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoYear)));
+ xSFFileInInfo->SetTag("genre", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoGenre)));
+ xSFFileInInfo->SetTag("copyright", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoCopyright)));
+ xSFFileInInfo->SetTag("comment", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoComment)));
+ if (!xSFFileInInfo->GetTagExists("utf8"))
+ xSFFileInInfo->SetTag("utf8", "1");
+ EndDialog(hwndDlg, IDOK);
+ break;
+ case IDCANCEL:
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ default:
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void XSFConfig::CallConfigDialog(HINSTANCE hInstance, HWND hwndParent)
+{
+ DialogBoxIndirectParam(hInstance, this->configDialog.GenerateTemplate(), hwndParent, XSFConfig::ConfigDialogProcStatic, reinterpret_cast<LPARAM>(this));
+}
+
+void XSFConfig::CallInfoDialog(HINSTANCE hInstance, HWND hwndParent)
+{
+ DialogBoxIndirectParam(hInstance, this->infoDialog.GenerateTemplate(), hwndParent, XSFConfig::InfoDialogProcStatic, reinterpret_cast<LPARAM>(this));
+}
+
+void XSFConfig::ResetConfigDefaults(HWND hwndDlg)
+{
+ SendMessageW(GetDlgItem(hwndDlg, idPlayInfinitely), BM_SETCHECK, XSFConfig::initPlayInfinitely ? BST_CHECKED : BST_UNCHECKED, 0);
+ SetWindowTextW(GetDlgItem(hwndDlg, idDefaultLength), XSFConfig::initDefaultLength.c_str());
+ SetWindowTextW(GetDlgItem(hwndDlg, idDefaultFade), XSFConfig::initDefaultFade.c_str());
+ SetWindowTextW(GetDlgItem(hwndDlg, idSkipSilenceOnStartSec), XSFConfig::initSkipSilenceOnStartSec.c_str());
+ SetWindowTextW(GetDlgItem(hwndDlg, idDetectSilenceSec), XSFConfig::initDetectSilenceSec.c_str());
+ SetWindowTextW(GetDlgItem(hwndDlg, idVolume), wstringify(XSFConfig::initVolume).c_str());
+ SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_SETCURSEL, XSFConfig::initVolumeType, 0);
+ SendMessageW(GetDlgItem(hwndDlg, idClipProtect), CB_SETCURSEL, XSFConfig::initPeakType, 0);
+ std::vector<unsigned>::const_iterator found = std::find(this->supportedSampleRates.begin(), this->supportedSampleRates.end(), XSFConfig::initSampleRate);
+ SendMessageW(GetDlgItem(hwndDlg, idSampleRate), CB_SETCURSEL, found - this->supportedSampleRates.begin(), 0);
+ SetWindowTextW(GetDlgItem(hwndDlg, idTitleFormat), XSFConfig::initTitleFormat.c_str());
+
+ this->ResetSpecificConfigDefaults(hwndDlg);
+}
+
+void XSFConfig::SaveConfigDialog(HWND hwndDlg)
+{
+ this->playInfinitely = SendMessageW(GetDlgItem(hwndDlg, idPlayInfinitely), BM_GETCHECK, 0, 0) == BST_CHECKED;
+ this->defaultLength = ConvertFuncs::StringToMS(this->GetTextFromWindow(GetDlgItem(hwndDlg, idDefaultLength)));
+ this->defaultFade = ConvertFuncs::StringToMS(this->GetTextFromWindow(GetDlgItem(hwndDlg, idDefaultFade)));
+ this->skipSilenceOnStartSec = ConvertFuncs::StringToMS(this->GetTextFromWindow(GetDlgItem(hwndDlg, idSkipSilenceOnStartSec)));
+ this->detectSilenceSec = ConvertFuncs::StringToMS(this->GetTextFromWindow(GetDlgItem(hwndDlg, idDetectSilenceSec)));
+ this->volume = convertTo<double>(this->GetTextFromWindow(GetDlgItem(hwndDlg, idVolume)), false);
+ this->volumeType = static_cast<VolumeType>(SendMessageW(GetDlgItem(hwndDlg, idReplayGain), CB_GETCURSEL, 0, 0));
+ this->peakType = static_cast<PeakType>(SendMessageW(GetDlgItem(hwndDlg, idClipProtect), CB_GETCURSEL, 0, 0));
+ this->sampleRate = XSFConfig::supportedSampleRates[SendMessageW(GetDlgItem(hwndDlg, idSampleRate), CB_GETCURSEL, 0, 0)];
+ this->titleFormat = this->GetTextFromWindow(GetDlgItem(hwndDlg, idTitleFormat));
+
+ this->SaveSpecificConfigDialog(hwndDlg);
+}
+
+void XSFConfig::CopyConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad)
+{
+ if (preLoad)
+ xSFPlayer->SetSampleRate(this->sampleRate);
+
+ this->CopySpecificConfigToMemory(xSFPlayer, preLoad);
+}
+
+bool XSFConfig::GetPlayInfinitely() const
+{
+ return this->playInfinitely;
+}
+
+unsigned long XSFConfig::GetSkipSilenceOnStartSec() const
+{
+ return this->skipSilenceOnStartSec;
+}
+
+unsigned long XSFConfig::GetDetectSilenceSec() const
+{
+ return this->detectSilenceSec;
+}
+
+unsigned long XSFConfig::GetDefaultLength() const
+{
+ return this->defaultLength;
+}
+
+unsigned long XSFConfig::GetDefaultFade() const
+{
+ return this->defaultFade;
+}
+
+double XSFConfig::GetVolume() const
+{
+ return this->volume;
+}
+
+VolumeType XSFConfig::GetVolumeType() const
+{
+ return this->volumeType;
+}
+
+PeakType XSFConfig::GetPeakType() const
+{
+ return this->peakType;
+}
+
+const std::wstring &XSFConfig::GetTitleFormat() const
+{
+ return this->titleFormat;
+}
+
--- /dev/null
+++ b/src/in_xsf_framework/XSFConfig.h
@@ -1,1 +1,99 @@
+/*
+ * xSF - Core configuration handler
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Partially based on the vio*sf framework
+ */
+#ifndef XSFCONFIG_H
+#define XSFCONFIG_H
+
+#include <memory>
+#include "XSFPlayer.h"
+#include "DialogBuilder.h"
+#include "convert.h"
+#include "windowsh_wrapper.h"
+#include <windowsx.h>
+
+class XSFConfigIO
+{
+protected:
+ XSFConfigIO() { }
+public:
+ // This is not defined in XSFConfig.cpp, it should be defined in your own config's source and return a pointer to your config's I/O class.
+ static XSFConfigIO *Create();
+
+ virtual ~XSFConfigIO() { }
+ virtual void SetValueString(const std::wstring &name, const std::wstring &value) = 0;
+ template<typename T> void SetValue(const std::wstring &name, const T &value) { this->SetValueString(name, wstringify(value)); }
+ void SetValue(const std::wstring &name, const std::wstring &value) { this->SetValueString(name, value); }
+ virtual std::wstring GetValueString(const std::wstring &name, const std::wstring &defaultValue) = 0;
+ template<typename T> T GetValue(const std::wstring &name, const T &defaultValue) { return convertTo<T>(this->GetValueString(name, wstringify(defaultValue))); }
+ std::wstring GetValue(const std::wstring &name, const std::wstring &defaultValue) { return this->GetValueString(name, defaultValue); }
+};
+
+class XSFConfig
+{
+protected:
+ bool playInfinitely;
+ unsigned long skipSilenceOnStartSec, detectSilenceSec, defaultLength, defaultFade;
+ double volume;
+ VolumeType volumeType;
+ PeakType peakType;
+ unsigned sampleRate;
+ std::wstring titleFormat;
+ DialogTemplate configDialog, configDialogProperty, infoDialog;
+ std::vector<unsigned> supportedSampleRates;
+ std::auto_ptr<XSFConfigIO> configIO;
+
+ XSFConfig();
+ std::wstring GetTextFromWindow(HWND hwnd);
+ virtual void LoadSpecificConfig() = 0;
+ virtual void GenerateSpecificDialogs() = 0;
+ virtual void SaveSpecificConfig() = 0;
+ virtual INT_PTR CALLBACK ConfigDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual INT_PTR CALLBACK InfoDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual void ResetSpecificConfigDefaults(HWND hwndDlg) = 0;
+ virtual void SaveSpecificConfigDialog(HWND hwndDlg) = 0;
+ virtual void CopySpecificConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad) = 0;
+public:
+ static bool initPlayInfinitely;
+ static std::wstring initSkipSilenceOnStartSec, initDetectSilenceSec, initDefaultLength, initDefaultFade, initTitleFormat;
+ static double initVolume;
+ static VolumeType initVolumeType;
+ static PeakType initPeakType;
+ // These are not defined in XSFConfig.cpp, they should be defined in your own config's source.
+ static unsigned initSampleRate;
+ static std::wstring commonName;
+ static std::wstring versionNumber;
+ // The Create function is not defined in XSFConfig.cpp, it should be defined in your own config's source and return a pointer to your config's class.
+ static XSFConfig *Create();
+
+ virtual ~XSFConfig() { }
+ void LoadConfig();
+ void SaveConfig();
+ void GenerateDialogs();
+ static INT_PTR CALLBACK ConfigDialogProcStatic(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ static INT_PTR CALLBACK InfoDialogProcStatic(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void CallConfigDialog(HINSTANCE hInstance, HWND hwndParent);
+ void CallInfoDialog(HINSTANCE hInstance, HWND hwndParent);
+ void ResetConfigDefaults(HWND hwndDlg);
+ void SaveConfigDialog(HWND hwndDlg);
+ void CopyConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad);
+
+ virtual void About(HWND parent) = 0;
+
+ bool GetPlayInfinitely() const;
+ unsigned long GetSkipSilenceOnStartSec() const;
+ unsigned long GetDetectSilenceSec() const;
+ unsigned long GetDefaultLength() const;
+ unsigned long GetDefaultFade() const;
+ double GetVolume() const;
+ VolumeType GetVolumeType() const;
+ PeakType GetPeakType() const;
+ const std::wstring &GetTitleFormat() const;
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/XSFConfig_Winamp.cpp
@@ -1,1 +1,76 @@
+/*
+ * xSF - Winamp-specification configuration handler
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Partially based on the vio*sf framework
+ */
+#include "XSFConfig.h"
+#include "XSFCommon.h"
+#include <winamp/in2.h>
+#include <winamp/wa_ipc.h>
+
+extern In_Module inMod;
+
+class XSFConfigIO_Winamp : public XSFConfigIO
+{
+protected:
+ friend class XSFConfigIO;
+ std::wstring iniFilename;
+
+ XSFConfigIO_Winamp();
+public:
+ void SetValueString(const std::wstring &name, const std::wstring &value);
+ std::wstring GetValueString(const std::wstring &name, const std::wstring &defaultValue);
+};
+
+XSFConfigIO *XSFConfigIO::Create()
+{
+ return new XSFConfigIO_Winamp();
+}
+
+XSFConfigIO_Winamp::XSFConfigIO_Winamp() : iniFilename(L"")
+{
+ if (SendMessage(inMod.hMainWindow, WM_WA_IPC, 0, IPC_GETVERSION) >= 0x2900)
+ this->iniFilename = String(reinterpret_cast<char *>(SendMessage(inMod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE))).GetWStr();
+ else
+ {
+ std::vector<wchar_t> executablePath(MAX_PATH / 2);
+
+ DWORD result;
+ do
+ {
+ executablePath.resize(executablePath.size() * 2);
+ result = GetModuleFileNameW(NULL, &executablePath[0], executablePath.size());
+ } while (result == executablePath.size());
+
+ if (!result)
+ throw std::runtime_error("Unable to get path to plugin.");
+
+ this->iniFilename = ExtractDirectoryFromPath(std::wstring(executablePath.begin(), executablePath.begin() + result)) + L"plugins.ini";
+ }
+}
+
+void XSFConfigIO_Winamp::SetValueString(const std::wstring &name, const std::wstring &value)
+{
+ WritePrivateProfileStringW(XSFConfig::commonName.c_str(), name.c_str(), value.c_str(), this->iniFilename.c_str());
+}
+
+std::wstring XSFConfigIO_Winamp::GetValueString(const std::wstring &name, const std::wstring &defaultValue)
+{
+ std::vector<wchar_t> value(MAX_PATH / 2);
+
+ DWORD result;
+ do
+ {
+ value.resize(value.size() * 2);
+ result = GetPrivateProfileStringW(XSFConfig::commonName.c_str(), name.c_str(), defaultValue.c_str(), &value[0], value.size(), this->iniFilename.c_str());
+ } while (result + 1 == value.size());
+
+ if (!result)
+ throw std::runtime_error("Unable to get value from INI file.");
+
+ return std::wstring(value.begin(), value.begin() + result);
+}
+
--- /dev/null
+++ b/src/in_xsf_framework/XSFFile.cpp
@@ -1,1 +1,476 @@
-
+/*
+ * xSF - File structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Partially based on the vio*sf framework
+ */
+
+#include <algorithm>
+#include <functional>
+#include <stdexcept>
+#include <zlib.h>
+#include "XSFFile.h"
+#include "XSFCommon.h"
+#include "convert.h"
+
+static inline void Set32BitsLE(uint32_t input, uint8_t *output)
+{
+ output[0] = input & 0xFF;
+ output[1] = (input >> 8) & 0xFF;
+ output[2] = (input >> 16) & 0xFF;
+ output[3] = (input >> 24) & 0xFF;
+}
+
+// The whitespace trimming was modified from the following answer on Stack Overflow:
+// http://stackoverflow.com/a/217605
+
+struct IsWhitespace : std::unary_function<char, bool>
+{
+ bool operator()(const char &x) const
+ {
+ return x >= 0x01 && x <= 0x20;
+ }
+};
+
+static inline std::string LeftTrimWhitespace(const std::string &orig)
+{
+ auto first_non_space = std::find_if(orig.begin(), orig.end(), std::not1(IsWhitespace()));
+ return std::string(first_non_space, orig.end());
+}
+
+static inline std::string RightTrimWhitespace(const std::string &orig)
+{
+ auto last_non_space = std::find_if(orig.rbegin(), orig.rend(), std::not1(IsWhitespace())).base();
+ return std::string(orig.begin(), last_non_space);
+}
+
+static inline std::string TrimWhitespace(const std::string &orig)
+{
+ return LeftTrimWhitespace(RightTrimWhitespace(orig));
+}
+
+XSFFile::XSFFile() : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName("")
+{
+}
+
+XSFFile::XSFFile(const std::string &filename) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename)
+{
+ this->ReadXSF(filename, 0, 0, true);
+}
+
+XSFFile::XSFFile(const std::string &filename, uint32_t programSizeOffset, uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename)
+{
+ this->ReadXSF(filename, programSizeOffset, programHeaderSize);
+}
+
+#ifdef _WIN32
+XSFFile::XSFFile(const std::wstring &filename) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename)
+{
+ this->ReadXSF(filename, 0, 0, true);
+}
+
+XSFFile::XSFFile(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize) : xSFType(0), hasFile(false), rawData(), reservedSection(), programSection(), tags(), fileName(filename)
+{
+ this->ReadXSF(filename, programSizeOffset, programHeaderSize);
+}
+#endif
+
+void XSFFile::ReadXSF(const std::string &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly)
+{
+ if (!FileExists(filename))
+ throw std::logic_error("File " + filename + " does not exist.");
+
+ std::ifstream xSF;
+ xSF.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+ xSF.open(filename.c_str(), std::ifstream::in | std::ifstream::binary);
+
+ this->ReadXSF(xSF, programSizeOffset, programHeaderSize, readTagsOnly);
+}
+
+#ifdef _WIN32
+void XSFFile::ReadXSF(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly)
+{
+ if (!FileExists(filename))
+ throw std::logic_error("File " + String(filename).GetAnsi() + " does not exist.");
+
+ std::ifstream xSF;
+ xSF.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+ xSF.open(filename.c_str(), std::ifstream::in | std::ifstream::binary);
+
+ this->ReadXSF(xSF, programSizeOffset, programHeaderSize, readTagsOnly);
+}
+#endif
+
+void XSFFile::ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly)
+{
+ xSF.seekg(0, std::ifstream::end);
+ auto filesize = xSF.tellg();
+ xSF.seekg(0, std::ifstream::beg);
+
+ if (filesize < 4)
+ throw std::runtime_error("File is too small.");
+
+ char PSFHeader[4];
+ xSF.read(PSFHeader, 4);
+
+ if (PSFHeader[0] != 'P' || PSFHeader[1] != 'S' || PSFHeader[2] != 'F')
+ throw std::runtime_error("Not a PSF file.");
+
+ this->xSFType = PSFHeader[3];
+
+ this->rawData.resize(4);
+ memcpy(&this->rawData[0], PSFHeader, 4);
+
+ if (filesize < 16)
+ throw std::runtime_error("File is too small.");
+
+ uint32_t reservedSize = Get32BitsLE(xSF), programCompressedSize = Get32BitsLE(xSF);
+ this->rawData.resize(reservedSize + programCompressedSize + 16);
+ Set32BitsLE(reservedSize, &this->rawData[4]);
+ Set32BitsLE(programCompressedSize, &this->rawData[8]);
+ xSF.read(reinterpret_cast<char *>(&this->rawData[12]), 4);
+
+ if (reservedSize)
+ {
+ if (filesize < reservedSize + 16)
+ throw std::runtime_error("File is too small.");
+
+ if (readTagsOnly)
+ xSF.read(reinterpret_cast<char *>(&this->rawData[16]), reservedSize);
+ else
+ {
+ this->reservedSection.resize(reservedSize);
+ xSF.read(reinterpret_cast<char *>(&this->reservedSection[0]), reservedSize);
+ memcpy(&this->rawData[16], &this->reservedSection[0], reservedSize);
+ }
+ }
+
+ if (programCompressedSize)
+ {
+ if (filesize < reservedSize + programCompressedSize + 16)
+ throw std::runtime_error("File is too small.");
+
+ if (readTagsOnly)
+ xSF.read(reinterpret_cast<char *>(&this->rawData[reservedSize + 16]), programCompressedSize);
+ else
+ {
+ auto programSectionCompressed = std::vector<uint8_t>(programCompressedSize);
+ xSF.read(reinterpret_cast<char *>(&programSectionCompressed[0]), programCompressedSize);
+ memcpy(&this->rawData[reservedSize + 16], &programSectionCompressed[0], programCompressedSize);
+
+ auto programSectionUncompressed = std::vector<uint8_t>(programHeaderSize);
+ unsigned long programUncompressedSize = programHeaderSize;
+ uncompress(&programSectionUncompressed[0], &programUncompressedSize, &programSectionCompressed[0], programCompressedSize);
+ programUncompressedSize = Get32BitsLE(&programSectionUncompressed[programSizeOffset]) + programHeaderSize;
+ this->programSection.resize(programUncompressedSize);
+ uncompress(&this->programSection[0], &programUncompressedSize, &programSectionCompressed[0], programCompressedSize);
+ }
+ }
+
+ if (xSF.tellg() != filesize && filesize >= reservedSize + programCompressedSize + 21)
+ {
+ char tagheader[6] = "";
+ xSF.read(tagheader, 5);
+ if (std::string(tagheader) == "[TAG]")
+ {
+ auto startOfTags = xSF.tellg();
+ unsigned lengthOfTags = static_cast<unsigned>(filesize - startOfTags);
+ if (lengthOfTags)
+ {
+ auto rawtags = std::vector<char>(lengthOfTags);
+ xSF.read(&rawtags[0], lengthOfTags);
+ std::string name, value;
+ bool onName = true;
+ for (unsigned x = 0; x < lengthOfTags; ++x)
+ {
+ char curr = rawtags[x];
+ if (curr == 0x0A)
+ {
+ if (!name.empty() && !value.empty())
+ {
+ name = TrimWhitespace(name);
+ value = TrimWhitespace(value);
+ if (this->tags.Exists(name))
+ this->tags[name] += "\n" + value;
+ else
+ this->tags[name] = value;
+ }
+ name = value = "";
+ onName = true;
+ continue;
+ }
+ if (curr == '=')
+ {
+ onName = false;
+ continue;
+ }
+ if (onName)
+ name += curr;
+ else
+ value += curr;
+ }
+ }
+ }
+ }
+
+ xSF.close();
+
+ this->hasFile = true;
+}
+
+bool XSFFile::IsValidType(uint8_t type) const
+{
+ return this->xSFType == type;
+}
+
+void XSFFile::Clear()
+{
+ this->xSFType = 0;
+ this->hasFile = false;
+ this->reservedSection.clear();
+ this->programSection.clear();
+ this->tags.Clear();
+}
+
+bool XSFFile::HasFile() const
+{
+ return this->hasFile;
+}
+
+std::vector<uint8_t> &XSFFile::GetReservedSection()
+{
+ return this->reservedSection;
+}
+
+std::vector<uint8_t> XSFFile::GetReservedSection() const
+{
+ return this->reservedSection;
+}
+
+std::vector<uint8_t> &XSFFile::GetProgramSection()
+{
+ return this->programSection;
+}
+
+std::vector<uint8_t> XSFFile::GetProgramSection() const
+{
+ return this->programSection;
+}
+
+const TagList &XSFFile::GetAllTags() const
+{
+ return this->tags;
+}
+
+void XSFFile::SetAllTags(const TagList &newTags)
+{
+ this->tags = newTags;
+}
+
+void XSFFile::SetTag(const std::string &name, const String &value)
+{
+ this->tags[name] = value.GetStr();
+}
+
+bool XSFFile::GetTagExists(const std::string &name) const
+{
+ return this->tags.Exists(name);
+}
+
+String XSFFile::GetTagValue(const std::string &name) const
+{
+ return String(this->GetTagExists(name) ? this->tags[name] : "", this->GetTagExists("utf8"));
+}
+
+unsigned long XSFFile::GetLengthMS(unsigned long defaultLength) const
+{
+ unsigned long length = 0;
+ String value = this->GetTagValue("length");
+ if (!value.empty())
+ length = ConvertFuncs::StringToMS(value.GetAnsi());
+ if (!length)
+ length = defaultLength;
+ return length;
+}
+
+unsigned long XSFFile::GetFadeMS(unsigned long defaultFade) const
+{
+ unsigned long fade = defaultFade;
+ String value = this->GetTagValue("fade");
+ if (!value.empty())
+ fade = ConvertFuncs::StringToMS(value.GetAnsi());
+ return fade;
+}
+
+double XSFFile::GetVolume(VolumeType preferredVolumeType, PeakType preferredPeakType) const
+{
+ if (preferredVolumeType == VOLUMETYPE_NONE)
+ return 1.0;
+ String replaygain_album_gain = this->GetTagValue("replaygain_album_gain"), replaygain_album_peak = this->GetTagValue("replaygain_album_peak");
+ String replaygain_track_gain = this->GetTagValue("replaygain_track_gain"), replaygain_track_peak = this->GetTagValue("replaygain_track_peak");
+ String volume = this->GetTagValue("volume");
+ double gain = 0.0;
+ bool hadReplayGain = false;
+ if (preferredVolumeType == VOLUMETYPE_REPLAYGAIN_ALBUM && !replaygain_album_gain.empty())
+ {
+ gain = convertTo<double>(replaygain_album_gain.GetAnsi(), false);
+ hadReplayGain = true;
+ }
+ if (!hadReplayGain && preferredVolumeType != VOLUMETYPE_VOLUME && !replaygain_track_gain.empty())
+ {
+ gain = convertTo<double>(replaygain_track_gain.GetAnsi(), false);
+ hadReplayGain = true;
+ }
+ if (hadReplayGain)
+ {
+ double vol = std::pow(10.0, gain / 20.0), peak = 1.0;
+ if (preferredPeakType == PEAKTYPE_REPLAYGAIN_ALBUM && !replaygain_album_peak.empty())
+ peak = convertTo<double>(replaygain_album_peak.GetAnsi(), false);
+ else if (preferredPeakType != PEAKTYPE_NONE && !replaygain_track_peak.empty())
+ peak = convertTo<double>(replaygain_track_peak.GetAnsi(), false);
+ return !fEqual(peak, 1.0) ? std::min(vol, 1.0 / peak) : vol;
+ }
+ return volume.empty() ? 1.0 : convertTo<double>(volume.GetAnsi(), false);
+}
+
+String XSFFile::FormattedTitleOptionalBlock(const std::wstring &block, bool &hadReplacement, unsigned level) const
+{
+ String formattedBlock;
+ for (size_t x = 0, len = block.length(); x < len; ++x)
+ {
+ wchar_t c = block[x];
+ if (c == L'%')
+ {
+ size_t origX = x;
+ for (++x; x < len; ++x)
+ if (block[x] == L'%')
+ break;
+ if (x != len)
+ {
+ std::wstring tagname = block.substr(origX + 1, x - origX - 1);
+ String value = this->GetTagValue(String(tagname).GetAnsi());
+ if (!value.empty())
+ {
+ formattedBlock += value;
+ hadReplacement = true;
+ }
+ }
+ continue;
+ }
+ if (c == L'[' && level + 1 < 10)
+ {
+ size_t origX = x;
+ unsigned nests = 0;
+ for (++x; x < len; ++x)
+ {
+ if (block[x] == L'[')
+ ++nests;
+ else if (block[x] == L']')
+ {
+ if (!nests)
+ break;
+ --nests;
+ }
+ }
+ if (x != len)
+ {
+ std::wstring innerBlock = block.substr(origX + 1, x - origX - 1);
+ bool hadInnerReplacement = false;
+ String replacedBlock = this->FormattedTitleOptionalBlock(innerBlock, hadInnerReplacement, level + 1);
+ if (hadInnerReplacement)
+ formattedBlock += replacedBlock;
+ }
+ continue;
+ }
+ formattedBlock += c;
+ }
+ return formattedBlock;
+}
+
+String XSFFile::GetFormattedTitle(const std::wstring &format) const
+{
+ String formattedTitle;
+ for (size_t x = 0, len = format.length(); x < len; ++x)
+ {
+ wchar_t c = format[x];
+ if (c == L'%')
+ {
+ size_t origX = x;
+ for (++x; x < len; ++x)
+ if (format[x] == L'%')
+ break;
+ if (x != len)
+ {
+ std::wstring tagname = format.substr(origX + 1, x - origX - 1);
+ String value = this->GetTagValue(String(tagname).GetAnsi());
+ if (value.empty())
+ formattedTitle += "???";
+ else
+ formattedTitle += value;
+ }
+ }
+ else if (c == L'[')
+ {
+ size_t origX = x;
+ unsigned nests = 0;
+ for (++x; x < len; ++x)
+ {
+ if (format[x] == L'[')
+ ++nests;
+ else if (format[x] == L']')
+ {
+ if (!nests)
+ break;
+ --nests;
+ }
+ }
+ if (x != len)
+ {
+ std::wstring block = format.substr(origX + 1, x - origX - 1);
+ bool hadReplacement = false;
+ String replacedBlock = this->FormattedTitleOptionalBlock(block, hadReplacement, 1);
+ if (hadReplacement)
+ formattedTitle += replacedBlock;
+ }
+ }
+ else
+ formattedTitle += c;
+ }
+ return formattedTitle;
+}
+
+String XSFFile::GetFilename() const
+{
+ return this->fileName;
+}
+
+String XSFFile::GetFilenameWithoutPath() const
+{
+ return ExtractDirectoryFromPath(this->fileName.GetStr());
+}
+
+void XSFFile::SaveFile() const
+{
+ std::ofstream xSF;
+ xSF.exceptions(std::ofstream::failbit);
+#ifdef _WIN32
+ xSF.open(this->fileName.GetWStrC(), std::ofstream::out | std::ofstream::binary);
+#else
+ xSF.open(this->fileName.GetStrC(), std::ofstream::out | std::ofstream::binary);
+#endif
+
+ xSF.write(reinterpret_cast<const char *>(&this->rawData[0]), this->rawData.size());
+
+ auto allTags = this->tags.GetTags();
+ if (!allTags.empty())
+ {
+ xSF.write("[TAG]", 5);
+ for (auto curr = allTags.begin(), end = allTags.end(); curr != end; ++curr)
+ {
+ xSF.write(curr->c_str(), curr->length());
+ xSF.write("\n", 1);
+ }
+ }
+}
+
--- /dev/null
+++ b/src/in_xsf_framework/XSFFile.h
@@ -1,1 +1,79 @@
+/*
+ * xSF - File structure
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Partially based on the vio*sf framework
+ */
+#ifndef XSFFILE_H
+#define XSFFILE_H
+
+#include "TagList.h"
+#include "BigSString.h"
+#include "pstdint.h"
+
+enum VolumeType
+{
+ VOLUMETYPE_NONE,
+ VOLUMETYPE_VOLUME,
+ VOLUMETYPE_REPLAYGAIN_TRACK,
+ VOLUMETYPE_REPLAYGAIN_ALBUM
+};
+
+enum PeakType
+{
+ PEAKTYPE_NONE,
+ PEAKTYPE_REPLAYGAIN_TRACK,
+ PEAKTYPE_REPLAYGAIN_ALBUM
+};
+
+class XSFFile
+{
+protected:
+ uint8_t xSFType;
+ bool hasFile;
+ std::vector<uint8_t> rawData, reservedSection, programSection;
+ TagList tags;
+ String fileName;
+ void ReadXSF(const std::string &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly = false);
+#ifdef _WIN32
+ void ReadXSF(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly = false);
+#endif
+ void ReadXSF(std::ifstream &xSF, uint32_t programSizeOffset, uint32_t programHeaderSize, bool readTagsOnly = false);
+ String FormattedTitleOptionalBlock(const std::wstring &block, bool &hadReplacement, unsigned level) const;
+public:
+ XSFFile();
+ XSFFile(const std::string &filename);
+ XSFFile(const std::string &filename, uint32_t programSizeOffset, uint32_t programHeaderSize);
+#ifdef _WIN32
+ XSFFile(const std::wstring &filename);
+ XSFFile(const std::wstring &filename, uint32_t programSizeOffset, uint32_t programHeaderSize);
+#endif
+ bool IsValidType(uint8_t type) const;
+ void Clear();
+ bool HasFile() const;
+ std::vector<uint8_t> &GetReservedSection();
+ std::vector<uint8_t> GetReservedSection() const;
+ std::vector<uint8_t> &GetProgramSection();
+ std::vector<uint8_t> GetProgramSection() const;
+ const TagList &GetAllTags() const;
+ void SetAllTags(const TagList &newTags);
+ void SetTag(const std::string &name, const String &value);
+ bool GetTagExists(const std::string &name) const;
+ String GetTagValue(const std::string &name) const;
+ template<typename T> T GetTagValue(const std::string &name, const T &defaultValue) const
+ {
+ return this->GetTagExists(name) ? convertTo<T>(this->GetTagValue(name).GetAnsi(), false) : defaultValue;
+ }
+ unsigned long GetLengthMS(unsigned long defaultLength) const;
+ unsigned long GetFadeMS(unsigned long defaultFade) const;
+ double GetVolume(VolumeType preferredVolumeType, PeakType preferredPeakType) const;
+ String GetFormattedTitle(const std::wstring &format) const;
+ String GetFilename() const;
+ String GetFilenameWithoutPath() const;
+ void SaveFile() const;
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/XSFPlayer.cpp
@@ -1,1 +1,234 @@
-
+/*
+ * xSF - Core Player
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ *
+ * Partially based on the vio*sf framework
+ */
+
+#include <cstring>
+#include "XSFPlayer.h"
+#include "XSFConfig.h"
+#include "XSFCommon.h"
+
+extern XSFConfig *xSFConfig;
+
+XSFPlayer::XSFPlayer() : xSF(NULL), sampleRate(0), detectedSilenceSample(0), detectedSilenceSec(0), skipSilenceOnStartSec(5), lengthSample(0), fadeSample(0), currentSample(0),
+ prevSampleL(XSFPlayer::CHECK_SILENCE_BIAS), prevSampleR(XSFPlayer::CHECK_SILENCE_BIAS), lengthInMS(-1), fadeInMS(-1), volume(1.0), ignoreVolume(false)
+{
+}
+
+XSFPlayer::XSFPlayer(const XSFPlayer &xSFPlayer) : xSF(new XSFFile()), sampleRate(xSFPlayer.sampleRate), detectedSilenceSample(xSFPlayer.detectedSilenceSample), detectedSilenceSec(xSFPlayer.detectedSilenceSec),
+ skipSilenceOnStartSec(xSFPlayer.skipSilenceOnStartSec), lengthSample(xSFPlayer.lengthSample), fadeSample(xSFPlayer.fadeSample), currentSample(xSFPlayer.currentSample), prevSampleL(xSFPlayer.prevSampleL),
+ prevSampleR(xSFPlayer.prevSampleR), lengthInMS(xSFPlayer.lengthInMS), fadeInMS(xSFPlayer.fadeInMS), volume(xSFPlayer.volume), ignoreVolume(xSFPlayer.ignoreVolume)
+{
+ *this->xSF = *xSFPlayer.xSF;
+}
+
+XSFPlayer &XSFPlayer::operator=(const XSFPlayer &xSFPlayer)
+{
+ if (this != &xSFPlayer)
+ {
+ if (!this->xSF)
+ this->xSF = new XSFFile();
+ *this->xSF = *xSFPlayer.xSF;
+ this->sampleRate = xSFPlayer.sampleRate;
+ this->detectedSilenceSample = xSFPlayer.detectedSilenceSample;
+ this->detectedSilenceSec = xSFPlayer.detectedSilenceSec;
+ this->skipSilenceOnStartSec = xSFPlayer.skipSilenceOnStartSec;
+ this->lengthSample = xSFPlayer.lengthSample;
+ this->fadeSample = xSFPlayer.fadeSample;
+ this->currentSample = xSFPlayer.currentSample;
+ this->prevSampleL = xSFPlayer.prevSampleL;
+ this->prevSampleR = xSFPlayer.prevSampleR;
+ this->lengthInMS = xSFPlayer.lengthInMS;
+ this->fadeInMS = xSFPlayer.fadeInMS;
+ this->volume = xSFPlayer.volume;
+ this->ignoreVolume = xSFPlayer.ignoreVolume;
+ }
+ return *this;
+}
+
+bool XSFPlayer::FillBuffer(std::vector<uint8_t> &buf, unsigned &samplesWritten)
+{
+ bool endFlag = false;
+ unsigned detectSilence = xSFConfig->GetDetectSilenceSec();
+ unsigned pos = 0, bufsize = buf.size() >> 2;
+ while (pos < bufsize)
+ {
+ unsigned remain = bufsize - pos, offset = pos;
+ this->GenerateSamples(buf, pos << 1, remain);
+ if (detectSilence || skipSilenceOnStartSec)
+ {
+ unsigned skipOffset = 0;
+ for (unsigned ofs = 0; ofs < remain; ++ofs)
+ {
+ short *bufShort = reinterpret_cast<short *>(&buf[0]);
+ unsigned long sampleL = bufShort[2 * (offset + ofs)], sampleR = bufShort[2 * (offset + ofs) + 1];
+ bool silence = (sampleL + XSFPlayer::CHECK_SILENCE_BIAS + XSFPlayer::CHECK_SILENCE_LEVEL) - this->prevSampleL <= XSFPlayer::CHECK_SILENCE_LEVEL * 2 &&
+ (sampleR + XSFPlayer::CHECK_SILENCE_BIAS + XSFPlayer::CHECK_SILENCE_LEVEL) - this->prevSampleR <= XSFPlayer::CHECK_SILENCE_LEVEL * 2;
+
+ if (silence)
+ {
+ if (++this->detectedSilenceSample >= this->sampleRate)
+ {
+ this->detectedSilenceSample -= this->sampleRate;
+ ++this->detectedSilenceSec;
+ if (this->skipSilenceOnStartSec && this->detectedSilenceSec >= this->skipSilenceOnStartSec)
+ {
+ this->skipSilenceOnStartSec = this->detectedSilenceSec = 0;
+ if (ofs)
+ skipOffset = ofs;
+ }
+ }
+ }
+ else
+ {
+ this->detectedSilenceSample = this->detectedSilenceSec = 0;
+ if (this->skipSilenceOnStartSec)
+ {
+ this->skipSilenceOnStartSec = 0;
+ if (ofs)
+ skipOffset = ofs;
+ }
+ }
+
+ prevSampleL = sampleL + XSFPlayer::CHECK_SILENCE_BIAS;
+ prevSampleR = sampleR + XSFPlayer::CHECK_SILENCE_BIAS;
+ }
+
+ if (!this->skipSilenceOnStartSec)
+ {
+ if (skipOffset)
+ {
+ std::vector<uint8_t> tmpBuf = std::vector<uint8_t>(2 * skipOffset);
+ memcpy(&tmpBuf[0], &buf[offset + 2 * skipOffset], 2 * skipOffset);
+ memcpy(&buf[offset], &tmpBuf[0], 2 * skipOffset);
+ pos += skipOffset;
+ }
+ else
+ pos += remain;
+ }
+ }
+ else
+ pos += remain;
+ }
+
+ /* Detect end of song */
+ if (!xSFConfig->GetPlayInfinitely())
+ {
+ if (this->currentSample >= this->lengthSample + this->fadeSample)
+ {
+ samplesWritten = 0;
+ return true;
+ }
+ if (this->currentSample + bufsize >= this->lengthSample + this->fadeSample)
+ {
+ bufsize = this->lengthSample + this->fadeSample - this->currentSample;
+ endFlag = true;
+ }
+ }
+
+ /* Volume */
+ if (!this->ignoreVolume && (!fEqual(this->volume, 1.0) || !fEqual(xSFConfig->GetVolume(), 1.0)))
+ {
+ double scale = this->volume * xSFConfig->GetVolume();
+ short *bufShort = reinterpret_cast<short *>(&buf[0]);
+ for (unsigned ofs = 0; ofs < bufsize; ++ofs)
+ {
+ double s1 = bufShort[2 * ofs] * scale, s2 = bufShort[2 * ofs + 1] * scale;
+ if (s1 > 0x7FFF)
+ s1 = 0x7FFF;
+ else if (s1 < -0x8000)
+ s1 = -0x8000;
+ if (s2 > 0x7FFF)
+ s2 = 0x7FFF;
+ else if (s2 < -0x8000)
+ s2 = -0x8000;
+ bufShort[2 * ofs] = static_cast<short>(s1);
+ bufShort[2 * ofs + 1] = static_cast<short>(s2);
+ }
+ }
+
+ /* Fading */
+ if (!xSFConfig->GetPlayInfinitely() && this->fadeSample && this->currentSample + bufsize >= this->lengthSample)
+ {
+ short *bufShort = reinterpret_cast<short *>(&buf[0]);
+ for (unsigned ofs = 0; ofs < bufsize; ++ofs)
+ {
+ if (this->currentSample + ofs >= this->lengthSample && this->currentSample + ofs < this->lengthSample + this->fadeSample)
+ {
+ int scale = static_cast<uint64_t>(this->lengthSample + this->fadeSample - (this->currentSample + ofs)) * 0x10000 / this->fadeSample;
+ bufShort[2 * ofs] = (bufShort[2 * ofs] * scale) >> 16;
+ bufShort[2 * ofs + 1] = (bufShort[2 * ofs + 1] * scale) >> 16;
+ }
+ else if (this->currentSample + ofs >= this->lengthSample + this->fadeSample)
+ bufShort[2 * ofs] = bufShort[2 * ofs + 1] = 0;
+ }
+ }
+
+ this->currentSample += bufsize;
+ samplesWritten = bufsize;
+ return endFlag;
+}
+
+bool XSFPlayer::Load()
+{
+ this->lengthInMS = this->xSF->GetLengthMS(xSFConfig->GetDefaultLength());
+ this->fadeInMS = this->xSF->GetFadeMS(xSFConfig->GetDefaultFade());
+ this->lengthSample = static_cast<uint64_t>(this->lengthInMS) * this->sampleRate / 1000;
+ this->fadeSample = static_cast<uint64_t>(this->fadeInMS) * this->sampleRate / 1000;
+ this->volume = this->xSF->GetVolume(xSFConfig->GetVolumeType(), xSFConfig->GetPeakType());
+ return true;
+}
+
+void XSFPlayer::SeekTop()
+{
+ this->skipSilenceOnStartSec = xSFConfig->GetSkipSilenceOnStartSec();
+ this->currentSample = this->detectedSilenceSec = this->detectedSilenceSample = 0;
+ this->prevSampleL = this->prevSampleR = XSFPlayer::CHECK_SILENCE_BIAS;
+}
+
+#ifdef WINAMP_PLUGIN
+
+static inline DWORD TicksDiff(DWORD prev, DWORD cur) { return cur >= prev ? cur - prev : 0xFFFFFFFF - prev + cur; }
+
+int XSFPlayer::Seek(unsigned seekPosition, volatile int *killswitch, std::vector<uint8_t> &buf, Out_Module *outMod)
+{
+ unsigned bufsize = buf.size() >> 2, seekSample = static_cast<uint64_t>(seekPosition) * this->sampleRate / 1000;
+ DWORD prevTick = outMod ? GetTickCount() : 0;
+ if (seekSample < this->currentSample)
+ {
+ this->Terminate();
+ this->Load();
+ this->SeekTop();
+ }
+ while (seekSample - this->currentSample > bufsize)
+ {
+ if (killswitch && *killswitch)
+ return 1;
+ if (outMod)
+ {
+ DWORD curTick = GetTickCount();
+ if (TicksDiff(prevTick, curTick) >= 500)
+ {
+ prevTick = curTick;
+ unsigned cur = static_cast<uint64_t>(this->currentSample) * 1000 / this->sampleRate;
+ outMod->Flush(cur);
+ }
+ }
+ this->GenerateSamples(buf, 0, bufsize);
+ this->currentSample += bufsize;
+ }
+ if (seekSample - this->currentSample > 0)
+ {
+ this->GenerateSamples(buf, 0, seekSample - this->currentSample);
+ this->currentSample = seekSample;
+ }
+ if (outMod)
+ outMod->Flush(seekPosition);
+ return 0;
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/XSFPlayer.h
@@ -1,1 +1,60 @@
+/*
+ * xSF - Core Player
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Partially based on the vio*sf framework
+ */
+#ifndef XSFPLAYER_H
+#define XSFPLAYER_H
+
+#include "XSFFile.h"
+
+#ifdef WINAMP_PLUGIN
+# include <winamp/out.h>
+#endif
+
+// This is a base class, a player for a specific type of xSF should inherit from this.
+class XSFPlayer
+{
+protected:
+ static const unsigned CHECK_SILENCE_BIAS = 0x8000000;
+ static const unsigned CHECK_SILENCE_LEVEL = 7;
+
+ XSFFile *xSF;
+ unsigned sampleRate, detectedSilenceSample, detectedSilenceSec, skipSilenceOnStartSec, lengthSample, fadeSample, currentSample;
+ unsigned long prevSampleL, prevSampleR;
+ int lengthInMS, fadeInMS;
+ double volume;
+ bool ignoreVolume;
+
+ XSFPlayer();
+ XSFPlayer(const XSFPlayer &xSFPLayer);
+public:
+ // These are not defined in XSFPlayer.cpp, they should be defined in your own player's source. The Create functions should return a pointer to your player's class.
+ static const char *WinampDescription;
+ static const char *WinampExts;
+ static XSFPlayer *Create(const std::string &fn);
+ static XSFPlayer *Create(const std::wstring &fn);
+
+ virtual ~XSFPlayer() { if (this->xSF) delete this->xSF; }
+ XSFPlayer &operator=(const XSFPlayer &xSFPlayer);
+ XSFFile *GetXSFFile() { return this->xSF; }
+ const XSFFile *GetXSFFile() const { return this->xSF; }
+ unsigned GetLengthInSamples() const { return this->lengthSample + this->fadeSample; }
+ unsigned GetSampleRate() const { return this->sampleRate; }
+ void SetSampleRate(unsigned newSampleRate) { this->sampleRate = newSampleRate; }
+ void IgnoreVolume() { this->ignoreVolume = true; }
+ virtual bool Load();
+ bool FillBuffer(std::vector<uint8_t> &buf, unsigned &samplesWritten);
+ virtual void GenerateSamples(std::vector<uint8_t> &buf, unsigned offset, unsigned samples) = 0;
+ void SeekTop();
+#ifdef WINAMP_PLUGIN
+ int Seek(unsigned seekPosition, volatile int *killswitch, std::vector<uint8_t> &buf, Out_Module *outMod);
+#endif
+ virtual void Terminate() = 0;
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/XSFTagList.cpp
@@ -1,1 +1,60 @@
+/*
+ * xSF Tag List
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ */
+#include <algorithm>
+#include "XSFTagList.h"
+
+eq_str XSFTagNameCompare::eqstr;
+
+bool XSFTagNameCompare::operator()(const std::pair<std::string, std::string> &v) const
+{
+ return XSFTagNameCompare::eqstr(v.first, this->name);
+}
+
+std::vector<std::string> XSFTagList::GetAllKeys() const
+{
+ std::vector<std::string> keys;
+ for (XSFTagList::Tags::const_iterator curr = this->tags.begin(), end = this->tags.end(); curr != end; ++curr)
+ keys.push_back(curr->first);
+ return keys;
+}
+
+bool XSFTagList::Exists(const std::string &name) const
+{
+ return std::find_if(this->tags.begin(), this->tags.end(), XSFTagNameCompare(name)) != this->tags.end();
+}
+
+std::string XSFTagList::operator[](const std::string &name) const
+{
+ XSFTagList::Tags::const_iterator tag = std::find_if(this->tags.begin(), this->tags.end(), XSFTagNameCompare(name));
+ if (tag == this->tags.end())
+ return "";
+ return tag->second;
+}
+
+std::string &XSFTagList::operator[](const std::string &name)
+{
+ XSFTagList::Tags::iterator tag = std::find_if(this->tags.begin(), this->tags.end(), XSFTagNameCompare(name));
+ if (tag == this->tags.end())
+ {
+ this->tags.push_back(std::make_pair(name, ""));
+ return this->tags[this->tags.size() - 1].second;
+ }
+ return tag->second;
+}
+
+void XSFTagList::Remove(const std::string &name)
+{
+ XSFTagList::Tags::iterator tag = std::find_if(this->tags.begin(), this->tags.end(), XSFTagNameCompare(name));
+ if (tag != this->tags.end())
+ this->tags.erase(tag);
+}
+
+void XSFTagList::Clear()
+{
+ this->tags.clear();
+}
+
--- /dev/null
+++ b/src/in_xsf_framework/XSFTagList.h
@@ -1,1 +1,39 @@
+/*
+ * xSF Tag List
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-21
+ */
+#ifndef XSFTAGLIST_H
+#define XSFTAGLIST_H
+
+#include <utility>
+#include <vector>
+#include "eqstr.h"
+
+struct XSFTagNameCompare
+{
+ XSFTagNameCompare(const std::string &Name) : name(Name) { }
+ bool operator()(const std::pair<std::string, std::string> &v) const;
+private:
+ static eq_str eqstr;
+ std::string name;
+};
+
+class XSFTagList
+{
+ typedef std::vector<std::pair<std::string, std::string> > Tags;
+
+ Tags tags;
+public:
+ XSFTagList() : tags() { }
+ std::vector<std::string> GetAllKeys() const;
+ bool Exists(const std::string &name) const;
+ std::string operator[](const std::string &name) const;
+ std::string &operator[](const std::string &name);
+ void Remove(const std::string &name);
+ void Clear();
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/convert.h
@@ -1,1 +1,157 @@
+/*
+ * Common conversion functions
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ */
+#ifndef _CONVERT_H_
+#define _CONVERT_H_
+
+#include <stdexcept>
+#include <string>
+#include <sstream>
+#include <typeinfo>
+#include <locale>
+#include <vector>
+#include <cmath>
+#include "BigSString.h"
+
+/*
+ * The following exception class and the *stringify and convert* functions are
+ * from the C++ FAQ, section 39, entry 3:
+ * http://www.parashift.com/c++-faq/convert-string-to-any.html
+ *
+ * The convert and convertTo functions were made into templates of std::basic_string
+ * to handle wide-character strings properly, as well as adding wstringify for the
+ * same reason.
+ */
+class BadConversion : public std::runtime_error
+{
+public:
+ BadConversion(const std::string &s) : std::runtime_error(s) { }
+};
+
+template<typename T> inline std::string stringify(const T &x)
+{
+ std::ostringstream o;
+ if (!(o << x))
+ throw BadConversion(std::string("stringify(") + typeid(x).name() + ")");
+ return o.str();
+}
+
+template<typename T> inline std::wstring wstringify(const T &x)
+{
+ std::wostringstream o;
+ if (!(o << x))
+ throw BadConversion(std::string("wstringify(") + typeid(x).name() + ")");
+ return o.str();
+}
+
+template<typename T, typename S> inline void convert(const std::basic_string<S> &s, T &x, bool failIfLeftoverChars = true)
+{
+ auto i = std::basic_istringstream<S>(s);
+ S c;
+ if (!(i >> x) || (failIfLeftoverChars && i.get(c)))
+ throw BadConversion(std::string("convert(") + typeid(S).name() + ")");
+}
+
+template<typename T, typename S> inline T convertTo(const std::basic_string<S> &s, bool failIfLeftoverChars = true)
+{
+ T x;
+ convert(s, x, failIfLeftoverChars);
+ return x;
+}
+
+// Miscellaneous conversion functions
+class ConvertFuncs
+{
+private:
+ static inline bool IsDigitsOnly(const std::string input, const std::locale &loc = std::locale::classic())
+ {
+ auto inputChars = std::vector<char>(input.begin(), input.end());
+ size_t length = inputChars.size();
+ auto masks = std::vector<std::ctype<char>::mask>(length);
+ std::use_facet<std::ctype<char> >(loc).is(&inputChars[0], &inputChars[length], &masks[0]);
+ for (size_t x = 0; x < length; ++x)
+ if (inputChars[x] != '.' && !(masks[x] & std::ctype<char>::digit))
+ return false;
+ return true;
+ }
+
+public:
+ static unsigned long StringToMS(const std::string &time)
+ {
+ unsigned long hours = 0, minutes = 0;
+ double seconds = 0.0;
+ std::string hoursStr, minutesStr, secondsStr;
+ size_t firstcolon = time.find(':');
+ if (firstcolon != std::string::npos)
+ {
+ size_t secondcolon = time.substr(firstcolon + 1).find(':');
+ if (secondcolon != std::string::npos)
+ {
+ secondcolon = firstcolon + secondcolon + 1;
+ hoursStr = time.substr(0, firstcolon);
+ minutesStr = time.substr(firstcolon + 1, secondcolon - firstcolon - 1);
+ secondsStr = time.substr(secondcolon + 1);
+ }
+ else
+ {
+ minutesStr = time.substr(0, firstcolon);
+ secondsStr = time.substr(firstcolon + 1);
+ }
+ }
+ else
+ secondsStr = time;
+ if (!hoursStr.empty())
+ {
+ if (!ConvertFuncs::IsDigitsOnly(hoursStr))
+ return 0;
+ hours = convertTo<unsigned long>(hoursStr, false);
+ }
+ if (!minutesStr.empty())
+ {
+ if (!ConvertFuncs::IsDigitsOnly(minutesStr))
+ return 0;
+ minutes = convertTo<unsigned long>(minutesStr, false);
+ }
+ if (!secondsStr.empty())
+ {
+ if (!ConvertFuncs::IsDigitsOnly(secondsStr))
+ return 0;
+ size_t comma = secondsStr.find(',');
+ if (comma != std::string::npos)
+ secondsStr[comma] = '.';
+ seconds = convertTo<double>(secondsStr, false);
+ }
+ seconds += minutes * 60 + hours * 1440;
+ return static_cast<unsigned long>(std::floor(seconds * 1000 + 0.5));
+ }
+
+ static unsigned long StringToMS(const std::wstring &time)
+ {
+ return ConvertFuncs::StringToMS(String(time).GetAnsi());
+ }
+
+ static std::string MSToString(unsigned long time)
+ {
+ double seconds = time / 1000.0;
+ if (seconds < 60)
+ return stringify(seconds);
+ unsigned long minutes = static_cast<unsigned long>(seconds) / 60;
+ seconds -= minutes * 60;
+ if (minutes < 60)
+ return stringify(minutes) + ":" + (seconds < 10 ? "0" : "") + stringify(seconds);
+ unsigned long hours = minutes / 60;
+ minutes %= 60;
+ return stringify(hours) + ":" + (minutes < 10 ? "0" : "") + stringify(minutes) + ":" + (seconds < 10 ? "0" : "") + stringify(seconds);
+ }
+
+ static std::wstring MSToWString(unsigned long time)
+ {
+ return String(ConvertFuncs::MSToString(time)).GetWStr();
+ }
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/eqstr.h
@@ -1,1 +1,44 @@
+/*
+ * Case-insensitive string equality
+ * Last modification on 2013-03-21
+ *
+ * Based on "How to do case-insensitive string comparison"
+ * By Matt Austern
+ * http://lafstern.org/matt/col2_new.pdf
+ */
+#ifndef EQSTR_H
+#define EQSTR_H
+
+#include <functional>
+#include <locale>
+#include <string>
+#include <algorithm>
+#include <climits>
+
+struct eq_str : std::binary_function<std::string, std::string, bool>
+{
+ struct eq_char : std::binary_function<char, char, bool>
+ {
+ const char *tab;
+ eq_char(const char *t) : tab(t) { }
+ bool operator()(char x, char y) const { return this->tab[x - CHAR_MIN] == this->tab[y - CHAR_MIN]; }
+ };
+
+ char tab[CHAR_MAX - CHAR_MIN + 1];
+
+ eq_str(const std::locale &L = std::locale::classic())
+ {
+ for (int i = CHAR_MIN; i <= CHAR_MAX; ++i)
+ this->tab[i - CHAR_MIN] = static_cast<char>(i);
+ std::use_facet<std::ctype<char> >(L).toupper(this->tab, this->tab + (CHAR_MAX - CHAR_MIN + 1));
+ }
+
+ bool operator()(const std::string &x, const std::string &y) const
+ {
+ return x.length() == y.length() && std::equal(x.begin(), x.end(), y.begin(), eq_char(this->tab));
+ }
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/in_xsf.cpp
@@ -1,1 +1,465 @@
-
+/*
+ * xSF - Winamp plugin
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
+ * Last modification on 2013-03-25
+ *
+ * Partially based on the vio*sf framework
+ */
+
+#include "XSFPlayer.h"
+#include "XSFConfig.h"
+#include "windowsh_wrapper.h"
+#include <winamp/in2.h>
+#include <winamp/wa_ipc.h>
+
+extern In_Module inMod;
+const XSFFile *xSFFile = NULL;
+XSFFile *xSFFileInInfo = NULL;
+XSFPlayer *xSFPlayer = NULL;
+XSFConfig *xSFConfig = NULL;
+bool paused;
+int seek_needed;
+double decode_pos_ms;
+HANDLE thread_handle = INVALID_HANDLE_VALUE;
+bool killThread = false;
+
+static const unsigned NumChannels = 2;
+static const unsigned BitsPerSample = 16;
+
+DWORD WINAPI playThread(void *b)
+{
+ bool done = false;
+ while (!*static_cast<bool *>(b))
+ {
+ if (seek_needed != -1)
+ {
+ decode_pos_ms = seek_needed - (seek_needed % 1000);
+ seek_needed = -1;
+ auto dummyBuffer = std::vector<uint8_t>(576 * NumChannels * (BitsPerSample / 8));
+ xSFPlayer->Seek(static_cast<unsigned>(decode_pos_ms), NULL, dummyBuffer, inMod.outMod);
+ }
+
+ if (done)
+ {
+ inMod.outMod->CanWrite();
+ if (!inMod.outMod->IsPlaying())
+ {
+ PostMessage(inMod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
+ return 0;
+ }
+ Sleep(10);
+ }
+ else if (static_cast<unsigned>(inMod.outMod->CanWrite()) >= ((576 * NumChannels * (BitsPerSample / 8)) << (inMod.dsp_isactive() ? 1 : 0)))
+ {
+ auto sampleBuffer = std::vector<uint8_t>(576 * NumChannels * (BitsPerSample / 8));
+ unsigned samplesWritten = 0;
+ done = xSFPlayer->FillBuffer(sampleBuffer, samplesWritten);
+ if (samplesWritten)
+ {
+ inMod.SAAddPCMData(reinterpret_cast<char *>(&sampleBuffer[0]), NumChannels, BitsPerSample, static_cast<int>(decode_pos_ms));
+ inMod.VSAAddPCMData(reinterpret_cast<char *>(&sampleBuffer[0]), NumChannels, BitsPerSample, static_cast<int>(decode_pos_ms));
+ if (inMod.dsp_isactive())
+ samplesWritten = inMod.dsp_dosamples(reinterpret_cast<short *>(&sampleBuffer[0]), samplesWritten, BitsPerSample, NumChannels, xSFPlayer->GetSampleRate());
+ decode_pos_ms += samplesWritten * 1000.0 / xSFPlayer->GetSampleRate();
+ inMod.outMod->Write(reinterpret_cast<char *>(&sampleBuffer[0]), samplesWritten * NumChannels * (BitsPerSample / 8));
+ }
+ }
+ else
+ Sleep(20);
+ }
+ return 0;
+}
+
+void config(HWND hwndParent)
+{
+ xSFConfig->CallConfigDialog(inMod.hDllInstance, hwndParent);
+}
+
+void about(HWND hwndParent)
+{
+ xSFConfig->About(hwndParent);
+}
+
+void init()
+{
+ xSFConfig = XSFConfig::Create();
+ xSFConfig->LoadConfig();
+ xSFConfig->GenerateDialogs();
+}
+
+void quit()
+{
+ delete xSFPlayer;
+ delete xSFConfig;
+}
+
+void getFileInfo(const in_char *file, in_char *title, int *length_in_ms)
+{
+ const XSFFile *xSF;
+ bool toFree = false;
+ if (!file || !*file)
+ xSF = xSFFile;
+ else
+ {
+ xSF = new XSFFile(file);
+ toFree = true;
+ }
+ if (title)
+ {
+ String formattedTitle = xSF->GetFormattedTitle(xSFConfig->GetTitleFormat()).Substring(0, GETFILEINFO_TITLE_LENGTH - 1);
+ formattedTitle.CopyToString(title);
+ }
+ if (length_in_ms)
+ *length_in_ms = xSF->GetLengthMS(xSFConfig->GetDefaultLength()) + xSF->GetFadeMS(xSFConfig->GetDefaultFade());
+ if (toFree)
+ delete xSF;
+}
+
+int infoBox(const in_char *file, HWND hwndParent)
+{
+ auto xSF = std::auto_ptr<XSFFile>(new XSFFile());
+ if (!file || !*file)
+ *xSF = *xSFFile;
+ else
+ {
+ auto tmpxSF = std::auto_ptr<XSFFile>(new XSFFile(file));
+ *xSF = *tmpxSF;
+ }
+ // TODO: Eventually make a dialog box for editing the info
+ /*xSFFileInInfo = xSF.get();
+ xSFConfig->CallInfoDialog(inMod.hDllInstance, hwndParent);*/
+ bool utf8 = xSF->GetTagExists("utf8");
+ auto tags = xSF->GetAllTags();
+ auto keys = tags.GetKeys();
+ String info;
+ for (unsigned x = 0, numTags = keys.size(); x < numTags; ++x)
+ {
+ if (x)
+ info += "\n";
+ info += String(keys[x] + "=") + String(tags[keys[x]], utf8);
+ }
+ MessageBoxW(hwndParent, info.GetWStrC(), xSF->GetFilenameWithoutPath().GetWStrC(), MB_OK);
+ return INFOBOX_EDITED;
+}
+
+int isOurFile(const in_char *fn)
+{
+ return 0;
+}
+
+int play(const in_char *fn)
+{
+ try
+ {
+ auto tmpxSFPlayer = std::auto_ptr<XSFPlayer>(XSFPlayer::Create(fn));
+ xSFConfig->CopyConfigToMemory(tmpxSFPlayer.get(), true);
+ if (!tmpxSFPlayer->Load())
+ return 1;
+ xSFConfig->CopyConfigToMemory(tmpxSFPlayer.get(), false);
+ xSFFile = tmpxSFPlayer->GetXSFFile();
+ paused = false;
+ seek_needed = -1;
+ decode_pos_ms = 0.0;
+
+ int maxlatency = inMod.outMod->Open(tmpxSFPlayer->GetSampleRate(), NumChannels, BitsPerSample, -1, -1);
+ if (maxlatency < 0)
+ return 1;
+ inMod.SetInfo((tmpxSFPlayer->GetSampleRate() * NumChannels * BitsPerSample) / 1000, tmpxSFPlayer->GetSampleRate() / 1000, NumChannels, 1);
+ inMod.SAVSAInit(maxlatency, tmpxSFPlayer->GetSampleRate());
+ inMod.VSASetInfo(tmpxSFPlayer->GetSampleRate(), NumChannels);
+ inMod.outMod->SetVolume(-666);
+
+ xSFPlayer = tmpxSFPlayer.release();
+ killThread = false;
+ thread_handle = CreateThread(NULL, 0, playThread, &killThread, 0, NULL);
+ return 0;
+ }
+ catch (const std::exception &)
+ {
+ return 1;
+ }
+}
+
+void pause()
+{
+ paused = true;
+ inMod.outMod->Pause(1);
+}
+
+void unPause()
+{
+ paused = false;
+ inMod.outMod->Pause(0);
+}
+
+int isPaused()
+{
+ return paused;
+}
+
+void stop()
+{
+ if (thread_handle != INVALID_HANDLE_VALUE)
+ {
+ killThread = true;
+ if (WaitForSingleObject(thread_handle, 2000) == WAIT_TIMEOUT)
+ {
+ MessageBoxW(inMod.hMainWindow, L"error asking thread to die!", L"error killing decode thread", 0);
+ TerminateThread(thread_handle, 0);
+ }
+ CloseHandle(thread_handle);
+ thread_handle = INVALID_HANDLE_VALUE;
+ }
+ inMod.outMod->Close();
+ inMod.SAVSADeInit();
+ delete xSFPlayer;
+ xSFPlayer = NULL;
+ xSFFile = NULL;
+}
+
+int getLength()
+{
+ if (!xSFFile->HasFile())
+ return -1000;
+ return xSFFile->GetLengthMS(xSFConfig->GetDefaultLength()) + xSFFile->GetFadeMS(xSFConfig->GetDefaultFade());
+}
+
+int getOutputTime()
+{
+ return inMod.outMod->GetOutputTime();
+}
+
+void setOutputTime(int time_in_ms)
+{
+ seek_needed = time_in_ms;
+}
+
+void setVolume(int volume)
+{
+ inMod.outMod->SetVolume(volume);
+}
+
+void setPan(int pan)
+{
+ inMod.outMod->SetPan(pan);
+}
+
+void eqSet(int on, char data[10], int preamp)
+{
+}
+
+In_Module inMod =
+{
+ IN_VER,
+ const_cast<char *>(XSFPlayer::WinampDescription), /* Unsafe but Winamp's SDK requires this */
+ NULL, /* Filled by Winamp */
+ NULL, /* Filled by Winamp */
+ const_cast<char *>(XSFPlayer::WinampExts), /* Unsafe but Winamp's SDK requires this */
+ 1,
+ IN_MODULE_FLAG_USES_OUTPUT_PLUGIN | IN_MODULE_FLAG_REPLAYGAIN,
+ config,
+ about,
+ init,
+ quit,
+ getFileInfo,
+ infoBox,
+ isOurFile,
+ play,
+ pause,
+ unPause,
+ isPaused,
+ stop,
+ getLength,
+ getOutputTime,
+ setOutputTime,
+ setVolume,
+ setPan,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Vis stuff, filled by Winamp */
+ NULL, NULL, /* DSP stuff, filled by Winamp */
+ eqSet,
+ NULL, /* Filled by Winamp */
+ NULL /* Filled by Winamp */
+};
+
+extern "C" __declspec(dllexport) In_Module *winampGetInModule2()
+{
+ return &inMod;
+}
+
+static eq_str eqstr;
+
+extern "C" __declspec(dllexport) int winampGetExtendedFileInfo(const char *fn, const char *data, char *dest, size_t destlen)
+{
+ if (eqstr(data, "type"))
+ {
+ dest[0] = '0';
+ dest[1] = 0;
+ return 1;
+ }
+ else if (eqstr(data, "family"))
+ {
+ return 0;
+ }
+ else
+ {
+ XSFFile file = XSFFile(fn);
+ std::string tagToGet = data;
+ if (eqstr(data, "album"))
+ tagToGet = "game";
+ if (!file.GetTagExists(tagToGet))
+ {
+ if (eqstr(tagToGet, "replaygain_track_gain"))
+ return 1;
+ return 0;
+ }
+ else if (eqstr(tagToGet, "length"))
+ {
+ strcpy(dest, stringify(file.GetLengthMS(xSFConfig->GetDefaultLength()) + file.GetFadeMS(xSFConfig->GetDefaultFade())).c_str());
+ return 1;
+ }
+ file.GetTagValue(tagToGet).Substring(0, destlen - 1).CopyToString(dest, true);
+ return 1;
+ }
+}
+
+extern "C" __declspec(dllexport) int winampGetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *dest, size_t destlen)
+{
+ if (eqstr(data, "type"))
+ {
+ dest[0] = L'0';
+ dest[1] = 0;
+ return 1;
+ }
+ else if (eqstr(data, "family"))
+ {
+ return 0;
+ }
+ else
+ {
+ XSFFile file = XSFFile(fn);
+ std::string tagToGet = data;
+ if (eqstr(data, "album"))
+ tagToGet = "game";
+ if (!file.GetTagExists(tagToGet))
+ {
+ if (eqstr(tagToGet, "replaygain_track_gain"))
+ return 1;
+ return 0;
+ }
+ else if (eqstr(tagToGet, "length"))
+ {
+ wcscpy(dest, wstringify(file.GetLengthMS(xSFConfig->GetDefaultLength()) + file.GetFadeMS(xSFConfig->GetDefaultFade())).c_str());
+ return 1;
+ }
+ file.GetTagValue(tagToGet).Substring(0, destlen - 1).CopyToString(dest);
+ return 1;
+ }
+}
+
+std::auto_ptr<XSFFile> extendedXSFFile;
+
+int wrapperWinampSetExtendedFileInfo(const char *data, const wchar_t *val)
+{
+ extendedXSFFile->SetTag(data, val);
+ return 1;
+}
+
+extern "C" __declspec(dllexport) int winampSetExtendedFileInfo(const char *fn, const char *data, const wchar_t *val)
+{
+ if (!extendedXSFFile.get() || extendedXSFFile->GetFilename().GetStr() != fn)
+ extendedXSFFile.reset(new XSFFile(fn));
+ return wrapperWinampSetExtendedFileInfo(data, val);
+}
+
+extern "C" __declspec(dllexport) int winampSetExtendedFileInfoW(const wchar_t *fn, const char *data, const wchar_t *val)
+{
+ if (!extendedXSFFile.get() || extendedXSFFile->GetFilename().GetWStr() != fn)
+ extendedXSFFile.reset(new XSFFile(fn));
+ return wrapperWinampSetExtendedFileInfo(data, val);
+}
+
+extern "C" __declspec(dllexport) int winampWriteExtendedFileInfo()
+{
+ if (!extendedXSFFile.get() || extendedXSFFile->GetFilename().empty())
+ return 0;
+ extendedXSFFile->SaveFile();
+ return 1;
+}
+
+extern "C" __declspec(dllexport) int winampClearExtendedFileInfoW(const wchar_t *fn)
+{
+ return 0;
+}
+
+intptr_t wrapperWinampGetExtendedRead_open(std::auto_ptr<XSFPlayer> tmpxSFPlayer, int *size, int *bps, int *nch, int *srate)
+{
+ xSFConfig->CopyConfigToMemory(tmpxSFPlayer.get(), true);
+ if (!tmpxSFPlayer->Load())
+ return 0;
+ tmpxSFPlayer->IgnoreVolume();
+ xSFConfig->CopyConfigToMemory(tmpxSFPlayer.get(), false);
+ if (size)
+ *size = tmpxSFPlayer->GetLengthInSamples() * NumChannels * (BitsPerSample / 8);
+ if (bps)
+ *bps = BitsPerSample;
+ if (nch)
+ *nch = NumChannels;
+ if (srate)
+ *srate = tmpxSFPlayer->GetSampleRate();
+ return reinterpret_cast<intptr_t>(tmpxSFPlayer.release());
+}
+
+extern "C" __declspec(dllexport) intptr_t winampGetExtendedRead_open(const char *fn, int *size, int *bps, int *nch, int *srate)
+{
+ auto tmpxSFPlayer = std::auto_ptr<XSFPlayer>(XSFPlayer::Create(fn));
+ return wrapperWinampGetExtendedRead_open(tmpxSFPlayer, size, bps, nch, srate);
+}
+
+extern "C" __declspec(dllexport) intptr_t winampGetExtendedRead_openW(const wchar_t *fn, int *size, int *bps, int *nch, int *srate)
+{
+ auto tmpxSFPlayer = std::auto_ptr<XSFPlayer>(XSFPlayer::Create(fn));
+ return wrapperWinampGetExtendedRead_open(tmpxSFPlayer, size, bps, nch, srate);
+}
+
+int extendedSeekNeeded = -1;
+
+extern "C" __declspec(dllexport) size_t winampGetExtendedRead_getData(intptr_t handle, char *dest, size_t len, int *killswitch)
+{
+ XSFPlayer *tmpxSFPlayer = reinterpret_cast<XSFPlayer *>(handle);
+ if (!tmpxSFPlayer)
+ return 0;
+ if (extendedSeekNeeded != -1)
+ {
+ auto dummyBuffer = std::vector<uint8_t>(576 * NumChannels * (BitsPerSample / 8));
+ if (tmpxSFPlayer->Seek(static_cast<unsigned>(extendedSeekNeeded), killswitch, dummyBuffer, NULL))
+ return 0;
+ extendedSeekNeeded = -1;
+ }
+ unsigned copied = 0;
+ bool done = false;
+ while (copied + (576 * NumChannels * (BitsPerSample / 8)) < len && !done)
+ {
+ auto sampleBuffer = std::vector<uint8_t>(576 * NumChannels * (BitsPerSample / 8));
+ unsigned samplesWritten = 0;
+ done = tmpxSFPlayer->FillBuffer(sampleBuffer, samplesWritten);
+ memcpy(&dest[copied], &sampleBuffer[0], samplesWritten * NumChannels * (BitsPerSample / 8));
+ copied += samplesWritten * NumChannels * (BitsPerSample / 8);
+ if (killswitch && *killswitch)
+ break;
+ }
+ return copied;
+}
+
+extern "C" __declspec(dllexport) int winampGetExtendedRead_setTime(intptr_t handle, int millisecs)
+{
+ extendedSeekNeeded = millisecs;
+ return 1;
+}
+
+extern "C" __declspec(dllexport) void winampGetExtendedRead_close(intptr_t handle)
+{
+ XSFPlayer *tmpxSFPlayer = reinterpret_cast<XSFPlayer *>(handle);
+ if (tmpxSFPlayer)
+ delete tmpxSFPlayer;
+}
+
--- /dev/null
+++ b/src/in_xsf_framework/ltstr.h
@@ -1,1 +1,44 @@
+/*
+ * Case-insensitive string comparison
+ * Last modification on 2012-03-21
+ *
+ * Based on "How to do case-insensitive string comparison"
+ * By Matt Austern
+ * http://lafstern.org/matt/col2_new.pdf
+ */
+#ifndef LTSTR_H
+#define LTSTR_H
+
+#include <functional>
+#include <locale>
+#include <string>
+#include <algorithm>
+#include <climits>
+
+struct lt_str : std::binary_function<std::string, std::string, bool>
+{
+ struct lt_char : std::binary_function<char, char, bool>
+ {
+ const char *tab;
+ lt_char(const char *t) : tab(t) { }
+ bool operator()(char x, char y) const { return this->tab[x - CHAR_MIN] < this->tab[y - CHAR_MIN]; }
+ };
+
+ char tab[CHAR_MAX - CHAR_MIN + 1];
+
+ lt_str(const std::locale &L = std::locale::classic())
+ {
+ for (int i = CHAR_MIN; i <= CHAR_MAX; ++i)
+ this->tab[i - CHAR_MIN] = static_cast<char>(i);
+ std::use_facet<std::ctype<char> >(L).toupper(this->tab, this->tab + (CHAR_MAX - CHAR_MIN + 1));
+ }
+
+ bool operator()(const std::string &x, const std::string &y) const
+ {
+ return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), lt_char(this->tab));
+ }
+};
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/pstdint.h
@@ -1,1 +1,801 @@
-
+/* A portable stdint.h
+ ****************************************************************************
+ * BSD License:
+ ****************************************************************************
+ *
+ * Copyright (c) 2005-2011 Paul Hsieh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************
+ *
+ * Version 0.1.12
+ *
+ * The ANSI C standard committee, for the C99 standard, specified the
+ * inclusion of a new standard include file called stdint.h. This is
+ * a very useful and long desired include file which contains several
+ * very precise definitions for integer scalar types that is
+ * critically important for making portable several classes of
+ * applications including cryptography, hashing, variable length
+ * integer libraries and so on. But for most developers its likely
+ * useful just for programming sanity.
+ *
+ * The problem is that most compiler vendors have decided not to
+ * implement the C99 standard, and the next C++ language standard
+ * (which has a lot more mindshare these days) will be a long time in
+ * coming and its unknown whether or not it will include stdint.h or
+ * how much adoption it will have. Either way, it will be a long time
+ * before all compilers come with a stdint.h and it also does nothing
+ * for the extremely large number of compilers available today which
+ * do not include this file, or anything comparable to it.
+ *
+ * So that's what this file is all about. Its an attempt to build a
+ * single universal include file that works on as many platforms as
+ * possible to deliver what stdint.h is supposed to. A few things
+ * that should be noted about this file:
+ *
+ * 1) It is not guaranteed to be portable and/or present an identical
+ * interface on all platforms. The extreme variability of the
+ * ANSI C standard makes this an impossibility right from the
+ * very get go. Its really only meant to be useful for the vast
+ * majority of platforms that possess the capability of
+ * implementing usefully and precisely defined, standard sized
+ * integer scalars. Systems which are not intrinsically 2s
+ * complement may produce invalid constants.
+ *
+ * 2) There is an unavoidable use of non-reserved symbols.
+ *
+ * 3) Other standard include files are invoked.
+ *
+ * 4) This file may come in conflict with future platforms that do
+ * include stdint.h. The hope is that one or the other can be
+ * used with no real difference.
+ *
+ * 5) In the current verison, if your platform can't represent
+ * int32_t, int16_t and int8_t, it just dumps out with a compiler
+ * error.
+ *
+ * 6) 64 bit integers may or may not be defined. Test for their
+ * presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX.
+ * Note that this is different from the C99 specification which
+ * requires the existence of 64 bit support in the compiler. If
+ * this is not defined for your platform, yet it is capable of
+ * dealing with 64 bits then it is because this file has not yet
+ * been extended to cover all of your system's capabilities.
+ *
+ * 7) (u)intptr_t may or may not be defined. Test for its presence
+ * with the test: #ifdef PTRDIFF_MAX. If this is not defined
+ * for your platform, then it is because this file has not yet
+ * been extended to cover all of your system's capabilities, not
+ * because its optional.
+ *
+ * 8) The following might not been defined even if your platform is
+ * capable of defining it:
+ *
+ * WCHAR_MIN
+ * WCHAR_MAX
+ * (u)int64_t
+ * PTRDIFF_MIN
+ * PTRDIFF_MAX
+ * (u)intptr_t
+ *
+ * 9) The following have not been defined:
+ *
+ * WINT_MIN
+ * WINT_MAX
+ *
+ * 10) The criteria for defining (u)int_least(*)_t isn't clear,
+ * except for systems which don't have a type that precisely
+ * defined 8, 16, or 32 bit types (which this include file does
+ * not support anyways). Default definitions have been given.
+ *
+ * 11) The criteria for defining (u)int_fast(*)_t isn't something I
+ * would trust to any particular compiler vendor or the ANSI C
+ * committee. It is well known that "compatible systems" are
+ * commonly created that have very different performance
+ * characteristics from the systems they are compatible with,
+ * especially those whose vendors make both the compiler and the
+ * system. Default definitions have been given, but its strongly
+ * recommended that users never use these definitions for any
+ * reason (they do *NOT* deliver any serious guarantee of
+ * improved performance -- not in this file, nor any vendor's
+ * stdint.h).
+ *
+ * 12) The following macros:
+ *
+ * PRINTF_INTMAX_MODIFIER
+ * PRINTF_INT64_MODIFIER
+ * PRINTF_INT32_MODIFIER
+ * PRINTF_INT16_MODIFIER
+ * PRINTF_LEAST64_MODIFIER
+ * PRINTF_LEAST32_MODIFIER
+ * PRINTF_LEAST16_MODIFIER
+ * PRINTF_INTPTR_MODIFIER
+ *
+ * are strings which have been defined as the modifiers required
+ * for the "d", "u" and "x" printf formats to correctly output
+ * (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t,
+ * (u)least32_t, (u)least16_t and (u)intptr_t types respectively.
+ * PRINTF_INTPTR_MODIFIER is not defined for some systems which
+ * provide their own stdint.h. PRINTF_INT64_MODIFIER is not
+ * defined if INT64_MAX is not defined. These are an extension
+ * beyond what C99 specifies must be in stdint.h.
+ *
+ * In addition, the following macros are defined:
+ *
+ * PRINTF_INTMAX_HEX_WIDTH
+ * PRINTF_INT64_HEX_WIDTH
+ * PRINTF_INT32_HEX_WIDTH
+ * PRINTF_INT16_HEX_WIDTH
+ * PRINTF_INT8_HEX_WIDTH
+ * PRINTF_INTMAX_DEC_WIDTH
+ * PRINTF_INT64_DEC_WIDTH
+ * PRINTF_INT32_DEC_WIDTH
+ * PRINTF_INT16_DEC_WIDTH
+ * PRINTF_INT8_DEC_WIDTH
+ *
+ * Which specifies the maximum number of characters required to
+ * print the number of that type in either hexadecimal or decimal.
+ * These are an extension beyond what C99 specifies must be in
+ * stdint.h.
+ *
+ * Compilers tested (all with 0 warnings at their highest respective
+ * settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32
+ * bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio
+ * .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3
+ *
+ * This file should be considered a work in progress. Suggestions for
+ * improvements, especially those which increase coverage are strongly
+ * encouraged.
+ *
+ * Acknowledgements
+ *
+ * The following people have made significant contributions to the
+ * development and testing of this file:
+ *
+ * Chris Howie
+ * John Steele Scott
+ * Dave Thorup
+ * John Dill
+ *
+ */
+
+#include <cstddef>
+#include <climits>
+#include <csignal>
+
+/*
+ * For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and
+ * do nothing else. On the Mac OS X version of gcc this is _STDINT_H_.
+ */
+
+#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined (__UINT_FAST64_TYPE__)) ) || (defined(_MSC_VER) && _MSC_VER >= 1600)) && !defined (_PSTDINT_H_INCLUDED)
+#include <stdint.h>
+#define _PSTDINT_H_INCLUDED
+# ifndef PRINTF_INT64_MODIFIER
+# define PRINTF_INT64_MODIFIER "ll"
+# endif
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER "l"
+# endif
+# ifndef PRINTF_INT16_MODIFIER
+# define PRINTF_INT16_MODIFIER "h"
+# endif
+# ifndef PRINTF_INTMAX_MODIFIER
+# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
+# endif
+# ifndef PRINTF_INT64_HEX_WIDTH
+# define PRINTF_INT64_HEX_WIDTH "16"
+# endif
+# ifndef PRINTF_INT32_HEX_WIDTH
+# define PRINTF_INT32_HEX_WIDTH "8"
+# endif
+# ifndef PRINTF_INT16_HEX_WIDTH
+# define PRINTF_INT16_HEX_WIDTH "4"
+# endif
+# ifndef PRINTF_INT8_HEX_WIDTH
+# define PRINTF_INT8_HEX_WIDTH "2"
+# endif
+# ifndef PRINTF_INT64_DEC_WIDTH
+# define PRINTF_INT64_DEC_WIDTH "20"
+# endif
+# ifndef PRINTF_INT32_DEC_WIDTH
+# define PRINTF_INT32_DEC_WIDTH "10"
+# endif
+# ifndef PRINTF_INT16_DEC_WIDTH
+# define PRINTF_INT16_DEC_WIDTH "5"
+# endif
+# ifndef PRINTF_INT8_DEC_WIDTH
+# define PRINTF_INT8_DEC_WIDTH "3"
+# endif
+# ifndef PRINTF_INTMAX_HEX_WIDTH
+# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
+# endif
+# ifndef PRINTF_INTMAX_DEC_WIDTH
+# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
+# endif
+
+/*
+ * Something really weird is going on with Open Watcom. Just pull some of
+ * these duplicated definitions from Open Watcom's stdint.h file for now.
+ */
+
+# if defined (__WATCOMC__) && __WATCOMC__ >= 1250
+# if !defined (INT64_C)
+# define INT64_C(x) (x + (INT64_MAX - INT64_MAX))
+# endif
+# if !defined (UINT64_C)
+# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
+# endif
+# if !defined (INT32_C)
+# define INT32_C(x) (x + (INT32_MAX - INT32_MAX))
+# endif
+# if !defined (UINT32_C)
+# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX))
+# endif
+# if !defined (INT16_C)
+# define INT16_C(x) (x)
+# endif
+# if !defined (UINT16_C)
+# define UINT16_C(x) (x)
+# endif
+# if !defined (INT8_C)
+# define INT8_C(x) (x)
+# endif
+# if !defined (UINT8_C)
+# define UINT8_C(x) (x)
+# endif
+# if !defined (UINT64_MAX)
+# define UINT64_MAX 18446744073709551615ULL
+# endif
+# if !defined (INT64_MAX)
+# define INT64_MAX 9223372036854775807LL
+# endif
+# if !defined (UINT32_MAX)
+# define UINT32_MAX 4294967295UL
+# endif
+# if !defined (INT32_MAX)
+# define INT32_MAX 2147483647L
+# endif
+# if !defined (INTMAX_MAX)
+# define INTMAX_MAX INT64_MAX
+# endif
+# if !defined (INTMAX_MIN)
+# define INTMAX_MIN INT64_MIN
+# endif
+# endif
+#endif
+
+#ifndef _PSTDINT_H_INCLUDED
+#define _PSTDINT_H_INCLUDED
+
+#ifndef SIZE_MAX
+# define SIZE_MAX (~(size_t)0)
+#endif
+
+/*
+ * Deduce the type assignments from limits.h under the assumption that
+ * integer sizes in bits are powers of 2, and follow the ANSI
+ * definitions.
+ */
+
+#ifndef UINT8_MAX
+# define UINT8_MAX 0xff
+#endif
+#ifndef uint8_t
+# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S)
+ typedef unsigned char uint8_t;
+# define UINT8_C(v) ((uint8_t) v)
+# else
+# error "Platform not supported"
+# endif
+#endif
+
+#ifndef INT8_MAX
+# define INT8_MAX 0x7f
+#endif
+#ifndef INT8_MIN
+# define INT8_MIN INT8_C(0x80)
+#endif
+#ifndef int8_t
+# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S)
+ typedef signed char int8_t;
+# define INT8_C(v) ((int8_t) v)
+# else
+# error "Platform not supported"
+# endif
+#endif
+
+#ifndef UINT16_MAX
+# define UINT16_MAX 0xffff
+#endif
+#ifndef uint16_t
+#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S)
+ typedef unsigned int uint16_t;
+# ifndef PRINTF_INT16_MODIFIER
+# define PRINTF_INT16_MODIFIER ""
+# endif
+# define UINT16_C(v) ((uint16_t) (v))
+#elif (USHRT_MAX == UINT16_MAX)
+ typedef unsigned short uint16_t;
+# define UINT16_C(v) ((uint16_t) (v))
+# ifndef PRINTF_INT16_MODIFIER
+# define PRINTF_INT16_MODIFIER "h"
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+#ifndef INT16_MAX
+# define INT16_MAX 0x7fff
+#endif
+#ifndef INT16_MIN
+# define INT16_MIN INT16_C(0x8000)
+#endif
+#ifndef int16_t
+#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S)
+ typedef signed int int16_t;
+# define INT16_C(v) ((int16_t) (v))
+# ifndef PRINTF_INT16_MODIFIER
+# define PRINTF_INT16_MODIFIER ""
+# endif
+#elif (SHRT_MAX == INT16_MAX)
+ typedef signed short int16_t;
+# define INT16_C(v) ((int16_t) (v))
+# ifndef PRINTF_INT16_MODIFIER
+# define PRINTF_INT16_MODIFIER "h"
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+#ifndef UINT32_MAX
+# define UINT32_MAX (0xffffffffUL)
+#endif
+#ifndef uint32_t
+#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S)
+ typedef unsigned long uint32_t;
+# define UINT32_C(v) v ## UL
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER "l"
+# endif
+#elif (UINT_MAX == UINT32_MAX)
+ typedef unsigned int uint32_t;
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER ""
+# endif
+# define UINT32_C(v) v ## U
+#elif (USHRT_MAX == UINT32_MAX)
+ typedef unsigned short uint32_t;
+# define UINT32_C(v) ((unsigned short) (v))
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER ""
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+#ifndef INT32_MAX
+# define INT32_MAX (0x7fffffffL)
+#endif
+#ifndef INT32_MIN
+# define INT32_MIN INT32_C(0x80000000)
+#endif
+#ifndef int32_t
+#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S)
+ typedef signed long int32_t;
+# define INT32_C(v) v ## L
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER "l"
+# endif
+#elif (INT_MAX == INT32_MAX)
+ typedef signed int int32_t;
+# define INT32_C(v) v
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER ""
+# endif
+#elif (SHRT_MAX == INT32_MAX)
+ typedef signed short int32_t;
+# define INT32_C(v) ((short) (v))
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER ""
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+/*
+ * The macro stdint_int64_defined is temporarily used to record
+ * whether or not 64 integer support is available. It must be
+ * defined for any 64 integer extensions for new platforms that are
+ * added.
+ */
+
+#undef stdint_int64_defined
+#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S)
+# if (__STDC__ && __STDC_VERSION__ >= 199901L) || defined (S_SPLINT_S)
+# define stdint_int64_defined
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+# define UINT64_C(v) v ## ULL
+# define INT64_C(v) v ## LL
+# ifndef PRINTF_INT64_MODIFIER
+# define PRINTF_INT64_MODIFIER "ll"
+# endif
+# endif
+#endif
+
+#if !defined (stdint_int64_defined)
+# if defined(__GNUC__)
+# define stdint_int64_defined
+ __extension__ typedef long long int64_t;
+ __extension__ typedef unsigned long long uint64_t;
+# define UINT64_C(v) v ## ULL
+# define INT64_C(v) v ## LL
+# ifndef PRINTF_INT64_MODIFIER
+# define PRINTF_INT64_MODIFIER "ll"
+# endif
+# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S)
+# define stdint_int64_defined
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+# define UINT64_C(v) v ## ULL
+# define INT64_C(v) v ## LL
+# ifndef PRINTF_INT64_MODIFIER
+# define PRINTF_INT64_MODIFIER "ll"
+# endif
+# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC)
+# define stdint_int64_defined
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+# define UINT64_C(v) v ## UI64
+# define INT64_C(v) v ## I64
+# ifndef PRINTF_INT64_MODIFIER
+# define PRINTF_INT64_MODIFIER "I64"
+# endif
+# endif
+#endif
+
+#if !defined (LONG_LONG_MAX) && defined (INT64_C)
+# define LONG_LONG_MAX INT64_C (9223372036854775807)
+#endif
+#ifndef ULONG_LONG_MAX
+# define ULONG_LONG_MAX UINT64_C (18446744073709551615)
+#endif
+
+#if !defined (INT64_MAX) && defined (INT64_C)
+# define INT64_MAX INT64_C (9223372036854775807)
+#endif
+#if !defined (INT64_MIN) && defined (INT64_C)
+# define INT64_MIN INT64_C (-9223372036854775808)
+#endif
+#if !defined (UINT64_MAX) && defined (INT64_C)
+# define UINT64_MAX UINT64_C (18446744073709551615)
+#endif
+
+/*
+ * Width of hexadecimal for number field.
+ */
+
+#ifndef PRINTF_INT64_HEX_WIDTH
+# define PRINTF_INT64_HEX_WIDTH "16"
+#endif
+#ifndef PRINTF_INT32_HEX_WIDTH
+# define PRINTF_INT32_HEX_WIDTH "8"
+#endif
+#ifndef PRINTF_INT16_HEX_WIDTH
+# define PRINTF_INT16_HEX_WIDTH "4"
+#endif
+#ifndef PRINTF_INT8_HEX_WIDTH
+# define PRINTF_INT8_HEX_WIDTH "2"
+#endif
+
+#ifndef PRINTF_INT64_DEC_WIDTH
+# define PRINTF_INT64_DEC_WIDTH "20"
+#endif
+#ifndef PRINTF_INT32_DEC_WIDTH
+# define PRINTF_INT32_DEC_WIDTH "10"
+#endif
+#ifndef PRINTF_INT16_DEC_WIDTH
+# define PRINTF_INT16_DEC_WIDTH "5"
+#endif
+#ifndef PRINTF_INT8_DEC_WIDTH
+# define PRINTF_INT8_DEC_WIDTH "3"
+#endif
+
+/*
+ * Ok, lets not worry about 128 bit integers for now. Moore's law says
+ * we don't need to worry about that until about 2040 at which point
+ * we'll have bigger things to worry about.
+ */
+
+#ifdef stdint_int64_defined
+ typedef int64_t intmax_t;
+ typedef uint64_t uintmax_t;
+# define INTMAX_MAX INT64_MAX
+# define INTMAX_MIN INT64_MIN
+# define UINTMAX_MAX UINT64_MAX
+# define UINTMAX_C(v) UINT64_C(v)
+# define INTMAX_C(v) INT64_C(v)
+# ifndef PRINTF_INTMAX_MODIFIER
+# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
+# endif
+# ifndef PRINTF_INTMAX_HEX_WIDTH
+# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
+# endif
+# ifndef PRINTF_INTMAX_DEC_WIDTH
+# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
+# endif
+#else
+ typedef int32_t intmax_t;
+ typedef uint32_t uintmax_t;
+# define INTMAX_MAX INT32_MAX
+# define UINTMAX_MAX UINT32_MAX
+# define UINTMAX_C(v) UINT32_C(v)
+# define INTMAX_C(v) INT32_C(v)
+# ifndef PRINTF_INTMAX_MODIFIER
+# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER
+# endif
+# ifndef PRINTF_INTMAX_HEX_WIDTH
+# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH
+# endif
+# ifndef PRINTF_INTMAX_DEC_WIDTH
+# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH
+# endif
+#endif
+
+/*
+ * Because this file currently only supports platforms which have
+ * precise powers of 2 as bit sizes for the default integers, the
+ * least definitions are all trivial. Its possible that a future
+ * version of this file could have different definitions.
+ */
+
+#ifndef stdint_least_defined
+ typedef int8_t int_least8_t;
+ typedef uint8_t uint_least8_t;
+ typedef int16_t int_least16_t;
+ typedef uint16_t uint_least16_t;
+ typedef int32_t int_least32_t;
+ typedef uint32_t uint_least32_t;
+# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER
+# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER
+# define UINT_LEAST8_MAX UINT8_MAX
+# define INT_LEAST8_MAX INT8_MAX
+# define UINT_LEAST16_MAX UINT16_MAX
+# define INT_LEAST16_MAX INT16_MAX
+# define UINT_LEAST32_MAX UINT32_MAX
+# define INT_LEAST32_MAX INT32_MAX
+# define INT_LEAST8_MIN INT8_MIN
+# define INT_LEAST16_MIN INT16_MIN
+# define INT_LEAST32_MIN INT32_MIN
+# ifdef stdint_int64_defined
+ typedef int64_t int_least64_t;
+ typedef uint64_t uint_least64_t;
+# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER
+# define UINT_LEAST64_MAX UINT64_MAX
+# define INT_LEAST64_MAX INT64_MAX
+# define INT_LEAST64_MIN INT64_MIN
+# endif
+#endif
+#undef stdint_least_defined
+
+/*
+ * The ANSI C committee pretending to know or specify anything about
+ * performance is the epitome of misguided arrogance. The mandate of
+ * this file is to *ONLY* ever support that absolute minimum
+ * definition of the fast integer types, for compatibility purposes.
+ * No extensions, and no attempt to suggest what may or may not be a
+ * faster integer type will ever be made in this file. Developers are
+ * warned to stay away from these types when using this or any other
+ * stdint.h.
+ */
+
+typedef int_least8_t int_fast8_t;
+typedef uint_least8_t uint_fast8_t;
+typedef int_least16_t int_fast16_t;
+typedef uint_least16_t uint_fast16_t;
+typedef int_least32_t int_fast32_t;
+typedef uint_least32_t uint_fast32_t;
+#define UINT_FAST8_MAX UINT_LEAST8_MAX
+#define INT_FAST8_MAX INT_LEAST8_MAX
+#define UINT_FAST16_MAX UINT_LEAST16_MAX
+#define INT_FAST16_MAX INT_LEAST16_MAX
+#define UINT_FAST32_MAX UINT_LEAST32_MAX
+#define INT_FAST32_MAX INT_LEAST32_MAX
+#define INT_FAST8_MIN INT_LEAST8_MIN
+#define INT_FAST16_MIN INT_LEAST16_MIN
+#define INT_FAST32_MIN INT_LEAST32_MIN
+#ifdef stdint_int64_defined
+ typedef int_least64_t int_fast64_t;
+ typedef uint_least64_t uint_fast64_t;
+# define UINT_FAST64_MAX UINT_LEAST64_MAX
+# define INT_FAST64_MAX INT_LEAST64_MAX
+# define INT_FAST64_MIN INT_LEAST64_MIN
+#endif
+
+#undef stdint_int64_defined
+
+/*
+ * Whatever piecemeal, per compiler thing we can do about the wchar_t
+ * type limits.
+ */
+
+#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__)
+# include <wchar.h>
+# ifndef WCHAR_MIN
+# define WCHAR_MIN 0
+# endif
+# ifndef WCHAR_MAX
+# define WCHAR_MAX ((wchar_t)-1)
+# endif
+#endif
+
+/*
+ * Whatever piecemeal, per compiler/platform thing we can do about the
+ * (u)intptr_t types and limits.
+ */
+
+#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)
+# define STDINT_H_UINTPTR_T_DEFINED
+#endif
+
+#ifndef STDINT_H_UINTPTR_T_DEFINED
+# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64)
+# define stdint_intptr_bits 64
+# elif defined (__WATCOMC__) || defined (__TURBOC__)
+# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
+# define stdint_intptr_bits 16
+# else
+# define stdint_intptr_bits 32
+# endif
+# elif defined (__i386__) || defined (_WIN32) || defined (WIN32)
+# define stdint_intptr_bits 32
+# elif defined (__INTEL_COMPILER)
+/* TODO -- what did Intel do about x86-64? */
+# endif
+
+# ifdef stdint_intptr_bits
+# define stdint_intptr_glue3_i(a,b,c) a##b##c
+# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c)
+# ifndef PRINTF_INTPTR_MODIFIER
+# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER)
+# endif
+# ifndef PTRDIFF_MAX
+# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
+# endif
+# ifndef PTRDIFF_MIN
+# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
+# endif
+# ifndef UINTPTR_MAX
+# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX)
+# endif
+# ifndef INTPTR_MAX
+# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
+# endif
+# ifndef INTPTR_MIN
+# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
+# endif
+# ifndef INTPTR_C
+# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x)
+# endif
+# ifndef UINTPTR_C
+# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x)
+# endif
+ typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t;
+ typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t;
+# else
+/* TODO -- This following is likely wrong for some platforms, and does
+ nothing for the definition of uintptr_t. */
+ typedef ptrdiff_t intptr_t;
+# endif
+# define STDINT_H_UINTPTR_T_DEFINED
+#endif
+
+/*
+ * Assumes sig_atomic_t is signed and we have a 2s complement machine.
+ */
+
+#ifndef SIG_ATOMIC_MAX
+# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1)
+#endif
+
+#endif
+
+#if defined (__TEST_PSTDINT_FOR_CORRECTNESS)
+
+/*
+ * Please compile with the maximum warning settings to make sure macros are not
+ * defined more than once.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define glue3_aux(x,y,z) x ## y ## z
+#define glue3(x,y,z) glue3_aux(x,y,z)
+
+#define DECLU(bits) glue3(uint,bits,_t) glue3(u,bits,=) glue3(UINT,bits,_C) (0);
+#define DECLI(bits) glue3(int,bits,_t) glue3(i,bits,=) glue3(INT,bits,_C) (0);
+
+#define DECL(us,bits) glue3(DECL,us,) (bits)
+
+#define TESTUMAX(bits) glue3(u,bits,=) glue3(~,u,bits); if (glue3(UINT,bits,_MAX) glue3(!=,u,bits)) printf ("Something wrong with UINT%d_MAX\n", bits)
+
+int main () {
+ DECL(I,8)
+ DECL(U,8)
+ DECL(I,16)
+ DECL(U,16)
+ DECL(I,32)
+ DECL(U,32)
+#ifdef INT64_MAX
+ DECL(I,64)
+ DECL(U,64)
+#endif
+ intmax_t imax = INTMAX_C(0);
+ uintmax_t umax = UINTMAX_C(0);
+ char str0[256], str1[256];
+
+ sprintf (str0, "%d %x\n", 0, ~0);
+
+ sprintf (str1, "%d %x\n", i8, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with i8 : %s\n", str1);
+ sprintf (str1, "%u %x\n", u8, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with u8 : %s\n", str1);
+ sprintf (str1, "%d %x\n", i16, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with i16 : %s\n", str1);
+ sprintf (str1, "%u %x\n", u16, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with u16 : %s\n", str1);
+ sprintf (str1, "%" PRINTF_INT32_MODIFIER "d %x\n", i32, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with i32 : %s\n", str1);
+ sprintf (str1, "%" PRINTF_INT32_MODIFIER "u %x\n", u32, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with u32 : %s\n", str1);
+#ifdef INT64_MAX
+ sprintf (str1, "%" PRINTF_INT64_MODIFIER "d %x\n", i64, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with i64 : %s\n", str1);
+#endif
+ sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "d %x\n", imax, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with imax : %s\n", str1);
+ sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "u %x\n", umax, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with umax : %s\n", str1);
+
+ TESTUMAX(8);
+ TESTUMAX(16);
+ TESTUMAX(32);
+#ifdef INT64_MAX
+ TESTUMAX(64);
+#endif
+
+ return EXIT_SUCCESS;
+}
+
+#endif
+
--- /dev/null
+++ b/src/in_xsf_framework/windowsh_wrapper.h
@@ -1,1 +1,34 @@
+/*
+ * Wrapper for windows.h, found at:
+ * http://learnwinapi.wordpress.com/2011/12/13/lesson-2-the-api-is-based-on-unicode/
+ */
+#ifndef WINDOWSH_WRAPPER_H
+#define WINDOWSH_WRAPPER_H
+
+#ifdef _MBCS
+# error "_MBCS (multi-byte character set) is defined, but only Unicode is supported"
+#endif
+#undef _UNICODE
+#define _UNICODE // For [tchar.h]
+#undef UNICODE
+#define UNICODE // For [windows.h]
+
+#undef NOMINMAX
+#define NOMINMAX // C++ standard library compatibility
+#undef STRICT
+#define STRICT // C++ type-checking compatibility
+
+#ifndef _WIN32_WINNT
+# define _WIN32_WINNT _WIN32_WINNT_WIN2K
+#endif
+#ifdef _MSC_VER // Visual C++ only (the SDK is Visual C++ specific).
+# include <SDKDDKVer.h> // E.g. g++ 4.4.1 does not support this file/scheme.
+#endif
+
+#undef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#endif
+