diff --git a/libgambatte/Makefile b/libgambatte/Makefile deleted file mode 100644 index 326af5d2cf..0000000000 --- a/libgambatte/Makefile +++ /dev/null @@ -1,66 +0,0 @@ -CXX = g++ -RM = rm -CP = cp - -MACHINE = $(shell $(CXX) -dumpmachine) -ifneq (,$(findstring i686,$(MACHINE))) - $(error 32 bit build no longer supported) -else ifneq (,$(findstring x86_64,$(MACHINE))) - ARCH = 64 -else - $(error Unknown arch) -endif - -CXXFLAGS = -Wall -Iinclude -Isrc -O3 -std=c++11 -fno-exceptions -flto -fPIC -TARGET = libgambatte.dll -LDFLAGS_32 = -static -static-libgcc -static-libstdc++ -LDFLAGS_64 = -LDFLAGS = -shared $(LDFLAGS_$(ARCH)) $(CXXFLAGS) - -DEST_32 = ../output/dll -DEST_64 = ../output/dll - -SRCS = \ - src/cinterface.cpp \ - src/cpu.cpp \ - src/gambatte.cpp \ - src/initstate.cpp \ - src/interruptrequester.cpp \ - src/memory.cpp \ - src/mem/cartridge.cpp \ - src/mem/memptrs.cpp \ - src/mem/rtc.cpp \ - src/mem/time.cpp \ - src/newstate.cpp \ - src/sound.cpp \ - src/sound/channel1.cpp \ - src/sound/channel2.cpp \ - src/sound/channel3.cpp \ - src/sound/channel4.cpp \ - src/sound/duty_unit.cpp \ - src/sound/envelope_unit.cpp \ - src/sound/length_counter.cpp \ - src/tima.cpp \ - src/video.cpp \ - src/video/lyc_irq.cpp \ - src/video/ly_counter.cpp \ - src/video/next_m0_time.cpp \ - src/video/ppu.cpp \ - src/video/sprite_mapper.cpp - -OBJS = $(SRCS:.cpp=.o) - -all: $(TARGET) - -%.o: %.cpp - $(CXX) -c -o $@ $< $(CXXFLAGS) - -$(TARGET) : $(OBJS) - $(CXX) -o $@ $(LDFLAGS) $(OBJS) - -clean: - $(RM) $(OBJS) - $(RM) $(TARGET) - -install: - $(CP) $(TARGET) $(DEST_$(ARCH)) diff --git a/libgambatte/array.h b/libgambatte/array.h deleted file mode 100644 index 9b692d8412..0000000000 --- a/libgambatte/array.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Sindre Aamås * - * sinamas@users.sourceforge.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License version 2 as * - * published by the Free Software Foundation. * - * * - * 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 version 2 for more details. * - * * - * You should have received a copy of the GNU General Public License * - * version 2 along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ -#ifndef ARRAY_H -#define ARRAY_H - -#include - -template -class SimpleArray : Uncopyable { -public: - explicit SimpleArray(std::size_t size = 0) : a_(size ? new T[size] : 0) {} - ~SimpleArray() { delete[] defined_ptr(a_); } - void reset(std::size_t size = 0) { delete[] defined_ptr(a_); a_ = size ? new T[size] : 0; } - T* get() const { return a_; } - operator T* () const { return a_; } - -private: - T* a_; -}; - -class Uncopyable { -protected: - Uncopyable() {} -private: - Uncopyable(Uncopyable const&); - Uncopyable& operator=(Uncopyable const&); -}; - -template -inline T* defined_ptr(T* t) { - typedef char type_is_defined[sizeof * t ? 1 : -1]; - (void)sizeof(type_is_defined); - return t; -} - -#endif \ No newline at end of file diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h deleted file mode 100644 index 368b2a4727..0000000000 --- a/libgambatte/include/gambatte.h +++ /dev/null @@ -1,174 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef GAMBATTE_H -#define GAMBATTE_H - -#include "gbint.h" -#include "loadres.h" -#include -#include -#include "newstate.h" - -namespace gambatte { - -enum { BG_PALETTE = 0, SP1_PALETTE = 1, SP2_PALETTE = 2 }; - -typedef void (*MemoryCallback)(int32_t address, int64_t cycleOffset); -typedef void (*CDCallback)(int32_t addr, int32_t addrtype, int32_t flags); - -enum eCDLog_AddrType -{ - eCDLog_AddrType_ROM, eCDLog_AddrType_HRAM, eCDLog_AddrType_WRAM, eCDLog_AddrType_CartRAM, - eCDLog_AddrType_None -}; - -enum eCDLog_Flags -{ - eCDLog_Flags_ExecFirst = 1, - eCDLog_Flags_ExecOperand = 2, - eCDLog_Flags_Data = 4, -}; - -class GB { -public: - GB(); - ~GB(); - - enum LoadFlag { - FORCE_DMG = 1, /**< Treat the ROM as not having CGB support regardless of what its header advertises. */ - GBA_CGB = 2, /**< Use GBA intial CPU register values when in CGB mode. */ - MULTICART_COMPAT = 4, /**< Use heuristics to detect and support some multicart MBCs disguised as MBC1. */ - }; - - /** - * Load ROM image. - * - * @param romfile Path to rom image file. Typically a .gbc, .gb, or .zip-file (if - * zip-support is compiled in). - * @param flags ORed combination of LoadFlags. - * @return 0 on success, negative value on failure. - */ - LoadRes load(char const *romfiledata, unsigned romfilelength, unsigned flags); - - int loadBios(char const *biosfiledata, std::size_t size); - - /** - * Emulates until at least 'samples' audio samples are produced in the - * supplied audio buffer, or until a video frame has been drawn. - * - * There are 35112 audio (stereo) samples in a video frame. - * May run for up to 2064 audio samples too long. - * - * An audio sample consists of two native endian 2s complement 16-bit PCM samples, - * with the left sample preceding the right one. Usually casting audioBuf to - * int16_t* is OK. The reason for using an uint_least32_t* in the interface is to - * avoid implementation-defined behavior without compromising performance. - * libgambatte is strictly c++98, so fixed-width types are not an option (and even - * c99/c++11 cannot guarantee their availability). - * - * Returns early when a new video frame has finished drawing in the video buffer, - * such that the caller may update the video output before the frame is overwritten. - * The return value indicates whether a new video frame has been drawn, and the - * exact time (in number of samples) at which it was completed. - * - * @param videoBuf 160x144 RGB32 (native endian) video frame buffer or 0 - * @param pitch distance in number of pixels (not bytes) from the start of one line - * to the next in videoBuf. - * @param audioBuf buffer with space >= samples + 2064 - * @param samples in: number of stereo samples to produce, - * out: actual number of samples produced - * @return sample offset in audioBuf at which the video frame was completed, or -1 - * if no new video frame was completed. - */ - std::ptrdiff_t runFor(gambatte::uint_least32_t *soundBuf, std::size_t &samples); - - void blitTo(gambatte::uint_least32_t *videoBuf, std::ptrdiff_t pitch); - - void setLayers(unsigned mask); - - /** - * Reset to initial state. - * Equivalent to reloading a ROM image, or turning a Game Boy Color off and on again. - */ - void reset(); - - /** - * @param palNum 0 <= palNum < 3. One of BG_PALETTE, SP1_PALETTE and SP2_PALETTE. - * @param colorNum 0 <= colorNum < 4 - */ - void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32); - - void setCgbPalette(unsigned *lut); - - /** Sets the callback used for getting input state. */ - void setInputGetter(unsigned (*getInput)()); - - void setReadCallback(MemoryCallback); - void setWriteCallback(MemoryCallback); - void setExecCallback(MemoryCallback); - void setCDCallback(CDCallback); - void setTraceCallback(void (*callback)(void *)); - void setScanlineCallback(void (*callback)(), int sl); - void setLinkCallback(void(*callback)()); - - /** Use cycle-based RTC instead of real-time. */ - void setTimeMode(bool useCycles); - - /** adjust the assumed clock speed of the CPU compared to the RTC */ - void setRtcDivisorOffset(long const rtcDivisorOffset); - - /** Returns true if the currently loaded ROM image is treated as having CGB support. */ - bool isCgb() const; - - /** Returns true if a ROM image is loaded. */ - bool isLoaded() const; - - /** Writes persistent cartridge data to disk. NOT Done implicitly on ROM close. */ - void loadSavedata(char const *data); - int saveSavedataLength(); - void saveSavedata(char *dest); - - // 0 = vram, 1 = rom, 2 = wram, 3 = cartram, 4 = oam, 5 = hram - bool getMemoryArea(int which, unsigned char **data, int *length); - - /** ROM header title of currently loaded ROM image. */ - std::string const romTitle() const; - - unsigned char externalRead(unsigned short addr); - void externalWrite(unsigned short addr, unsigned char val); - - int linkStatus(int which); - - void getRegs(int *dest); - - void setInterruptAddresses(int *addrs, int numAddrs); - int getHitInterruptAddress(); - - templatevoid SyncState(NewState *ns); - -private: - struct Priv; - Priv *const p_; - - GB(GB const &); - GB & operator=(GB const &); -}; -} - -#endif diff --git a/libgambatte/include/gbint.h b/libgambatte/include/gbint.h deleted file mode 100644 index 272a9e8318..0000000000 --- a/libgambatte/include/gbint.h +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef GAMBATTE_INT_H -#define GAMBATTE_INT_H - -// note that this is a hack to overcome the fact that libgambatte's original defines are not propagated. -#define HAVE_CSTDINT - -#ifdef HAVE_CSTDINT - -#include - -namespace gambatte { -using std::uint_least32_t; -using std::uint_least16_t; -} - -#elif defined(HAVE_STDINT_H) - -#include - -namespace gambatte { -using ::uint_least32_t; -using ::uint_least16_t; -} - -#else - -namespace gambatte { -#ifdef CHAR_LEAST_32 -typedef unsigned char uint_least32_t; -#elif defined(SHORT_LEAST_32) -typedef unsigned short uint_least32_t; -#elif defined(INT_LEAST_32) -typedef unsigned uint_least32_t; -#else -typedef unsigned long uint_least32_t; -#endif - -#ifdef CHAR_LEAST_16 -typedef unsigned char uint_least16_t; -#else -typedef unsigned short uint_least16_t; -#endif -} - -#endif - -#endif diff --git a/libgambatte/include/loadres.h b/libgambatte/include/loadres.h deleted file mode 100644 index 6ee5e370b5..0000000000 --- a/libgambatte/include/loadres.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef GAMBATTE_LOADRES_H -#define GAMBATTE_LOADRES_H - -#include - -namespace gambatte { - -enum LoadRes { - LOADRES_BAD_FILE_OR_UNKNOWN_MBC = -0x7FFF, - LOADRES_IO_ERROR, - LOADRES_UNSUPPORTED_MBC_HUC3 = -0x1FE, - LOADRES_UNSUPPORTED_MBC_TAMA5, - LOADRES_UNSUPPORTED_MBC_POCKET_CAMERA, - LOADRES_UNSUPPORTED_MBC_MBC7 = -0x122, - LOADRES_UNSUPPORTED_MBC_MBC6 = -0x120, - LOADRES_UNSUPPORTED_MBC_MBC4 = -0x117, - LOADRES_UNSUPPORTED_MBC_MMM01 = -0x10D, - LOADRES_OK = 0 -}; - -} - -#endif diff --git a/libgambatte/libgambatte.sln b/libgambatte/libgambatte.sln deleted file mode 100644 index 4849245619..0000000000 --- a/libgambatte/libgambatte.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgambatte", "libgambatte.vcxproj", "{5D630682-7BDA-474D-B387-0EB420DDC199}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5D630682-7BDA-474D-B387-0EB420DDC199}.Debug|Win32.ActiveCfg = Release|x64 - {5D630682-7BDA-474D-B387-0EB420DDC199}.Debug|Win32.Build.0 = Release|x64 - {5D630682-7BDA-474D-B387-0EB420DDC199}.Debug|x64.ActiveCfg = Release|x64 - {5D630682-7BDA-474D-B387-0EB420DDC199}.Debug|x64.Build.0 = Release|x64 - {5D630682-7BDA-474D-B387-0EB420DDC199}.Release|Win32.ActiveCfg = Release|Win32 - {5D630682-7BDA-474D-B387-0EB420DDC199}.Release|Win32.Build.0 = Release|Win32 - {5D630682-7BDA-474D-B387-0EB420DDC199}.Release|x64.ActiveCfg = Release|x64 - {5D630682-7BDA-474D-B387-0EB420DDC199}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/libgambatte/libgambatte.vcxproj b/libgambatte/libgambatte.vcxproj deleted file mode 100644 index 9934cb6173..0000000000 --- a/libgambatte/libgambatte.vcxproj +++ /dev/null @@ -1,237 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {5D630682-7BDA-474D-B387-0EB420DDC199} - Win32Proj - libgambatte - 10.0 - - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - ..\output\dll - - - true - ..\output\dll - - - false - ..\output\dll - - - false - ..\output\dll - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions) - include;src;src\common - 4244;4373;4800;4804 - - - Windows - true - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions) - include;src;src\common - 4244;4373;4800;4804 - - - Windows - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions) - include;src;src\common - 4244;4373;4800;4804 - - - Windows - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGAMBATTE_EXPORTS;%(PreprocessorDefinitions) - include;src;src\common - 4244;4373;4800;4804 - - - Windows - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libgambatte/libgambatte.vcxproj.filters b/libgambatte/libgambatte.vcxproj.filters deleted file mode 100644 index 318ef9d04d..0000000000 --- a/libgambatte/libgambatte.vcxproj.filters +++ /dev/null @@ -1,228 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/libgambatte/src/Interrupter.cpp b/libgambatte/src/Interrupter.cpp deleted file mode 100644 index 3ee5af603e..0000000000 --- a/libgambatte/src/Interrupter.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "interrupter.h" -#include "memory.h" - -namespace gambatte { - - Interrupter::Interrupter(unsigned short& sp, unsigned short& pc, unsigned char& opcode, bool& prefetched) - : sp_(sp) - , pc_(pc) - , opcode_(opcode) - , prefetched_(prefetched) - { - } - - void Interrupter::prefetch(unsigned long cc, Memory& mem) { - if (!prefetched_) { - opcode_ = mem.read(pc_, cc); - pc_ = (pc_ + 1) & 0xFFFF; - prefetched_ = true; - } - } - - unsigned long Interrupter::interrupt(unsigned long cc, Memory& memory) { - // undo prefetch (presumably unconditional on hw). - if (prefetched_) { - pc_ = (pc_ - 1) & 0xFFFF; - prefetched_ = false; - } - cc += 12; - sp_ = (sp_ - 1) & 0xFFFF; - memory.write(sp_, pc_ >> 8, cc); - cc += 4; - - unsigned const pendingIrqs = memory.pendingIrqs(cc); - unsigned const n = pendingIrqs & -pendingIrqs; - unsigned address; - if (n <= 4) { - static unsigned char const lut[] = { 0x00, 0x40, 0x48, 0x48, 0x50 }; - address = lut[n]; - } - else - address = 0x50 + n; - - sp_ = (sp_ - 1) & 0xFFFF; - memory.write(sp_, pc_ & 0xFF, cc); - memory.ackIrq(n, cc); - pc_ = address; - cc += 4; - - if (address == 0x40 && !gsCodes_.empty()) - applyVblankCheats(cc, memory); - - return cc; - } - - static int asHex(char c) { - return c >= 'A' ? c - 'A' + 0xA : c - '0'; - } - - void Interrupter::setGameShark(std::string const& codes) { - std::string code; - gsCodes_.clear(); - - for (std::size_t pos = 0; pos < codes.length(); pos += code.length() + 1) { - code = codes.substr(pos, codes.find(';', pos) - pos); - if (code.length() >= 8) { - GsCode gs; - gs.type = asHex(code[0]) << 4 | asHex(code[1]); - gs.value = (asHex(code[2]) << 4 | asHex(code[3])) & 0xFF; - gs.address = (asHex(code[4]) << 4 - | asHex(code[5]) - | asHex(code[6]) << 12 - | asHex(code[7]) << 8) & 0xFFFF; - gsCodes_.push_back(gs); - } - } - } - - void Interrupter::applyVblankCheats(unsigned long const cc, Memory& memory) { - for (std::size_t i = 0, size = gsCodes_.size(); i < size; ++i) { - if (gsCodes_[i].type == 0x01) - memory.write(gsCodes_[i].address, gsCodes_[i].value, cc); - } - } - -} \ No newline at end of file diff --git a/libgambatte/src/array.h b/libgambatte/src/array.h deleted file mode 100644 index 239af8f2ca..0000000000 --- a/libgambatte/src/array.h +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Sindre Aamås * - * sinamas@users.sourceforge.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License version 2 as * - * published by the Free Software Foundation. * - * * - * 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 version 2 for more details. * - * * - * You should have received a copy of the GNU General Public License * - * version 2 along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ -#ifndef ARRAY_H -#define ARRAY_H - -#include - -template -class SimpleArray : Uncopyable { -public: - explicit SimpleArray(std::size_t size = 0) : a_(size ? new T[size] : 0) {} - ~SimpleArray() { delete[] defined_ptr(a_); } - void reset(std::size_t size = 0) { delete[] defined_ptr(a_); a_ = size ? new T[size] : 0; } - T* get() const { return a_; } - operator T* () const { return a_; } - -private: - T* a_; -}; - -class Uncopyable { -protected: - Uncopyable() {} -private: - Uncopyable(Uncopyable const&); - Uncopyable& operator=(Uncopyable const&); -}; - -template -inline T* defined_ptr(T* t) { - typedef char type_is_defined[sizeof * t ? 1 : -1]; - (void)sizeof(type_is_defined); - return t; -} - -template -inline void defined_delete(T* t) { delete defined_ptr(t); } - -struct defined_deleter { template static void del(T* p) { defined_delete(p); } }; - -#endif \ No newline at end of file diff --git a/libgambatte/src/cinterface.cpp b/libgambatte/src/cinterface.cpp deleted file mode 100644 index f9b4ced4fb..0000000000 --- a/libgambatte/src/cinterface.cpp +++ /dev/null @@ -1,205 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "cinterface.h" -#include "gambatte.h" -#include -#include -#include "newstate.h" - -// new is actually called in a few different places, so replace all of them for determinism guarantees -void *operator new(std::size_t n) { - void *p = std::malloc(n); - std::memset(p, 0, n); - return p; -} - -void operator delete(void *p) { - std::free(p); -} - -namespace { - -using namespace gambatte; - - GBEXPORT GB * gambatte_create() { - return new GB(); -} - -GBEXPORT void gambatte_destroy(GB *g) { - delete g; -} - -GBEXPORT int gambatte_load(GB *g, char const *romfiledata, unsigned romfilelength, unsigned flags) { - return g->load(romfiledata, romfilelength, flags); -} - -GBEXPORT int gambatte_loadbios(GB *g, char const *biosfiledata, unsigned size) { - return g->loadBios(biosfiledata, size); -} - -GBEXPORT int gambatte_runfor(GB *g, short *soundbuf, unsigned *samples) { - std::size_t sampv = *samples; - int ret = g->runFor((unsigned int *) soundbuf, sampv); - *samples = sampv; - return ret; -} - -GBEXPORT void gambatte_blitto(GB *g, unsigned int *videobuf, int pitch) { - g->blitTo((unsigned int *)videobuf, pitch); -} - -GBEXPORT void gambatte_setlayers(GB *g, unsigned mask) { - g->setLayers(mask); -} - -GBEXPORT void gambatte_settimemode(GB *g, bool useCycles) { - g->setTimeMode(useCycles); -} - -GBEXPORT void gambatte_setrtcdivisoroffset(GB *g, int rtcDivisorOffset) { - g->setRtcDivisorOffset(rtcDivisorOffset); -} - -GBEXPORT void gambatte_reset(GB *g) { - g->reset(); -} - -GBEXPORT void gambatte_setdmgpalettecolor(GB *g, unsigned palnum, unsigned colornum, unsigned rgb32) { - g->setDmgPaletteColor(palnum, colornum, rgb32); -} - -GBEXPORT void gambatte_setcgbpalette(GB *g, unsigned *lut) { - g->setCgbPalette(lut); -} - -GBEXPORT void gambatte_setinputgetter(GB *g, unsigned (*getinput)(void)) { - g->setInputGetter(getinput); -} - -GBEXPORT void gambatte_setreadcallback(GB *g, MemoryCallback callback) { - g->setReadCallback(callback); -} - -GBEXPORT void gambatte_setwritecallback(GB *g, MemoryCallback callback) { - g->setWriteCallback(callback); -} - -GBEXPORT void gambatte_setexeccallback(GB *g, MemoryCallback callback) { - g->setExecCallback(callback); -} - -GBEXPORT void gambatte_setcdcallback(GB *g, CDCallback cdc) { - g->setCDCallback(cdc); -} - - -GBEXPORT void gambatte_settracecallback(GB *g, void (*callback)(void *)) { - g->setTraceCallback(callback); -} - -GBEXPORT void gambatte_setscanlinecallback(GB *g, void (*callback)(), int sl) { - g->setScanlineCallback(callback, sl); -} - -GBEXPORT void gambatte_setlinkcallback(GB *g, void(*callback)()) { - g->setLinkCallback(callback); -} - -GBEXPORT int gambatte_iscgb(GB *g) { - return g->isCgb(); -} - -GBEXPORT int gambatte_isloaded(GB *g) { - return g->isLoaded(); -} - -GBEXPORT void gambatte_savesavedata(GB *g, char *dest) { - g->saveSavedata(dest); -} - -GBEXPORT void gambatte_loadsavedata(GB *g, char const *data) { - g->loadSavedata(data); -} - -GBEXPORT int gambatte_savesavedatalength(GB *g) { - return g->saveSavedataLength(); -} - -GBEXPORT int gambatte_newstatelen(GB *g) { - NewStateDummy dummy; - g->SyncState(&dummy); - return dummy.GetLength(); -} - -GBEXPORT int gambatte_newstatesave(GB *g, char *data, int len) { - NewStateExternalBuffer saver(data, len); - g->SyncState(&saver); - return !saver.Overflow() && saver.GetLength() == len; -} - -GBEXPORT int gambatte_newstateload(GB *g, char const *data, int len) { - NewStateExternalBuffer loader((char *)data, len); - g->SyncState(&loader); - return !loader.Overflow() && loader.GetLength() == len; -} - -GBEXPORT void gambatte_newstatesave_ex(GB *g, FPtrs *ff) { - NewStateExternalFunctions saver(ff); - g->SyncState(&saver); -} - -GBEXPORT void gambatte_newstateload_ex(GB *g, FPtrs *ff) { - NewStateExternalFunctions loader(ff); - g->SyncState(&loader); -} - -GBEXPORT void gambatte_romtitle(GB *g, char *dest) { - std::strcpy(dest, g->romTitle().c_str()); -} - -GBEXPORT int gambatte_getmemoryarea(GB *g, int which, unsigned char **data, int *length) { - return g->getMemoryArea(which, data, length); -} - -GBEXPORT unsigned char gambatte_cpuread(GB *g, unsigned short addr) { - return g->externalRead(addr); -} - -GBEXPORT void gambatte_cpuwrite(GB *g, unsigned short addr, unsigned char val) { - g->externalWrite(addr, val); -} - -GBEXPORT int gambatte_linkstatus(GB *g, int which) -{ - return g->linkStatus(which); -} - -GBEXPORT void gambatte_getregs(GB *g, int *dest) { - g->getRegs(dest); -} - -GBEXPORT void gambatte_setinterruptaddresses(GB *g, int *addrs, int numAddrs) { - g->setInterruptAddresses(addrs, numAddrs); -} - -GBEXPORT int gambatte_gethitinterruptaddress(GB *g) { - return g->getHitInterruptAddress(); -} - -} diff --git a/libgambatte/src/cinterface.h b/libgambatte/src/cinterface.h deleted file mode 100644 index e92f942ece..0000000000 --- a/libgambatte/src/cinterface.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef CINTERFACE_H -#define CINTERFACE_H - -// these are all documented on the C# side - -#ifdef _WIN32 -#define GBEXPORT extern "C" __declspec(dllexport) -#elif __linux__ -#define GBEXPORT extern "C" -#endif - -#endif diff --git a/libgambatte/src/counterdef.h b/libgambatte/src/counterdef.h deleted file mode 100644 index c48b80cdfa..0000000000 --- a/libgambatte/src/counterdef.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef COUNTERDEF_H -#define COUNTERDEF_H - -namespace gambatte { - -enum { disabled_time = 0xfffffffful }; - -} - -#endif diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp deleted file mode 100644 index 72e3d43fbd..0000000000 --- a/libgambatte/src/cpu.cpp +++ /dev/null @@ -1,2084 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "cpu.h" -#include "memory.h" -#include "savestate.h" - -namespace gambatte { - -CPU::CPU() -: mem_(Interrupter(sp, pc, opcode_, prefetched_)) -, cycleCounter_(0) -, pc(0x100) -, sp(0xFFFE) -, hf1(0xF) -, hf2(0xF) -, zf(0) -, cf(0x100) -, a(0x01) -, b(0x00) -, c(0x13) -, d(0x00) -, e(0xD8) -, h(0x01) -, l(0x4D) -, opcode_(0) -, prefetched_(false) -, numInterruptAddresses() -, tracecallback(0) -{ -} - -long CPU::runFor(unsigned long const cycles) { - mem_.setBasetime(cycleCounter_); - process(cycles); - - long const csb = mem_.cyclesSinceBlit(cycleCounter_); - - if (cycleCounter_ & 0x80000000) - cycleCounter_ = mem_.resetCounters(cycleCounter_); - - return csb; -} - -enum { hf2_hcf = 0x200, hf2_subf = 0x400, hf2_incf = 0x800 }; - -static unsigned updateHf2FromHf1(unsigned const hf1, unsigned hf2) { - unsigned lhs = hf1 & 0xF; - unsigned rhs = (hf2 & 0xF) + (hf2 >> 8 & 1); - if (hf2 & hf2_incf) { - lhs = rhs; - rhs = 1; - } - - unsigned res = hf2 & hf2_subf - ? lhs - rhs - : (lhs + rhs) << 5; - - hf2 |= res & hf2_hcf; - return hf2; -} - -static inline unsigned toF(unsigned hf2, unsigned cf, unsigned zf) { - return ((hf2 & (hf2_subf | hf2_hcf)) | (cf & 0x100)) >> 4 - | (zf & 0xFF ? 0 : 0x80); -} - -static inline unsigned zfFromF(unsigned f) { return ~f & 0x80; } -static inline unsigned hf2FromF(unsigned f) { return f << 4 & (hf2_subf | hf2_hcf); } -static inline unsigned cfFromF(unsigned f) { return f << 4 & 0x100; } - -void CPU::setStatePtrs(SaveState &state) { - mem_.setStatePtrs(state); -} - -void CPU::loadState(SaveState const &state) { - mem_.loadState(state); - - cycleCounter_ = state.cpu.cycleCounter; - pc = state.cpu.pc & 0xFFFF; - sp = state.cpu.sp & 0xFFFF; - a = state.cpu.a & 0xFF; - b = state.cpu.b & 0xFF; - c = state.cpu.c & 0xFF; - d = state.cpu.d & 0xFF; - e = state.cpu.e & 0xFF; - zf = zfFromF(state.cpu.f); - hf2 = hf2FromF(state.cpu.f); - cf = cfFromF(state.cpu.f); - h = state.cpu.h & 0xFF; - l = state.cpu.l & 0xFF; - opcode_ = state.cpu.opcode; - prefetched_ = state.cpu.prefetched; - if (state.cpu.skip) { - opcode_ = mem_.read(pc, cycleCounter_); - prefetched_ = true; - } - -} - -// The main reasons for the use of macros is to more conveniently be able to tweak -// which variables are local and which are not, combined with the fact that at the -// time they were written GCC had a tendency to not be able to keep hot variables -// in regs if you took an address/reference in an inline function. - -#define bc() ( b * 0x100u | c ) -#define de() ( d * 0x100u | e ) -#define hl() ( h * 0x100u | l ) - -#define READ(dest, addr) do { (dest) = mem_.read(addr, cycleCounter); cycleCounter += 4; } while (0) -#define PC_READ(dest) do { (dest) = mem_.read_excb(pc, cycleCounter, false); pc = (pc + 1) & 0xFFFF; cycleCounter += 4; } while (0) -#define PC_READ_FIRST(dest) do { (dest) = mem_.read_excb(pc, cycleCounter, true); pc = (pc + 1) & 0xFFFF; cycleCounter += 4; } while (0) -#define FF_READ(dest, addr) do { (dest) = mem_.ff_read(addr, cycleCounter); cycleCounter += 4; } while (0) - -#define WRITE(addr, data) do { mem_.write(addr, data, cycleCounter); cycleCounter += 4; } while (0) -#define FF_WRITE(addr, data) do { mem_.ff_write(addr, data, cycleCounter); cycleCounter += 4; } while (0) - -#define PC_MOD(data) do { pc = data; cycleCounter += 4; } while (0) - -#define PUSH(r1, r2) do { \ - sp = (sp - 1) & 0xFFFF; \ - WRITE(sp, (r1)); \ - sp = (sp - 1) & 0xFFFF; \ - WRITE(sp, (r2)); \ -} while (0) - -// CB OPCODES (Shifts, rotates and bits): -// swap r (8 cycles): -// Swap upper and lower nibbles of 8-bit register, reset flags, check zero flag: -#define swap_r(r) do { \ - cf = hf2 = 0; \ - zf = (r); \ - (r) = (zf << 4 | zf >> 4) & 0xFF; \ -} while (0) - -// rlc r (8 cycles): -// Rotate 8-bit register left, store old bit7 in CF. Reset SF and HCF, Check ZF: -#define rlc_r(r) do { \ - cf = (r) << 1; \ - zf = cf | cf >> 8; \ - (r) = zf & 0xFF; \ - hf2 = 0; \ -} while (0) - -// rl r (8 cycles): -// Rotate 8-bit register left through CF, store old bit7 in CF, old CF value becomes bit0. Reset SF and HCF, Check ZF: -#define rl_r(r) do { \ - unsigned const oldcf = cf >> 8 & 1; \ - cf = (r) << 1; \ - zf = cf | oldcf; \ - (r) = zf & 0xFF; \ - hf2 = 0; \ -} while (0) - -// rrc r (8 cycles): -// Rotate 8-bit register right, store old bit0 in CF. Reset SF and HCF, Check ZF: -#define rrc_r(r) do { \ - zf = (r); \ - cf = zf << 8; \ - (r) = (zf | cf) >> 1 & 0xFF; \ - hf2 = 0; \ -} while (0) - -// rr r (8 cycles): -// Rotate 8-bit register right through CF, store old bit0 in CF, old CF value becomes bit7. Reset SF and HCF, Check ZF: -#define rr_r(r) do { \ - unsigned const oldcf = cf & 0x100; \ - cf = (r) * 0x100u; \ - (r) = zf = ((r) | oldcf) >> 1; \ - hf2 = 0; \ -} while (0) - -// sla r (8 cycles): -// Shift 8-bit register left, store old bit7 in CF. Reset SF and HCF, Check ZF: -#define sla_r(r) do { \ - zf = cf = (r) << 1; \ - (r) = zf & 0xFF; \ - hf2 = 0; \ -} while (0) - -// sra r (8 cycles): -// Shift 8-bit register right, store old bit0 in CF. bit7=old bit7. Reset SF and HCF, Check ZF: -#define sra_r(r) do { \ - cf = (r) * 0x100u; \ - zf = (r) >> 1; \ - (r) = zf | ((r) & 0x80); \ - hf2 = 0; \ -} while (0) - -// srl r (8 cycles): -// Shift 8-bit register right, store old bit0 in CF. Reset SF and HCF, Check ZF: -#define srl_r(r) do { \ - zf = (r); \ - cf = (r) * 0x100u; \ - zf >>= 1; \ - (r) = zf; \ - hf2 = 0; \ -} while (0) - -// bit n,r (8 cycles): -// bit n,(hl) (12 cycles): -// Test bitn in 8-bit value, check ZF, unset SF, set HCF: -#define bitn_u8(bitmask, u8) do { \ - zf = (u8) & (bitmask); \ - hf2 = hf2_hcf; \ -} while (0) - -#define bit0_u8(u8) bitn_u8(0x01, (u8)) -#define bit1_u8(u8) bitn_u8(0x02, (u8)) -#define bit2_u8(u8) bitn_u8(0x04, (u8)) -#define bit3_u8(u8) bitn_u8(0x08, (u8)) -#define bit4_u8(u8) bitn_u8(0x10, (u8)) -#define bit5_u8(u8) bitn_u8(0x20, (u8)) -#define bit6_u8(u8) bitn_u8(0x40, (u8)) -#define bit7_u8(u8) bitn_u8(0x80, (u8)) - -// set n,r (8 cycles): -// Set bitn of 8-bit register: -#define set0_r(r) ( (r) |= 0x01 ) -#define set1_r(r) ( (r) |= 0x02 ) -#define set2_r(r) ( (r) |= 0x04 ) -#define set3_r(r) ( (r) |= 0x08 ) -#define set4_r(r) ( (r) |= 0x10 ) -#define set5_r(r) ( (r) |= 0x20 ) -#define set6_r(r) ( (r) |= 0x40 ) -#define set7_r(r) ( (r) |= 0x80 ) - -// set n,(hl) (16 cycles): -// Set bitn of value at address stored in HL: -#define setn_mem_hl(n) do { \ - unsigned const hl = hl(); \ - unsigned val; \ - READ(val, hl); \ - val |= 1 << (n); \ - WRITE(hl, val); \ -} while (0) - -// res n,r (8 cycles): -// Unset bitn of 8-bit register: -#define res0_r(r) ( (r) &= 0xFE ) -#define res1_r(r) ( (r) &= 0xFD ) -#define res2_r(r) ( (r) &= 0xFB ) -#define res3_r(r) ( (r) &= 0xF7 ) -#define res4_r(r) ( (r) &= 0xEF ) -#define res5_r(r) ( (r) &= 0xDF ) -#define res6_r(r) ( (r) &= 0xBF ) -#define res7_r(r) ( (r) &= 0x7F ) - -// res n,(hl) (16 cycles): -// Unset bitn of value at address stored in HL: -#define resn_mem_hl(n) do { \ - unsigned const hl = hl(); \ - unsigned val; \ - READ(val, hl); \ - val &= ~(1u << (n)); \ - WRITE(hl, val); \ -} while (0) - - -// 16-BIT LOADS: -// ld rr,nn (12 cycles) -// set rr to 16-bit value of next 2 bytes in memory -#define ld_rr_nn(r1, r2) do { \ - PC_READ(r2); \ - PC_READ(r1); \ -} while (0) - -// push rr (16 cycles): -// Push value of register pair onto stack: -#define push_rr(r1, r2) do { \ - cycleCounter += 4; \ - PUSH(r1, r2); \ -} while (0) - -// pop rr (12 cycles): -// Pop two bytes off stack into register pair: -#define pop_rr(r1, r2) do { \ - READ(r2, sp); \ - sp = (sp + 1) & 0xFFFF; \ - READ(r1, sp); \ - sp = (sp + 1) & 0xFFFF; \ -} while (0) - -// 8-BIT ALU: -// add a,r (4 cycles): -// add a,(addr) (8 cycles): -// Add 8-bit value to A, check flags: -#define add_a_u8(u8) do { \ - hf1 = a; \ - hf2 = u8; \ - zf = cf = a + hf2; \ - a = zf & 0xFF; \ -} while (0) - -// adc a,r (4 cycles): -// adc a,(addr) (8 cycles): -// Add 8-bit value+CF to A, check flags: -#define adc_a_u8(u8) do { \ - hf1 = a; \ - hf2 = (cf & 0x100) | (u8); \ - zf = cf = (cf >> 8 & 1) + (u8) + a; \ - a = zf & 0xFF; \ -} while (0) - -// sub a,r (4 cycles): -// sub a,(addr) (8 cycles): -// Subtract 8-bit value from A, check flags: -#define sub_a_u8(u8) do { \ - hf1 = a; \ - hf2 = u8; \ - zf = cf = a - hf2; \ - a = zf & 0xFF; \ - hf2 |= hf2_subf; \ -} while (0) - -// sbc a,r (4 cycles): -// sbc a,(addr) (8 cycles): -// Subtract CF and 8-bit value from A, check flags: -#define sbc_a_u8(u8) do { \ - hf1 = a; \ - hf2 = hf2_subf | (cf & 0x100) | (u8); \ - zf = cf = a - ((cf >> 8) & 1) - (u8); \ - a = zf & 0xFF; \ -} while (0) - -// and a,r (4 cycles): -// and a,(addr) (8 cycles): -// bitwise and 8-bit value into A, check flags: -#define and_a_u8(u8) do { \ - hf2 = hf2_hcf; \ - cf = 0; \ - a &= (u8); \ - zf = a; \ -} while (0) - -// or a,r (4 cycles): -// or a,(hl) (8 cycles): -// bitwise or 8-bit value into A, check flags: -#define or_a_u8(u8) do { \ - cf = hf2 = 0; \ - a |= (u8); \ - zf = a; \ -} while (0) - -// xor a,r (4 cycles): -// xor a,(hl) (8 cycles): -// bitwise xor 8-bit value into A, check flags: -#define xor_a_u8(u8) do { \ - cf = hf2 = 0; \ - a ^= (u8); \ - zf = a; \ -} while (0) - -// cp a,r (4 cycles): -// cp a,(addr) (8 cycles): -// Compare (subtract without storing result) 8-bit value to A, check flags: -#define cp_a_u8(u8) do { \ - hf1 = a; \ - hf2 = u8; \ - zf = cf = a - hf2; \ - hf2 |= hf2_subf; \ -} while (0) - -// inc r (4 cycles): -// Increment value of 8-bit register, check flags except CF: -#define inc_r(r) do { \ - hf2 = (r) | hf2_incf; \ - zf = (r) + 1; \ - (r) = zf & 0xFF; \ -} while (0) - -// dec r (4 cycles): -// Decrement value of 8-bit register, check flags except CF: -#define dec_r(r) do { \ - hf2 = (r) | hf2_incf | hf2_subf; \ - zf = (r) - 1; \ - (r) = zf & 0xFF; \ -} while (0) - -// 16-BIT ARITHMETIC -// add hl,rr (8 cycles): -// add 16-bit register to HL, check flags except ZF: -#define add_hl_rr(rh, rl) do { \ - cf = l + (rl); \ - l = cf & 0xFF; \ - hf1 = h; \ - hf2 = (cf & 0x100) | (rh); \ - cf = h + (cf >> 8) + (rh); \ - h = cf & 0xFF; \ - cycleCounter += 4; \ -} while (0) - -// inc rr (8 cycles): -// Increment 16-bit register: -#define inc_rr(rh, rl) do { \ - unsigned const lowinc = (rl) + 1; \ - (rl) = lowinc & 0xFF; \ - (rh) = ((rh) + (lowinc >> 8)) & 0xFF; \ - cycleCounter += 4; \ -} while (0) - -// dec rr (8 cycles): -// Decrement 16-bit register: -#define dec_rr(rh, rl) do { \ - unsigned const lowdec = (rl) - 1; \ - (rl) = lowdec & 0xFF; \ - (rh) = ((rh) - (lowdec >> 8 & 1)) & 0xFF; \ - cycleCounter += 4; \ -} while (0) - -#define sp_plus_n(sumout) do { \ - unsigned disp; \ - PC_READ(disp); \ - disp = (disp ^ 0x80) - 0x80; \ -\ - unsigned const res = sp + disp; \ - cf = sp ^ disp ^ res; \ - hf2 = cf << 5 & hf2_hcf; \ - zf = 1; \ - cycleCounter += 4; \ - (sumout) = res & 0xFFFF; \ -} while (0) - -// JUMPS: -// jp nn (16 cycles): -// Jump to address stored in the next two bytes in memory: -#define jp_nn() do { \ - unsigned imm0, imm1; \ - PC_READ(imm0); \ - PC_READ(imm1); \ - PC_MOD(imm1 << 8 | imm0); \ -} while (0) - -// jr disp (12 cycles): -// Jump to value of next (signed) byte in memory+current address: -#define jr_disp() do { \ - unsigned disp; \ - PC_READ(disp); \ - disp = (disp ^ 0x80) - 0x80; \ - PC_MOD((pc + disp) & 0xFFFF); \ -} while (0) - -// CALLS, RESTARTS AND RETURNS: -// call nn (24 cycles): -// Jump to 16-bit immediate operand and push return address onto stack: -#define call_nn() do { \ - unsigned const npc = (pc + 2) & 0xFFFF; \ - jp_nn(); \ - PUSH(npc >> 8, npc & 0xFF); \ -} while (0) - -// rst n (16 Cycles): -// Push present address onto stack, jump to address n (one of 00h,08h,10h,18h,20h,28h,30h,38h): -#define rst_n(n) do { \ - push_rr(pc >> 8, pc & 0xFF); \ - pc = (n); \ -} while (0) - -// ret (16 cycles): -// Pop two bytes from the stack and jump to that address: -#define ret() do { \ - unsigned low, high; \ - pop_rr(high, low); \ - PC_MOD(high << 8 | low); \ -} while (0) - -namespace { - unsigned long freeze(Memory & mem, unsigned long cc) { - mem.freeze(cc); - if (cc < mem.nextEventTime()) { - unsigned long cycles = mem.nextEventTime() - cc; - cc += cycles + (-cycles & 3); - } - return cc; - } -} - -void CPU::process(unsigned long const cycles) { - mem_.setEndtime(cycleCounter_, cycles); - mem_.updateInput(); - - hitInterruptAddress = -1; - - //unsigned char a = a_; - unsigned long cycleCounter = cycleCounter_; - - while (mem_.isActive()) { - //unsigned short pc = pc_; - - if (mem_.halted()) { - if (cycleCounter < mem_.nextEventTime()) { - unsigned long cycles = mem_.nextEventTime() - cycleCounter; - cycleCounter += cycles + (-cycles & 3); - } - } else while (cycleCounter < mem_.nextEventTime()) { - unsigned char opcode; - -#ifdef DLLABLES - for (int i = 0; i < numInterruptAddresses; ++i) { - if (pc == (interruptAddresses[i] & 0xFFFF)) { - unsigned bank = interruptAddresses[i] >> 16; - - if (!bank || bank == mem_.curRomBank()) { - hitInterruptAddress = interruptAddresses[i]; - mem_.setEndtime(cycleCounter, 0); - break; - } - } - } - - if (hitInterruptAddress != -1) - break; -#endif - - if (tracecallback) { - int result[14]; - result[0] = cycleCounter; - result[1] = pc; - result[2] = sp; - result[3] = a; - result[4] = b; - result[5] = c; - result[6] = d; - result[7] = e; - result[8] = toF(hf2, cf, zf); - result[9] = h; - result[10] = l; - result[11] = prefetched_; - //PC_READ_FIRST(opcode); - result[12] = opcode; - result[13] = mem_.debugGetLY(); - tracecallback((void *)result); - } - else { - //PC_READ_FIRST(opcode); - } - - if (!prefetched_) { - PC_READ(opcode); - } - else { - opcode = opcode_; - cycleCounter += 4; - prefetched_ = false; - } - - switch (opcode) { - case 0x00: - break; - case 0x01: - ld_rr_nn(b, c); - break; - case 0x02: - WRITE(bc(), a); - break; - case 0x03: - inc_rr(b, c); - break; - case 0x04: - inc_r(b); - break; - case 0x05: - dec_r(b); - break; - case 0x06: - PC_READ(b); - break; - - // rlca (4 cycles): - // Rotate 8-bit register A left, store old bit7 in CF. Reset SF, HCF, ZF: - case 0x07: - cf = a << 1; - a = (cf | cf >> 8) & 0xFF; - hf2 = 0; - zf = 1; - break; - - // ld (nn),SP (20 cycles): - // Put value of SP into address given by next 2 bytes in memory: - case 0x08: - { - unsigned imml, immh; - PC_READ(imml); - PC_READ(immh); - - unsigned const addr = immh << 8 | imml; - WRITE(addr, sp & 0xFF); - WRITE((addr + 1) & 0xFFFF, sp >> 8); - } - - break; - - case 0x09: - add_hl_rr(b, c); - break; - case 0x0A: - READ(a, bc()); - break; - case 0x0B: - dec_rr(b, c); - break; - case 0x0C: - inc_r(c); - break; - case 0x0D: - dec_r(c); - break; - case 0x0E: - PC_READ(c); - break; - - // rrca (4 cycles): - // Rotate 8-bit register A right, store old bit0 in CF. Reset SF, HCF, ZF: - case 0x0F: - cf = a * 0x100u | a; - a = cf >> 1 & 0xFF; - hf2 = 0; - zf = 1; - break; - - // stop (4 cycles): - // Halt CPU and LCD display until button pressed: - case 0x10: - PC_READ(opcode_); - cycleCounter = mem_.stop(cycleCounter - 4, prefetched_); - if (cycleCounter < mem_.nextEventTime()) { - unsigned long cycles = mem_.nextEventTime() - cycleCounter; - cycleCounter += cycles + (-cycles & 3); - } - - break; - - case 0x11: - ld_rr_nn(d, e); - break; - case 0x12: - WRITE(de(), a); - break; - case 0x13: - inc_rr(d, e); - break; - case 0x14: - inc_r(d); - break; - case 0x15: - dec_r(d); - break; - case 0x16: - PC_READ(d); - break; - - // rla (4 cycles): - // Rotate 8-bit register A left through CF, store old bit7 in CF, - // old CF value becomes bit0. Reset SF, HCF, ZF: - case 0x17: - { - unsigned oldcf = cf >> 8 & 1; - cf = a << 1; - a = (cf | oldcf) & 0xFF; - } - - hf2 = 0; - zf = 1; - break; - - case 0x18: - jr_disp(); - break; - case 0x19: - add_hl_rr(d, e); - break; - case 0x1A: - READ(a, de()); - break; - case 0x1B: - dec_rr(d, e); - break; - case 0x1C: - inc_r(e); - break; - case 0x1D: - dec_r(e); - break; - case 0x1E: - PC_READ(e); - break; - - // rra (4 cycles): - // Rotate 8-bit register A right through CF, store old bit0 in CF, - // old CF value becomes bit7. Reset SF, HCF, ZF: - case 0x1F: - { - unsigned oldcf = cf & 0x100; - cf = a * 0x100u; - a = (a | oldcf) >> 1; - } - - hf2 = 0; - zf = 1; - break; - - // jr nz,disp (12;8 cycles): - // Jump to value of next (signed) byte in memory+current address if ZF is unset: - case 0x20: - if (zf & 0xFF) { - jr_disp(); - } else { - PC_MOD((pc + 1) & 0xFFFF); - } - - break; - - case 0x21: ld_rr_nn(h, l); break; - - // ldi (hl),a (8 cycles): - // Put A into memory address in hl. Increment HL: - case 0x22: - { - unsigned addr = hl(); - WRITE(addr, a); - - addr = (addr + 1) & 0xFFFF; - l = addr; - h = addr >> 8; - } - - break; - - case 0x23: - inc_rr(h, l); - break; - case 0x24: - inc_r(h); - break; - case 0x25: - dec_r(h); - break; - case 0x26: - PC_READ(h); - break; - - // daa (4 cycles): - // Adjust register A to correctly represent a BCD. Check ZF, HF and CF: - case 0x27: - hf2 = updateHf2FromHf1(hf1, hf2); - - { - unsigned correction = cf & 0x100 ? 0x60 : 0x00; - - if (hf2 & hf2_hcf) - correction |= 0x06; - - if (!(hf2 &= hf2_subf)) { - if ((a & 0x0F) > 0x09) - correction |= 0x06; - if (a > 0x99) - correction |= 0x60; - - a += correction; - } else - a -= correction; - - cf = correction << 2 & 0x100; - zf = a; - a &= 0xFF; - } - - break; - - // jr z,disp (12;8 cycles): - // Jump to value of next (signed) byte in memory+current address if ZF is set: - case 0x28: - if (zf & 0xFF) { - PC_MOD((pc + 1) & 0xFFFF); - } else { - jr_disp(); - } - - break; - - case 0x29: - add_hl_rr(h, l); - break; - - // ldi a,(hl) (8 cycles): - // Put value at address in hl into A. Increment HL: - case 0x2A: - { - unsigned addr = hl(); - READ(a, addr); - - addr = (addr + 1) & 0xFFFF; - l = addr; - h = addr >> 8; - } - - break; - - case 0x2B: - dec_rr(h, l); - break; - case 0x2C: - inc_r(l); - break; - case 0x2D: - dec_r(l); - break; - case 0x2E: - PC_READ(l); - break; - - // cpl (4 cycles): - // Complement register A. (Flip all bits), set SF and HCF: - case 0x2F: - hf2 = hf2_subf | hf2_hcf; - a ^= 0xFF; - break; - - // jr nc,disp (12;8 cycles): - // Jump to value of next (signed) byte in memory+current address if CF is unset: - case 0x30: - if (cf & 0x100) { - PC_MOD((pc + 1) & 0xFFFF); - } else { - jr_disp(); - } - - break; - - // ld sp,nn (12 cycles) - // set sp to 16-bit value of next 2 bytes in memory - case 0x31: - { - unsigned imml, immh; - PC_READ(imml); - PC_READ(immh); - - sp = immh << 8 | imml; - } - - break; - - // ldd (hl),a (8 cycles): - // Put A into memory address in hl. Decrement HL: - case 0x32: - { - unsigned addr = hl(); - WRITE(addr, a); - - addr = (addr - 1) & 0xFFFF; - l = addr; - h = addr >> 8; - } - - break; - - case 0x33: - sp = (sp + 1) & 0xFFFF; - cycleCounter += 4; - break; - - // inc (hl) (12 cycles): - // Increment value at address in hl, check flags except CF: - case 0x34: - { - unsigned const addr = hl(); - READ(hf2, addr); - zf = hf2 + 1; - WRITE(addr, zf & 0xFF); - hf2 |= hf2_incf; - } - - break; - - // dec (hl) (12 cycles): - // Decrement value at address in hl, check flags except CF: - case 0x35: - { - unsigned const addr = hl(); - READ(hf2, addr); - zf = hf2 - 1; - WRITE(addr, zf & 0xFF); - hf2 |= hf2_incf | hf2_subf; - } - - break; - - // ld (hl),n (12 cycles): - // set memory at address in hl to value of next byte in memory: - case 0x36: - { - unsigned imm; - PC_READ(imm); - WRITE(hl(), imm); - } - - break; - - // scf (4 cycles): - // Set CF. Unset SF and HCF: - case 0x37: - cf = 0x100; - hf2 = 0; - break; - - // jr c,disp (12;8 cycles): - // Jump to value of next (signed) byte in memory+current address if CF is set: - case 0x38: - if (cf & 0x100) { - jr_disp(); - } else { - PC_MOD((pc + 1) & 0xFFFF); - } - - break; - - // add hl,sp (8 cycles): - // add SP to HL, check flags except ZF: - case 0x39: - cf = l + sp; - l = cf & 0xFF; - hf1 = h; - hf2 = ((cf ^ sp) & 0x100) | sp >> 8; - cf >>= 8; - cf += h; - h = cf & 0xFF; - cycleCounter += 4; - break; - - // ldd a,(hl) (8 cycles): - // Put value at address in hl into A. Decrement HL: - case 0x3A: - { - unsigned addr = hl(); - a = mem_.read(addr, cycleCounter); - cycleCounter += 4; - - addr = (addr - 1) & 0xFFFF; - l = addr; - h = addr >> 8; - } - - break; - - case 0x3B: - sp = (sp - 1) & 0xFFFF; - cycleCounter += 4; - break; - - case 0x3C: - inc_r(a); - break; - case 0x3D: - dec_r(a); - break; - case 0x3E: - PC_READ(a); - break; - - // ccf (4 cycles): - // Complement CF (unset if set vv.) Unset SF and HCF. - case 0x3F: - cf ^= 0x100; - hf2 = 0; - break; - - case 0x40: /*b = b;*/ break; - case 0x41: b = c; break; - case 0x42: b = d; break; - case 0x43: b = e; break; - case 0x44: b = h; break; - case 0x45: b = l; break; - case 0x46: READ(b, hl()); break; - case 0x47: b = a; break; - - case 0x48: c = b; break; - case 0x49: /*c = c;*/ break; - case 0x4A: c = d; break; - case 0x4B: c = e; break; - case 0x4C: c = h; break; - case 0x4D: c = l; break; - case 0x4E: READ(c, hl()); break; - case 0x4F: c = a; break; - - case 0x50: d = b; break; - case 0x51: d = c; break; - case 0x52: /*d = d;*/ break; - case 0x53: d = e; break; - case 0x54: d = h; break; - case 0x55: d = l; break; - case 0x56: READ(d, hl()); break; - case 0x57: d = a; break; - - case 0x58: e = b; break; - case 0x59: e = c; break; - case 0x5A: e = d; break; - case 0x5B: /*e = e;*/ break; - case 0x5C: e = h; break; - case 0x5D: e = l; break; - case 0x5E: READ(e, hl()); break; - case 0x5F: e = a; break; - - case 0x60: h = b; break; - case 0x61: h = c; break; - case 0x62: h = d; break; - case 0x63: h = e; break; - case 0x64: /*h = h;*/ break; - case 0x65: h = l; break; - case 0x66: READ(h, hl()); break; - case 0x67: h = a; break; - - case 0x68: l = b; break; - case 0x69: l = c; break; - case 0x6A: l = d; break; - case 0x6B: l = e; break; - case 0x6C: l = h; break; - case 0x6D: /*l = l;*/ break; - case 0x6E: READ(l, hl()); break; - case 0x6F: l = a; break; - - case 0x70: WRITE(hl(), b); break; - case 0x71: WRITE(hl(), c); break; - case 0x72: WRITE(hl(), d); break; - case 0x73: WRITE(hl(), e); break; - case 0x74: WRITE(hl(), h); break; - case 0x75: WRITE(hl(), l); break; - - // halt (4 cycles): - case 0x76: - opcode_ = mem_.read(pc, cycleCounter); - if (mem_.pendingIrqs(cycleCounter)) { - prefetched_ = true; - } else { - prefetched_ = mem_.halt(cycleCounter); - cycleCounter += 4 + 4 * !mem_.isCgb(); - if (cycleCounter < mem_.nextEventTime()) { - unsigned long cycles = mem_.nextEventTime() - cycleCounter; - cycleCounter += cycles + (-cycles & 3); - } - } - - break; - - case 0x77: WRITE(hl(), a); break; - case 0x78: a = b; break; - case 0x79: a = c; break; - case 0x7A: a = d; break; - case 0x7B: a = e; break; - case 0x7C: a = h; break; - case 0x7D: a = l; break; - case 0x7E: READ(a, hl()); break; - case 0x7F: /*a = a;*/ break; - - case 0x80: add_a_u8(b); break; - case 0x81: add_a_u8(c); break; - case 0x82: add_a_u8(d); break; - case 0x83: add_a_u8(e); break; - case 0x84: add_a_u8(h); break; - case 0x85: add_a_u8(l); break; - case 0x86: { unsigned data; READ(data, hl()); add_a_u8(data); } break; - case 0x87: add_a_u8(a); break; - - case 0x88: adc_a_u8(b); break; - case 0x89: adc_a_u8(c); break; - case 0x8A: adc_a_u8(d); break; - case 0x8B: adc_a_u8(e); break; - case 0x8C: adc_a_u8(h); break; - case 0x8D: adc_a_u8(l); break; - case 0x8E: { unsigned data; READ(data, hl()); adc_a_u8(data); } break; - case 0x8F: adc_a_u8(a); break; - - case 0x90: sub_a_u8(b); break; - case 0x91: sub_a_u8(c); break; - case 0x92: sub_a_u8(d); break; - case 0x93: sub_a_u8(e); break; - case 0x94: sub_a_u8(h); break; - case 0x95: sub_a_u8(l); break; - case 0x96: { unsigned data; READ(data, hl()); sub_a_u8(data); } break; - - // A-A is always 0: - case 0x97: - hf2 = hf2_subf; - cf = zf = a = 0; - break; - - case 0x98: sbc_a_u8(b); break; - case 0x99: sbc_a_u8(c); break; - case 0x9A: sbc_a_u8(d); break; - case 0x9B: sbc_a_u8(e); break; - case 0x9C: sbc_a_u8(h); break; - case 0x9D: sbc_a_u8(l); break; - case 0x9E: { unsigned data; READ(data, hl()); sbc_a_u8(data); } break; - case 0x9F: sbc_a_u8(a); break; - - case 0xA0: and_a_u8(b); break; - case 0xA1: and_a_u8(c); break; - case 0xA2: and_a_u8(d); break; - case 0xA3: and_a_u8(e); break; - case 0xA4: and_a_u8(h); break; - case 0xA5: and_a_u8(l); break; - case 0xA6: { unsigned data; READ(data, hl()); and_a_u8(data); } break; - - // A&A will always be A: - case 0xA7: - zf = a; - cf = 0; - hf2 = hf2_hcf; - break; - - case 0xA8: xor_a_u8(b); break; - case 0xA9: xor_a_u8(c); break; - case 0xAA: xor_a_u8(d); break; - case 0xAB: xor_a_u8(e); break; - case 0xAC: xor_a_u8(h); break; - case 0xAD: xor_a_u8(l); break; - case 0xAE: { unsigned data; READ(data, hl()); xor_a_u8(data); } break; - - // A^A will always be 0: - case 0xAF: cf = hf2 = zf = a = 0; break; - - case 0xB0: or_a_u8(b); break; - case 0xB1: or_a_u8(c); break; - case 0xB2: or_a_u8(d); break; - case 0xB3: or_a_u8(e); break; - case 0xB4: or_a_u8(h); break; - case 0xB5: or_a_u8(l); break; - case 0xB6: { unsigned data; READ(data, hl()); or_a_u8(data); } break; - - // A|A will always be A: - case 0xB7: - zf = a; - hf2 = cf = 0; - break; - - case 0xB8: cp_a_u8(b); break; - case 0xB9: cp_a_u8(c); break; - case 0xBA: cp_a_u8(d); break; - case 0xBB: cp_a_u8(e); break; - case 0xBC: cp_a_u8(h); break; - case 0xBD: cp_a_u8(l); break; - case 0xBE: { unsigned data; READ(data, hl()); cp_a_u8(data); } break; - - // A always equals A: - case 0xBF: - cf = zf = 0; - hf2 = hf2_subf; - break; - - // ret nz (20;8 cycles): - // Pop two bytes from the stack and jump to that address, if ZF is unset: - case 0xC0: - cycleCounter += 4; - - if (zf & 0xFF) - ret(); - - break; - - case 0xC1: - pop_rr(b, c); - break; - - // jp nz,nn (16;12 cycles): - // Jump to address stored in next two bytes in memory if ZF is unset: - case 0xC2: - if (zf & 0xFF) { - jp_nn(); - } else { - PC_MOD((pc + 2) & 0xFFFF); - cycleCounter += 4; - } - - break; - - case 0xC3: - jp_nn(); - break; - - // call nz,nn (24;12 cycles): - // Push address of next instruction onto stack and then jump to - // address stored in next two bytes in memory, if ZF is unset: - case 0xC4: - if (zf & 0xFF) { - call_nn(); - } else { - PC_MOD((pc + 2) & 0xFFFF); - cycleCounter += 4; - } - - break; - - case 0xC5: - push_rr(b, c); - break; - case 0xC6: - { - unsigned data; - PC_READ(data); - add_a_u8(data); - } - - break; - - case 0xC7: - rst_n(0x00); - break; - - // ret z (20;8 cycles): - // Pop two bytes from the stack and jump to that address, if ZF is set: - case 0xC8: - cycleCounter += 4; - - if (!(zf & 0xFF)) - ret(); - - break; - - // ret (16 cycles): - // Pop two bytes from the stack and jump to that address: - case 0xC9: - ret(); - break; - - // jp z,nn (16;12 cycles): - // Jump to address stored in next two bytes in memory if ZF is set: - case 0xCA: - if (zf & 0xFF) { - PC_MOD((pc + 2) & 0xFFFF); - cycleCounter += 4; - } else { - jp_nn(); - } - - break; - - - // CB OPCODES (Shifts, rotates and bits): - case 0xCB: - PC_READ(opcode); - - switch (opcode) { - case 0x00: rlc_r(b); break; - case 0x01: rlc_r(c); break; - case 0x02: rlc_r(d); break; - case 0x03: rlc_r(e); break; - case 0x04: rlc_r(h); break; - case 0x05: rlc_r(l); break; - - // rlc (hl) (16 cycles): - // Rotate 8-bit value stored at address in HL left, store old bit7 in CF. - // Reset SF and HCF. Check ZF: - case 0x06: - { - unsigned const addr = hl(); - READ(cf, addr); - cf <<= 1; - zf = cf | (cf >> 8); - WRITE(addr, zf & 0xFF); - hf2 = 0; - } - - break; - - case 0x07: rlc_r(a); break; - - case 0x08: rrc_r(b); break; - case 0x09: rrc_r(c); break; - case 0x0A: rrc_r(d); break; - case 0x0B: rrc_r(e); break; - case 0x0C: rrc_r(h); break; - case 0x0D: rrc_r(l); break; - - // rrc (hl) (16 cycles): - // Rotate 8-bit value stored at address in HL right, store old bit0 in CF. - // Reset SF and HCF. Check ZF: - case 0x0E: - { - unsigned const addr = hl(); - READ(zf, addr); - cf = zf << 8; - WRITE(addr, (zf | cf) >> 1 & 0xFF); - hf2 = 0; - } - - break; - - case 0x0F: rrc_r(a); break; - - case 0x10: rl_r(b); break; - case 0x11: rl_r(c); break; - case 0x12: rl_r(d); break; - case 0x13: rl_r(e); break; - case 0x14: rl_r(h); break; - case 0x15: rl_r(l); break; - - // rl (hl) (16 cycles): - // Rotate 8-bit value stored at address in HL left thorugh CF, - // store old bit7 in CF, old CF value becoms bit0. Reset SF and HCF. Check ZF: - case 0x16: - { - unsigned const addr = hl(); - unsigned const oldcf = cf >> 8 & 1; - READ(cf, addr); - cf <<= 1; - zf = cf | oldcf; - WRITE(addr, zf & 0xFF); - hf2 = 0; - } - break; - - case 0x17: rl_r(a); break; - - case 0x18: rr_r(b); break; - case 0x19: rr_r(c); break; - case 0x1A: rr_r(d); break; - case 0x1B: rr_r(e); break; - case 0x1C: rr_r(h); break; - case 0x1D: rr_r(l); break; - - // rr (hl) (16 cycles): - // Rotate 8-bit value stored at address in HL right thorugh CF, - // store old bit0 in CF, old CF value becoms bit7. Reset SF and HCF. Check ZF: - case 0x1E: - { - unsigned const addr = hl(); - READ(zf, addr); - - unsigned const oldcf = cf & 0x100; - cf = zf << 8; - zf = (zf | oldcf) >> 1; - WRITE(addr, zf); - hf2 = 0; - } - - break; - - case 0x1F: rr_r(a); break; - - case 0x20: sla_r(b); break; - case 0x21: sla_r(c); break; - case 0x22: sla_r(d); break; - case 0x23: sla_r(e); break; - case 0x24: sla_r(h); break; - case 0x25: sla_r(l); break; - - // sla (hl) (16 cycles): - // Shift 8-bit value stored at address in HL left, store old bit7 in CF. - // Reset SF and HCF. Check ZF: - case 0x26: - { - unsigned const addr = hl(); - READ(cf, addr); - cf <<= 1; - zf = cf; - WRITE(addr, zf & 0xFF); - hf2 = 0; - } - - break; - - case 0x27: sla_r(a); break; - - case 0x28: sra_r(b); break; - case 0x29: sra_r(c); break; - case 0x2A: sra_r(d); break; - case 0x2B: sra_r(e); break; - case 0x2C: sra_r(h); break; - case 0x2D: sra_r(l); break; - - // sra (hl) (16 cycles): - // Shift 8-bit value stored at address in HL right, store old bit0 in CF, - // bit7=old bit7. Reset SF and HCF. Check ZF: - case 0x2E: - { - unsigned const addr = hl(); - READ(cf, addr); - zf = cf >> 1; - WRITE(addr, zf | (cf & 0x80)); - cf <<= 8; - hf2 = 0; - } - - break; - - case 0x2F: sra_r(a); break; - - case 0x30: swap_r(b); break; - case 0x31: swap_r(c); break; - case 0x32: swap_r(d); break; - case 0x33: swap_r(e); break; - case 0x34: swap_r(h); break; - case 0x35: swap_r(l); break; - - // swap (hl) (16 cycles): - // Swap upper and lower nibbles of 8-bit value stored at address in HL, - // reset flags, check zero flag: - case 0x36: - { - unsigned const addr = hl(); - READ(zf, addr); - WRITE(addr, (zf << 4 | zf >> 4) & 0xFF); - cf = hf2 = 0; - } - - break; - - case 0x37: swap_r(a); break; - - case 0x38: srl_r(b); break; - case 0x39: srl_r(c); break; - case 0x3A: srl_r(d); break; - case 0x3B: srl_r(e); break; - case 0x3C: srl_r(h); break; - case 0x3D: srl_r(l); break; - - // srl (hl) (16 cycles): - // Shift 8-bit value stored at address in HL right, - // store old bit0 in CF. Reset SF and HCF. Check ZF: - case 0x3E: - { - unsigned const addr = hl(); - READ(cf, addr); - zf = cf >> 1; - WRITE(addr, zf); - cf <<= 8; - hf2 = 0; - } - - break; - - case 0x3F: srl_r(a); break; - - case 0x40: bit0_u8(b); break; - case 0x41: bit0_u8(c); break; - case 0x42: bit0_u8(d); break; - case 0x43: bit0_u8(e); break; - case 0x44: bit0_u8(h); break; - case 0x45: bit0_u8(l); break; - case 0x46: { unsigned data; READ(data, hl()); bit0_u8(data); } break; - case 0x47: bit0_u8(a); break; - - case 0x48: bit1_u8(b); break; - case 0x49: bit1_u8(c); break; - case 0x4A: bit1_u8(d); break; - case 0x4B: bit1_u8(e); break; - case 0x4C: bit1_u8(h); break; - case 0x4D: bit1_u8(l); break; - case 0x4E: { unsigned data; READ(data, hl()); bit1_u8(data); } break; - case 0x4F: bit1_u8(a); break; - - case 0x50: bit2_u8(b); break; - case 0x51: bit2_u8(c); break; - case 0x52: bit2_u8(d); break; - case 0x53: bit2_u8(e); break; - case 0x54: bit2_u8(h); break; - case 0x55: bit2_u8(l); break; - case 0x56: { unsigned data; READ(data, hl()); bit2_u8(data); } break; - case 0x57: bit2_u8(a); break; - - case 0x58: bit3_u8(b); break; - case 0x59: bit3_u8(c); break; - case 0x5A: bit3_u8(d); break; - case 0x5B: bit3_u8(e); break; - case 0x5C: bit3_u8(h); break; - case 0x5D: bit3_u8(l); break; - case 0x5E: { unsigned data; READ(data, hl()); bit3_u8(data); } break; - case 0x5F: bit3_u8(a); break; - - case 0x60: bit4_u8(b); break; - case 0x61: bit4_u8(c); break; - case 0x62: bit4_u8(d); break; - case 0x63: bit4_u8(e); break; - case 0x64: bit4_u8(h); break; - case 0x65: bit4_u8(l); break; - case 0x66: { unsigned data; READ(data, hl()); bit4_u8(data); } break; - case 0x67: bit4_u8(a); break; - - case 0x68: bit5_u8(b); break; - case 0x69: bit5_u8(c); break; - case 0x6A: bit5_u8(d); break; - case 0x6B: bit5_u8(e); break; - case 0x6C: bit5_u8(h); break; - case 0x6D: bit5_u8(l); break; - case 0x6E: { unsigned data; READ(data, hl()); bit5_u8(data); } break; - case 0x6F: bit5_u8(a); break; - - case 0x70: bit6_u8(b); break; - case 0x71: bit6_u8(c); break; - case 0x72: bit6_u8(d); break; - case 0x73: bit6_u8(e); break; - case 0x74: bit6_u8(h); break; - case 0x75: bit6_u8(l); break; - case 0x76: { unsigned data; READ(data, hl()); bit6_u8(data); } break; - case 0x77: bit6_u8(a); break; - - case 0x78: bit7_u8(b); break; - case 0x79: bit7_u8(c); break; - case 0x7A: bit7_u8(d); break; - case 0x7B: bit7_u8(e); break; - case 0x7C: bit7_u8(h); break; - case 0x7D: bit7_u8(l); break; - case 0x7E: { unsigned data; READ(data, hl()); bit7_u8(data); } break; - case 0x7F: bit7_u8(a); break; - - case 0x80: res0_r(b); break; - case 0x81: res0_r(c); break; - case 0x82: res0_r(d); break; - case 0x83: res0_r(e); break; - case 0x84: res0_r(h); break; - case 0x85: res0_r(l); break; - case 0x86: resn_mem_hl(0); break; - case 0x87: res0_r(a); break; - - case 0x88: res1_r(b); break; - case 0x89: res1_r(c); break; - case 0x8A: res1_r(d); break; - case 0x8B: res1_r(e); break; - case 0x8C: res1_r(h); break; - case 0x8D: res1_r(l); break; - case 0x8E: resn_mem_hl(1); break; - case 0x8F: res1_r(a); break; - - case 0x90: res2_r(b); break; - case 0x91: res2_r(c); break; - case 0x92: res2_r(d); break; - case 0x93: res2_r(e); break; - case 0x94: res2_r(h); break; - case 0x95: res2_r(l); break; - case 0x96: resn_mem_hl(2); break; - case 0x97: res2_r(a); break; - - case 0x98: res3_r(b); break; - case 0x99: res3_r(c); break; - case 0x9A: res3_r(d); break; - case 0x9B: res3_r(e); break; - case 0x9C: res3_r(h); break; - case 0x9D: res3_r(l); break; - case 0x9E: resn_mem_hl(3); break; - case 0x9F: res3_r(a); break; - - case 0xA0: res4_r(b); break; - case 0xA1: res4_r(c); break; - case 0xA2: res4_r(d); break; - case 0xA3: res4_r(e); break; - case 0xA4: res4_r(h); break; - case 0xA5: res4_r(l); break; - case 0xA6: resn_mem_hl(4); break; - case 0xA7: res4_r(a); break; - - case 0xA8: res5_r(b); break; - case 0xA9: res5_r(c); break; - case 0xAA: res5_r(d); break; - case 0xAB: res5_r(e); break; - case 0xAC: res5_r(h); break; - case 0xAD: res5_r(l); break; - case 0xAE: resn_mem_hl(5); break; - case 0xAF: res5_r(a); break; - - case 0xB0: res6_r(b); break; - case 0xB1: res6_r(c); break; - case 0xB2: res6_r(d); break; - case 0xB3: res6_r(e); break; - case 0xB4: res6_r(h); break; - case 0xB5: res6_r(l); break; - case 0xB6: resn_mem_hl(6); break; - case 0xB7: res6_r(a); break; - - case 0xB8: res7_r(b); break; - case 0xB9: res7_r(c); break; - case 0xBA: res7_r(d); break; - case 0xBB: res7_r(e); break; - case 0xBC: res7_r(h); break; - case 0xBD: res7_r(l); break; - case 0xBE: resn_mem_hl(7); break; - case 0xBF: res7_r(a); break; - - case 0xC0: set0_r(b); break; - case 0xC1: set0_r(c); break; - case 0xC2: set0_r(d); break; - case 0xC3: set0_r(e); break; - case 0xC4: set0_r(h); break; - case 0xC5: set0_r(l); break; - case 0xC6: setn_mem_hl(0); break; - case 0xC7: set0_r(a); break; - - case 0xC8: set1_r(b); break; - case 0xC9: set1_r(c); break; - case 0xCA: set1_r(d); break; - case 0xCB: set1_r(e); break; - case 0xCC: set1_r(h); break; - case 0xCD: set1_r(l); break; - case 0xCE: setn_mem_hl(1); break; - case 0xCF: set1_r(a); break; - - case 0xD0: set2_r(b); break; - case 0xD1: set2_r(c); break; - case 0xD2: set2_r(d); break; - case 0xD3: set2_r(e); break; - case 0xD4: set2_r(h); break; - case 0xD5: set2_r(l); break; - case 0xD6: setn_mem_hl(2); break; - case 0xD7: set2_r(a); break; - - case 0xD8: set3_r(b); break; - case 0xD9: set3_r(c); break; - case 0xDA: set3_r(d); break; - case 0xDB: set3_r(e); break; - case 0xDC: set3_r(h); break; - case 0xDD: set3_r(l); break; - case 0xDE: setn_mem_hl(3); break; - case 0xDF: set3_r(a); break; - - case 0xE0: set4_r(b); break; - case 0xE1: set4_r(c); break; - case 0xE2: set4_r(d); break; - case 0xE3: set4_r(e); break; - case 0xE4: set4_r(h); break; - case 0xE5: set4_r(l); break; - case 0xE6: setn_mem_hl(4); break; - case 0xE7: set4_r(a); break; - - case 0xE8: set5_r(b); break; - case 0xE9: set5_r(c); break; - case 0xEA: set5_r(d); break; - case 0xEB: set5_r(e); break; - case 0xEC: set5_r(h); break; - case 0xED: set5_r(l); break; - case 0xEE: setn_mem_hl(5); break; - case 0xEF: set5_r(a); break; - - case 0xF0: set6_r(b); break; - case 0xF1: set6_r(c); break; - case 0xF2: set6_r(d); break; - case 0xF3: set6_r(e); break; - case 0xF4: set6_r(h); break; - case 0xF5: set6_r(l); break; - case 0xF6: setn_mem_hl(6); break; - case 0xF7: set6_r(a); break; - - case 0xF8: set7_r(b); break; - case 0xF9: set7_r(c); break; - case 0xFA: set7_r(d); break; - case 0xFB: set7_r(e); break; - case 0xFC: set7_r(h); break; - case 0xFD: set7_r(l); break; - case 0xFE: setn_mem_hl(7); break; - case 0xFF: set7_r(a); break; - } - - break; - - - // call z,nn (24;12 cycles): - // Push address of next instruction onto stack and then jump to - // address stored in next two bytes in memory, if ZF is set: - case 0xCC: - if (zf & 0xFF) { - PC_MOD((pc + 2) & 0xFFFF); - cycleCounter += 4; - } else { - call_nn(); - } - - break; - - case 0xCD: - call_nn(); - break; - - case 0xCE: - { - unsigned data; - PC_READ(data); - adc_a_u8(data); - } - - break; - - case 0xCF: - rst_n(0x08); - break; - - // ret nc (20;8 cycles): - // Pop two bytes from the stack and jump to that address, if CF is unset: - case 0xD0: - cycleCounter += 4; - - if (!(cf & 0x100)) - ret(); - - break; - - case 0xD1: - pop_rr(d, e); - break; - - // jp nc,nn (16;12 cycles): - // Jump to address stored in next two bytes in memory if CF is unset: - case 0xD2: - if (cf & 0x100) { - PC_MOD((pc + 2) & 0xFFFF); - cycleCounter += 4; - } else { - jp_nn(); - } - - break; - - case 0xD3: // not specified. should freeze. - cycleCounter = freeze(mem_, cycleCounter); - break; - - // call nc,nn (24;12 cycles): - // Push address of next instruction onto stack and then jump to - // address stored in next two bytes in memory, if CF is unset: - case 0xD4: - if (cf & 0x100) { - PC_MOD((pc + 2) & 0xFFFF); - cycleCounter += 4; - } else { - call_nn(); - } - - break; - - case 0xD5: - push_rr(d, e); - break; - - case 0xD6: - { - unsigned data; - PC_READ(data); - sub_a_u8(data); - } - - break; - - case 0xD7: - rst_n(0x10); - break; - - // ret c (20;8 cycles): - // Pop two bytes from the stack and jump to that address, if CF is set: - case 0xD8: - cycleCounter += 4; - - if (cf & 0x100) - ret(); - - break; - - // reti (16 cycles): - // Pop two bytes from the stack and jump to that address, then enable interrupts: - case 0xD9: - { - unsigned sl, sh; - pop_rr(sh, sl); - mem_.ei(cycleCounter); - PC_MOD(sh << 8 | sl); - } - - break; - - // jp c,nn (16;12 cycles): - // Jump to address stored in next two bytes in memory if CF is set: - case 0xDA: - if (cf & 0x100) { - jp_nn(); - } else { - PC_MOD((pc + 2) & 0xFFFF); - cycleCounter += 4; - } - - break; - - case 0xDB: // not specified. should freeze. - cycleCounter = freeze(mem_, cycleCounter); - break; - - // call z,nn (24;12 cycles): - // Push address of next instruction onto stack and then jump to - // address stored in next two bytes in memory, if CF is set: - case 0xDC: - if (cf & 0x100) { - call_nn(); - } else { - PC_MOD((pc + 2) & 0xFFFF); - cycleCounter += 4; - } - - break; - case 0xDD: // not specified. should freeze. - cycleCounter = freeze(mem_, cycleCounter); - break; - - case 0xDE: - { - unsigned data; - PC_READ(data); - sbc_a_u8(data); - } - - break; - - case 0xDF: - rst_n(0x18); - break; - - // ld ($FF00+n),a (12 cycles): - // Put value in A into address (0xFF00 + next byte in memory): - case 0xE0: - { - unsigned imm; - PC_READ(imm); - FF_WRITE(imm, a); - } - - break; - - case 0xE1: - pop_rr(h, l); - break; - - // ld ($FF00+C),a (8 ycles): - // Put A into address (0xFF00 + register C): - case 0xE2: - FF_WRITE(c, a); - break; - - case 0xE3: - case 0xE4: // not specified. should freeze. - cycleCounter = freeze(mem_, cycleCounter); - break; - - case 0xE5: - push_rr(h, l); - break; - - case 0xE6: - { - unsigned data; - PC_READ(data); - and_a_u8(data); - } - - break; - - case 0xE7: - rst_n(0x20); - break; - - // add sp,n (16 cycles): - // Add next (signed) byte in memory to SP, reset ZF and SF, check HCF and CF: - case 0xE8: - sp_plus_n(sp); - cycleCounter += 4; - break; - - // jp hl (4 cycles): - // Jump to address in hl: - case 0xE9: - pc = hl(); - break; - - // ld (nn),a (16 cycles): - // set memory at address given by the next 2 bytes to value in A: - // Incrementing PC before call, because of possible interrupt. - case 0xEA: - { - unsigned imml, immh; - PC_READ(imml); - PC_READ(immh); - WRITE(immh << 8 | imml, a); - } - - break; - - case 0xEB: // not specified. should freeze. - case 0xEC: // not specified. should freeze. - case 0xED: // not specified. should freeze. - cycleCounter = freeze(mem_, cycleCounter); - break; - - case 0xEE: - { - unsigned data; - PC_READ(data); - xor_a_u8(data); - } - - break; - - case 0xEF: - rst_n(0x28); - break; - - // ld a,($FF00+n) (12 cycles): - // Put value at address (0xFF00 + next byte in memory) into A: - case 0xF0: - { - unsigned imm; - PC_READ(imm); - FF_READ(a, imm); - } - - break; - - case 0xF1: - { - unsigned F; - pop_rr(a, F); - zf = zfFromF(F); - hf2 = hf2FromF(F); - cf = cfFromF(F); - } - - break; - - // ld a,($FF00+C) (8 cycles): - // Put value at address (0xFF00 + register C) into A: - case 0xF2: - FF_READ(a, c); - break; - - // di (4 cycles): - case 0xF3: - mem_.di(); - break; - - case 0xF4: // not specified. should freeze. - cycleCounter = freeze(mem_, cycleCounter); - break; - - case 0xF5: - hf2 = updateHf2FromHf1(hf1, hf2); - - { - unsigned F = toF(hf2, cf, zf); - push_rr(a, F); - } - - break; - - case 0xF6: - { - unsigned data; - PC_READ(data); - or_a_u8(data); - } - - break; - - case 0xF7: - rst_n(0x30); - break; - - // ldhl sp,n (12 cycles): - // Put (sp+next (signed) byte in memory) into hl (unsets ZF and SF, may enable HF and CF): - case 0xF8: - { - unsigned sum; - sp_plus_n(sum); - l = sum & 0xFF; - h = sum >> 8; - } - - break; - - // ld sp,hl (8 cycles): - // Put value in HL into SP - case 0xF9: - sp = hl(); - cycleCounter += 4; - break; - - // ld a,(nn) (16 cycles): - // set A to value in memory at address given by the 2 next bytes. - case 0xFA: - { - unsigned imml, immh; - PC_READ(imml); - PC_READ(immh); - - READ(a, immh << 8 | imml); - } - - break; - - // ei (4 cycles): - // Enable Interrupts after next instruction: - case 0xFB: - mem_.ei(cycleCounter); - break; - - case 0xFC: // not specified. should freeze. - case 0xFD: // not specified. should freeze - cycleCounter = freeze(mem_, cycleCounter); - break; - case 0xFE: - { - unsigned data; - PC_READ(data); - - cp_a_u8(data); - } - - break; - - case 0xFF: - rst_n(0x38); - break; - } - } - - //pc_ = pc; - cycleCounter = mem_.event(cycleCounter); - } - - //a_ = a; - cycleCounter_ = cycleCounter; -} - -void CPU::getRegs(int *dest) { - hf2 = updateHf2FromHf1(hf1, hf2); - - dest[0] = pc; - dest[1] = sp; - dest[2] = a; - dest[3] = b; - dest[4] = c; - dest[5] = d; - dest[6] = e; - dest[7] = toF(hf2, cf, zf); - dest[8] = h; - dest[9] = l; -} - -void CPU::setInterruptAddresses(int *addrs, int numAddrs) { - interruptAddresses = addrs; - numInterruptAddresses = numAddrs; -} - -int CPU::getHitInterruptAddress() { - return hitInterruptAddress; -} - -SYNCFUNC(CPU) -{ - SSS(mem_); - NSS(cycleCounter_); - NSS(pc); - NSS(sp); - NSS(hf1); - NSS(hf2); - NSS(zf); - NSS(cf); - NSS(a); - NSS(b); - NSS(c); - NSS(d); - NSS(e); - NSS(h); - NSS(l); - NSS(opcode_); - NSS(prefetched_); -} - -} diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h deleted file mode 100644 index 85df4edfe6..0000000000 --- a/libgambatte/src/cpu.h +++ /dev/null @@ -1,134 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef CPU_H -#define CPU_H - -#include "memory.h" -#include "newstate.h" - -namespace gambatte { - -class CPU { -public: - CPU(); - long runFor(unsigned long cycles); - void setStatePtrs(SaveState &state); - void loadState(SaveState const &state); - void setLayers(unsigned mask) { mem_.setLayers(mask); } - void loadSavedata(char const *data) { mem_.loadSavedata(data, cycleCounter_); } - int saveSavedataLength() {return mem_.saveSavedataLength(); } - void saveSavedata(char *dest) { mem_.saveSavedata(dest, cycleCounter_); } - - bool getMemoryArea(int which, unsigned char **data, int *length) { return mem_.getMemoryArea(which, data, length); } - - void setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch) { - mem_.setVideoBuffer(videoBuf, pitch); - } - - void setInputGetter(unsigned (*getInput)()) { - mem_.setInputGetter(getInput); - } - - void setReadCallback(MemoryCallback callback) { - mem_.setReadCallback(callback); - } - - void setWriteCallback(MemoryCallback callback) { - mem_.setWriteCallback(callback); - } - - void setExecCallback(MemoryCallback callback) { - mem_.setExecCallback(callback); - } - - void setCDCallback(CDCallback cdc) { - mem_.setCDCallback(cdc); - } - - void setTraceCallback(void (*callback)(void *)) { - tracecallback = callback; - } - - void setScanlineCallback(void (*callback)(), int sl) { - mem_.setScanlineCallback(callback, sl); - } - - void setLinkCallback(void(*callback)()) { - mem_.setLinkCallback(callback); - } - - LoadRes load(char const *romfiledata, unsigned romfilelength, unsigned flags) { - return mem_.loadROM(romfiledata, romfilelength, flags); - } - - bool loaded() const { return mem_.loaded(); } - char const * romTitle() const { return mem_.romTitle(); } - void setSoundBuffer(uint_least32_t *buf) { mem_.setSoundBuffer(buf); } - std::size_t fillSoundBuffer() { return mem_.fillSoundBuffer(cycleCounter_); } - bool isCgb() const { return mem_.isCgb(); } - - void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) { - mem_.setDmgPaletteColor(palNum, colorNum, rgb32); - } - - void setCgbPalette(unsigned *lut) { - mem_.setCgbPalette(lut); - } - void setTimeMode(bool useCycles) { mem_.setTimeMode(useCycles, cycleCounter_); } - void setRtcDivisorOffset(long const rtcDivisorOffset) { mem_.setRtcDivisorOffset(rtcDivisorOffset); } - - void setBios(char const *buffer, std::size_t size) { mem_.setBios(buffer, size); } - - unsigned char externalRead(unsigned short addr) {return mem_.peek(addr); } - - void externalWrite(unsigned short addr, unsigned char val) { - mem_.write_nocb(addr, val, cycleCounter_); - } - - int linkStatus(int which) { return mem_.linkStatus(which); } - - void getRegs(int *dest); - void setInterruptAddresses(int *addrs, int numAddrs); - int getHitInterruptAddress(); - -private: - Memory mem_; - unsigned long cycleCounter_; - unsigned short pc; - unsigned short sp; - unsigned hf1, hf2, zf, cf; - unsigned char a, b, c, d, e, /*f,*/ h, l; - unsigned char opcode_; - bool prefetched_; - - int *interruptAddresses; - int numInterruptAddresses; - int hitInterruptAddress; - - void process(unsigned long cycles); - - void (*tracecallback)(void *); - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp deleted file mode 100644 index 50a3447fce..0000000000 --- a/libgambatte/src/gambatte.cpp +++ /dev/null @@ -1,245 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "gambatte.h" -#include "cpu.h" -#include "initstate.h" -#include "savestate.h" -#include -#include - -namespace gambatte { - -struct GB::Priv { - CPU cpu; - unsigned loadflags; - unsigned layersMask; - - uint_least32_t vbuff[160*144]; - - Priv() : loadflags(0), layersMask(layer_mask_bg | layer_mask_window | layer_mask_obj) - { - } -}; - -GB::GB() : p_(new Priv) {} - -GB::~GB() { - delete p_; -} - -std::ptrdiff_t GB::runFor(gambatte::uint_least32_t *const soundBuf, std::size_t &samples) { - if (!p_->cpu.loaded()) { - samples = 0; - return -1; - } - - p_->cpu.setVideoBuffer(p_->vbuff, 160); - p_->cpu.setSoundBuffer(soundBuf); - - long const cyclesSinceBlit = p_->cpu.runFor(samples * 2); - samples = p_->cpu.fillSoundBuffer(); - return cyclesSinceBlit >= 0 - ? static_cast(samples) - (cyclesSinceBlit >> 1) - : cyclesSinceBlit; -} - -void GB::setLayers(unsigned mask) { - p_->cpu.setLayers(mask); -} - -void GB::blitTo(gambatte::uint_least32_t *videoBuf, std::ptrdiff_t pitch) { - gambatte::uint_least32_t *src = p_->vbuff; - gambatte::uint_least32_t *dst = videoBuf; - - for (int i = 0; i < 144; i++) - { - std::memcpy(dst, src, sizeof gambatte::uint_least32_t * 160); - src += 160; - dst += pitch; - } -} - -void GB::reset() { - if (p_->cpu.loaded()) { - - int length = p_->cpu.saveSavedataLength(); - char *s; - if (length > 0) - { - s = (char *) std::malloc(length); - p_->cpu.saveSavedata(s); - } - - SaveState state; - p_->cpu.setStatePtrs(state); - setInitState(state, !(p_->loadflags & FORCE_DMG)); - p_->cpu.loadState(state); - if (length > 0) - { - p_->cpu.loadSavedata(s); - std::free(s); - } - } -} - -void GB::setInputGetter(unsigned (*getInput)()) { - p_->cpu.setInputGetter(getInput); -} - -void GB::setReadCallback(MemoryCallback callback) { - p_->cpu.setReadCallback(callback); -} - -void GB::setWriteCallback(MemoryCallback callback) { - p_->cpu.setWriteCallback(callback); -} - -void GB::setExecCallback(MemoryCallback callback) { - p_->cpu.setExecCallback(callback); -} - -void GB::setCDCallback(CDCallback cdc) { - p_->cpu.setCDCallback(cdc); -} - -void GB::setTraceCallback(void (*callback)(void *)) { - p_->cpu.setTraceCallback(callback); -} - -void GB::setScanlineCallback(void (*callback)(), int sl) { - p_->cpu.setScanlineCallback(callback, sl); -} - -void GB::setLinkCallback(void(*callback)()) { - p_->cpu.setLinkCallback(callback); -} - -void GB::setTimeMode(bool useCycles) { - p_->cpu.setTimeMode(useCycles); -} - -void GB::setRtcDivisorOffset(long const rtcDivisorOffset) { - p_->cpu.setRtcDivisorOffset(rtcDivisorOffset); -} - -LoadRes GB::load(char const *romfiledata, unsigned romfilelength, unsigned const flags) { - LoadRes const loadres = p_->cpu.load(romfiledata, romfilelength, flags); - - if (loadres == LOADRES_OK) { - SaveState state; - p_->cpu.setStatePtrs(state); - p_->loadflags = flags; - setInitState(state, !(flags & FORCE_DMG)); - p_->cpu.loadState(state); - } - - return loadres; -} - -int GB::loadBios(char const* biosfiledata, std::size_t size) { - p_->cpu.setBios(biosfiledata, size); - return 0; -} - -bool GB::isCgb() const { - return p_->cpu.isCgb(); -} - -bool GB::isLoaded() const { - return p_->cpu.loaded(); -} - -void GB::saveSavedata(char *dest) { - if (p_->cpu.loaded()) - p_->cpu.saveSavedata(dest); -} -void GB::loadSavedata(char const *data) { - if (p_->cpu.loaded()) - p_->cpu.loadSavedata(data); -} -int GB::saveSavedataLength() { - if (p_->cpu.loaded()) - return p_->cpu.saveSavedataLength(); - else - return -1; -} - -bool GB::getMemoryArea(int which, unsigned char **data, int *length) { - if (p_->cpu.loaded()) - return p_->cpu.getMemoryArea(which, data, length); - else - return false; -} - -unsigned char GB::externalRead(unsigned short addr) { - if (p_->cpu.loaded()) - return p_->cpu.externalRead(addr); - else - return 0; -} - -void GB::externalWrite(unsigned short addr, unsigned char val) { - if (p_->cpu.loaded()) - p_->cpu.externalWrite(addr, val); -} - - -void GB::setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) { - p_->cpu.setDmgPaletteColor(palNum, colorNum, rgb32); -} - -void GB::setCgbPalette(unsigned *lut) { - p_->cpu.setCgbPalette(lut); -} - -std::string const GB::romTitle() const { - if (p_->cpu.loaded()) { - char title[0x11]; - std::memcpy(title, p_->cpu.romTitle(), 0x10); - title[title[0xF] & 0x80 ? 0xF : 0x10] = '\0'; - return std::string(title); - } - - return std::string(); -} - -int GB::linkStatus(int which) { - return p_->cpu.linkStatus(which); -} - -void GB::getRegs(int *dest) { - p_->cpu.getRegs(dest); -} - -void GB::setInterruptAddresses(int *addrs, int numAddrs) { - p_->cpu.setInterruptAddresses(addrs, numAddrs); -} - -int GB::getHitInterruptAddress() { - return p_->cpu.getHitInterruptAddress(); -} - -SYNCFUNC(GB) -{ - SSS(p_->cpu); - NSS(p_->loadflags); - NSS(p_->vbuff); -} - -} diff --git a/libgambatte/src/initstate.cpp b/libgambatte/src/initstate.cpp deleted file mode 100644 index 64b6825ffe..0000000000 --- a/libgambatte/src/initstate.cpp +++ /dev/null @@ -1,1341 +0,0 @@ -// -// Copyright (C) 2008 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "initstate.h" -#include "counterdef.h" -#include "savestate.h" -#include "sound/sound_unit.h" -#include "mem/time.h" -#include -#include - -namespace { - -static void setInitialCgbWram(unsigned char wram[]) { - static struct { unsigned short addr; unsigned char val; } const cgbWramDumpDiff[] = { - { 0x0083, 0x7F }, { 0x008B, 0x10 }, { 0x00C0, 0x7F }, { 0x00E1, 0x7F }, - { 0x00E2, 0x7F }, { 0x00EA, 0x10 }, { 0x010A, 0x40 }, { 0x0179, 0x01 }, - { 0x01AF, 0x01 }, { 0x0201, 0xFB }, { 0x0254, 0xF7 }, { 0x0264, 0x7F }, - { 0x02D1, 0xBF }, { 0x02D2, 0xFB }, { 0x0301, 0xF7 }, { 0x0313, 0xF7 }, - { 0x0315, 0x7F }, { 0x0325, 0x7F }, { 0x0339, 0x04 }, { 0x0354, 0x7F }, - { 0x0375, 0xFD }, { 0x0391, 0xFB }, { 0x03AC, 0x40 }, { 0x03C5, 0xFB }, - { 0x03FB, 0x20 }, { 0x0412, 0xF7 }, { 0x0422, 0xF7 }, { 0x04B1, 0xFB }, - { 0x04B5, 0x7F }, { 0x04C6, 0x7F }, { 0x04D0, 0xFB }, { 0x04D2, 0xDF }, - { 0x0504, 0x7F }, { 0x051C, 0x01 }, { 0x0523, 0xFD }, { 0x0532, 0xF7 }, - { 0x0535, 0xF7 }, { 0x0606, 0x7F }, { 0x0690, 0xF7 }, { 0x0697, 0xFB }, - { 0x0698, 0x02 }, { 0x06B5, 0x7F }, { 0x06E4, 0x7F }, { 0x06F1, 0xDF }, - { 0x06F9, 0x04 }, { 0x0730, 0xFD }, { 0x0783, 0xFB }, { 0x07B5, 0x7F }, - { 0x07B6, 0xF7 }, { 0x080E, 0xF7 }, { 0x081C, 0xF7 }, { 0x0849, 0xBF }, - { 0x0859, 0xF7 }, { 0x085E, 0x7F }, { 0x085F, 0x7F }, { 0x0869, 0x7F }, - { 0x086D, 0x7F }, { 0x086E, 0x7F }, { 0x0879, 0xBF }, { 0x087C, 0xFB }, - { 0x0889, 0xBB }, { 0x089A, 0xF7 }, { 0x089D, 0xD7 }, { 0x089E, 0x9F }, - { 0x08A9, 0x7F }, { 0x08AA, 0xFB }, { 0x08AC, 0x7F }, { 0x08AF, 0xF7 }, - { 0x08BB, 0xDF }, { 0x08D8, 0xFB }, { 0x08DB, 0x7F }, { 0x08DC, 0xBF }, - { 0x08E8, 0xF7 }, { 0x08FB, 0x7D }, { 0x08FC, 0x7F }, { 0x08FD, 0xFD }, - { 0x090A, 0xFB }, { 0x091C, 0xF7 }, { 0x091E, 0xDF }, { 0x0929, 0xF7 }, - { 0x092B, 0xF7 }, { 0x092C, 0xF7 }, { 0x092D, 0xFB }, { 0x094B, 0xF7 }, - { 0x094D, 0x7F }, { 0x095B, 0x7B }, { 0x0969, 0xF7 }, { 0x097C, 0x7F }, - { 0x097E, 0xF7 }, { 0x09DC, 0x5F }, { 0x09EB, 0xFD }, { 0x09EE, 0xDF }, - { 0x09EF, 0x7F }, { 0x09FB, 0xBF }, { 0x09FE, 0xF7 }, { 0x0A0A, 0xF7 }, - { 0x0A0E, 0xBF }, { 0x0A0F, 0x7F }, { 0x0A1A, 0xBF }, { 0x0A1C, 0x3F }, - { 0x0A2A, 0xFD }, { 0x0A2E, 0xF7 }, { 0x0A3C, 0xDF }, { 0x0A3E, 0xF7 }, - { 0x0A4B, 0xFB }, { 0x0A4F, 0xDF }, { 0x0A5C, 0xF7 }, { 0x0A6E, 0xF7 }, - { 0x0A7E, 0xB7 }, { 0x0A7F, 0xF7 }, { 0x0A81, 0x01 }, { 0x0A8D, 0xDF }, - { 0x0A9F, 0x7F }, { 0x0AAB, 0xFD }, { 0x0AAC, 0xFB }, { 0x0ABE, 0xBF }, - { 0x0AC9, 0xFB }, { 0x0ACF, 0xF7 }, { 0x0ADC, 0xF5 }, { 0x0ADD, 0xBF }, - { 0x0AEA, 0x7B }, { 0x0AEB, 0x7F }, { 0x0AF8, 0xFB }, { 0x0AFB, 0xDF }, - { 0x0B0D, 0x7F }, { 0x0B2E, 0xFD }, { 0x0B39, 0xF7 }, { 0x0B48, 0xBF }, - { 0x0B5D, 0x7F }, { 0x0B6B, 0x7F }, { 0x0B6D, 0xFB }, { 0x0B76, 0x10 }, - { 0x0B8B, 0x7F }, { 0x0B8C, 0xF5 }, { 0x0B8D, 0xDF }, { 0x0B9F, 0xBF }, - { 0x0BB9, 0xDF }, { 0x0BBF, 0x7F }, { 0x0BCE, 0xF7 }, { 0x0BDF, 0x7F }, - { 0x0BE9, 0x7F }, { 0x0BEE, 0xF7 }, { 0x0BF9, 0x7F }, { 0x0BFE, 0xB7 }, - { 0x0C09, 0xFD }, { 0x0C0C, 0xFD }, { 0x0C0D, 0xFD }, { 0x0C0F, 0xFB }, - { 0x0C18, 0xDB }, { 0x0C1A, 0xF7 }, { 0x0C1B, 0xBF }, { 0x0C1E, 0xF7 }, - { 0x0C29, 0x7F }, { 0x0C2D, 0xFD }, { 0x0C3F, 0x77 }, { 0x0C5B, 0xF7 }, - { 0x0C5E, 0xBF }, { 0x0C6B, 0x7F }, { 0x0C78, 0x7F }, { 0x0C79, 0xF7 }, - { 0x0C7D, 0xF7 }, { 0x0C8F, 0x77 }, { 0x0C9A, 0xF7 }, { 0x0CBB, 0xDB }, - { 0x0CBC, 0xF9 }, { 0x0CCE, 0x7F }, { 0x0CD8, 0xDF }, { 0x0CF8, 0x7F }, - { 0x0CFE, 0xFB }, { 0x0CFF, 0x7F }, { 0x0D09, 0xDB }, { 0x0D1C, 0xDF }, - { 0x0D1F, 0xF7 }, { 0x0D29, 0x7F }, { 0x0D2E, 0x7B }, { 0x0D39, 0x77 }, - { 0x0D3A, 0xFB }, { 0x0D3B, 0x7F }, { 0x0D3C, 0xDF }, { 0x0D3E, 0xFB }, - { 0x0D59, 0x7F }, { 0x0D5E, 0xDF }, { 0x0D6E, 0xFD }, { 0x0D78, 0xF7 }, - { 0x0D79, 0xFB }, { 0x0D7A, 0x7F }, { 0x0D8B, 0xFB }, { 0x0D8F, 0xBF }, - { 0x0D9B, 0xF7 }, { 0x0DBA, 0xBF }, { 0x0DBF, 0xD7 }, { 0x0DC9, 0x7F }, - { 0x0DCA, 0xF7 }, { 0x0DD8, 0xFB }, { 0x0DD9, 0xFB }, { 0x0DDA, 0xFD }, - { 0x0DDB, 0xF7 }, { 0x0DDD, 0xF7 }, { 0x0DDE, 0xF7 }, { 0x0DFB, 0xFB }, - { 0x0DFD, 0x7F }, { 0x0E08, 0xFB }, { 0x0E09, 0xFB }, { 0x0E18, 0xFB }, - { 0x0E29, 0xB7 }, { 0x0E2B, 0xFB }, { 0x0E3D, 0xF7 }, { 0x0E43, 0x20 }, - { 0x0E48, 0xF7 }, { 0x0E4D, 0xF7 }, { 0x0E5F, 0xF7 }, { 0x0E69, 0x7F }, - { 0x0E6B, 0xFB }, { 0x0E7E, 0x7B }, { 0x0E89, 0x7F }, { 0x0E8B, 0xFB }, - { 0x0E8D, 0xF7 }, { 0x0E99, 0xBF }, { 0x0E9B, 0xF7 }, { 0x0E9D, 0xF7 }, - { 0x0E9F, 0xF7 }, { 0x0EAB, 0xDF }, { 0x0EAF, 0xF7 }, { 0x0EB9, 0xDF }, - { 0x0EBD, 0x7F }, { 0x0EBE, 0xFB }, { 0x0ECB, 0xDF }, { 0x0ECE, 0xF7 }, - { 0x0ECF, 0x7F }, { 0x0EDF, 0xDF }, { 0x0EEB, 0xFD }, { 0x0EF8, 0xD7 }, - { 0x0EFC, 0x77 }, { 0x0EFD, 0xDF }, { 0x0EFF, 0x7F }, { 0x0F08, 0xF7 }, - { 0x0F0D, 0xDF }, { 0x0F1E, 0x7F }, { 0x0F2C, 0xDF }, { 0x0F2D, 0xF7 }, - { 0x0F2E, 0xFB }, { 0x0F2F, 0x7F }, { 0x0F38, 0xFB }, { 0x0F3B, 0xDF }, - { 0x0F43, 0x10 }, { 0x0F4B, 0x57 }, { 0x0F4C, 0x7F }, { 0x0F5F, 0xD7 }, - { 0x0F78, 0xBF }, { 0x0F8F, 0xBB }, { 0x0F9F, 0xF7 }, { 0x0FAB, 0xFD }, - { 0x0FAF, 0xF7 }, { 0x0FB8, 0xFB }, { 0x0FBE, 0x7F }, { 0x0FD9, 0xB3 }, - { 0x0FDD, 0xFB }, { 0x0FDF, 0x7F }, { 0x0FF2, 0xF7 }, { 0x0FFC, 0xF7 }, - { 0x10B0, 0xF7 }, { 0x10E0, 0xFD }, { 0x112B, 0x40 }, { 0x1150, 0xDF }, - { 0x1184, 0xBF }, { 0x1188, 0x01 }, { 0x11C1, 0x7F }, { 0x11E4, 0x7F }, - { 0x11F1, 0x7F }, { 0x1211, 0xF7 }, { 0x1214, 0xFD }, { 0x1215, 0xF7 }, - { 0x1244, 0xFB }, { 0x125B, 0x20 }, { 0x126C, 0x04 }, { 0x1272, 0xFD }, - { 0x12C1, 0xDF }, { 0x12DB, 0x10 }, { 0x12F0, 0x7F }, { 0x1364, 0xF7 }, - { 0x13F2, 0xFB }, { 0x1413, 0xDF }, { 0x1430, 0xF7 }, { 0x1436, 0xF7 }, - { 0x1450, 0x7F }, { 0x1470, 0xF7 }, { 0x1472, 0x7F }, { 0x14B4, 0xDF }, - { 0x14B6, 0xFB }, { 0x1516, 0xF7 }, { 0x151B, 0x01 }, { 0x1565, 0x7F }, - { 0x1597, 0xBF }, { 0x15A6, 0x7F }, { 0x15B0, 0x7F }, { 0x15C5, 0xBF }, - { 0x15D5, 0xFB }, { 0x15F2, 0xFD }, { 0x15FC, 0x04 }, { 0x161A, 0x10 }, - { 0x1689, 0x20 }, { 0x16A7, 0xFB }, { 0x170A, 0x02 }, { 0x1732, 0xFD }, - { 0x1744, 0x7F }, { 0x1759, 0x01 }, { 0x1761, 0xF7 }, { 0x1774, 0xF7 }, - { 0x1795, 0xFD }, { 0x179B, 0x10 }, { 0x17C4, 0xF7 }, { 0x1808, 0xDF }, - { 0x180B, 0xDF }, { 0x180F, 0x77 }, { 0x181D, 0x7F }, { 0x181F, 0xF7 }, - { 0x182C, 0x7F }, { 0x183F, 0x7F }, { 0x184A, 0x7F }, { 0x184D, 0x7F }, - { 0x184E, 0xF7 }, { 0x1859, 0x7F }, { 0x185F, 0x7F }, { 0x1864, 0x01 }, - { 0x1868, 0x3F }, { 0x186E, 0x9F }, { 0x186F, 0xF7 }, { 0x187A, 0xFB }, - { 0x188F, 0xBF }, { 0x189D, 0x7F }, { 0x189E, 0xFB }, { 0x18AA, 0xDF }, - { 0x18BE, 0x7F }, { 0x18CF, 0x7F }, { 0x18DB, 0x77 }, { 0x18DC, 0xDF }, - { 0x18E8, 0x77 }, { 0x18E9, 0x7F }, { 0x18FB, 0xF7 }, { 0x18FE, 0xF7 }, - { 0x191E, 0x7F }, { 0x191F, 0x7F }, { 0x1929, 0xBF }, { 0x192D, 0xDF }, - { 0x194C, 0xFB }, { 0x194E, 0xDF }, { 0x195B, 0x7F }, { 0x1968, 0xBF }, - { 0x196A, 0xF7 }, { 0x197F, 0xF7 }, { 0x198B, 0x7F }, { 0x198E, 0x7F }, - { 0x199B, 0xFB }, { 0x19A8, 0xDF }, { 0x19AA, 0xB7 }, { 0x19AB, 0x77 }, - { 0x19AD, 0xFD }, { 0x19B8, 0xBF }, { 0x19BE, 0xFD }, { 0x19BF, 0xDF }, - { 0x19DC, 0x7F }, { 0x19DF, 0x7D }, { 0x19EA, 0xDF }, { 0x19EC, 0xDF }, - { 0x19EF, 0x7F }, { 0x19FB, 0xFB }, { 0x19FC, 0xF7 }, { 0x19FD, 0xBF }, - { 0x19FF, 0xFE }, { 0x1A08, 0xDF }, { 0x1A0B, 0xF7 }, { 0x1A0D, 0x7F }, - { 0x1A0F, 0x7F }, { 0x1A1A, 0xBF }, { 0x1A1D, 0xBF }, { 0x1A1F, 0x7F }, - { 0x1A29, 0xFD }, { 0x1A2A, 0xFD }, { 0x1A2F, 0xF7 }, { 0x1A3E, 0x7F }, - { 0x1A49, 0xFD }, { 0x1A4A, 0xBB }, { 0x1A4C, 0xF7 }, { 0x1A4F, 0x7F }, - { 0x1A68, 0xF7 }, { 0x1A6D, 0xBF }, { 0x1A78, 0xBF }, { 0x1A7D, 0x7F }, - { 0x1A7E, 0xF7 }, { 0x1A9B, 0xF7 }, { 0x1A9C, 0xBF }, { 0x1A9D, 0xF7 }, - { 0x1A9F, 0x7F }, { 0x1AAA, 0x7F }, { 0x1ABF, 0xBF }, { 0x1ACA, 0xBF }, - { 0x1ACF, 0xF7 }, { 0x1ADA, 0xF7 }, { 0x1AEA, 0xFD }, { 0x1AFF, 0xFD }, - { 0x1B0B, 0xF7 }, { 0x1B19, 0x7F }, { 0x1B1D, 0xF7 }, { 0x1B1E, 0xF7 }, - { 0x1B29, 0xDF }, { 0x1B3B, 0xFB }, { 0x1B3C, 0xF7 }, { 0x1B4D, 0xFB }, - { 0x1B4F, 0xF7 }, { 0x1B6D, 0x7F }, { 0x1B6E, 0xF7 }, { 0x1B78, 0xF7 }, - { 0x1B9B, 0x7F }, { 0x1B9E, 0xDF }, { 0x1B9F, 0x7F }, { 0x1BAB, 0xBF }, - { 0x1BAF, 0xFD }, { 0x1BB8, 0xFB }, { 0x1BBA, 0xF7 }, { 0x1BBF, 0xF7 }, - { 0x1BCD, 0xDF }, { 0x1BDA, 0xDF }, { 0x1BDE, 0x77 }, { 0x1BF8, 0xBF }, - { 0x1BFC, 0xFD }, { 0x1BFD, 0xFB }, { 0x1BFE, 0xF7 }, { 0x1C0C, 0xF7 }, - { 0x1C0E, 0x7F }, { 0x1C1A, 0x7F }, { 0x1C1C, 0xFB }, { 0x1C2E, 0xFB }, - { 0x1C3E, 0xFD }, { 0x1C4D, 0x7F }, { 0x1C4F, 0xF7 }, { 0x1C5F, 0x7F }, - { 0x1C6A, 0xFD }, { 0x1C6E, 0xFB }, { 0x1C89, 0xFB }, { 0x1C8B, 0xFD }, - { 0x1C8E, 0xFD }, { 0x1C9A, 0xFB }, { 0x1C9C, 0x7F }, { 0x1CA8, 0xBF }, - { 0x1CA9, 0xBF }, { 0x1CAE, 0xBF }, { 0x1CB9, 0xF7 }, { 0x1CBA, 0x7F }, - { 0x1CBD, 0xDF }, { 0x1CCF, 0xF7 }, { 0x1D0C, 0xFB }, { 0x1D0F, 0x7F }, - { 0x1D18, 0xBF }, { 0x1D1F, 0xF7 }, { 0x1D28, 0xDF }, { 0x1D29, 0xF7 }, - { 0x1D2F, 0xF7 }, { 0x1D48, 0xD7 }, { 0x1D4A, 0xF7 }, { 0x1D59, 0xF7 }, - { 0x1D63, 0x40 }, { 0x1D6A, 0xF7 }, { 0x1D6C, 0xBF }, { 0x1D6E, 0xF7 }, - { 0x1D7D, 0xBF }, { 0x1D8E, 0xB7 }, { 0x1D9B, 0xFB }, { 0x1D9E, 0xFD }, - { 0x1DAD, 0x7F }, { 0x1DAF, 0x7F }, { 0x1DC8, 0xF7 }, { 0x1DCA, 0xBF }, - { 0x1DCF, 0xFB }, { 0x1DDB, 0xF7 }, { 0x1DDE, 0xBF }, { 0x1DE9, 0xBF }, - { 0x1E0F, 0xFD }, { 0x1E1B, 0xFD }, { 0x1E2B, 0xDF }, { 0x1E2D, 0x7F }, - { 0x1E39, 0xFB }, { 0x1E3A, 0x04 }, { 0x1E3D, 0xDF }, { 0x1E48, 0x5F }, - { 0x1E4D, 0x7F }, { 0x1E5E, 0x7F }, { 0x1E6B, 0x7F }, { 0x1E6F, 0x3F }, - { 0x1E7B, 0xFB }, { 0x1E7E, 0xF7 }, { 0x1E89, 0x7F }, { 0x1E8C, 0x7B }, - { 0x1E8F, 0xF7 }, { 0x1E99, 0xF7 }, { 0x1E9C, 0xF7 }, { 0x1E9F, 0xFB }, - { 0x1EA8, 0xFD }, { 0x1EAC, 0x7F }, { 0x1EAD, 0xF7 }, { 0x1EBF, 0xF7 }, - { 0x1ECF, 0x7F }, { 0x1EDC, 0xDF }, { 0x1EDD, 0xFD }, { 0x1EDE, 0x77 }, - { 0x1EDF, 0xF7 }, { 0x1EEE, 0xF5 }, { 0x1EEF, 0xF7 }, { 0x1EFB, 0xF3 }, - { 0x1F08, 0x7F }, { 0x1F09, 0xF7 }, { 0x1F0C, 0x7F }, { 0x1F19, 0xFB }, - { 0x1F1E, 0xFD }, { 0x1F2A, 0x02 }, { 0x1F38, 0xF7 }, { 0x1F4B, 0xDF }, - { 0x1F4F, 0xBF }, { 0x1F5C, 0xFD }, { 0x1F5D, 0xDF }, { 0x1F5F, 0x7F }, - { 0x1F78, 0xFB }, { 0x1F7A, 0x01 }, { 0x1F85, 0x01 }, { 0x1F88, 0x7F }, - { 0x1F89, 0xDF }, { 0x1F8B, 0xF7 }, { 0x1F9E, 0xFD }, { 0x1F9F, 0x7F }, - { 0x1FA8, 0xFB }, { 0x1FAC, 0xDF }, { 0x1FAE, 0xF7 }, { 0x1FAF, 0xDF }, - { 0x1FBB, 0xBF }, { 0x1FBE, 0xFB }, { 0x1FCB, 0x7F }, { 0x1FCE, 0x7F }, - { 0x1FD9, 0xF7 }, { 0x1FDE, 0xFB }, { 0x1FDF, 0x7F }, { 0x1FEB, 0x7F }, - { 0x1FF8, 0x7F }, { 0x1FFB, 0xDF }, { 0x1FFC, 0x7F }, { 0x1FFD, 0x7F }, - { 0x1FFE, 0xF7 }, { 0x2008, 0x1C }, { 0x200B, 0x03 }, { 0x2840, 0xFF }, - { 0x2841, 0x7F }, { 0x2842, 0xFF }, { 0x2843, 0x7F }, { 0x2844, 0xFF }, - { 0x2845, 0x7F }, { 0x2846, 0xFF }, { 0x2847, 0x7F }, { 0x2848, 0xFF }, - { 0x2849, 0x7F }, { 0x284A, 0xFF }, { 0x284B, 0x7F }, { 0x284C, 0xFF }, - { 0x284D, 0x7F }, { 0x284E, 0xFF }, { 0x284F, 0x7F }, { 0x2850, 0xFF }, - { 0x2851, 0x7F }, { 0x2852, 0xFF }, { 0x2853, 0x7F }, { 0x2854, 0xFF }, - { 0x2855, 0x7F }, { 0x2856, 0xFF }, { 0x2857, 0x7F }, { 0x2858, 0xFF }, - { 0x2859, 0x7F }, { 0x285A, 0xFF }, { 0x285B, 0x7F }, { 0x285C, 0xFF }, - { 0x285D, 0x7F }, { 0x285E, 0xFF }, { 0x285F, 0x7F }, { 0x2860, 0xFF }, - { 0x2861, 0x7F }, { 0x2862, 0xFF }, { 0x2863, 0x7F }, { 0x2864, 0xFF }, - { 0x2865, 0x7F }, { 0x2866, 0xFF }, { 0x2867, 0x7F }, { 0x2868, 0xFF }, - { 0x2869, 0x7F }, { 0x286A, 0xFF }, { 0x286B, 0x7F }, { 0x286C, 0xFF }, - { 0x286D, 0x7F }, { 0x286E, 0xFF }, { 0x286F, 0x7F }, { 0x2870, 0xFF }, - { 0x2871, 0x7F }, { 0x2872, 0xFF }, { 0x2873, 0x7F }, { 0x2874, 0xFF }, - { 0x2875, 0x7F }, { 0x2876, 0xFF }, { 0x2877, 0x7F }, { 0x2878, 0xFF }, - { 0x2879, 0x7F }, { 0x287A, 0xFF }, { 0x287B, 0x7F }, { 0x287C, 0xFF }, - { 0x287D, 0x7F }, { 0x287E, 0xFF }, { 0x287F, 0x7F }, { 0x2900, 0x80 }, - { 0x2901, 0x80 }, { 0x2902, 0x40 }, { 0x2903, 0x88 }, { 0x2904, 0x88 }, - { 0x2905, 0x68 }, { 0x2906, 0xDE }, { 0x2907, 0xDE }, { 0x2908, 0x70 }, - { 0x2909, 0xDE }, { 0x290A, 0xDE }, { 0x290B, 0x78 }, { 0x290C, 0x20 }, - { 0x290D, 0x20 }, { 0x290E, 0x38 }, { 0x290F, 0x20 }, { 0x2910, 0x20 }, - { 0x2911, 0x90 }, { 0x2912, 0x20 }, { 0x2913, 0x20 }, { 0x2914, 0xA0 }, - { 0x2915, 0xE0 }, { 0x2916, 0xE0 }, { 0x2917, 0xC0 }, { 0x2918, 0x98 }, - { 0x2919, 0x98 }, { 0x291A, 0x48 }, { 0x291B, 0x80 }, { 0x291C, 0x80 }, - { 0x291D, 0x50 }, { 0x291E, 0x1E }, { 0x291F, 0x1E }, { 0x2920, 0x58 }, - { 0x2921, 0x20 }, { 0x2922, 0x20 }, { 0x2923, 0xE0 }, { 0x2924, 0x88 }, - { 0x2925, 0x88 }, { 0x2926, 0x10 }, { 0x2927, 0x20 }, { 0x2928, 0x20 }, - { 0x2929, 0x10 }, { 0x292A, 0x20 }, { 0x292B, 0x20 }, { 0x292C, 0x18 }, - { 0x292D, 0xE0 }, { 0x292E, 0xE0 }, { 0x2930, 0x18 }, { 0x2931, 0x18 }, - { 0x2932, 0x20 }, { 0x2933, 0xA8 }, { 0x2934, 0xA8 }, { 0x2935, 0x20 }, - { 0x2936, 0x18 }, { 0x2937, 0x18 }, { 0x2939, 0x20 }, { 0x293A, 0x20 }, - { 0x293B, 0xD8 }, { 0x293C, 0xC8 }, { 0x293D, 0xC8 }, { 0x293E, 0xE0 }, - { 0x2941, 0x40 }, { 0x2942, 0x28 }, { 0x2943, 0x28 }, { 0x2944, 0x28 }, - { 0x2945, 0x18 }, { 0x2946, 0x18 }, { 0x2947, 0x60 }, { 0x2948, 0x20 }, - { 0x2949, 0x20 }, { 0x294A, 0xE0 }, { 0x294D, 0x08 }, { 0x294E, 0xE0 }, - { 0x294F, 0xE0 }, { 0x2950, 0x30 }, { 0x2951, 0xD0 }, { 0x2952, 0xD0 }, - { 0x2953, 0xD0 }, { 0x2954, 0x20 }, { 0x2955, 0x20 }, { 0x2956, 0xE8 }, - { 0x2957, 0xFF }, { 0x2958, 0xFF }, { 0x2959, 0xBF }, { 0x2A00, 0xFF }, - { 0x2A01, 0x7F }, { 0x2A02, 0xDF }, { 0x2A03, 0x01 }, { 0x2A04, 0x12 }, - { 0x2A05, 0x01 }, { 0x2A08, 0xFF }, { 0x2A09, 0x7F }, { 0x2A0A, 0xDF }, - { 0x2A0B, 0x01 }, { 0x2A0C, 0x12 }, { 0x2A0D, 0x01 }, { 0x2A10, 0xFF }, - { 0x2A11, 0x7F }, { 0x2A12, 0xB5 }, { 0x2A13, 0x42 }, { 0x2A14, 0xC8 }, - { 0x2A15, 0x3D }, { 0x2A18, 0x1F }, { 0x2A19, 0x23 }, { 0x2A1A, 0x5F }, - { 0x2A1B, 0x03 }, { 0x2A1C, 0xF2 }, { 0x2A1E, 0x09 }, { 0x2A20, 0x1F }, - { 0x2A21, 0x23 }, { 0x2A22, 0x5F }, { 0x2A23, 0x03 }, { 0x2A24, 0xF2 }, - { 0x2A26, 0x09 }, { 0x2A28, 0xFF }, { 0x2A29, 0x4F }, { 0x2A2A, 0xD2 }, - { 0x2A2B, 0x7E }, { 0x2A2C, 0x4C }, { 0x2A2D, 0x3A }, { 0x2A2E, 0xE0 }, - { 0x2A2F, 0x1C }, { 0x2A30, 0xFF }, { 0x2A31, 0x7F }, { 0x2A32, 0xFF }, - { 0x2A33, 0x7F }, { 0x2A34, 0x8C }, { 0x2A35, 0x7E }, { 0x2A37, 0x7C }, - { 0x2A38, 0xFF }, { 0x2A39, 0x7F }, { 0x2A3A, 0xFF }, { 0x2A3B, 0x7F }, - { 0x2A3C, 0x8C }, { 0x2A3D, 0x7E }, { 0x2A3F, 0x7C }, { 0x2A40, 0xED }, - { 0x2A41, 0x03 }, { 0x2A42, 0xFF }, { 0x2A43, 0x7F }, { 0x2A44, 0x5F }, - { 0x2A45, 0x25 }, { 0x2A48, 0xFF }, { 0x2A49, 0x7F }, { 0x2A4A, 0xFF }, - { 0x2A4B, 0x7F }, { 0x2A4C, 0x8C }, { 0x2A4D, 0x7E }, { 0x2A4F, 0x7C }, - { 0x2A50, 0xFF }, { 0x2A51, 0x7F }, { 0x2A52, 0xFF }, { 0x2A53, 0x7F }, - { 0x2A54, 0x8C }, { 0x2A55, 0x7E }, { 0x2A57, 0x7C }, { 0x2A58, 0x6A }, - { 0x2A59, 0x03 }, { 0x2A5A, 0x1F }, { 0x2A5B, 0x02 }, { 0x2A5C, 0xFF }, - { 0x2A5D, 0x03 }, { 0x2A5E, 0xFF }, { 0x2A5F, 0x7F }, { 0x2A60, 0xFF }, - { 0x2A61, 0x7F }, { 0x2A62, 0x1F }, { 0x2A63, 0x42 }, { 0x2A64, 0xF2 }, - { 0x2A65, 0x1C }, { 0x2A68, 0xFF }, { 0x2A69, 0x7F }, { 0x2A6A, 0x1F }, - { 0x2A6B, 0x42 }, { 0x2A6C, 0xF2 }, { 0x2A6D, 0x1C }, { 0x2A70, 0xFF }, - { 0x2A71, 0x7F }, { 0x2A72, 0xEF }, { 0x2A73, 0x03 }, { 0x2A74, 0xD6 }, - { 0x2A75, 0x01 }, { 0x2A78, 0xFF }, { 0x2A79, 0x7F }, { 0x2A7A, 0x1F }, - { 0x2A7B, 0x42 }, { 0x2A7C, 0xF2 }, { 0x2A7D, 0x1C }, { 0x2A80, 0xFF }, - { 0x2A81, 0x7F }, { 0x2A82, 0x1F }, { 0x2A83, 0x42 }, { 0x2A84, 0xF2 }, - { 0x2A85, 0x1C }, { 0x2A88, 0xFF }, { 0x2A89, 0x7F }, { 0x2A8A, 0xEA }, - { 0x2A8B, 0x03 }, { 0x2A8C, 0x1F }, { 0x2A8D, 0x01 }, { 0x2A90, 0xFF }, - { 0x2A91, 0x7F }, { 0x2A92, 0x1F }, { 0x2A93, 0x42 }, { 0x2A94, 0xF2 }, - { 0x2A95, 0x1C }, { 0x2A98, 0xFF }, { 0x2A99, 0x7F }, { 0x2A9A, 0x1F }, - { 0x2A9B, 0x42 }, { 0x2A9C, 0xF2 }, { 0x2A9D, 0x1C }, { 0x2AA0, 0xFF }, - { 0x2AA1, 0x7F }, { 0x2AA2, 0x7F }, { 0x2AA3, 0x02 }, { 0x2AA4, 0x1F }, - { 0x2AA8, 0xFF }, { 0x2AA9, 0x7F }, { 0x2AAA, 0x8C }, { 0x2AAB, 0x7E }, - { 0x2AAD, 0x7C }, { 0x2AB0, 0xFF }, { 0x2AB1, 0x7F }, { 0x2AB2, 0x8C }, - { 0x2AB3, 0x7E }, { 0x2AB5, 0x7C }, { 0x2AB8, 0xFF }, { 0x2AB9, 0x7F }, - { 0x2ABA, 0xFF }, { 0x2ABB, 0x03 }, { 0x2ABC, 0x1F }, { 0x2AC0, 0x9F }, - { 0x2AC1, 0x29 }, { 0x2AC2, 0x1A }, { 0x2AC4, 0x0C }, { 0x2AC8, 0x9F }, - { 0x2AC9, 0x29 }, { 0x2ACA, 0x1A }, { 0x2ACC, 0x0C }, { 0x2AD0, 0x74 }, - { 0x2AD1, 0x7E }, { 0x2AD2, 0xFF }, { 0x2AD3, 0x03 }, { 0x2AD4, 0x80 }, - { 0x2AD5, 0x01 }, { 0x2AD8, 0xFF }, { 0x2AD9, 0x7F }, { 0x2ADA, 0xDF }, - { 0x2ADB, 0x01 }, { 0x2ADC, 0x12 }, { 0x2ADD, 0x01 }, { 0x2AE0, 0xFF }, - { 0x2AE1, 0x7F }, { 0x2AE2, 0xDF }, { 0x2AE3, 0x01 }, { 0x2AE4, 0x12 }, - { 0x2AE5, 0x01 }, { 0x2AE8, 0xFF }, { 0x2AE9, 0x67 }, { 0x2AEA, 0xAC }, - { 0x2AEB, 0x77 }, { 0x2AEC, 0x13 }, { 0x2AED, 0x1A }, { 0x2AEE, 0x6B }, - { 0x2AEF, 0x2D }, { 0x2AF2, 0xFF }, { 0x2AF3, 0x7F }, { 0x2AF4, 0x1F }, - { 0x2AF5, 0x42 }, { 0x2AF6, 0xF2 }, { 0x2AF7, 0x1C }, { 0x2AFA, 0xFF }, - { 0x2AFB, 0x7F }, { 0x2AFC, 0x1F }, { 0x2AFD, 0x42 }, { 0x2AFE, 0xF2 }, - { 0x2AFF, 0x1C }, { 0x2B00, 0xD6 }, { 0x2B01, 0x7E }, { 0x2B02, 0xFF }, - { 0x2B03, 0x4B }, { 0x2B04, 0x75 }, { 0x2B05, 0x21 }, { 0x2B08, 0xFF }, - { 0x2B09, 0x7F }, { 0x2B0A, 0x1F }, { 0x2B0B, 0x42 }, { 0x2B0C, 0xF2 }, - { 0x2B0D, 0x1C }, { 0x2B10, 0xFF }, { 0x2B11, 0x7F }, { 0x2B12, 0x1F }, - { 0x2B13, 0x42 }, { 0x2B14, 0xF2 }, { 0x2B15, 0x1C }, { 0x2B18, 0xFF }, - { 0x2B19, 0x7F }, { 0x2B1A, 0x8C }, { 0x2B1B, 0x7E }, { 0x2B1D, 0x7C }, - { 0x2B20, 0x1F }, { 0x2B21, 0x23 }, { 0x2B22, 0x5F }, { 0x2B23, 0x03 }, - { 0x2B24, 0xF2 }, { 0x2B26, 0x09 }, { 0x2B28, 0x1F }, { 0x2B29, 0x23 }, - { 0x2B2A, 0x5F }, { 0x2B2B, 0x03 }, { 0x2B2C, 0xF2 }, { 0x2B2E, 0x09 }, - { 0x2B30, 0xFF }, { 0x2B31, 0x7F }, { 0x2B32, 0x31 }, { 0x2B33, 0x6E }, - { 0x2B34, 0x4A }, { 0x2B35, 0x45 }, { 0x2B38, 0xFF }, { 0x2B39, 0x7F }, - { 0x2B3A, 0x1F }, { 0x2B3B, 0x42 }, { 0x2B3C, 0xF2 }, { 0x2B3D, 0x1C }, - { 0x2B40, 0xFF }, { 0x2B41, 0x7F }, { 0x2B42, 0x1F }, { 0x2B43, 0x42 }, - { 0x2B44, 0xF2 }, { 0x2B45, 0x1C }, { 0x2B48, 0xFF }, { 0x2B49, 0x7F }, - { 0x2B4A, 0x31 }, { 0x2B4B, 0x6E }, { 0x2B4C, 0x4A }, { 0x2B4D, 0x45 }, - { 0x2B50, 0xFF }, { 0x2B51, 0x7F }, { 0x2B52, 0x1F }, { 0x2B53, 0x42 }, - { 0x2B54, 0xF2 }, { 0x2B55, 0x1C }, { 0x2B58, 0xFF }, { 0x2B59, 0x7F }, - { 0x2B5A, 0x1F }, { 0x2B5B, 0x42 }, { 0x2B5C, 0xF2 }, { 0x2B5D, 0x1C }, - { 0x2B60, 0xFF }, { 0x2B61, 0x7F }, { 0x2B62, 0xEF }, { 0x2B63, 0x1B }, - { 0x2B65, 0x02 }, { 0x2B68, 0xFF }, { 0x2B69, 0x7F }, { 0x2B6A, 0x8C }, - { 0x2B6B, 0x7E }, { 0x2B6D, 0x7C }, { 0x2B70, 0xFF }, { 0x2B71, 0x7F }, - { 0x2B72, 0x8C }, { 0x2B73, 0x7E }, { 0x2B75, 0x7C }, { 0x2B78, 0xFF }, - { 0x2B79, 0x7F }, { 0x2B7A, 0xBF }, { 0x2B7B, 0x32 }, { 0x2B7C, 0xD0 }, - { 0x2B80, 0xFF }, { 0x2B81, 0x7F }, { 0x2B82, 0xEF }, { 0x2B83, 0x1B }, - { 0x2B85, 0x02 }, { 0x2B88, 0xFF }, { 0x2B89, 0x7F }, { 0x2B8A, 0xEF }, - { 0x2B8B, 0x1B }, { 0x2B8D, 0x02 }, { 0x2B90, 0xFF }, { 0x2B91, 0x7F }, - { 0x2B92, 0x1F }, { 0x2B93, 0x42 }, { 0x2B94, 0xF2 }, { 0x2B95, 0x1C }, - { 0x2B98, 0xFF }, { 0x2B99, 0x7F }, { 0x2B9A, 0xE0 }, { 0x2B9B, 0x03 }, - { 0x2B9C, 0x06 }, { 0x2B9D, 0x02 }, { 0x2B9E, 0x20 }, { 0x2B9F, 0x01 }, - { 0x2BA0, 0xFF }, { 0x2BA1, 0x7F }, { 0x2BA2, 0xE0 }, { 0x2BA3, 0x03 }, - { 0x2BA4, 0x06 }, { 0x2BA5, 0x02 }, { 0x2BA6, 0x20 }, { 0x2BA7, 0x01 }, - { 0x2BA8, 0xFF }, { 0x2BA9, 0x7F }, { 0x2BAA, 0x1F }, { 0x2BAB, 0x42 }, - { 0x2BAC, 0xF2 }, { 0x2BAD, 0x1C }, { 0x2BB0, 0xFF }, { 0x2BB1, 0x7F }, - { 0x2BB2, 0xEF }, { 0x2BB3, 0x1B }, { 0x2BB5, 0x02 }, { 0x2BB8, 0xFF }, - { 0x2BB9, 0x7F }, { 0x2BBA, 0xEF }, { 0x2BBB, 0x1B }, { 0x2BBD, 0x02 }, - { 0x2BC0, 0xFF }, { 0x2BC1, 0x7F }, { 0x2BC2, 0xBF }, { 0x2BC3, 0x32 }, - { 0x2BC4, 0xD0 }, { 0x2BC8, 0xFF }, { 0x2BC9, 0x7F }, { 0x2BCA, 0x1F }, - { 0x2BCB, 0x42 }, { 0x2BCC, 0xF2 }, { 0x2BCD, 0x1C }, { 0x2BD0, 0xFF }, - { 0x2BD1, 0x7F }, { 0x2BD2, 0x1F }, { 0x2BD3, 0x42 }, { 0x2BD4, 0xF2 }, - { 0x2BD5, 0x1C }, { 0x2BDB, 0x42 }, { 0x2BDC, 0x7F }, { 0x2BDD, 0x03 }, - { 0x2BDE, 0xFF }, { 0x2BDF, 0x7F }, { 0x2BE0, 0xFF }, { 0x2BE1, 0x03 }, - { 0x2BE2, 0x1F }, { 0x2BE4, 0x0C }, { 0x2BE8, 0xFF }, { 0x2BE9, 0x03 }, - { 0x2BEA, 0x1F }, { 0x2BEC, 0x0C }, { 0x2BF0, 0xFF }, { 0x2BF1, 0x7F }, - { 0x2BF2, 0x8C }, { 0x2BF3, 0x7E }, { 0x2BF5, 0x7C }, { 0x2BF8, 0xFF }, - { 0x2BF9, 0x7F }, { 0x2BFA, 0xBF }, { 0x2BFB, 0x32 }, { 0x2BFC, 0xD0 }, - { 0x2C00, 0xFF }, { 0x2C01, 0x7F }, { 0x2C02, 0xBF }, { 0x2C03, 0x32 }, - { 0x2C04, 0xD0 }, { 0x2C08, 0xFF }, { 0x2C09, 0x7F }, { 0x2C0A, 0xB5 }, - { 0x2C0B, 0x42 }, { 0x2C0C, 0xC8 }, { 0x2C0D, 0x3D }, { 0x2C10, 0xFF }, - { 0x2C11, 0x7F }, { 0x2C12, 0x94 }, { 0x2C13, 0x52 }, { 0x2C14, 0x4A }, - { 0x2C15, 0x29 }, { 0x2C18, 0xFF }, { 0x2C19, 0x7F }, { 0x2C1A, 0x94 }, - { 0x2C1B, 0x52 }, { 0x2C1C, 0x4A }, { 0x2C1D, 0x29 }, { 0x2C20, 0xFF }, - { 0x2C21, 0x7F }, { 0x2C22, 0x94 }, { 0x2C23, 0x52 }, { 0x2C24, 0x4A }, - { 0x2C25, 0x29 }, { 0x2C28, 0xFF }, { 0x2C29, 0x7F }, { 0x2C2A, 0xEF }, - { 0x2C2B, 0x1B }, { 0x2C2D, 0x02 }, { 0x2C30, 0xFF }, { 0x2C31, 0x7F }, - { 0x2C32, 0xEF }, { 0x2C33, 0x1B }, { 0x2C35, 0x02 }, { 0x2C38, 0xFF }, - { 0x2C39, 0x53 }, { 0x2C3A, 0x5F }, { 0x2C3B, 0x4A }, { 0x2C3C, 0x52 }, - { 0x2C3D, 0x7E }, { 0x2C40, 0xFF }, { 0x2C41, 0x7F }, { 0x2C42, 0x1F }, - { 0x2C43, 0x42 }, { 0x2C44, 0xF2 }, { 0x2C45, 0x1C }, { 0x2C48, 0xFF }, - { 0x2C49, 0x7F }, { 0x2C4A, 0x1F }, { 0x2C4B, 0x42 }, { 0x2C4C, 0xF2 }, - { 0x2C4D, 0x1C }, { 0x2C50, 0xFF }, { 0x2C51, 0x7F }, { 0x2C52, 0x8C }, - { 0x2C53, 0x7E }, { 0x2C55, 0x7C }, { 0x2C58, 0xFF }, { 0x2C59, 0x7F }, - { 0x2C5A, 0xBF }, { 0x2C5B, 0x32 }, { 0x2C5C, 0xD0 }, { 0x2C60, 0xFF }, - { 0x2C61, 0x7F }, { 0x2C62, 0xBF }, { 0x2C63, 0x32 }, { 0x2C64, 0xD0 }, - { 0x2C68, 0x9F }, { 0x2C69, 0x63 }, { 0x2C6A, 0x79 }, { 0x2C6B, 0x42 }, - { 0x2C6C, 0xB0 }, { 0x2C6D, 0x15 }, { 0x2C6E, 0xCB }, { 0x2C6F, 0x04 }, - { 0x2C70, 0xFF }, { 0x2C71, 0x7F }, { 0x2C72, 0x8C }, { 0x2C73, 0x7E }, - { 0x2C75, 0x7C }, { 0x2C78, 0xFF }, { 0x2C79, 0x7F }, { 0x2C7A, 0x8C }, - { 0x2C7B, 0x7E }, { 0x2C7D, 0x7C }, { 0x2C80, 0xFF }, { 0x2C81, 0x7F }, - { 0x2C82, 0xFF }, { 0x2C83, 0x03 }, { 0x2C84, 0x2F }, { 0x2C85, 0x01 }, - { 0x2C88, 0xFF }, { 0x2C89, 0x7F }, { 0x2C8A, 0x3F }, { 0x2C8B, 0x03 }, - { 0x2C8C, 0x93 }, { 0x2C8D, 0x01 }, { 0x2C90, 0xFF }, { 0x2C91, 0x7F }, - { 0x2C92, 0x3F }, { 0x2C93, 0x03 }, { 0x2C94, 0x93 }, { 0x2C95, 0x01 }, - { 0x2C98, 0xFF }, { 0x2C99, 0x7F }, { 0x2C9A, 0x3F }, { 0x2C9B, 0x03 }, - { 0x2C9C, 0x93 }, { 0x2C9D, 0x01 }, { 0x2CA0, 0xFF }, { 0x2CA1, 0x7F }, - { 0x2CA2, 0x1F }, { 0x2CA3, 0x42 }, { 0x2CA4, 0xF2 }, { 0x2CA5, 0x1C }, - { 0x2CA8, 0xFF }, { 0x2CA9, 0x7F }, { 0x2CAA, 0x1F }, { 0x2CAB, 0x42 }, - { 0x2CAC, 0xF2 }, { 0x2CAD, 0x1C }, { 0x2CB0, 0xFF }, { 0x2CB1, 0x7F }, - { 0x2CB2, 0xEF }, { 0x2CB3, 0x1B }, { 0x2CB4, 0x80 }, { 0x2CB5, 0x61 }, - { 0x2CB8, 0x20 }, { 0x2CB9, 0x21 }, { 0x2CBA, 0x22 }, { 0x2CBB, 0x80 }, - { 0x2CBC, 0x81 }, { 0x2CBD, 0x82 }, { 0x2CBE, 0x10 }, { 0x2CBF, 0x11 }, - { 0x2CC0, 0x20 }, { 0x2CC1, 0x21 }, { 0x2CC2, 0x22 }, { 0x2CC3, 0x80 }, - { 0x2CC4, 0x81 }, { 0x2CC5, 0x82 }, { 0x2CC6, 0x10 }, { 0x2CC7, 0x11 }, - { 0x2CC9, 0xFF }, { 0x2CCA, 0x7F }, { 0x2CCB, 0xFF }, { 0x2CCC, 0x03 }, - { 0x2CCD, 0x1F }, { 0x2CD0, 0xFF }, { 0x2CD1, 0x7F }, { 0x2CD2, 0xBF }, - { 0x2CD3, 0x32 }, { 0x2CD4, 0xD0 }, { 0x2CD8, 0xFF }, { 0x2CD9, 0x7F }, - { 0x2CDA, 0xBF }, { 0x2CDB, 0x32 }, { 0x2CDC, 0xD0 }, { 0x2CE0, 0xFF }, - { 0x2CE1, 0x7F }, { 0x2CE2, 0xBF }, { 0x2CE3, 0x32 }, { 0x2CE4, 0xD0 }, - { 0x2CE8, 0xFF }, { 0x2CE9, 0x7F }, { 0x2CEA, 0xBF }, { 0x2CEB, 0x32 }, - { 0x2CEC, 0xD0 }, { 0x2CF0, 0xFF }, { 0x2CF1, 0x7F }, { 0x2CF2, 0xBF }, - { 0x2CF3, 0x32 }, { 0x2CF4, 0xD0 }, { 0x2CF8, 0xFF }, { 0x2CF9, 0x7F }, - { 0x2CFA, 0xBF }, { 0x2CFB, 0x32 }, { 0x2CFC, 0xD0 }, { 0x307F, 0x40 }, - { 0x30E9, 0x02 }, { 0x30F4, 0xBF }, { 0x3107, 0xF7 }, { 0x3180, 0x3F }, - { 0x31BB, 0x10 }, { 0x31F4, 0xDF }, { 0x3212, 0x7F }, { 0x3225, 0x7F }, - { 0x326A, 0x01 }, { 0x32B0, 0x7F }, { 0x32B5, 0xF7 }, { 0x32F0, 0xFD }, - { 0x32F6, 0x7F }, { 0x3300, 0x7F }, { 0x3311, 0xF7 }, { 0x3331, 0xDF }, - { 0x3354, 0xF7 }, { 0x3397, 0xBF }, { 0x33BC, 0x04 }, { 0x3437, 0xDF }, - { 0x34D1, 0x7F }, { 0x34E1, 0xDF }, { 0x3510, 0xBF }, { 0x3547, 0x7F }, - { 0x3573, 0xF7 }, { 0x3586, 0xDF }, { 0x35A5, 0xBF }, { 0x35B0, 0xF7 }, - { 0x35D7, 0xF7 }, { 0x3601, 0xDF }, { 0x3607, 0xBD }, { 0x3634, 0xF7 }, - { 0x3690, 0xF7 }, { 0x369A, 0x04 }, { 0x36C8, 0x10 }, { 0x36D2, 0xF7 }, - { 0x36E3, 0xBF }, { 0x3705, 0xFD }, { 0x371C, 0x40 }, { 0x371D, 0x01 }, - { 0x371F, 0x04 }, { 0x372E, 0x40 }, { 0x3731, 0xDF }, { 0x3768, 0x01 }, - { 0x3780, 0xBF }, { 0x37A7, 0x7F }, { 0x37CD, 0x01 }, { 0x37F6, 0xF7 }, - { 0x3808, 0x7F }, { 0x380C, 0xBF }, { 0x3834, 0x02 }, { 0x383A, 0xBF }, - { 0x384D, 0xBF }, { 0x385A, 0x7F }, { 0x385D, 0x7F }, { 0x386B, 0xBF }, - { 0x387B, 0xFB }, { 0x387C, 0xFD }, { 0x3889, 0xBF }, { 0x388A, 0x7F }, - { 0x38A8, 0xF7 }, { 0x38AA, 0x7F }, { 0x38AE, 0xBF }, { 0x38BC, 0x7F }, - { 0x38EC, 0xDF }, { 0x38FB, 0xF7 }, { 0x38FC, 0xFD }, { 0x390B, 0xBF }, - { 0x392B, 0x7F }, { 0x392D, 0xBF }, { 0x393D, 0xFB }, { 0x3958, 0xFD }, - { 0x395F, 0xF7 }, { 0x396F, 0x7F }, { 0x3979, 0xDF }, { 0x397F, 0x7F }, - { 0x3989, 0xF3 }, { 0x398F, 0x7F }, { 0x3998, 0xBF }, { 0x399E, 0xF7 }, - { 0x399F, 0xFB }, { 0x39AC, 0xF7 }, { 0x39AD, 0xDF }, { 0x39AE, 0xF7 }, - { 0x39AF, 0xF7 }, { 0x39BA, 0xF7 }, { 0x39BB, 0xF7 }, { 0x39BE, 0xFB }, - { 0x39BF, 0x7F }, { 0x39C8, 0xFB }, { 0x39CC, 0xF7 }, { 0x39D9, 0x7F }, - { 0x39DE, 0x7F }, { 0x39DF, 0x7F }, { 0x39EA, 0xF7 }, { 0x39FD, 0xBF }, - { 0x39FE, 0xF7 }, { 0x3A09, 0x7F }, { 0x3A18, 0xBF }, { 0x3A1B, 0xBF }, - { 0x3A1D, 0xF7 }, { 0x3A2B, 0xBF }, { 0x3A2C, 0xF7 }, { 0x3A2F, 0x7F }, - { 0x3A3E, 0xDF }, { 0x3A4E, 0x7F }, { 0x3A4F, 0x7F }, { 0x3A5D, 0x7F }, - { 0x3A6D, 0xDF }, { 0x3A6E, 0xDF }, { 0x3A8B, 0xF7 }, { 0x3A99, 0xBF }, - { 0x3A9D, 0x7F }, { 0x3A9E, 0xF7 }, { 0x3AAB, 0xF7 }, { 0x3AAC, 0xDF }, - { 0x3AAE, 0xF7 }, { 0x3ACD, 0xD7 }, { 0x3ACE, 0xF7 }, { 0x3AD8, 0x7F }, - { 0x3AE9, 0xFD }, { 0x3AEB, 0x3F }, { 0x3AFB, 0xF7 }, { 0x3B1C, 0xF5 }, - { 0x3B2B, 0xF7 }, { 0x3B2C, 0x9F }, { 0x3B2D, 0xBF }, { 0x3B3C, 0xDB }, - { 0x3B3D, 0xF7 }, { 0x3B3E, 0x7F }, { 0x3B3F, 0xFB }, { 0x3B48, 0xFB }, - { 0x3B4B, 0x7F }, { 0x3B4C, 0xF7 }, { 0x3B5A, 0x7F }, { 0x3B6A, 0x7F }, - { 0x3B6B, 0xBF }, { 0x3B7B, 0xFB }, { 0x3B7D, 0x7F }, { 0x3B7F, 0xBF }, - { 0x3B8D, 0xFB }, { 0x3B8F, 0x5F }, { 0x3B98, 0x7F }, { 0x3B9A, 0x7F }, - { 0x3B9E, 0xFD }, { 0x3BAB, 0xFD }, { 0x3BAC, 0xDF }, { 0x3BAF, 0xF7 }, - { 0x3BB2, 0x02 }, { 0x3BBB, 0x7F }, { 0x3BCE, 0xFD }, { 0x3BDB, 0xBF }, - { 0x3C18, 0x7F }, { 0x3C1F, 0x7F }, { 0x3C2B, 0xF7 }, { 0x3C39, 0xFD }, - { 0x3C4A, 0x77 }, { 0x3C4C, 0x7F }, { 0x3C59, 0xBF }, { 0x3C5F, 0xFB }, - { 0x3C68, 0x7F }, { 0x3C69, 0xDF }, { 0x3C6A, 0xBB }, { 0x3C6F, 0x7F }, - { 0x3C79, 0xF7 }, { 0x3C8B, 0xDF }, { 0x3C9A, 0x5F }, { 0x3CA9, 0x7F }, - { 0x3CAF, 0xBF }, { 0x3CB8, 0xBF }, { 0x3CB9, 0x7F }, { 0x3CBA, 0x7F }, - { 0x3CBB, 0x7F }, { 0x3CBC, 0xBF }, { 0x3CBF, 0xDD }, { 0x3CC8, 0xDF }, - { 0x3CCF, 0x7F }, { 0x3CDD, 0xF7 }, { 0x3CDE, 0x77 }, { 0x3CE8, 0xF7 }, - { 0x3CEB, 0xDF }, { 0x3CEF, 0xFB }, { 0x3CF0, 0x01 }, { 0x3CF9, 0x7F }, - { 0x3CFB, 0xF7 }, { 0x3D19, 0xF7 }, { 0x3D2A, 0xFB }, { 0x3D2F, 0x7F }, - { 0x3D3B, 0xDD }, { 0x3D3F, 0xFB }, { 0x3D48, 0xBF }, { 0x3D5B, 0xF7 }, - { 0x3D6F, 0xBF }, { 0x3D7D, 0xFB }, { 0x3D8A, 0x7F }, { 0x3D8C, 0xFB }, - { 0x3D96, 0x40 }, { 0x3D9F, 0x7F }, { 0x3DAA, 0xF7 }, { 0x3DAD, 0xF7 }, - { 0x3DAF, 0x77 }, { 0x3DB8, 0x7F }, { 0x3DBC, 0xBF }, { 0x3DBD, 0xDF }, - { 0x3DC9, 0xF7 }, { 0x3DEF, 0xDF }, { 0x3DFA, 0xDF }, { 0x3DFD, 0xFD }, - { 0x3DFE, 0xFB }, { 0x3E18, 0xFB }, { 0x3E1F, 0xF7 }, { 0x3E2D, 0xDF }, - { 0x3E2F, 0xFB }, { 0x3E3D, 0x7F }, { 0x3E3F, 0xFB }, { 0x3E48, 0xF5 }, - { 0x3E49, 0xFD }, { 0x3E5C, 0xFB }, { 0x3E5F, 0x5F }, { 0x3E6D, 0xBF }, - { 0x3E6F, 0x7F }, { 0x3E7C, 0xFD }, { 0x3E7E, 0x7F }, { 0x3E88, 0xFD }, - { 0x3E9E, 0xFD }, { 0x3EAE, 0x7F }, { 0x3EBC, 0xDF }, { 0x3ECD, 0x77 }, - { 0x3EED, 0xF7 }, { 0x3EFB, 0x7F }, { 0x3F08, 0xF7 }, { 0x3F0F, 0xFD }, - { 0x3F1D, 0xBF }, { 0x3F1E, 0x9F }, { 0x3F29, 0xFB }, { 0x3F2E, 0x7F }, - { 0x3F39, 0xDF }, { 0x3F3F, 0xDF }, { 0x3F48, 0xDF }, { 0x3F4E, 0xFB }, - { 0x3F69, 0xFD }, { 0x3F7C, 0xFD }, { 0x3F7E, 0x3F }, { 0x3F89, 0xF7 }, - { 0x3F9B, 0xF7 }, { 0x3F9E, 0xF7 }, { 0x3FAE, 0x7F }, { 0x3FB2, 0xDF }, - { 0x3FBC, 0xF7 }, { 0x3FD9, 0xBD }, { 0x3FDB, 0xD7 }, { 0x3FDE, 0x7F }, - { 0x3FEE, 0x7F }, { 0x3FEF, 0x7F }, { 0x3FFE, 0x7B }, { 0x4045, 0x7F }, - { 0x408C, 0x20 }, { 0x40A7, 0xFD }, { 0x40B3, 0xD7 }, { 0x40D1, 0x7F }, - { 0x40E0, 0x77 }, { 0x40FE, 0x40 }, { 0x4103, 0x7F }, { 0x4130, 0xBF }, - { 0x413D, 0x10 }, { 0x4152, 0xF7 }, { 0x4159, 0x01 }, { 0x417D, 0x02 }, - { 0x41A5, 0xDF }, { 0x41A7, 0x7F }, { 0x4218, 0x40 }, { 0x421F, 0x02 }, - { 0x4222, 0xF7 }, { 0x4286, 0xF7 }, { 0x42E3, 0x9F }, { 0x4303, 0xFB }, - { 0x434E, 0x04 }, { 0x43BA, 0x01 }, { 0x4408, 0x01 }, { 0x4413, 0xF7 }, - { 0x442E, 0x20 }, { 0x443B, 0x01 }, { 0x44C7, 0x7F }, { 0x44E0, 0x7F }, - { 0x44E7, 0xF7 }, { 0x4523, 0xF7 }, { 0x4534, 0x7F }, { 0x4546, 0x7F }, - { 0x4579, 0x10 }, { 0x458A, 0x01 }, { 0x4594, 0xFB }, { 0x459A, 0x02 }, - { 0x45B4, 0xF7 }, { 0x45B6, 0xFD }, { 0x45C5, 0x7F }, { 0x45D5, 0x7F }, - { 0x45F0, 0xF7 }, { 0x4613, 0xFB }, { 0x4638, 0x01 }, { 0x4678, 0x01 }, - { 0x4694, 0xBF }, { 0x46A0, 0xF7 }, { 0x46CE, 0x01 }, { 0x46D6, 0xBF }, - { 0x46F4, 0xF7 }, { 0x46F5, 0xDF }, { 0x4710, 0x7F }, { 0x4727, 0x7F }, - { 0x472B, 0x04 }, { 0x4730, 0xBF }, { 0x4736, 0x7F }, { 0x4762, 0xF7 }, - { 0x476C, 0x04 }, { 0x477B, 0x04 }, { 0x47D5, 0xFB }, { 0x47E4, 0xBF }, - { 0x47F0, 0xDF }, { 0x4809, 0x7F }, { 0x480D, 0x7F }, { 0x481E, 0xDF }, - { 0x4828, 0x7F }, { 0x482E, 0xFD }, { 0x4838, 0xFD }, { 0x483D, 0x7F }, - { 0x483F, 0xFB }, { 0x484B, 0xFD }, { 0x484D, 0x7F }, { 0x485E, 0xFD }, - { 0x486F, 0xBF }, { 0x4878, 0xDF }, { 0x4888, 0xFB }, { 0x4889, 0xF7 }, - { 0x488D, 0x7F }, { 0x48A9, 0x7F }, { 0x48AC, 0xDF }, { 0x48AE, 0x7F }, - { 0x48B4, 0x01 }, { 0x48BC, 0xF7 }, { 0x48BD, 0xBB }, { 0x48BE, 0xF7 }, - { 0x48C8, 0xFB }, { 0x48CB, 0xDF }, { 0x48CC, 0x7F }, { 0x48ED, 0xFB }, - { 0x48EE, 0x7F }, { 0x48F0, 0x10 }, { 0x490B, 0xB7 }, { 0x4929, 0x7F }, - { 0x492E, 0xBF }, { 0x4930, 0x01 }, { 0x493D, 0xDF }, { 0x4948, 0xFB }, - { 0x494A, 0x7F }, { 0x494E, 0xFB }, { 0x496E, 0x5F }, { 0x496F, 0xDF }, - { 0x4979, 0xF7 }, { 0x498E, 0xDF }, { 0x499A, 0xFB }, { 0x499D, 0xF7 }, - { 0x499F, 0xF7 }, { 0x49A9, 0xBF }, { 0x49AA, 0x7F }, { 0x49BD, 0xF7 }, - { 0x49BE, 0xFD }, { 0x49C9, 0xBF }, { 0x49DE, 0x7F }, { 0x49EB, 0xFD }, - { 0x49EE, 0x7F }, { 0x4A1B, 0xF7 }, { 0x4A1D, 0x77 }, { 0x4A1E, 0x7F }, - { 0x4A1F, 0xBF }, { 0x4A2B, 0xDF }, { 0x4A30, 0x40 }, { 0x4A3F, 0xF3 }, - { 0x4A4F, 0xFB }, { 0x4A58, 0xF7 }, { 0x4A69, 0xF7 }, { 0x4A6B, 0xF7 }, - { 0x4A6E, 0xF7 }, { 0x4A7E, 0xFD }, { 0x4A8F, 0x7F }, { 0x4A99, 0x7F }, - { 0x4A9A, 0xF7 }, { 0x4A9D, 0x7F }, { 0x4A9E, 0xFB }, { 0x4AAE, 0xFD }, - { 0x4AB9, 0x7F }, { 0x4ABC, 0x7F }, { 0x4ABD, 0xF7 }, { 0x4ACB, 0xBF }, - { 0x4ACE, 0xF7 }, { 0x4ACF, 0xDF }, { 0x4ADC, 0xF7 }, { 0x4ADE, 0xFB }, - { 0x4AEE, 0xBF }, { 0x4AFF, 0x7F }, { 0x4B1B, 0xFB }, { 0x4B1E, 0xF3 }, - { 0x4B28, 0xF7 }, { 0x4B3A, 0xF7 }, { 0x4B3B, 0x5D }, { 0x4B3D, 0xFB }, - { 0x4B3F, 0x3F }, { 0x4B4D, 0xBF }, { 0x4B4E, 0xF7 }, { 0x4B5F, 0x7F }, - { 0x4B6E, 0xFB }, { 0x4B8A, 0xDF }, { 0x4B8F, 0x7F }, { 0x4B90, 0x10 }, - { 0x4B9B, 0xDD }, { 0x4B9F, 0x7F }, { 0x4BA9, 0x7F }, { 0x4BAC, 0xBF }, - { 0x4BB9, 0xFD }, { 0x4BC8, 0xFB }, { 0x4BCA, 0xFB }, { 0x4BCB, 0xDB }, - { 0x4BCD, 0x77 }, { 0x4BDB, 0xFD }, { 0x4BDC, 0xF7 }, { 0x4BDF, 0x7F }, - { 0x4BE9, 0x7F }, { 0x4BF9, 0xF7 }, { 0x4BFA, 0xFB }, { 0x4BFB, 0xBF }, - { 0x4BFD, 0x77 }, { 0x4BFE, 0xF9 }, { 0x4C0A, 0x7F }, { 0x4C0F, 0xBF }, - { 0x4C18, 0xFD }, { 0x4C19, 0xBF }, { 0x4C1B, 0xF7 }, { 0x4C1C, 0x7F }, - { 0x4C1E, 0x7F }, { 0x4C1F, 0x7F }, { 0x4C38, 0xF7 }, { 0x4C3D, 0xF7 }, - { 0x4C48, 0xDF }, { 0x4C4A, 0xF7 }, { 0x4C4D, 0xDF }, { 0x4C5D, 0xF7 }, - { 0x4C68, 0x7F }, { 0x4C6B, 0x7F }, { 0x4C6F, 0x7F }, { 0x4C7F, 0x7F }, - { 0x4C81, 0x40 }, { 0x4C88, 0xFB }, { 0x4C99, 0xF7 }, { 0x4C9C, 0x7F }, - { 0x4C9D, 0x7F }, { 0x4CAE, 0x7F }, { 0x4CAF, 0x7F }, { 0x4CBA, 0xBF }, - { 0x4CBB, 0x7F }, { 0x4CBC, 0xFB }, { 0x4CBF, 0xF7 }, { 0x4CCA, 0xBF }, - { 0x4CCB, 0xBF }, { 0x4CCF, 0xBF }, { 0x4CDA, 0xF3 }, { 0x4CDB, 0xBF }, - { 0x4CE8, 0xFD }, { 0x4CEB, 0xFB }, { 0x4CED, 0xDF }, { 0x4D08, 0xBF }, - { 0x4D0A, 0x77 }, { 0x4D19, 0xFB }, { 0x4D1C, 0xFB }, { 0x4D1F, 0xBF }, - { 0x4D2F, 0x7D }, { 0x4D39, 0xBF }, { 0x4D3A, 0xDF }, { 0x4D3B, 0x77 }, - { 0x4D5A, 0xBF }, { 0x4D5B, 0x77 }, { 0x4D5E, 0xF7 }, { 0x4D7A, 0xB7 }, - { 0x4D7B, 0xF7 }, { 0x4D7C, 0x7F }, { 0x4D7F, 0x7F }, { 0x4D8D, 0xDF }, - { 0x4D8F, 0xF7 }, { 0x4D9F, 0x7F }, { 0x4DBD, 0x7F }, { 0x4DCC, 0xBF }, - { 0x4DCF, 0x7F }, { 0x4DD8, 0xFD }, { 0x4DDB, 0x7F }, { 0x4DE5, 0x04 }, - { 0x4DFA, 0xBF }, { 0x4E0B, 0xDF }, { 0x4E0C, 0x7F }, { 0x4E19, 0xFD }, - { 0x4E1B, 0xF7 }, { 0x4E1F, 0xFB }, { 0x4E4F, 0x7F }, { 0x4E69, 0x7F }, - { 0x4E6F, 0xFD }, { 0x4E7B, 0xFB }, { 0x4E7F, 0xBF }, { 0x4E89, 0xF7 }, - { 0x4E98, 0xFB }, { 0x4E9E, 0x7F }, { 0x4EA8, 0xF7 }, { 0x4EA9, 0xFD }, - { 0x4EBB, 0xD7 }, { 0x4EC8, 0xBF }, { 0x4EE0, 0x40 }, { 0x4EEC, 0xF7 }, - { 0x4EFB, 0xFB }, { 0x4EFC, 0x7F }, { 0x4EFF, 0xFD }, { 0x4F0C, 0x7F }, - { 0x4F0D, 0xFB }, { 0x4F1D, 0xFB }, { 0x4F28, 0xBF }, { 0x4F3D, 0xBF }, - { 0x4F4D, 0xDF }, { 0x4F4F, 0xFB }, { 0x4F5C, 0xF7 }, { 0x4F5E, 0xF7 }, - { 0x4F6F, 0xFD }, { 0x4F78, 0xF7 }, { 0x4F7B, 0xF7 }, { 0x4F7D, 0x7F }, - { 0x4F85, 0x10 }, { 0x4F99, 0xFD }, { 0x4F9D, 0x7F }, { 0x4F9F, 0x7F }, - { 0x4FAB, 0xFB }, { 0x4FAC, 0x7F }, { 0x4FAD, 0x7D }, { 0x4FAF, 0xFD }, - { 0x4FBD, 0xF7 }, { 0x4FC8, 0x7D }, { 0x4FD9, 0x9F }, { 0x4FDE, 0x7F }, - { 0x4FE9, 0x7F }, { 0x4FED, 0xFD }, { 0x4FEE, 0xFD }, { 0x4FF9, 0xF7 }, - { 0x4FFC, 0xBF }, { 0x4FFF, 0x7F }, { 0x5008, 0x01 }, { 0x5063, 0xBF }, - { 0x5086, 0xBF }, { 0x509A, 0x04 }, { 0x50B1, 0xF7 }, { 0x50DC, 0x04 }, - { 0x5131, 0x7F }, { 0x514E, 0x20 }, { 0x515A, 0x10 }, { 0x517B, 0x01 }, - { 0x518F, 0x01 }, { 0x51A2, 0xBF }, { 0x51D1, 0x7F }, { 0x5201, 0xFB }, - { 0x5212, 0xF7 }, { 0x5219, 0x04 }, { 0x5232, 0xF7 }, { 0x5242, 0x7F }, - { 0x531B, 0x01 }, { 0x5347, 0x7F }, { 0x5367, 0x7F }, { 0x5372, 0xF7 }, - { 0x5384, 0xFD }, { 0x53B4, 0xFB }, { 0x53D0, 0xF7 }, { 0x5410, 0xFB }, - { 0x5442, 0xFD }, { 0x5455, 0x7F }, { 0x5456, 0xBF }, { 0x5462, 0x7F }, - { 0x5490, 0xBF }, { 0x5524, 0xFB }, { 0x5542, 0xF7 }, { 0x5562, 0xDF }, - { 0x5575, 0xF7 }, { 0x5581, 0xDF }, { 0x5582, 0xBF }, { 0x55D7, 0x7F }, - { 0x55F6, 0xF7 }, { 0x5612, 0xDF }, { 0x5613, 0x7F }, { 0x5627, 0xFB }, - { 0x5644, 0x7F }, { 0x56FA, 0x02 }, { 0x5725, 0xF7 }, { 0x5734, 0xFD }, - { 0x5739, 0x02 }, { 0x57E9, 0x20 }, { 0x580A, 0xFB }, { 0x580D, 0x7F }, - { 0x5819, 0x7F }, { 0x581E, 0xFD }, { 0x582F, 0xF7 }, { 0x584D, 0xBF }, - { 0x584F, 0xFB }, { 0x5859, 0xF7 }, { 0x586D, 0xBF }, { 0x587C, 0xDF }, - { 0x587E, 0xF7 }, { 0x5889, 0xFD }, { 0x5898, 0xBF }, { 0x589C, 0xF7 }, - { 0x58AA, 0xBF }, { 0x58CB, 0xDF }, { 0x58EE, 0xF7 }, { 0x58FF, 0x7F }, - { 0x590E, 0xFB }, { 0x5918, 0xBF }, { 0x5929, 0x7F }, { 0x592A, 0xBF }, - { 0x592B, 0xFD }, { 0x593A, 0xBF }, { 0x593E, 0x7F }, { 0x5949, 0x7F }, - { 0x595B, 0x7F }, { 0x5979, 0x7F }, { 0x597D, 0x7F }, { 0x5988, 0x7F }, - { 0x5989, 0xBF }, { 0x598B, 0x7F }, { 0x5998, 0xBF }, { 0x599F, 0xFD }, - { 0x59A8, 0xDF }, { 0x59AE, 0xFD }, { 0x59B8, 0x7F }, { 0x59CA, 0xFB }, - { 0x59CE, 0x7F }, { 0x59CF, 0xFB }, { 0x59DD, 0xBF }, { 0x59EA, 0xFB }, - { 0x59EB, 0x7F }, { 0x59F8, 0xF7 }, { 0x59F9, 0xFD }, { 0x59FA, 0xF7 }, - { 0x5A0F, 0xDF }, { 0x5A1A, 0xF7 }, { 0x5A1D, 0x7F }, { 0x5A1F, 0xBF }, - { 0x5A2E, 0xF7 }, { 0x5A3F, 0x7F }, { 0x5A59, 0xDF }, { 0x5A5A, 0xB7 }, - { 0x5A5F, 0x7F }, { 0x5A6D, 0xF7 }, { 0x5A7C, 0xDF }, { 0x5A8F, 0x7F }, - { 0x5A98, 0x7B }, { 0x5AAA, 0x7F }, { 0x5AAF, 0x7F }, { 0x5ABC, 0x7F }, - { 0x5ABD, 0xFD }, { 0x5ACD, 0xDF }, { 0x5AD9, 0xBF }, { 0x5ADF, 0x7F }, - { 0x5AE8, 0x7F }, { 0x5AEA, 0xF7 }, { 0x5AED, 0xF7 }, { 0x5AFE, 0xF7 }, - { 0x5AFF, 0x5F }, { 0x5B09, 0xFB }, { 0x5B0A, 0xFB }, { 0x5B0E, 0xBF }, - { 0x5B0F, 0x7B }, { 0x5B28, 0xFD }, { 0x5B2B, 0xFB }, { 0x5B2E, 0xBF }, - { 0x5B2F, 0xFB }, { 0x5B3D, 0xF7 }, { 0x5B3F, 0xF7 }, { 0x5B49, 0x7F }, - { 0x5B4E, 0xF7 }, { 0x5B5E, 0xF7 }, { 0x5B6B, 0x7F }, { 0x5B6C, 0xBF }, - { 0x5B6F, 0x7F }, { 0x5B79, 0x7F }, { 0x5B7E, 0x5F }, { 0x5B8E, 0xDF }, - { 0x5B99, 0xF3 }, { 0x5B9F, 0xD7 }, { 0x5BA8, 0xBF }, { 0x5BAA, 0xBF }, - { 0x5BAC, 0xF7 }, { 0x5BAD, 0x77 }, { 0x5BBA, 0x7F }, { 0x5BBE, 0xF7 }, - { 0x5BCA, 0xBF }, { 0x5BCF, 0x5F }, { 0x5BD2, 0x40 }, { 0x5BDB, 0xF7 }, - { 0x5BEA, 0xF7 }, { 0x5BEB, 0xF7 }, { 0x5BFB, 0xBB }, { 0x5BFD, 0xF7 }, - { 0x5C0E, 0x7F }, { 0x5C0F, 0xDF }, { 0x5C1A, 0xF7 }, { 0x5C28, 0x7F }, - { 0x5C2B, 0xF7 }, { 0x5C3D, 0xDF }, { 0x5C3E, 0xFB }, { 0x5C4A, 0xDF }, - { 0x5C4C, 0xDF }, { 0x5C4D, 0xFD }, { 0x5C5C, 0x7F }, { 0x5C6D, 0x7F }, - { 0x5C7F, 0x7F }, { 0x5C85, 0x01 }, { 0x5C8A, 0xFD }, { 0x5C8B, 0x7F }, - { 0x5C9B, 0xBF }, { 0x5C9F, 0x7F }, { 0x5CAE, 0x7F }, { 0x5CAF, 0x7F }, - { 0x5CB9, 0xFB }, { 0x5CCE, 0xFD }, { 0x5CD3, 0x04 }, { 0x5CD6, 0x01 }, - { 0x5CDF, 0xFD }, { 0x5CEB, 0x7F }, { 0x5CF9, 0xBF }, { 0x5D0B, 0xBF }, - { 0x5D1D, 0xFD }, { 0x5D1E, 0x7F }, { 0x5D2B, 0xFD }, { 0x5D2C, 0xFD }, - { 0x5D2D, 0x7F }, { 0x5D2F, 0xBF }, { 0x5D3A, 0x7F }, { 0x5D3B, 0xF7 }, - { 0x5D4B, 0xFB }, { 0x5D4D, 0xFB }, { 0x5D4F, 0xF7 }, { 0x5D5A, 0xFD }, - { 0x5D5B, 0xDF }, { 0x5D5C, 0x7F }, { 0x5D5E, 0xBF }, { 0x5D69, 0xFB }, - { 0x5D6B, 0xB7 }, { 0x5D6D, 0xBF }, { 0x5D70, 0x02 }, { 0x5D78, 0xF7 }, - { 0x5D7F, 0xFB }, { 0x5D8A, 0xDF }, { 0x5D8F, 0xFD }, { 0x5D99, 0xBF }, - { 0x5D9E, 0xDF }, { 0x5DAC, 0xFB }, { 0x5DCB, 0x7F }, { 0x5DCD, 0xBF }, - { 0x5DDB, 0xD7 }, { 0x5DDE, 0x7F }, { 0x5DE9, 0x7F }, { 0x5DEA, 0xFB }, - { 0x5DFF, 0x7F }, { 0x5E19, 0xF7 }, { 0x5E1F, 0xFB }, { 0x5E28, 0xBF }, - { 0x5E2D, 0xDF }, { 0x5E3D, 0x7F }, { 0x5E49, 0x7F }, { 0x5E4E, 0xFB }, - { 0x5E5C, 0xBF }, { 0x5E68, 0xFD }, { 0x5E6C, 0xDF }, { 0x5E6D, 0xDF }, - { 0x5E79, 0xDF }, { 0x5E7D, 0x7F }, { 0x5E99, 0x7F }, { 0x5EAF, 0xBF }, - { 0x5EBC, 0xDF }, { 0x5EC8, 0xBF }, { 0x5ECC, 0xF7 }, { 0x5ED2, 0xBF }, - { 0x5EF9, 0xF7 }, { 0x5EFE, 0xDF }, { 0x5F08, 0xF7 }, { 0x5F0F, 0xF7 }, - { 0x5F18, 0xFD }, { 0x5F19, 0x7F }, { 0x5F1B, 0xFD }, { 0x5F3F, 0x7F }, - { 0x5F4C, 0xFD }, { 0x5F4E, 0xF7 }, { 0x5F5C, 0x7F }, { 0x5F5D, 0xF7 }, - { 0x5F5E, 0x7F }, { 0x5F69, 0xFB }, { 0x5F6C, 0xFD }, { 0x5F6F, 0xDF }, - { 0x5F92, 0xF7 }, { 0x5FAD, 0x7F }, { 0x5FAE, 0xF7 }, { 0x5FCD, 0xF7 }, - { 0x5FCF, 0xBF }, { 0x5FDC, 0xF7 }, { 0x5FDE, 0x7F }, { 0x5FDF, 0x7F }, - { 0x5FEB, 0x7F }, { 0x5FED, 0xDF }, { 0x5FF8, 0xDF }, { 0x600C, 0x20 }, - { 0x6041, 0xBF }, { 0x6045, 0x7F }, { 0x6062, 0xF7 }, { 0x6077, 0xBF }, - { 0x60A0, 0xDF }, { 0x60C1, 0x7F }, { 0x60C7, 0xFD }, { 0x60CB, 0x40 }, - { 0x60E8, 0x01 }, { 0x6118, 0x02 }, { 0x613C, 0x01 }, { 0x6143, 0xF7 }, - { 0x614A, 0x40 }, { 0x615B, 0x10 }, { 0x616F, 0x01 }, { 0x617C, 0x01 }, - { 0x6190, 0xDF }, { 0x6196, 0xF7 }, { 0x61A6, 0x7F }, { 0x61D6, 0xF7 }, - { 0x61F8, 0x04 }, { 0x61FA, 0x10 }, { 0x6201, 0x7F }, { 0x62A7, 0xBF }, - { 0x62D4, 0x7F }, { 0x6322, 0xF7 }, { 0x6361, 0xFB }, { 0x6363, 0x7F }, - { 0x6374, 0xF7 }, { 0x6392, 0x7F }, { 0x639F, 0x01 }, { 0x63A0, 0xF7 }, - { 0x63A1, 0x7F }, { 0x63D9, 0x20 }, { 0x63E8, 0x01 }, { 0x6406, 0x7F }, - { 0x6424, 0x7F }, { 0x6437, 0x7F }, { 0x643B, 0x01 }, { 0x64B1, 0xFB }, - { 0x6514, 0xF7 }, { 0x6536, 0xFD }, { 0x6546, 0x7F }, { 0x6578, 0x01 }, - { 0x6582, 0x7F }, { 0x65A3, 0xFB }, { 0x65B9, 0x01 }, { 0x65C9, 0x01 }, - { 0x65E0, 0xF7 }, { 0x6612, 0xDF }, { 0x6632, 0xF7 }, { 0x6636, 0x7F }, - { 0x6651, 0xF7 }, { 0x6666, 0xF7 }, { 0x6675, 0x7F }, { 0x6684, 0x7F }, - { 0x6687, 0x7F }, { 0x66E9, 0x40 }, { 0x6706, 0xFD }, { 0x6713, 0xDF }, - { 0x6758, 0x11 }, { 0x6773, 0xF7 }, { 0x6776, 0xBF }, { 0x67F0, 0x7F }, - { 0x682B, 0xFB }, { 0x682C, 0xFB }, { 0x683E, 0xF5 }, { 0x683F, 0x7F }, - { 0x6849, 0xF7 }, { 0x685C, 0xF5 }, { 0x686C, 0x7F }, { 0x686D, 0xF7 }, - { 0x686E, 0x7F }, { 0x687E, 0xDF }, { 0x6889, 0x7F }, { 0x688E, 0xBF }, - { 0x688F, 0x7F }, { 0x689B, 0xF7 }, { 0x689C, 0xF7 }, { 0x689E, 0x7F }, - { 0x68CB, 0xBF }, { 0x68E9, 0x7F }, { 0x68EA, 0xDF }, { 0x68EB, 0x7F }, - { 0x68EF, 0xF7 }, { 0x690B, 0xF7 }, { 0x6918, 0xBF }, { 0x691D, 0xF7 }, - { 0x6929, 0x7F }, { 0x6938, 0x7F }, { 0x693A, 0x3F }, { 0x693E, 0x3F }, - { 0x6949, 0xF7 }, { 0x694C, 0x7F }, { 0x694D, 0xDF }, { 0x694E, 0x77 }, - { 0x695A, 0xFD }, { 0x697B, 0x7F }, { 0x697E, 0x7F }, { 0x6989, 0x7F }, - { 0x698A, 0x7F }, { 0x698E, 0xF7 }, { 0x698F, 0xF7 }, { 0x699B, 0xDF }, - { 0x699E, 0x5F }, { 0x699F, 0xDF }, { 0x69AD, 0x7F }, { 0x69C9, 0xF7 }, - { 0x69D9, 0xF7 }, { 0x69DC, 0xF7 }, { 0x69F9, 0xBF }, { 0x69FA, 0xF7 }, - { 0x69FC, 0x7F }, { 0x6A09, 0xF7 }, { 0x6A1B, 0x7F }, { 0x6A2A, 0xF7 }, - { 0x6A2D, 0xFD }, { 0x6A3C, 0xFD }, { 0x6A3D, 0x7F }, { 0x6A3F, 0x7F }, - { 0x6A5A, 0xBF }, { 0x6A6C, 0xFB }, { 0x6A6F, 0xFD }, { 0x6A7A, 0xF7 }, - { 0x6A7B, 0x7B }, { 0x6A89, 0x7F }, { 0x6A9F, 0x7F }, { 0x6AAB, 0xDF }, - { 0x6AB8, 0xF7 }, { 0x6ABE, 0xFD }, { 0x6AC8, 0xFD }, { 0x6ACB, 0x7F }, - { 0x6ACF, 0xD7 }, { 0x6ADC, 0xFD }, { 0x6AEA, 0xBF }, { 0x6AEB, 0xF7 }, - { 0x6AF8, 0xFB }, { 0x6AFD, 0xBF }, { 0x6B1A, 0x7F }, { 0x6B1F, 0x7F }, - { 0x6B2D, 0xFD }, { 0x6B2E, 0xD7 }, { 0x6B3E, 0xDF }, { 0x6B4B, 0xF7 }, - { 0x6B4D, 0xFB }, { 0x6B4F, 0xBF }, { 0x6B5E, 0x7B }, { 0x6B5F, 0x7F }, - { 0x6B6C, 0xFB }, { 0x6B6F, 0xDF }, { 0x6B88, 0xDD }, { 0x6B8A, 0xFB }, - { 0x6B8B, 0x77 }, { 0x6BA8, 0x7F }, { 0x6BAA, 0xF7 }, { 0x6BCA, 0xFB }, - { 0x6BCB, 0xF7 }, { 0x6BDB, 0xDF }, { 0x6BDC, 0xBF }, { 0x6BDD, 0x77 }, - { 0x6BDF, 0xFD }, { 0x6BE8, 0x7F }, { 0x6BE9, 0xF7 }, { 0x6BED, 0x7F }, - { 0x6BF8, 0xFD }, { 0x6BF9, 0xF5 }, { 0x6BFA, 0xF7 }, { 0x6BFD, 0xF5 }, - { 0x6BFE, 0xF7 }, { 0x6BFF, 0xBF }, { 0x6C09, 0xFB }, { 0x6C0F, 0x7F }, - { 0x6C29, 0xD7 }, { 0x6C2F, 0x7F }, { 0x6C3A, 0xDF }, { 0x6C3E, 0xF7 }, - { 0x6C4E, 0xBF }, { 0x6C5E, 0x7F }, { 0x6C5F, 0xDF }, { 0x6C79, 0xDF }, - { 0x6C7A, 0x7F }, { 0x6C7E, 0xBF }, { 0x6C8B, 0x7F }, { 0x6C8D, 0xDF }, - { 0x6C99, 0xFD }, { 0x6C9A, 0xBF }, { 0x6C9E, 0x7F }, { 0x6CA9, 0x7F }, - { 0x6CAA, 0xF7 }, { 0x6CAC, 0xFB }, { 0x6CAD, 0x7F }, { 0x6CAF, 0xF7 }, - { 0x6CC9, 0xFB }, { 0x6CDC, 0xFD }, { 0x6CEC, 0xDF }, { 0x6CEF, 0xBF }, - { 0x6CFB, 0x7F }, { 0x6D1D, 0xFD }, { 0x6D1F, 0xDF }, { 0x6D2B, 0xD9 }, - { 0x6D3B, 0x7F }, { 0x6D3C, 0xB7 }, { 0x6D4D, 0xBF }, { 0x6D58, 0x7F }, - { 0x6D5C, 0x7F }, { 0x6D6D, 0xFD }, { 0x6D7E, 0x7F }, { 0x6D89, 0xBF }, - { 0x6D9B, 0x7F }, { 0x6D9F, 0xF7 }, { 0x6DB9, 0x7F }, { 0x6DBF, 0xFB }, - { 0x6DE9, 0x7F }, { 0x6DEA, 0xF7 }, { 0x6DEC, 0xBF }, { 0x6DFB, 0x7F }, - { 0x6E09, 0x7F }, { 0x6E0F, 0x7F }, { 0x6E10, 0x01 }, { 0x6E12, 0xDF }, - { 0x6E1E, 0xFB }, { 0x6E28, 0xF7 }, { 0x6E2E, 0xFB }, { 0x6E4E, 0x7F }, - { 0x6E72, 0x7F }, { 0x6E79, 0x7F }, { 0x6E7E, 0x9F }, { 0x6E88, 0x7F }, - { 0x6E8E, 0xF7 }, { 0x6E9E, 0xBF }, { 0x6EAC, 0xFD }, { 0x6EAD, 0xF7 }, - { 0x6EAF, 0x7F }, { 0x6EB9, 0xFB }, { 0x6EBE, 0x7F }, { 0x6EC9, 0x7F }, - { 0x6EE8, 0xF7 }, { 0x6EE9, 0x77 }, { 0x6EEB, 0xF7 }, { 0x6EEC, 0x7F }, - { 0x6F04, 0x04 }, { 0x6F0C, 0x7F }, { 0x6F0E, 0x7F }, { 0x6F18, 0xDF }, - { 0x6F1F, 0x7F }, { 0x6F2B, 0xFB }, { 0x6F2E, 0xFD }, { 0x6F3C, 0xF7 }, - { 0x6F3F, 0x7F }, { 0x6F4D, 0xFB }, { 0x6F59, 0x77 }, { 0x6F5E, 0x7F }, - { 0x6F6B, 0xFB }, { 0x6F6E, 0x9F }, { 0x6F9F, 0x7F }, { 0x6FAD, 0xB7 }, - { 0x6FBF, 0xF7 }, { 0x6FC8, 0xDF }, { 0x6FCD, 0x3F }, { 0x6FCE, 0xBB }, - { 0x6FDC, 0x7F }, { 0x6FDD, 0xDF }, { 0x6FEF, 0xF7 }, { 0x6FFB, 0xFB }, - { 0x6FFD, 0x77 }, { 0x701E, 0x10 }, { 0x7047, 0x7F }, { 0x7076, 0xF7 }, - { 0x707C, 0x10 }, { 0x70D5, 0xFD }, { 0x70F4, 0xDF }, { 0x710C, 0x04 }, - { 0x711A, 0x01 }, { 0x714E, 0x06 }, { 0x716F, 0x01 }, { 0x71A3, 0xDF }, - { 0x71B0, 0xFD }, { 0x71DE, 0x10 }, { 0x7206, 0xBF }, { 0x720C, 0x40 }, - { 0x7223, 0xFB }, { 0x726C, 0x04 }, { 0x7272, 0xF7 }, { 0x72A5, 0xBF }, - { 0x72C0, 0xF7 }, { 0x72DE, 0x01 }, { 0x72F8, 0x04 }, { 0x7302, 0xDF }, - { 0x7313, 0x7F }, { 0x7332, 0xF7 }, { 0x7372, 0xF7 }, { 0x73EB, 0x40 }, - { 0x7410, 0xDF }, { 0x7423, 0xF7 }, { 0x7432, 0xF7 }, { 0x7433, 0xF7 }, - { 0x744A, 0x01 }, { 0x748B, 0x01 }, { 0x7490, 0xF7 }, { 0x749A, 0x01 }, - { 0x7526, 0xFB }, { 0x7536, 0x7F }, { 0x7540, 0x7F }, { 0x7557, 0x7F }, - { 0x757F, 0x04 }, { 0x7584, 0x7F }, { 0x75B8, 0x01 }, { 0x75C2, 0xF7 }, - { 0x75C6, 0x7F }, { 0x75D5, 0xB7 }, { 0x75F8, 0x01 }, { 0x7607, 0xDF }, - { 0x764F, 0x02 }, { 0x7694, 0x7F }, { 0x7697, 0xFD }, { 0x76CC, 0x10 }, - { 0x76D0, 0xF7 }, { 0x76E0, 0xF7 }, { 0x7702, 0xF7 }, { 0x7721, 0x7F }, - { 0x7752, 0xFB }, { 0x77B6, 0xFB }, { 0x77B8, 0x01 }, { 0x77C2, 0xF7 }, - { 0x77D2, 0xF7 }, { 0x77D3, 0x7F }, { 0x77E3, 0xFD }, { 0x780B, 0x7F }, - { 0x780F, 0x3F }, { 0x7818, 0xF7 }, { 0x7834, 0x01 }, { 0x784C, 0x7F }, - { 0x784F, 0x5F }, { 0x785B, 0x7F }, { 0x7878, 0x7F }, { 0x7888, 0x7F }, - { 0x7889, 0xFB }, { 0x788A, 0xFB }, { 0x788B, 0xF7 }, { 0x78B9, 0x7F }, - { 0x78CB, 0xDF }, { 0x78CD, 0x7F }, { 0x78DA, 0xF7 }, { 0x78EA, 0xF7 }, - { 0x78FB, 0xFB }, { 0x790B, 0x7F }, { 0x790C, 0xF7 }, { 0x790D, 0xDF }, - { 0x790E, 0xFB }, { 0x790F, 0xFD }, { 0x791A, 0x7F }, { 0x791D, 0xBF }, - { 0x793B, 0xF7 }, { 0x793F, 0x7F }, { 0x7949, 0xFD }, { 0x794F, 0xFB }, - { 0x795C, 0x7F }, { 0x7960, 0x01 }, { 0x7968, 0xBF }, { 0x7969, 0xFD }, - { 0x7978, 0x7F }, { 0x797D, 0xF7 }, { 0x798D, 0xFE }, { 0x798E, 0xBF }, - { 0x79A9, 0x7F }, { 0x79AD, 0xF7 }, { 0x79BB, 0xFD }, { 0x79C8, 0xF7 }, - { 0x79C9, 0x7F }, { 0x79DB, 0x7F }, { 0x79DE, 0x7F }, { 0x79E9, 0xFB }, - { 0x79F8, 0xB7 }, { 0x79FB, 0xBF }, { 0x79FF, 0xBF }, { 0x7A0C, 0xF3 }, - { 0x7A0F, 0xDD }, { 0x7A18, 0x7F }, { 0x7A38, 0x7F }, { 0x7A39, 0x7F }, - { 0x7A49, 0xBF }, { 0x7A4B, 0x77 }, { 0x7A4C, 0x7F }, { 0x7A51, 0x40 }, - { 0x7A6D, 0xFD }, { 0x7A6F, 0x7F }, { 0x7A8E, 0x7F }, { 0x7AAF, 0xDF }, - { 0x7ABB, 0x7F }, { 0x7ACE, 0xBF }, { 0x7ADC, 0xDF }, { 0x7ADF, 0xB7 }, - { 0x7AEE, 0xF7 }, { 0x7AEF, 0xFB }, { 0x7AF8, 0xF7 }, { 0x7AFB, 0x7F }, - { 0x7AFE, 0xFB }, { 0x7B0F, 0xDF }, { 0x7B19, 0xFD }, { 0x7B1F, 0xFD }, - { 0x7B29, 0xF5 }, { 0x7B2D, 0x7F }, { 0x7B2F, 0xF7 }, { 0x7B38, 0x7F }, - { 0x7B3C, 0xFB }, { 0x7B3D, 0xFD }, { 0x7B4A, 0xF7 }, { 0x7B4B, 0xF7 }, - { 0x7B5A, 0x7F }, { 0x7B5E, 0x7F }, { 0x7B5F, 0xBF }, { 0x7B6D, 0xBF }, - { 0x7B6F, 0x33 }, { 0x7B7A, 0xF7 }, { 0x7B7B, 0xFB }, { 0x7B7F, 0x7F }, - { 0x7B8E, 0x7F }, { 0x7B95, 0x04 }, { 0x7B99, 0xF7 }, { 0x7BA9, 0x7F }, - { 0x7BB8, 0x7F }, { 0x7BB9, 0xFD }, { 0x7BCE, 0x7F }, { 0x7BCF, 0x7F }, - { 0x7BD8, 0xD7 }, { 0x7BDA, 0x7F }, { 0x7BDC, 0x7F }, { 0x7BDE, 0xF7 }, - { 0x7BE9, 0xFB }, { 0x7BF8, 0x9F }, { 0x7BFA, 0xBF }, { 0x7BFB, 0xDF }, - { 0x7BFE, 0xF7 }, { 0x7BFF, 0x77 }, { 0x7C08, 0x7F }, { 0x7C0A, 0xDF }, - { 0x7C1A, 0x7F }, { 0x7C1C, 0xF7 }, { 0x7C2E, 0x7F }, { 0x7C2F, 0x7F }, - { 0x7C3E, 0xF7 }, { 0x7C48, 0xF7 }, { 0x7C59, 0x7F }, { 0x7C5C, 0xF7 }, - { 0x7C7B, 0xF7 }, { 0x7C7F, 0xFB }, { 0x7CB9, 0xDF }, { 0x7CBF, 0x7F }, - { 0x7CD9, 0x7F }, { 0x7CDA, 0x7F }, { 0x7CDD, 0x7F }, { 0x7CFD, 0xDF }, - { 0x7D08, 0xFD }, { 0x7D1D, 0xF7 }, { 0x7D2D, 0xD7 }, { 0x7D2F, 0x7F }, - { 0x7D3B, 0xBF }, { 0x7D4A, 0xDF }, { 0x7D4D, 0xF7 }, { 0x7D4E, 0x7F }, - { 0x7D5A, 0x7F }, { 0x7D5B, 0xDF }, { 0x7D5F, 0xDF }, { 0x7D6A, 0xBF }, - { 0x7D6C, 0xFB }, { 0x7D6E, 0xF9 }, { 0x7D78, 0xF7 }, { 0x7D7D, 0xDF }, - { 0x7D7E, 0x7F }, { 0x7D8D, 0xF7 }, { 0x7D8E, 0xF7 }, { 0x7D8F, 0x5F }, - { 0x7D98, 0x77 }, { 0x7D9A, 0xF7 }, { 0x7D9D, 0xDF }, { 0x7D9E, 0xFB }, - { 0x7DB8, 0xF7 }, { 0x7DB9, 0xF7 }, { 0x7DBB, 0xDF }, { 0x7DBC, 0xDF }, - { 0x7DBF, 0xDF }, { 0x7DCC, 0xBF }, { 0x7DD9, 0xF7 }, { 0x7DEA, 0xDF }, - { 0x7DEC, 0xFD }, { 0x7DEE, 0xDD }, { 0x7DF9, 0xF7 }, { 0x7DFD, 0x7F }, - { 0x7E02, 0xFD }, { 0x7E0B, 0xFD }, { 0x7E18, 0xF7 }, { 0x7E1B, 0xFB }, - { 0x7E1D, 0x7F }, { 0x7E48, 0xFB }, { 0x7E4A, 0x01 }, { 0x7E6C, 0xDF }, - { 0x7E6F, 0xF7 }, { 0x7E8E, 0xFD }, { 0x7EDD, 0x7F }, { 0x7EEA, 0x20 }, - { 0x7EEB, 0xBF }, { 0x7EEF, 0xEF }, { 0x7EFD, 0x77 }, { 0x7EFE, 0x7F }, - { 0x7EFF, 0xDF }, { 0x7F28, 0xF7 }, { 0x7F2C, 0xF7 }, { 0x7F2E, 0x7B }, - { 0x7F2F, 0xF7 }, { 0x7F36, 0x10 }, { 0x7F3D, 0xFD }, { 0x7F49, 0x7F }, - { 0x7F58, 0x7B }, { 0x7F5E, 0xDF }, { 0x7F68, 0xF7 }, { 0x7F6C, 0xF7 }, - { 0x7F7B, 0xF9 }, { 0x7F7E, 0xDF }, { 0x7F8D, 0xDF }, { 0x7F92, 0xF7 }, - { 0x7F98, 0xF7 }, { 0x7F9C, 0x7F }, { 0x7FA9, 0xB9 }, { 0x7FAB, 0x7B }, - { 0x7FBC, 0x7F }, { 0x7FBF, 0xF7 }, { 0x7FC9, 0x7F }, { 0x7FCB, 0x7F }, - { 0x7FCD, 0xBF }, { 0x7FCE, 0x7F }, { 0x7FCF, 0xFB }, { 0x7FDB, 0xF7 }, - { 0x7FDF, 0x7F }, { 0x7FE8, 0xDF }, { 0x7FEC, 0xFB }, { 0x7FF2, 0xF7 } - }; - - for (unsigned addr = 0x0000; addr < 0x0800; addr += 0x10) { - std::memset(wram + addr + 0x00, 0xFF, 0x08); - std::memset(wram + addr + 0x08, 0x00, 0x08); - } - - for (unsigned addr = 0x0800; addr < 0x1000; addr += 0x10) { - std::memset(wram + addr + 0x00, 0x00, 0x08); - std::memset(wram + addr + 0x08, 0xFF, 0x08); - } - - for (unsigned addr = 0x0E00; addr < 0x1000; addr += 0x10) { - wram[addr + 0x02] = 0xFF; - wram[addr + 0x0A] = 0x00; - } - - for (unsigned addr = 0x1000; addr < 0x8000; addr += 0x1000) { - if (0x2000 != addr) - std::memcpy(wram + addr, wram, 0x1000); - } - - std::memset(wram + 0x2000, 0, 0x1000); - - for (std::size_t i = 0; i < sizeof cgbWramDumpDiff / sizeof cgbWramDumpDiff[0]; ++i) - wram[cgbWramDumpDiff[i].addr] = cgbWramDumpDiff[i].val; -} - -static void setInitialDmgWram(unsigned char wram[]) { - static struct { unsigned short addr; unsigned char val; } const dmgWramDumpDiff[] = { - { 0x0000, 0x08 }, { 0x0004, 0x08 }, { 0x0008, 0x4D }, { 0x000A, 0x80 }, - { 0x0010, 0x02 }, { 0x0018, 0x04 }, { 0x0020, 0x10 }, { 0x0028, 0x05 }, - { 0x002C, 0x08 }, { 0x0038, 0x21 }, { 0x003A, 0x40 }, { 0x0060, 0x02 }, - { 0x0066, 0x03 }, { 0x0068, 0x40 }, { 0x0072, 0x80 }, { 0x0074, 0x40 }, - { 0x0076, 0x80 }, { 0x007C, 0x80 }, { 0x007E, 0x20 }, { 0x0080, 0x0C }, - { 0x0088, 0x08 }, { 0x008C, 0x02 }, { 0x008E, 0x04 }, { 0x0092, 0x01 }, - { 0x0098, 0x02 }, { 0x00A2, 0x08 }, { 0x00A8, 0x02 }, { 0x00AC, 0x15 }, - { 0x00B0, 0x02 }, { 0x00B2, 0x80 }, { 0x00B6, 0x80 }, { 0x00B8, 0x06 }, - { 0x00BA, 0x01 }, { 0x00BC, 0x08 }, { 0x00C4, 0x04 }, { 0x00C8, 0x02 }, - { 0x00CC, 0x01 }, { 0x00D0, 0x85 }, { 0x00D8, 0x81 }, { 0x00DC, 0x01 }, - { 0x00DE, 0x01 }, { 0x00E0, 0x01 }, { 0x00E6, 0x08 }, { 0x00E8, 0x44 }, - { 0x00EC, 0x44 }, { 0x00F0, 0x40 }, { 0x00F4, 0x20 }, { 0x00FA, 0x04 }, - { 0x00FC, 0x12 }, { 0x00FE, 0x01 }, { 0x0103, 0x7F }, { 0x0107, 0xFD }, - { 0x0113, 0xFB }, { 0x0119, 0xBF }, { 0x011B, 0xEF }, { 0x011D, 0xFB }, - { 0x0121, 0xFB }, { 0x0133, 0xF7 }, { 0x0135, 0x6F }, { 0x0137, 0xBD }, - { 0x013F, 0xF6 }, { 0x0145, 0xF7 }, { 0x0149, 0xDF }, { 0x014D, 0xFA }, - { 0x014F, 0xFE }, { 0x0151, 0xFD }, { 0x0161, 0xFD }, { 0x0165, 0xBF }, - { 0x0171, 0xFD }, { 0x0173, 0xEF }, { 0x0177, 0xFE }, { 0x0179, 0x7F }, - { 0x0185, 0xF7 }, { 0x0189, 0xEF }, { 0x0199, 0xF7 }, { 0x01AB, 0xEF }, - { 0x01B1, 0x7F }, { 0x01B3, 0xEF }, { 0x01B5, 0xBF }, { 0x01C1, 0xFB }, - { 0x01C9, 0xFB }, { 0x01CB, 0xEF }, { 0x01CF, 0xBF }, { 0x01D5, 0x7F }, - { 0x01E1, 0xDD }, { 0x01E7, 0xF7 }, { 0x01F5, 0xFE }, { 0x0218, 0x01 }, - { 0x0220, 0x08 }, { 0x0226, 0x08 }, { 0x022C, 0x20 }, { 0x0230, 0x50 }, - { 0x0238, 0x01 }, { 0x0246, 0x02 }, { 0x0256, 0x10 }, { 0x0258, 0x40 }, - { 0x0260, 0x70 }, { 0x0264, 0x04 }, { 0x0268, 0x28 }, { 0x0278, 0x02 }, - { 0x0284, 0x10 }, { 0x0298, 0x20 }, { 0x029A, 0x10 }, { 0x02A0, 0x44 }, - { 0x02AE, 0x20 }, { 0x02B2, 0x20 }, { 0x02C0, 0x28 }, { 0x02CA, 0x64 }, - { 0x02D0, 0x20 }, { 0x02E0, 0x80 }, { 0x02E8, 0x02 }, { 0x02EA, 0x02 }, - { 0x02EE, 0x08 }, { 0x02F0, 0x0C }, { 0x02F2, 0x02 }, { 0x0305, 0xDF }, - { 0x0307, 0xFE }, { 0x0309, 0xFD }, { 0x030F, 0xBF }, { 0x0311, 0xFB }, - { 0x0325, 0xDF }, { 0x0329, 0xFD }, { 0x0335, 0xFD }, { 0x033B, 0xF7 }, - { 0x0345, 0xFB }, { 0x0347, 0xFD }, { 0x034B, 0xEF }, { 0x0353, 0xF9 }, - { 0x035B, 0xBF }, { 0x035D, 0xBF }, { 0x0361, 0xF5 }, { 0x0369, 0xBF }, - { 0x0375, 0xFD }, { 0x0381, 0xEF }, { 0x0383, 0xDF }, { 0x038D, 0xF7 }, - { 0x0391, 0xF7 }, { 0x039B, 0xFE }, { 0x03A9, 0xDF }, { 0x03B3, 0xFB }, - { 0x03C1, 0xFE }, { 0x03CD, 0xFB }, { 0x03DB, 0xFB }, { 0x03DD, 0x7F }, - { 0x03E1, 0x7F }, { 0x03ED, 0xFD }, { 0x03F3, 0xFD }, { 0x03FD, 0xFB }, - { 0x0406, 0x20 }, { 0x040E, 0x04 }, { 0x0412, 0x05 }, { 0x041C, 0x08 }, - { 0x0420, 0x10 }, { 0x0422, 0x40 }, { 0x0428, 0x40 }, { 0x042A, 0x08 }, - { 0x0430, 0x32 }, { 0x0434, 0x02 }, { 0x0438, 0x80 }, { 0x043A, 0x01 }, - { 0x044A, 0x02 }, { 0x0452, 0x50 }, { 0x0458, 0x01 }, { 0x0470, 0x14 }, - { 0x0478, 0xA0 }, { 0x047A, 0x01 }, { 0x048E, 0x01 }, { 0x0490, 0x04 }, - { 0x0492, 0x10 }, { 0x0496, 0x50 }, { 0x0498, 0x02 }, { 0x049E, 0x0C }, - { 0x04A2, 0x40 }, { 0x04A6, 0x01 }, { 0x04A8, 0xC0 }, { 0x04B0, 0x02 }, - { 0x04BE, 0x20 }, { 0x04C2, 0x01 }, { 0x04C8, 0x01 }, { 0x04CC, 0x01 }, - { 0x04D0, 0x01 }, { 0x04D2, 0x20 }, { 0x04DE, 0x01 }, { 0x04E0, 0x0C }, - { 0x04E2, 0x18 }, { 0x04EA, 0x08 }, { 0x04EE, 0x01 }, { 0x04F2, 0x90 }, - { 0x04F8, 0x20 }, { 0x04FA, 0x81 }, { 0x04FC, 0x40 }, { 0x0505, 0xF7 }, - { 0x0509, 0xFE }, { 0x0511, 0xCD }, { 0x0517, 0xF3 }, { 0x0525, 0xF7 }, - { 0x052B, 0xF7 }, { 0x052D, 0x7F }, { 0x052F, 0xBF }, { 0x0531, 0xEF }, - { 0x0533, 0xBF }, { 0x0545, 0xFB }, { 0x055D, 0xF7 }, { 0x0583, 0xFE }, - { 0x0593, 0xFE }, { 0x05AB, 0xEF }, { 0x05B1, 0xDF }, { 0x05BD, 0x6F }, - { 0x05CB, 0xBF }, { 0x05CD, 0xFB }, { 0x05CF, 0xFB }, { 0x05D3, 0xFB }, - { 0x05FB, 0xD5 }, { 0x05FD, 0xF7 }, { 0x0600, 0x82 }, { 0x0606, 0x04 }, - { 0x0618, 0x28 }, { 0x0630, 0x40 }, { 0x0638, 0x08 }, { 0x0640, 0x20 }, - { 0x0654, 0x40 }, { 0x0658, 0x22 }, { 0x065C, 0x84 }, { 0x0664, 0x06 }, - { 0x066E, 0x10 }, { 0x0672, 0x01 }, { 0x0678, 0x04 }, { 0x0680, 0x10 }, - { 0x0686, 0x80 }, { 0x068A, 0x42 }, { 0x0690, 0x12 }, { 0x06A8, 0x11 }, - { 0x06B0, 0x40 }, { 0x06CE, 0x08 }, { 0x06D8, 0x10 }, { 0x06DC, 0x81 }, - { 0x06E2, 0x06 }, { 0x06F0, 0x04 }, { 0x0713, 0xF9 }, { 0x0715, 0xBF }, - { 0x071B, 0xDF }, { 0x071D, 0xFD }, { 0x0725, 0xFD }, { 0x0745, 0xEF }, - { 0x0749, 0xFA }, { 0x0753, 0xBF }, { 0x075B, 0xBF }, { 0x075F, 0xFD }, - { 0x0763, 0xDF }, { 0x0771, 0xDF }, { 0x078F, 0xF7 }, { 0x0799, 0xFD }, - { 0x07A5, 0xEF }, { 0x07D3, 0x7F }, { 0x07DD, 0xBF }, { 0x07E3, 0xFD }, - { 0x07E5, 0xF6 }, { 0x07EB, 0xFD }, { 0x07FB, 0xBF }, { 0x0803, 0xBF }, - { 0x080F, 0xED }, { 0x0811, 0xBF }, { 0x0813, 0xF7 }, { 0x081B, 0x7F }, - { 0x0827, 0xFA }, { 0x0829, 0x7F }, { 0x082F, 0xEF }, { 0x0833, 0xEF }, - { 0x083F, 0xEF }, { 0x0841, 0xDF }, { 0x0843, 0xFE }, { 0x084D, 0xFB }, - { 0x0877, 0xBF }, { 0x087F, 0xFB }, { 0x088D, 0xFE }, { 0x088F, 0x7F }, - { 0x089F, 0xEF }, { 0x08A5, 0xBF }, { 0x08A9, 0xEF }, { 0x08AB, 0xFD }, - { 0x08B1, 0xEF }, { 0x08B5, 0xEF }, { 0x08BF, 0xDF }, { 0x08C7, 0xDF }, - { 0x08CF, 0xFB }, { 0x08DD, 0xFE }, { 0x08DF, 0xF7 }, { 0x08E3, 0x5A }, - { 0x08E7, 0xBF }, { 0x08EB, 0xFB }, { 0x08ED, 0xF9 }, { 0x08EF, 0xFB }, - { 0x08F7, 0x9F }, { 0x08FF, 0xDF }, { 0x0914, 0x94 }, { 0x0916, 0x11 }, - { 0x0918, 0x21 }, { 0x091C, 0x01 }, { 0x0922, 0x40 }, { 0x0926, 0x08 }, - { 0x092C, 0x04 }, { 0x0934, 0x10 }, { 0x0938, 0x02 }, { 0x093A, 0x08 }, - { 0x096A, 0x02 }, { 0x0986, 0x10 }, { 0x0988, 0x20 }, { 0x09A2, 0x03 }, - { 0x09AA, 0x02 }, { 0x09B2, 0x08 }, { 0x09B8, 0x08 }, { 0x09BE, 0x10 }, - { 0x09C2, 0x02 }, { 0x09CA, 0x40 }, { 0x09D4, 0x40 }, { 0x09E2, 0x01 }, - { 0x09E8, 0x10 }, { 0x09EC, 0x40 }, { 0x0A01, 0xEF }, { 0x0A07, 0x6F }, - { 0x0A17, 0xD7 }, { 0x0A27, 0xFE }, { 0x0A2D, 0xFB }, { 0x0A2F, 0xBF }, - { 0x0A33, 0xEF }, { 0x0A37, 0xFE }, { 0x0A5F, 0xFA }, { 0x0A67, 0xFB }, - { 0x0A8D, 0xDF }, { 0x0A8F, 0xFD }, { 0x0A91, 0xEF }, { 0x0A97, 0xFD }, - { 0x0A9F, 0xFC }, { 0x0AA7, 0xEF }, { 0x0AAD, 0xEF }, { 0x0AB1, 0xBF }, - { 0x0ABF, 0x7F }, { 0x0AD9, 0xDF }, { 0x0AF7, 0xFE }, { 0x0AFF, 0xBE }, - { 0x0B14, 0x10 }, { 0x0B24, 0x08 }, { 0x0B2C, 0x02 }, { 0x0B44, 0x08 }, - { 0x0B46, 0x01 }, { 0x0B4E, 0x80 }, { 0x0B52, 0x10 }, { 0x0B54, 0x80 }, - { 0x0B6A, 0x04 }, { 0x0B72, 0x08 }, { 0x0B88, 0x20 }, { 0x0BB6, 0x20 }, - { 0x0BC2, 0x04 }, { 0x0BCE, 0x10 }, { 0x0BD8, 0x08 }, { 0x0BEC, 0x40 }, - { 0x0C0F, 0xFE }, { 0x0C11, 0xBF }, { 0x0C17, 0xB7 }, { 0x0C19, 0x7F }, - { 0x0C23, 0xFB }, { 0x0C27, 0xFE }, { 0x0C2D, 0xDF }, { 0x0C2F, 0xBB }, - { 0x0C37, 0xEF }, { 0x0C3F, 0xBD }, { 0x0C49, 0xFD }, { 0x0C4F, 0xF7 }, - { 0x0C5F, 0xBF }, { 0x0C61, 0xDF }, { 0x0C67, 0x37 }, { 0x0C6B, 0xDF }, - { 0x0C73, 0xF7 }, { 0x0C7D, 0x7F }, { 0x0C87, 0xDC }, { 0x0C89, 0xDF }, - { 0x0C8B, 0xFD }, { 0x0C91, 0xEF }, { 0x0CA3, 0xFB }, { 0x0CA5, 0xFB }, - { 0x0CB7, 0xF6 }, { 0x0CBF, 0x3F }, { 0x0CC5, 0xFB }, { 0x0CC7, 0x7F }, - { 0x0CD1, 0x7F }, { 0x0CD5, 0x7F }, { 0x0CD7, 0xEF }, { 0x0CD9, 0x7F }, - { 0x0CE5, 0xBF }, { 0x0CF5, 0x7F }, { 0x0CFB, 0x7F }, { 0x0CFF, 0xFE }, - { 0x0D02, 0x01 }, { 0x0D0A, 0x11 }, { 0x0D0C, 0x80 }, { 0x0D0E, 0x08 }, - { 0x0D12, 0x40 }, { 0x0D16, 0x0B }, { 0x0D1E, 0x08 }, { 0x0D22, 0x01 }, - { 0x0D26, 0x04 }, { 0x0D28, 0x04 }, { 0x0D2A, 0x01 }, { 0x0D2E, 0x02 }, - { 0x0D32, 0x10 }, { 0x0D44, 0x11 }, { 0x0D4E, 0x04 }, { 0x0D52, 0x80 }, - { 0x0D5A, 0x40 }, { 0x0D5E, 0x04 }, { 0x0D72, 0x01 }, { 0x0D76, 0x02 }, - { 0x0D7A, 0x04 }, { 0x0D7C, 0x80 }, { 0x0D82, 0x80 }, { 0x0D84, 0x04 }, - { 0x0D90, 0x04 }, { 0x0DA0, 0x01 }, { 0x0DA4, 0x02 }, { 0x0DB0, 0x04 }, - { 0x0DB4, 0x04 }, { 0x0DB6, 0x10 }, { 0x0DBC, 0x08 }, { 0x0DC2, 0x08 }, - { 0x0DD0, 0x28 }, { 0x0DD2, 0x10 }, { 0x0DD6, 0x10 }, { 0x0DE2, 0x08 }, - { 0x0E17, 0xFE }, { 0x0E19, 0xDF }, { 0x0E2B, 0xEF }, { 0x0E2F, 0xFD }, - { 0x0E37, 0xF3 }, { 0x0E39, 0xDF }, { 0x0E3F, 0xDF }, { 0x0E4F, 0xFE }, - { 0x0E53, 0xFB }, { 0x0E5B, 0xEF }, { 0x0E5D, 0xF7 }, { 0x0E5F, 0xFD }, - { 0x0E71, 0xFB }, { 0x0E77, 0xFD }, { 0x0E7B, 0xFB }, { 0x0E7F, 0xFD }, - { 0x0E85, 0x7F }, { 0x0E8B, 0xFD }, { 0x0E9B, 0x7B }, { 0x0EA7, 0xFE }, - { 0x0EBB, 0xFB }, { 0x0ED7, 0x77 }, { 0x0EE1, 0xDF }, { 0x0EE3, 0xF7 }, - { 0x0EEF, 0xFE }, { 0x0EFB, 0xFE }, { 0x0EFF, 0xF7 }, { 0x0F02, 0x10 }, - { 0x0F06, 0x20 }, { 0x0F0A, 0x02 }, { 0x0F1C, 0x10 }, { 0x0F32, 0x08 }, - { 0x0F54, 0x10 }, { 0x0F84, 0x10 }, { 0x0F92, 0x40 }, { 0x0FA6, 0x08 }, - { 0x0FAA, 0x02 }, { 0x0FB6, 0x40 }, { 0x0FCE, 0x0A }, { 0x0FD2, 0x10 }, - { 0x0FD4, 0x10 }, { 0x0FE0, 0x04 }, { 0x0FF0, 0x04 }, { 0x1000, 0x80 }, - { 0x1004, 0x08 }, { 0x1008, 0x09 }, { 0x1010, 0x02 }, { 0x1012, 0x20 }, - { 0x1020, 0x05 }, { 0x1024, 0x01 }, { 0x1026, 0x10 }, { 0x102A, 0x02 }, - { 0x1032, 0x40 }, { 0x1034, 0x08 }, { 0x1036, 0x03 }, { 0x1038, 0x01 }, - { 0x103E, 0x40 }, { 0x1040, 0x40 }, { 0x1042, 0x12 }, { 0x1046, 0x02 }, - { 0x1050, 0x22 }, { 0x1056, 0x80 }, { 0x1058, 0x10 }, { 0x105E, 0x40 }, - { 0x1066, 0x04 }, { 0x1068, 0x02 }, { 0x106C, 0x60 }, { 0x1070, 0x80 }, - { 0x1076, 0x40 }, { 0x1078, 0x66 }, { 0x107C, 0x02 }, { 0x1080, 0x40 }, - { 0x1088, 0x01 }, { 0x108A, 0x80 }, { 0x108E, 0x10 }, { 0x1090, 0x31 }, - { 0x1092, 0x20 }, { 0x1098, 0x11 }, { 0x109A, 0x80 }, { 0x10A0, 0x05 }, - { 0x10A4, 0x01 }, { 0x10A6, 0x81 }, { 0x10A8, 0x01 }, { 0x10AA, 0x01 }, - { 0x10B0, 0x40 }, { 0x10B4, 0x40 }, { 0x10B6, 0x20 }, { 0x10B8, 0x03 }, - { 0x10BC, 0x88 }, { 0x10BE, 0x02 }, { 0x10C0, 0x30 }, { 0x10C4, 0x42 }, - { 0x10C6, 0x10 }, { 0x10C8, 0x01 }, { 0x10D4, 0x40 }, { 0x10D8, 0x80 }, - { 0x10DE, 0x10 }, { 0x10E0, 0x10 }, { 0x10E2, 0x10 }, { 0x10E4, 0x01 }, - { 0x10E8, 0x26 }, { 0x10EE, 0x10 }, { 0x10F0, 0x80 }, { 0x10F6, 0x40 }, - { 0x10F8, 0x01 }, { 0x10FA, 0x20 }, { 0x10FC, 0x04 }, { 0x10FE, 0x80 }, - { 0x1101, 0xFD }, { 0x1113, 0x7F }, { 0x1115, 0xEF }, { 0x1117, 0xFB }, - { 0x1121, 0x7F }, { 0x1139, 0xF7 }, { 0x1141, 0xFD }, { 0x1153, 0xFD }, - { 0x1159, 0xF5 }, { 0x115F, 0x7F }, { 0x116D, 0xF7 }, { 0x1171, 0x7E }, - { 0x1179, 0xDF }, { 0x117B, 0xFB }, { 0x117F, 0xDF }, { 0x1189, 0x7F }, - { 0x1195, 0xDF }, { 0x119D, 0xDF }, { 0x119F, 0xD7 }, { 0x11A7, 0xF9 }, - { 0x11AB, 0xAF }, { 0x11AD, 0xBF }, { 0x11B9, 0xDF }, { 0x11BB, 0xBF }, - { 0x11C5, 0xF9 }, { 0x11CF, 0x7F }, { 0x11D5, 0x7F }, { 0x11DF, 0xEF }, - { 0x11E1, 0xFE }, { 0x11E7, 0xDF }, { 0x11E9, 0xF7 }, { 0x11ED, 0xFB }, - { 0x1208, 0x01 }, { 0x1218, 0x16 }, { 0x1230, 0x04 }, { 0x1242, 0x0C }, - { 0x1246, 0x80 }, { 0x1260, 0x01 }, { 0x1276, 0x10 }, { 0x1278, 0x10 }, - { 0x1280, 0x04 }, { 0x1284, 0x44 }, { 0x1286, 0x01 }, { 0x128A, 0x02 }, - { 0x1290, 0x80 }, { 0x12A0, 0x02 }, { 0x12A8, 0x50 }, { 0x12B0, 0x08 }, - { 0x12B2, 0x40 }, { 0x12B4, 0x10 }, { 0x12B6, 0x02 }, { 0x12B8, 0x04 }, - { 0x12C0, 0x04 }, { 0x12CC, 0x20 }, { 0x12D0, 0x42 }, { 0x12D8, 0x10 }, - { 0x12DA, 0x10 }, { 0x12E4, 0x08 }, { 0x12F0, 0x40 }, { 0x12F2, 0x40 }, - { 0x12F8, 0x42 }, { 0x12FC, 0x80 }, { 0x12FE, 0x40 }, { 0x1301, 0xFD }, - { 0x1307, 0x7F }, { 0x1309, 0x3F }, { 0x1325, 0xDF }, { 0x132F, 0xFB }, - { 0x134D, 0x7F }, { 0x1351, 0xDB }, { 0x1353, 0xE7 }, { 0x1357, 0xEF }, - { 0x1363, 0xF7 }, { 0x136D, 0xF7 }, { 0x136F, 0xF7 }, { 0x1389, 0x7F }, - { 0x138B, 0xFE }, { 0x138D, 0x7F }, { 0x139B, 0xEB }, { 0x13A1, 0xEF }, - { 0x13BB, 0xEF }, { 0x13C7, 0x7F }, { 0x13D5, 0xF7 }, { 0x13EB, 0xFD }, - { 0x13F5, 0xDF }, { 0x13F7, 0xFE }, { 0x1400, 0x11 }, { 0x1408, 0x90 }, - { 0x140E, 0x20 }, { 0x1414, 0x10 }, { 0x1416, 0x01 }, { 0x1418, 0x10 }, - { 0x1420, 0x20 }, { 0x1428, 0x0C }, { 0x142C, 0x11 }, { 0x1430, 0x01 }, - { 0x1434, 0x20 }, { 0x1438, 0x10 }, { 0x143A, 0x02 }, { 0x143E, 0x10 }, - { 0x1440, 0xA1 }, { 0x144A, 0x20 }, { 0x144C, 0x80 }, { 0x1450, 0x12 }, - { 0x1452, 0x80 }, { 0x1458, 0x80 }, { 0x145A, 0x41 }, { 0x145C, 0x02 }, - { 0x1460, 0x12 }, { 0x1466, 0x82 }, { 0x1468, 0x18 }, { 0x1470, 0x08 }, - { 0x1472, 0x24 }, { 0x147C, 0x20 }, { 0x147E, 0x81 }, { 0x1484, 0x10 }, - { 0x1488, 0x04 }, { 0x1490, 0x04 }, { 0x1492, 0x08 }, { 0x1498, 0x60 }, - { 0x149C, 0x02 }, { 0x14A0, 0x80 }, { 0x14A2, 0x51 }, { 0x14A8, 0x04 }, - { 0x14AC, 0x02 }, { 0x14B0, 0x01 }, { 0x14B8, 0x10 }, { 0x14BA, 0x80 }, - { 0x14BE, 0x14 }, { 0x14C0, 0x02 }, { 0x14C4, 0x80 }, { 0x14C8, 0x8C }, - { 0x14CA, 0x0C }, { 0x14D2, 0x80 }, { 0x14D8, 0x08 }, { 0x14DC, 0x80 }, - { 0x14E8, 0x90 }, { 0x14EA, 0x09 }, { 0x14F0, 0x04 }, { 0x14F4, 0x04 }, - { 0x14F8, 0x44 }, { 0x14FA, 0x02 }, { 0x14FC, 0x40 }, { 0x14FE, 0x08 }, - { 0x1505, 0xFE }, { 0x150D, 0xF7 }, { 0x1513, 0xDF }, { 0x151B, 0xEF }, - { 0x151F, 0xDF }, { 0x1527, 0x7F }, { 0x152B, 0xBB }, { 0x152D, 0xFE }, - { 0x152F, 0xFD }, { 0x1531, 0xDF }, { 0x1539, 0xBF }, { 0x153B, 0xFE }, - { 0x1541, 0xDF }, { 0x1547, 0xBF }, { 0x154B, 0x7F }, { 0x156B, 0x7F }, - { 0x157D, 0xBF }, { 0x1585, 0xFE }, { 0x1587, 0xEF }, { 0x1591, 0xDF }, - { 0x1593, 0xEF }, { 0x1597, 0xFB }, { 0x1599, 0xF7 }, { 0x159B, 0xBF }, - { 0x15A3, 0xD5 }, { 0x15A5, 0xBF }, { 0x15B3, 0xEB }, { 0x15B5, 0xFE }, - { 0x15C3, 0xF7 }, { 0x15C5, 0xEF }, { 0x15C9, 0xFD }, { 0x15D1, 0xFE }, - { 0x15D7, 0xFE }, { 0x15D9, 0xEF }, { 0x15DD, 0xFB }, { 0x15E1, 0x7B }, - { 0x15E3, 0xBF }, { 0x15E9, 0xFD }, { 0x15F5, 0x7F }, { 0x15FB, 0xEF }, - { 0x1600, 0x20 }, { 0x160A, 0x10 }, { 0x161E, 0x04 }, { 0x1620, 0x02 }, - { 0x1630, 0x04 }, { 0x1636, 0x40 }, { 0x1640, 0x2C }, { 0x1646, 0x20 }, - { 0x1654, 0x20 }, { 0x1656, 0x18 }, { 0x1658, 0x4A }, { 0x165A, 0x20 }, - { 0x165C, 0x80 }, { 0x1664, 0x08 }, { 0x1668, 0x02 }, { 0x1670, 0x48 }, - { 0x167A, 0x20 }, { 0x1680, 0x10 }, { 0x1682, 0x08 }, { 0x1684, 0x40 }, - { 0x168C, 0x01 }, { 0x1698, 0x21 }, { 0x169E, 0x40 }, { 0x16A0, 0x03 }, - { 0x16A2, 0x40 }, { 0x16A4, 0x01 }, { 0x16A6, 0x01 }, { 0x16B6, 0x10 }, - { 0x16B8, 0x80 }, { 0x16BA, 0x02 }, { 0x16BC, 0x01 }, { 0x16D0, 0x04 }, - { 0x16D2, 0x02 }, { 0x16D8, 0x81 }, { 0x16E8, 0x03 }, { 0x16EE, 0x80 }, - { 0x16F8, 0xA4 }, { 0x1703, 0xFE }, { 0x172B, 0xEF }, { 0x172D, 0xBF }, - { 0x173B, 0xDF }, { 0x1745, 0x3D }, { 0x1749, 0xFB }, { 0x174B, 0xDF }, - { 0x1753, 0xDF }, { 0x1759, 0xFD }, { 0x1763, 0xEF }, { 0x1765, 0xBF }, - { 0x1775, 0xBF }, { 0x177D, 0xDF }, { 0x1781, 0xFE }, { 0x1789, 0xEF }, - { 0x178B, 0xFE }, { 0x1791, 0xEF }, { 0x1793, 0xDF }, { 0x1795, 0xEF }, - { 0x179B, 0xFE }, { 0x17A7, 0xFB }, { 0x17AD, 0xFE }, { 0x17B3, 0xFB }, - { 0x17B5, 0xFA }, { 0x17B9, 0xFB }, { 0x17C3, 0xFB }, { 0x17DB, 0xFB }, - { 0x17EB, 0xBF }, { 0x17F3, 0xFB }, { 0x1803, 0xBD }, { 0x1813, 0xBF }, - { 0x181B, 0x7E }, { 0x1827, 0xFD }, { 0x1833, 0xFE }, { 0x1837, 0xDB }, - { 0x1839, 0xF7 }, { 0x1845, 0xDF }, { 0x184B, 0xFD }, { 0x1853, 0xDF }, - { 0x1867, 0xFD }, { 0x186F, 0xF7 }, { 0x1879, 0xDF }, { 0x187D, 0xEF }, - { 0x1889, 0xFB }, { 0x188F, 0x9F }, { 0x1893, 0xDF }, { 0x1897, 0xFD }, - { 0x189B, 0x7F }, { 0x18A9, 0xFD }, { 0x18AF, 0xFB }, { 0x18B5, 0xBF }, - { 0x18B7, 0x2F }, { 0x18BD, 0xFE }, { 0x18BF, 0xFB }, { 0x18CD, 0xBF }, - { 0x18D3, 0xF5 }, { 0x18D5, 0x7F }, { 0x18D7, 0xFD }, { 0x18E1, 0xFD }, - { 0x18E3, 0xEF }, { 0x18E5, 0x7F }, { 0x18EB, 0xFE }, { 0x18EF, 0xDF }, - { 0x18F3, 0xEF }, { 0x18F7, 0xEF }, { 0x18FB, 0x7B }, { 0x18FD, 0xDF }, - { 0x18FF, 0xDF }, { 0x190A, 0x40 }, { 0x1910, 0x20 }, { 0x1916, 0x04 }, - { 0x1920, 0x01 }, { 0x1924, 0x02 }, { 0x1926, 0x02 }, { 0x1936, 0x40 }, - { 0x1946, 0x04 }, { 0x195A, 0x10 }, { 0x195C, 0x40 }, { 0x1968, 0x20 }, - { 0x197C, 0x08 }, { 0x1988, 0x08 }, { 0x1994, 0x20 }, { 0x1996, 0x20 }, - { 0x199A, 0x12 }, { 0x19BA, 0x08 }, { 0x19C4, 0x01 }, { 0x19CC, 0x04 }, - { 0x19D4, 0x04 }, { 0x19DA, 0x80 }, { 0x19DC, 0x40 }, { 0x19E2, 0x02 }, - { 0x19EE, 0x80 }, { 0x19F4, 0x02 }, { 0x19F6, 0x90 }, { 0x19FC, 0x02 }, - { 0x19FE, 0x1A }, { 0x1A11, 0xDF }, { 0x1A1F, 0xEE }, { 0x1A25, 0xFB }, - { 0x1A27, 0xF7 }, { 0x1A2D, 0xF5 }, { 0x1A2F, 0xFA }, { 0x1A3B, 0xEF }, - { 0x1A3F, 0xFB }, { 0x1A4B, 0xDF }, { 0x1A6F, 0xFB }, { 0x1A77, 0xF7 }, - { 0x1A81, 0xE7 }, { 0x1A8F, 0xE7 }, { 0x1A93, 0xDF }, { 0x1A9F, 0xDF }, - { 0x1AAD, 0xEF }, { 0x1AC7, 0xF7 }, { 0x1AD5, 0xFE }, { 0x1ADF, 0xFB }, - { 0x1AE3, 0xBF }, { 0x1AED, 0xF7 }, { 0x1AF1, 0xFE }, { 0x1AF9, 0xFD }, - { 0x1B1A, 0x02 }, { 0x1B26, 0x10 }, { 0x1B6C, 0x02 }, { 0x1B84, 0x04 }, - { 0x1B88, 0x40 }, { 0x1BA0, 0x08 }, { 0x1BAE, 0x08 }, { 0x1BBC, 0x02 }, - { 0x1BF4, 0x04 }, { 0x1C07, 0xDF }, { 0x1C0B, 0x7F }, { 0x1C0F, 0xDF }, - { 0x1C13, 0xBF }, { 0x1C1B, 0xFB }, { 0x1C1F, 0xEF }, { 0x1C27, 0xBD }, - { 0x1C2F, 0x77 }, { 0x1C3D, 0xEF }, { 0x1C3F, 0xF7 }, { 0x1C41, 0xF7 }, - { 0x1C43, 0xFE }, { 0x1C45, 0xDF }, { 0x1C47, 0xFE }, { 0x1C4F, 0xEF }, - { 0x1C53, 0xF3 }, { 0x1C5D, 0xDF }, { 0x1C5F, 0xBB }, { 0x1C61, 0xFB }, - { 0x1C67, 0xFE }, { 0x1C69, 0xFD }, { 0x1C6B, 0xFE }, { 0x1C73, 0xFB }, - { 0x1C7B, 0xFE }, { 0x1C7D, 0xEF }, { 0x1C83, 0xEF }, { 0x1C87, 0x3F }, - { 0x1C8B, 0xEF }, { 0x1C8F, 0xD9 }, { 0x1C97, 0xEF }, { 0x1C9B, 0xEF }, - { 0x1C9F, 0xF7 }, { 0x1CA3, 0xFD }, { 0x1CA7, 0xBF }, { 0x1CA9, 0xF7 }, - { 0x1CAB, 0xFB }, { 0x1CAD, 0xFD }, { 0x1CB1, 0x7F }, { 0x1CB3, 0xBB }, - { 0x1CB9, 0xFD }, { 0x1CBB, 0xFB }, { 0x1CC7, 0xF6 }, { 0x1CCF, 0xBF }, - { 0x1CD3, 0xEB }, { 0x1CE1, 0xBF }, { 0x1CF1, 0xFD }, { 0x1CF5, 0x7F }, - { 0x1CF7, 0xEF }, { 0x1CFD, 0xDF }, { 0x1CFF, 0xFD }, { 0x1D02, 0x04 }, - { 0x1D06, 0x40 }, { 0x1D08, 0x92 }, { 0x1D10, 0x04 }, { 0x1D1A, 0x02 }, - { 0x1D1C, 0x08 }, { 0x1D24, 0x08 }, { 0x1D30, 0x01 }, { 0x1D34, 0x04 }, - { 0x1D3A, 0x22 }, { 0x1D3E, 0x04 }, { 0x1D56, 0x10 }, { 0x1D5A, 0x02 }, - { 0x1D7E, 0x40 }, { 0x1D8E, 0x01 }, { 0x1D90, 0x20 }, { 0x1D9A, 0x10 }, - { 0x1DA0, 0x04 }, { 0x1DA4, 0x02 }, { 0x1DAC, 0x21 }, { 0x1DBE, 0x20 }, - { 0x1DC2, 0x20 }, { 0x1DD6, 0x40 }, { 0x1DD8, 0x08 }, { 0x1DF2, 0x01 }, - { 0x1DFE, 0x80 }, { 0x1E01, 0xEF }, { 0x1E05, 0xEF }, { 0x1E1D, 0xDF }, - { 0x1E27, 0xDD }, { 0x1E2F, 0x7F }, { 0x1E33, 0xF5 }, { 0x1E37, 0xFB }, - { 0x1E3F, 0xF7 }, { 0x1E4B, 0xDF }, { 0x1E5F, 0x7F }, { 0x1E71, 0xEB }, - { 0x1E7F, 0xBF }, { 0x1E8F, 0xDF }, { 0x1E97, 0xBF }, { 0x1E9B, 0xEF }, - { 0x1E9F, 0xF7 }, { 0x1EA7, 0xFD }, { 0x1EB3, 0xFB }, { 0x1EB7, 0x7F }, - { 0x1EC5, 0x7F }, { 0x1EDF, 0x7F }, { 0x1EE9, 0xF7 }, { 0x1EF3, 0xFD }, - { 0x1F02, 0x10 }, { 0x1F04, 0x05 }, { 0x1F20, 0x04 }, { 0x1F24, 0x10 }, - { 0x1F3A, 0x80 }, { 0x1F44, 0x04 }, { 0x1F46, 0x04 }, { 0x1F4E, 0x40 }, - { 0x1F50, 0x01 }, { 0x1F54, 0x03 }, { 0x1F60, 0x03 }, { 0x1F72, 0x01 }, - { 0x1F76, 0x04 }, { 0x1F7A, 0x02 }, { 0x1F86, 0x80 }, { 0x1F8C, 0x02 }, - { 0x1FA2, 0x40 }, { 0x1FB6, 0x80 }, { 0x1FC6, 0x10 }, { 0x1FCC, 0x20 }, - { 0x1FD2, 0x20 }, { 0x1FD8, 0x04 }, { 0x1FDC, 0x10 }, { 0x1FDE, 0x04 } - }; - - for (unsigned addr = 0x0000; addr < 0x0800; addr += 0x200) { - std::memset(wram + addr , 0x00, 0x100); - std::memset(wram + addr + 0x100, 0xFF, 0x100); - } - - for (unsigned addr = 0x0800; addr < 0x1000; addr += 0x200) { - std::memset(wram + addr , 0xFF, 0x100); - std::memset(wram + addr + 0x100, 0x00, 0x100); - } - - std::memcpy(wram + 0x1000, wram, 0x1000); - - for (std::size_t i = 0; i < sizeof dmgWramDumpDiff / sizeof dmgWramDumpDiff[0]; ++i) - wram[dmgWramDumpDiff[i].addr] = dmgWramDumpDiff[i].val; -} - -static void setInitialVram(unsigned char vram[], bool const cgb) { - static unsigned char const even_numbered_8010_to_81a0_dump[] = { - 0xF0, 0xF0, 0xFC, 0xFC, 0xFC, 0xFC, 0xF3, 0xF3, - 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, - 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0xF3, 0xF3, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xCF, - 0x00, 0x00, 0x0F, 0x0F, 0x3F, 0x3F, 0x0F, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x0F, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xF3, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFF, 0xFF, - 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, - 0xF3, 0xF3, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, - 0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, - 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, - 0xF3, 0xF3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, - 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, - 0x3C, 0x3C, 0x3F, 0x3F, 0x3C, 0x3C, 0x0F, 0x0F, - 0x3C, 0x3C, 0xFC, 0xFC, 0x00, 0x00, 0xFC, 0xFC, - 0xFC, 0xFC, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, - 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF0, 0xF0, - 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, - 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xC3, 0xC3, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFC, 0xFC, - 0x3C, 0x42, 0xB9, 0xA5, 0xB9, 0xA5, 0x42, 0x3C - }; - - std::memset(vram, 0, 0x4000); - - for (std::size_t i = 0; i < sizeof even_numbered_8010_to_81a0_dump; ++i) { - vram[0x0010 + i * 2] = even_numbered_8010_to_81a0_dump[i]; - } - - if (!cgb) { - unsigned i = 1; - - for (unsigned addr = 0x1904; addr < 0x1910; ++addr) - vram[addr] = i++; - - vram[0x1910] = 0x19; - - for (unsigned addr = 0x1924; addr < 0x1930; ++addr) - vram[addr] = i++; - } -} - -static void setInitialCgbIoamhram(unsigned char ioamhram[]) { - static unsigned char const feaxDump[0x60] = { - 0x08, 0x01, 0xEF, 0xDE, 0x06, 0x4A, 0xCD, 0xBD, - 0x08, 0x01, 0xEF, 0xDE, 0x06, 0x4A, 0xCD, 0xBD, - 0x08, 0x01, 0xEF, 0xDE, 0x06, 0x4A, 0xCD, 0xBD, - 0x08, 0x01, 0xEF, 0xDE, 0x06, 0x4A, 0xCD, 0xBD, - 0x00, 0x90, 0xF7, 0x7F, 0xC0, 0xB1, 0xBC, 0xFB, - 0x00, 0x90, 0xF7, 0x7F, 0xC0, 0xB1, 0xBC, 0xFB, - 0x00, 0x90, 0xF7, 0x7F, 0xC0, 0xB1, 0xBC, 0xFB, - 0x00, 0x90, 0xF7, 0x7F, 0xC0, 0xB1, 0xBC, 0xFB, - 0x24, 0x13, 0xFD, 0x3A, 0x10, 0x10, 0xAD, 0x45, - 0x24, 0x13, 0xFD, 0x3A, 0x10, 0x10, 0xAD, 0x45, - 0x24, 0x13, 0xFD, 0x3A, 0x10, 0x10, 0xAD, 0x45, - 0x24, 0x13, 0xFD, 0x3A, 0x10, 0x10, 0xAD, 0x45 - }; - - static unsigned char const ffxxDump[0x100] = { - 0xCF, 0x00, 0x7C, 0xFF, 0x00, 0x00, 0x00, 0xF8, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, - 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, - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, - 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7E, 0xFF, 0xFE, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xC0, 0xFF, 0xC1, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, - 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x8F, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, - 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, - 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, - 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, - 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, - 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E, - 0x45, 0xEC, 0x42, 0xFA, 0x08, 0xB7, 0x07, 0x5D, - 0x01, 0xF5, 0xC0, 0xFF, 0x08, 0xFC, 0x00, 0xE5, - 0x0B, 0xF8, 0xC2, 0xCA, 0xF4, 0xF9, 0x0D, 0x7F, - 0x44, 0x6D, 0x19, 0xFE, 0x46, 0x97, 0x33, 0x5E, - 0x08, 0xFF, 0xD1, 0xFF, 0xC6, 0x8B, 0x24, 0x74, - 0x12, 0xFC, 0x00, 0x9F, 0x94, 0xB7, 0x06, 0xD5, - 0x40, 0x7A, 0x20, 0x9E, 0x04, 0x5F, 0x41, 0x2F, - 0x3D, 0x77, 0x36, 0x75, 0x81, 0x8A, 0x70, 0x3A, - 0x98, 0xD1, 0x71, 0x02, 0x4D, 0x01, 0xC1, 0xFF, - 0x0D, 0x00, 0xD3, 0x05, 0xF9, 0x00, 0x0B, 0x00 - }; - - std::memset(ioamhram, 0x00, 0x0A0); - std::memcpy(ioamhram + 0x0A0, feaxDump, sizeof feaxDump); - std::memcpy(ioamhram + 0x100, ffxxDump, sizeof ffxxDump); -} - -static void setInitialDmgIoamhram(unsigned char ioamhram[]) { - static unsigned char const oamDump[0xA0] = { - 0xBB, 0xD8, 0xC4, 0x04, 0xCD, 0xAC, 0xA1, 0xC7, - 0x7D, 0x85, 0x15, 0xF0, 0xAD, 0x19, 0x11, 0x6A, - 0xBA, 0xC7, 0x76, 0xF8, 0x5C, 0xA0, 0x67, 0x0A, - 0x7B, 0x75, 0x56, 0x3B, 0x65, 0x5C, 0x4D, 0xA3, - 0x00, 0x05, 0xD7, 0xC9, 0x1B, 0xCA, 0x11, 0x6D, - 0x38, 0xE7, 0x13, 0x2A, 0xB1, 0x10, 0x72, 0x4D, - 0xA7, 0x47, 0x13, 0x89, 0x7C, 0x62, 0x5F, 0x90, - 0x64, 0x2E, 0xD3, 0xEF, 0xAB, 0x01, 0x15, 0x85, - 0xE8, 0x2A, 0x6E, 0x4A, 0x1F, 0xBE, 0x49, 0xB1, - 0xE6, 0x0F, 0x93, 0xE2, 0xB6, 0x87, 0x5D, 0x35, - 0xD8, 0xD4, 0x4A, 0x45, 0xCA, 0xB3, 0x33, 0x74, - 0x18, 0xC1, 0x16, 0xFB, 0x8F, 0xA4, 0x8E, 0x70, - 0xCD, 0xB4, 0x4A, 0xDC, 0xE6, 0x34, 0x32, 0x41, - 0xF9, 0x84, 0x6A, 0x99, 0xEC, 0x92, 0xF1, 0x8B, - 0x5D, 0xA5, 0x09, 0xCF, 0x3A, 0x93, 0xBC, 0xE0, - 0x15, 0x19, 0xE4, 0xB6, 0x9A, 0x04, 0x3B, 0xC1, - 0x96, 0xB7, 0x56, 0x85, 0x6A, 0xAA, 0x1E, 0x2A, - 0x80, 0xEE, 0xE7, 0x46, 0x76, 0x8B, 0x0D, 0xBA, - 0x24, 0x40, 0x42, 0x05, 0x0E, 0x04, 0x20, 0xA6, - 0x5E, 0xC1, 0x97, 0x7E, 0x44, 0x05, 0x01, 0xA9 - }; - - static unsigned char const ffxxDump[0x100] = { - 0xCF, 0x00, 0x7E, 0xFF, 0xD3, 0x00, 0x00, 0xF8, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, - 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, - 0x71, 0x72, 0xD5, 0x91, 0x58, 0xBB, 0x2A, 0xFA, - 0xCF, 0x3C, 0x54, 0x75, 0x48, 0xCF, 0x8F, 0xD9, - 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, - 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x2B, 0x0B, 0x64, 0x2F, 0xAF, 0x15, 0x60, 0x6D, - 0x61, 0x4E, 0xAC, 0x45, 0x0F, 0xDA, 0x92, 0xF3, - 0x83, 0x38, 0xE4, 0x4E, 0xA7, 0x6C, 0x38, 0x58, - 0xBE, 0xEA, 0xE5, 0x81, 0xB4, 0xCB, 0xBF, 0x7B, - 0x59, 0xAD, 0x50, 0x13, 0x5E, 0xF6, 0xB3, 0xC1, - 0xDC, 0xDF, 0x9E, 0x68, 0xD7, 0x59, 0x26, 0xF3, - 0x62, 0x54, 0xF8, 0x36, 0xB7, 0x78, 0x6A, 0x22, - 0xA7, 0xDD, 0x88, 0x15, 0xCA, 0x96, 0x39, 0xD3, - 0xE6, 0x55, 0x6E, 0xEA, 0x90, 0x76, 0xB8, 0xFF, - 0x50, 0xCD, 0xB5, 0x1B, 0x1F, 0xA5, 0x4D, 0x2E, - 0xB4, 0x09, 0x47, 0x8A, 0xC4, 0x5A, 0x8C, 0x4E, - 0xE7, 0x29, 0x50, 0x88, 0xA8, 0x66, 0x85, 0x4B, - 0xAA, 0x38, 0xE7, 0x6B, 0x45, 0x3E, 0x30, 0x37, - 0xBA, 0xC5, 0x31, 0xF2, 0x71, 0xB4, 0xCF, 0x29, - 0xBC, 0x7F, 0x7E, 0xD0, 0xC7, 0xC3, 0xBD, 0xCF, - 0x59, 0xEA, 0x39, 0x01, 0x2E, 0x00, 0x69, 0x00 - }; - - std::memcpy(ioamhram , oamDump, sizeof oamDump); - std::memset(ioamhram + 0x0A0, 0x00, 0x060); - std::memcpy(ioamhram + 0x100, ffxxDump, sizeof ffxxDump); -} - -} // anon namespace - -void gambatte::setInitState(SaveState &state, const bool cgb) { - static unsigned char const cgbObjpDump[0x40] = { - 0x00, 0x00, 0xF2, 0xAB, - 0x61, 0xC2, 0xD9, 0xBA, - 0x88, 0x6E, 0xDD, 0x63, - 0x28, 0x27, 0xFB, 0x9F, - 0x35, 0x42, 0xD6, 0xD4, - 0x50, 0x48, 0x57, 0x5E, - 0x23, 0x3E, 0x3D, 0xCA, - 0x71, 0x21, 0x37, 0xC0, - 0xC6, 0xB3, 0xFB, 0xF9, - 0x08, 0x00, 0x8D, 0x29, - 0xA3, 0x20, 0xDB, 0x87, - 0x62, 0x05, 0x5D, 0xD4, - 0x0E, 0x08, 0xFE, 0xAF, - 0x20, 0x02, 0xD7, 0xFF, - 0x07, 0x6A, 0x55, 0xEC, - 0x83, 0x40, 0x0B, 0x77 - }; - - state.cpu.cycleCounter = 8; - state.cpu.pc = 0; - state.cpu.sp = 0; - state.cpu.a = 0; - state.cpu.b = 0; - state.cpu.c = 0; - state.cpu.d = 0; - state.cpu.e = 0; - state.cpu.f = 0; - state.cpu.h = 0; - state.cpu.l = 0; - state.cpu.opcode = 0x00; - state.cpu.prefetched = false; - state.cpu.skip = false; - state.mem.biosMode = true; - - std::memset(state.mem.sram.ptr, 0xFF, state.mem.sram.size()); - - setInitialVram(state.mem.vram.ptr, cgb); - - if (cgb) { - setInitialCgbWram(state.mem.wram.ptr); - setInitialCgbIoamhram(state.mem.ioamhram.ptr); - } else { - setInitialDmgWram(state.mem.wram.ptr); - setInitialDmgIoamhram(state.mem.ioamhram.ptr); - } - - state.mem.ioamhram.ptr[0x104] = 0; - state.mem.ioamhram.ptr[0x140] = 0; - state.mem.ioamhram.ptr[0x144] = 0x00; - - // DIV, TIMA, and the PSG frame sequencer are clocked by bits of the - // cycle counter less divLastUpdate (equivalent to a counter that is - // reset on DIV write). - state.mem.divLastUpdate = 0; - state.mem.timaLastUpdate = 0; - state.mem.tmatime = disabled_time; - state.mem.nextSerialtime = disabled_time; - state.mem.lastOamDmaUpdate = disabled_time; - state.mem.unhaltTime = disabled_time; - state.mem.minIntTime = 0; - state.mem.rombank = 1; - state.mem.dmaSource = 0; - state.mem.dmaDestination = 0; - state.mem.rambank = 0; - state.mem.oamDmaPos = 0xFE; - state.mem.haltHdmaState = 0; - state.mem.IME = false; - state.mem.halted = false; - state.mem.enableRam = false; - state.mem.rambankMode = false; - state.mem.hdmaTransfer = false; - state.mem.stopped = false; - - - for (int i = 0x00; i < 0x40; i += 0x02) { - state.ppu.bgpData.ptr[i ] = 0xFF; - state.ppu.bgpData.ptr[i + 1] = 0x7F; - } - - std::memcpy(state.ppu.objpData.ptr, cgbObjpDump, sizeof cgbObjpDump); - - if (!cgb) { - state.ppu.bgpData.ptr[0] = state.mem.ioamhram.get()[0x147]; - state.ppu.objpData.ptr[0] = state.mem.ioamhram.get()[0x148]; - state.ppu.objpData.ptr[1] = state.mem.ioamhram.get()[0x149]; - } - - for (int pos = 0; pos < 80; ++pos) - state.ppu.oamReaderBuf.ptr[pos] = state.mem.ioamhram.ptr[(pos * 2 & ~3) | (pos & 1)]; - - std::fill_n(state.ppu.oamReaderSzbuf.ptr, 40, false); - std::memset(state.ppu.spAttribList, 0, sizeof state.ppu.spAttribList); - std::memset(state.ppu.spByte0List, 0, sizeof state.ppu.spByte0List); - std::memset(state.ppu.spByte1List, 0, sizeof state.ppu.spByte1List); - state.ppu.videoCycles = 0; - state.ppu.enableDisplayM0Time = state.cpu.cycleCounter; - state.ppu.winYPos = 0xFF; - state.ppu.xpos = 0; - state.ppu.endx = 0; - state.ppu.reg0 = 0; - state.ppu.reg1 = 0; - state.ppu.tileword = 0; - state.ppu.ntileword = 0; - state.ppu.attrib = 0; - state.ppu.nattrib = 0; - state.ppu.state = 0; - state.ppu.nextSprite = 0; - state.ppu.currentSprite = 0; - state.ppu.lyc = state.mem.ioamhram.get()[0x145]; - state.ppu.m0lyc = state.mem.ioamhram.get()[0x145]; - state.ppu.weMaster = false; - state.ppu.winDrawState = 0; - state.ppu.wscx = 0; - state.ppu.lastM0Time = 1234; - state.ppu.nextM0Irq = 0; - state.ppu.oldWy = state.mem.ioamhram.get()[0x14A]; - state.ppu.pendingLcdstatIrq = false; - state.ppu.notCgbDmg = true; - - // spu.cycleCounter >> 12 & 7 represents the frame sequencer position. - state.spu.cycleCounter = state.cpu.cycleCounter >> 1; - state.spu.lastUpdate = 0; - - state.spu.ch1.sweep.counter = SoundUnit::counter_disabled; - state.spu.ch1.sweep.shadow = 0; - state.spu.ch1.sweep.nr0 = 0; - state.spu.ch1.sweep.neg = false; - state.spu.ch1.duty.nextPosUpdate = SoundUnit::counter_disabled; - state.spu.ch1.duty.pos = 0; - state.spu.ch1.duty.high = false; - state.spu.ch1.duty.nr3 = 0; - state.spu.ch1.env.counter = SoundUnit::counter_disabled; - state.spu.ch1.env.volume = 0; - state.spu.ch1.lcounter.counter = SoundUnit::counter_disabled; - state.spu.ch1.lcounter.lengthCounter = 0; - state.spu.ch1.nr4 = 0; - state.spu.ch1.master = false; - - state.spu.ch2.duty.nextPosUpdate = SoundUnit::counter_disabled; - state.spu.ch2.duty.nr3 = 0; - state.spu.ch2.duty.pos = 0; - state.spu.ch2.duty.high = false; - state.spu.ch2.env.counter = SoundUnit::counter_disabled; - state.spu.ch2.env.volume = 0; - state.spu.ch2.lcounter.counter = SoundUnit::counter_disabled; - state.spu.ch2.lcounter.lengthCounter = 0; - state.spu.ch2.nr4 = 0; - state.spu.ch2.master = false; - - std::memcpy(state.spu.ch3.waveRam.ptr, state.mem.ioamhram.get() + 0x130, 0x10); - state.spu.ch3.lcounter.counter = SoundUnit::counter_disabled; - state.spu.ch3.lcounter.lengthCounter = 0x100; - state.spu.ch3.waveCounter = SoundUnit::counter_disabled; - state.spu.ch3.lastReadTime = SoundUnit::counter_disabled; - state.spu.ch3.nr3 = 0; - state.spu.ch3.nr4 = 0; - state.spu.ch3.wavePos = 0; - state.spu.ch3.sampleBuf = 0; - state.spu.ch3.master = false; - - state.spu.ch4.lfsr.counter = state.spu.cycleCounter + 4; - state.spu.ch4.lfsr.reg = 0xFF; - state.spu.ch4.env.counter = SoundUnit::counter_disabled; - state.spu.ch4.env.volume = 0; - state.spu.ch4.lcounter.counter = SoundUnit::counter_disabled; - state.spu.ch4.lcounter.lengthCounter = 0; - state.spu.ch4.nr4 = 0; - state.spu.ch4.master = false; - - state.time.seconds = 0; - state.time.lastTimeSec = Time::now().tv_sec; - state.time.lastTimeUsec = Time::now().tv_usec; - state.time.lastCycles = state.cpu.cycleCounter; - - state.rtc.haltTime = state.time.seconds; - state.rtc.dataDh = 0; - state.rtc.dataDl = 0; - state.rtc.dataH = 0; - state.rtc.dataM = 0; - state.rtc.dataS = 0; - state.rtc.lastLatchData = false; - - state.huc3.haltTime = state.time.seconds; - state.huc3.dataTime = 0; - state.huc3.writingTime = 0; - state.huc3.halted = false; - state.huc3.shift = 0; - state.huc3.ramValue = 1; - state.huc3.modeflag = 2; // huc3_none -} diff --git a/libgambatte/src/initstate.h b/libgambatte/src/initstate.h deleted file mode 100644 index 13b0f28e16..0000000000 --- a/libgambatte/src/initstate.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (C) 2008 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef INITSTATE_H -#define INITSTATE_H - -#include - -namespace gambatte { - -void setInitState(struct SaveState &state, bool cgb); -} - -#endif diff --git a/libgambatte/src/insertion_sort.h b/libgambatte/src/insertion_sort.h deleted file mode 100644 index 8b76d9385a..0000000000 --- a/libgambatte/src/insertion_sort.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef INSERTION_SORT_H -#define INSERTION_SORT_H - -#include - -template -void insertionSort(T *const start, T *const end, Less less) { - if (start >= end) - return; - - T *a = start; - - while (++a < end) { - T const e = *a; - T *b = a; - - while (b != start && less(e, *(b - 1))) { - *b = *(b - 1); - b = b - 1; - } - - *b = e; - } -} - -template -inline void insertionSort(T *start, T *end) { - insertionSort(start, end, std::less()); -} - -#endif /*INSERTION_SORT_H*/ diff --git a/libgambatte/src/interrupter.h b/libgambatte/src/interrupter.h deleted file mode 100644 index 5daa808835..0000000000 --- a/libgambatte/src/interrupter.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef INTERRUPTER_H -#define INTERRUPTER_H - -#include -#include - -namespace gambatte { - - struct GsCode { - unsigned short address; - unsigned char value; - unsigned char type; - }; - - class Memory; - - class Interrupter { - public: - Interrupter(unsigned short& sp, unsigned short& pc, unsigned char& opcode, bool& prefetched); - void prefetch(unsigned long cc, Memory& mem); - unsigned long interrupt(unsigned long cycleCounter, Memory& memory); - void setGameShark(std::string const& codes); - - private: - unsigned short& sp_; - unsigned short& pc_; - unsigned char& opcode_; - bool& prefetched_; - std::vector gsCodes_; - - void applyVblankCheats(unsigned long cc, Memory& mem); - }; - -} - -#endif diff --git a/libgambatte/src/interruptrequester.cpp b/libgambatte/src/interruptrequester.cpp deleted file mode 100644 index eaa0fce20f..0000000000 --- a/libgambatte/src/interruptrequester.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// -// Copyright (C) 2010 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "interruptrequester.h" -#include "savestate.h" - -namespace gambatte { - -InterruptRequester::InterruptRequester() -: eventTimes_(disabled_time) -, minIntTime_(0) -, ifreg_(0) -, iereg_(0) -{ -} - -void InterruptRequester::loadState(SaveState const &state) { - minIntTime_ = state.mem.minIntTime; - ifreg_ = state.mem.ioamhram.get()[0x10F]; - iereg_ = state.mem.ioamhram.get()[0x1FF] & 0x1F; - intFlags_.set(state.mem.IME, state.mem.halted); - - eventTimes_.setValue(intFlags_.imeOrHalted() && pendingIrqs() - ? minIntTime_ - : static_cast(disabled_time)); -} - -void InterruptRequester::resetCc(unsigned long oldCc, unsigned long newCc) { - minIntTime_ = minIntTime_ < oldCc ? 0 : minIntTime_ - (oldCc - newCc); - - if (eventTimes_.value(intevent_interrupts) != disabled_time) - eventTimes_.setValue(minIntTime_); -} - -void InterruptRequester::ei(unsigned long cc) { - intFlags_.setIme(); - minIntTime_ = cc + 1; - - if (pendingIrqs()) - eventTimes_.setValue(minIntTime_); -} - -void InterruptRequester::di() { - intFlags_.unsetIme(); - - if (!intFlags_.imeOrHalted()) - eventTimes_.setValue(disabled_time); -} - -void InterruptRequester::halt() { - intFlags_.setHalted(); - - if (pendingIrqs()) - eventTimes_.setValue(minIntTime_); -} - -void InterruptRequester::unhalt() { - intFlags_.unsetHalted(); - - if (!intFlags_.imeOrHalted()) - eventTimes_.setValue(disabled_time); -} - -void InterruptRequester::flagIrq(unsigned bit) { - ifreg_ |= bit; - - if (intFlags_.imeOrHalted() && pendingIrqs()) - eventTimes_.setValue(minIntTime_); -} - -void InterruptRequester::flagIrq(unsigned bit, unsigned long cc) { - unsigned const prevPending = pendingIrqs(); - ifreg_ |= bit; - - if (!prevPending && pendingIrqs() && intFlags_.imeOrHalted()) { - minIntTime_ = std::max(minIntTime_, cc); - eventTimes_.setValue(minIntTime_); - } -} - -void InterruptRequester::setIereg(unsigned iereg) { - iereg_ = iereg & 0x1F; - - if (intFlags_.imeOrHalted()) { - eventTimes_.setValue(pendingIrqs() - ? minIntTime_ - : static_cast(disabled_time)); - } -} - -void InterruptRequester::setIfreg(unsigned ifreg) { - ifreg_ = ifreg; - - if (intFlags_.imeOrHalted()) { - eventTimes_.setValue(pendingIrqs() - ? minIntTime_ - : static_cast(disabled_time)); - } -} - -void InterruptRequester::setMinIntTime(unsigned long cc) { - minIntTime_ = cc; - - if (eventTimes_.value(intevent_interrupts) < minIntTime_) - eventTimes_.setValue(minIntTime_); -} - -SYNCFUNC(InterruptRequester) -{ - SSS(eventTimes_); - NSS(minIntTime_); - NSS(ifreg_); - NSS(iereg_); - NSS(intFlags_.flags_); -} - -} diff --git a/libgambatte/src/interruptrequester.h b/libgambatte/src/interruptrequester.h deleted file mode 100644 index 1b8aa3230f..0000000000 --- a/libgambatte/src/interruptrequester.h +++ /dev/null @@ -1,105 +0,0 @@ -// -// Copyright (C) 2010 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef INTERRUPT_REQUESTER_H -#define INTERRUPT_REQUESTER_H - -#include "counterdef.h" -#include "minkeeper.h" -#include "newstate.h" - -namespace gambatte { - -struct SaveState; - -enum IntEventId { intevent_unhalt, - intevent_end, - intevent_blit, - intevent_serial, - intevent_oam, - intevent_dma, - intevent_tima, - intevent_video, - intevent_interrupts, intevent_last = intevent_interrupts }; - -class InterruptRequester { -public: - InterruptRequester(); - void loadState(SaveState const &); - void resetCc(unsigned long oldCc, unsigned long newCc); - unsigned ifreg() const { return ifreg_; } - unsigned iereg() const { return iereg_; } - unsigned pendingIrqs() const { return ifreg_ & iereg_; } - bool ime() const { return intFlags_.ime(); } - bool halted() const { return intFlags_.halted(); } - void ei(unsigned long cc); - void di(); - void halt(); - void unhalt(); - void flagIrq(unsigned bit); - void flagIrq(unsigned bit, unsigned long cc); - void ackIrq(unsigned bit) { ifreg_ &= ~bit; } - void setIereg(unsigned iereg); - void setIfreg(unsigned ifreg); - void setMinIntTime(unsigned long cc); - - IntEventId minEventId() const { return static_cast(eventTimes_.min()); } - unsigned long minEventTime() const { return eventTimes_.minValue(); } - template void setEventTime(unsigned long value) { eventTimes_.setValue(value); } - void setEventTime(IntEventId id, unsigned long value) { eventTimes_.setValue(id, value); } - unsigned long eventTime(IntEventId id) const { return eventTimes_.value(id); } - -private: - class IntFlags { - friend class InterruptRequester; - public: - IntFlags() : flags_(0) {} - bool ime() const { return flags_ & flag_ime; } - bool halted() const { return flags_ & flag_halted; } - bool imeOrHalted() const { return flags_; } - void setIme() { flags_ |= flag_ime; } - void unsetIme() { flags_ &= ~(1u * flag_ime); } - void setHalted() { flags_ |= flag_halted; } - void unsetHalted() { flags_ &= ~(1u * flag_halted); } - void set(bool ime, bool halted) { flags_ = halted * flag_halted + ime * flag_ime; } - - private: - unsigned char flags_; - enum { flag_ime = 1, flag_halted = 2 }; - }; - - MinKeeper eventTimes_; - unsigned long minIntTime_; - unsigned ifreg_; - unsigned iereg_; - IntFlags intFlags_; - - -public: - templatevoid SyncState(NewState *ns); -}; - -inline void flagHdmaReq(InterruptRequester &intreq) { intreq.setEventTime(0); } -inline void flagGdmaReq(InterruptRequester &intreq) { intreq.setEventTime(1); } -inline void ackDmaReq(InterruptRequester &intreq) { intreq.setEventTime(disabled_time); } -inline bool hdmaReqFlagged(InterruptRequester const &intreq) { return intreq.eventTime(intevent_dma) == 0; } -inline bool gdmaReqFlagged(InterruptRequester const &intreq) { return intreq.eventTime(intevent_dma) == 1; } - -} - -#endif diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp deleted file mode 100644 index 3424ffe96a..0000000000 --- a/libgambatte/src/mem/cartridge.cpp +++ /dev/null @@ -1,904 +0,0 @@ -// -// Copyright (C) 2007-2010 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "cartridge.h" -#include "../savestate.h" -#include -#include -#include -#include - -using namespace gambatte; - -namespace { - -unsigned toMulti64Rombank(unsigned rombank) { - return (rombank >> 1 & 0x30) | (rombank & 0xF); -} - -class DefaultMbc : public Mbc { -public: - virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const { - return (addr < rombank_size()) == (bank == 0); - } - - virtual void SyncState(NewState *ns, bool isReader) - { - } -}; - -class Mbc0 : public DefaultMbc { -public: - explicit Mbc0(MemPtrs &memptrs) - : memptrs_(memptrs) - , enableRam_(false) - { - } - - virtual unsigned char curRomBank() const { - return 1; - } - - virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) { - if (p < rambank_size()) { - enableRam_ = (data & 0xF) == 0xA; - memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0); - } - } - - virtual void loadState(SaveState::Mem const &ss) { - enableRam_ = ss.enableRam; - memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0); - } - -private: - MemPtrs &memptrs_; - bool enableRam_; - -public: - virtual void SyncState(NewState *ns, bool isReader) - { - NSS(enableRam_); - } -}; - -inline unsigned rambanks(MemPtrs const &memptrs) { - return (memptrs.rambankdataend() - memptrs.rambankdata()) / rambank_size(); -} - -inline unsigned rombanks(MemPtrs const &memptrs) { - return (memptrs.romdataend() - memptrs.romdata()) / rombank_size(); -} - -class Mbc1 : public DefaultMbc { -public: - explicit Mbc1(MemPtrs &memptrs) - : memptrs_(memptrs) - , rombank_(1) - , rambank_(0) - , enableRam_(false) - , rambankMode_(false) - { - } - - virtual unsigned char curRomBank() const { - return rombank_; - } - - virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) { - switch (p >> 13 & 3) { - case 0: - enableRam_ = (data & 0xF) == 0xA; - setRambank(); - break; - case 1: - rombank_ = rambankMode_ ? data & 0x1F : (rombank_ & 0x60) | (data & 0x1F); - setRombank(); - break; - case 2: - if (rambankMode_) { - rambank_ = data & 3; - setRambank(); - } else { - rombank_ = (data << 5 & 0x60) | (rombank_ & 0x1F); - setRombank(); - } - - break; - case 3: - // Should this take effect immediately rather? - rambankMode_ = data & 1; - break; - } - } - - virtual void loadState(SaveState::Mem const &ss) { - rombank_ = ss.rombank; - rambank_ = ss.rambank; - enableRam_ = ss.enableRam; - rambankMode_ = ss.rambankMode; - setRambank(); - setRombank(); - } - -private: - MemPtrs &memptrs_; - unsigned char rombank_; - unsigned char rambank_; - bool enableRam_; - bool rambankMode_; - - static unsigned adjustedRombank(unsigned bank) { return bank & 0x1F ? bank : bank | 1; } - - void setRambank() const { - memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, - rambank_ & (rambanks(memptrs_) - 1)); - } - - void setRombank() const { memptrs_.setRombank(adjustedRombank(rombank_) & (rombanks(memptrs_) - 1)); } - - -public: - virtual void SyncState(NewState *ns, bool isReader) - { - NSS(rombank_); - NSS(rambank_); - NSS(enableRam_); - NSS(rambankMode_); - } -}; - -class Mbc1Multi64 : public Mbc { -public: - explicit Mbc1Multi64(MemPtrs &memptrs) - : memptrs_(memptrs) - , rombank_(1) - , enableRam_(false) - , rombank0Mode_(false) - { - } - - virtual unsigned char curRomBank() const { - return rombank_; - } - - virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) { - switch (p >> 13 & 3) { - case 0: - enableRam_ = (data & 0xF) == 0xA; - memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0); - break; - case 1: - rombank_ = (rombank_ & 0x60) | (data & 0x1F); - memptrs_.setRombank(rombank0Mode_ - ? adjustedRombank(toMulti64Rombank(rombank_)) - : adjustedRombank(rombank_) & (rombanks(memptrs_) - 1)); - break; - case 2: - rombank_ = (data << 5 & 0x60) | (rombank_ & 0x1F); - setRombank(); - break; - case 3: - rombank0Mode_ = data & 1; - setRombank(); - break; - } - } - - virtual void loadState(SaveState::Mem const &ss) { - rombank_ = ss.rombank; - enableRam_ = ss.enableRam; - rombank0Mode_ = ss.rambankMode; - memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0); - setRombank(); - } - - virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const { - return (addr < 0x4000) == ((bank & 0xF) == 0); - } - -private: - MemPtrs &memptrs_; - unsigned char rombank_; - bool enableRam_; - bool rombank0Mode_; - - static unsigned adjustedRombank(unsigned bank) { return bank & 0x1F ? bank : bank | 1; } - - void setRombank() const { - if (rombank0Mode_) { - unsigned const rb = toMulti64Rombank(rombank_); - memptrs_.setRombank0(rb & 0x30); - memptrs_.setRombank(adjustedRombank(rb)); - } else { - memptrs_.setRombank0(0); - memptrs_.setRombank(adjustedRombank(rombank_) & (rombanks(memptrs_) - 1)); - } - } - -public: - virtual void SyncState(NewState *ns, bool isReader) - { - NSS(rombank_); - NSS(enableRam_); - NSS(rombank0Mode_); - } -}; - -class Mbc2 : public DefaultMbc { -public: - explicit Mbc2(MemPtrs &memptrs) - : memptrs_(memptrs) - , rombank_(1) - , enableRam_(false) - { - } - - virtual unsigned char curRomBank() const { - return rombank_; - } - - virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) { - switch (p & 0x6100) { - case 0x0000: - enableRam_ = (data & 0xF) == 0xA; - memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0); - break; - case 0x2100: - rombank_ = data & 0xF; - memptrs_.setRombank(rombank_ & (rombanks(memptrs_) - 1)); - break; - } - } - - virtual void loadState(SaveState::Mem const &ss) { - rombank_ = ss.rombank; - enableRam_ = ss.enableRam; - memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0); - memptrs_.setRombank(rombank_ & (rombanks(memptrs_) - 1)); - } - -private: - MemPtrs &memptrs_; - unsigned char rombank_; - bool enableRam_; - -public: - virtual void SyncState(NewState *ns, bool isReader) - { - NSS(rombank_); - NSS(enableRam_); - } -}; - -class Mbc3 : public DefaultMbc { -public: - Mbc3(MemPtrs &memptrs, Rtc *const rtc) - : memptrs_(memptrs) - , rtc_(rtc) - , rombank_(1) - , rambank_(0) - , enableRam_(false) - { - } - - virtual unsigned char curRomBank() const { - return rombank_; - } - - virtual void romWrite(unsigned const p, unsigned const data, unsigned long const cc) { - switch (p >> 13 & 3) { - case 0: - enableRam_ = (data & 0xF) == 0xA; - setRambank(); - break; - case 1: - rombank_ = data & 0x7F; - setRombank(); - break; - case 2: - rambank_ = data; - setRambank(); - break; - case 3: - if (rtc_) - rtc_->latch(data, cc); - - break; - } - } - - virtual void loadState(SaveState::Mem const &ss) { - rombank_ = ss.rombank; - rambank_ = ss.rambank; - enableRam_ = ss.enableRam; - setRambank(); - setRombank(); - } - -private: - MemPtrs &memptrs_; - Rtc *const rtc_; - unsigned char rombank_; - unsigned char rambank_; - bool enableRam_; - - void setRambank() const { - unsigned flags = enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0; - - if (rtc_) { - rtc_->set(enableRam_, rambank_); - - if (rtc_->activeData()) - flags |= MemPtrs::rtc_en; - } - - memptrs_.setRambank(flags, rambank_ & (rambanks(memptrs_) - 1)); - } - - void setRombank() const { - memptrs_.setRombank(std::max(rombank_ & (rombanks(memptrs_) - 1), 1u)); - } - -public: - virtual void SyncState(NewState *ns, bool isReader) - { - NSS(rombank_); - NSS(rambank_); - NSS(enableRam_); - } -}; - -class HuC1 : public DefaultMbc { -public: - explicit HuC1(MemPtrs &memptrs) - : memptrs_(memptrs) - , rombank_(1) - , rambank_(0) - , enableRam_(false) - , rambankMode_(false) - { - } - - virtual unsigned char curRomBank() const { - return rombank_; - } - - virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) { - switch (p >> 13 & 3) { - case 0: - enableRam_ = (data & 0xF) == 0xA; - setRambank(); - break; - case 1: - rombank_ = data & 0x3F; - setRombank(); - break; - case 2: - rambank_ = data & 3; - rambankMode_ ? setRambank() : setRombank(); - break; - case 3: - rambankMode_ = data & 1; - setRambank(); - setRombank(); - break; - } - } - - virtual void loadState(SaveState::Mem const &ss) { - rombank_ = ss.rombank; - rambank_ = ss.rambank; - enableRam_ = ss.enableRam; - rambankMode_ = ss.rambankMode; - setRambank(); - setRombank(); - } - -private: - MemPtrs &memptrs_; - unsigned char rombank_; - unsigned char rambank_; - bool enableRam_; - bool rambankMode_; - - void setRambank() const { - memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : MemPtrs::read_en, - rambankMode_ ? rambank_ & (rambanks(memptrs_) - 1) : 0); - } - - void setRombank() const { - memptrs_.setRombank((rambankMode_ ? rombank_ : rambank_ << 6 | rombank_) - & (rombanks(memptrs_) - 1)); - } - -public: - virtual void SyncState(NewState *ns, bool isReader) - { - NSS(rombank_); - NSS(rambank_); - NSS(enableRam_); - NSS(rambankMode_); - } -}; - -class HuC3 : public DefaultMbc { -public: - HuC3(MemPtrs& memptrs, HuC3Chip* const huc3) - : memptrs_(memptrs) - , huc3_(huc3) - , rombank_(1) - , rambank_(0) - , ramflag_(0) - { - } - - virtual unsigned char curRomBank() const { - return rombank_; - } - - virtual bool disabledRam() const { - return false; - } - - virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) { - switch (p >> 13 & 3) { - case 0: - ramflag_ = data; - //printf("[HuC3] set ramflag to %02X\n", data); - setRambank(); - break; - case 1: - //printf("[HuC3] set rombank to %02X\n", data); - rombank_ = data; - setRombank(); - break; - case 2: - //printf("[HuC3] set rambank to %02X\n", data); - rambank_ = data; - setRambank(); - break; - case 3: - // GEST: "programs will write 1 here" - break; - } - } - - virtual void SyncState(NewState *ns, bool isReader) - { - NSS(rombank_); - NSS(rambank_); - NSS(ramflag_); - } - - virtual void loadState(SaveState::Mem const& ss) { - rombank_ = ss.rombank; - rambank_ = ss.rambank; - ramflag_ = ss.HuC3RAMflag; - setRambank(); - setRombank(); - } - -private: - MemPtrs& memptrs_; - HuC3Chip* const huc3_; - unsigned char rombank_; - unsigned char rambank_; - unsigned char ramflag_; - - void setRambank() const { - huc3_->setRamflag(ramflag_); - - unsigned flags; - if (ramflag_ >= 0x0B && ramflag_ < 0x0F) { - // System registers mode - flags = MemPtrs::read_en | MemPtrs::write_en | MemPtrs::rtc_en; - } - else if (ramflag_ == 0x0A || ramflag_ > 0x0D) { - // Read/write mode - flags = MemPtrs::read_en | MemPtrs::write_en; - } - else { - // Read-only mode ?? - flags = MemPtrs::read_en; - } - - memptrs_.setRambank(flags, rambank_ & (rambanks(memptrs_) - 1)); - } - - void setRombank() const { - memptrs_.setRombank(std::max(rombank_ & (rombanks(memptrs_) - 1), 1u)); - } -}; - -class Mbc5 : public DefaultMbc { -public: - explicit Mbc5(MemPtrs &memptrs) - : memptrs_(memptrs) - , rombank_(1) - , rambank_(0) - , enableRam_(false) - { - } - - virtual unsigned char curRomBank() const { - return rombank_; - } - - virtual void romWrite(unsigned const p, unsigned const data, unsigned long const /*cc*/) { - switch (p >> 13 & 3) { - case 0: - enableRam_ = (data & 0xF) == 0xA; - setRambank(); - break; - case 1: - rombank_ = p < 0x3000 - ? (rombank_ & 0x100) | data - : (data << 8 & 0x100) | (rombank_ & 0xFF); - setRombank(); - break; - case 2: - rambank_ = data & 0xF; - setRambank(); - break; - case 3: - break; - } - } - - virtual void loadState(SaveState::Mem const &ss) { - rombank_ = ss.rombank; - rambank_ = ss.rambank; - enableRam_ = ss.enableRam; - setRambank(); - setRombank(); - } - -private: - MemPtrs &memptrs_; - unsigned short rombank_; - unsigned char rambank_; - bool enableRam_; - - void setRambank() const { - memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, - rambank_ & (rambanks(memptrs_) - 1)); - } - - void setRombank() const { memptrs_.setRombank(rombank_ & (rombanks(memptrs_) - 1)); } - -public: - virtual void SyncState(NewState *ns, bool isReader) - { - NSS(rombank_); - NSS(rambank_); - NSS(enableRam_); - } -}; - -std::string stripExtension(std::string const& str) { - std::string::size_type const lastDot = str.find_last_of('.'); - std::string::size_type const lastSlash = str.find_last_of('/'); - - if (lastDot != std::string::npos && (lastSlash == std::string::npos || lastSlash < lastDot)) - return str.substr(0, lastDot); - - return str; -} - -std::string stripDir(std::string const& str) { - std::string::size_type const lastSlash = str.find_last_of('/'); - if (lastSlash != std::string::npos) - return str.substr(lastSlash + 1); - - return str; -} - -void enforce8bit(unsigned char* data, std::size_t size) { - if (static_cast(0x100)) - while (size--) - *data++ &= 0xFF; -} - -unsigned pow2ceil(unsigned n) { - --n; - n |= n >> 1; - n |= n >> 2; - n |= n >> 4; - n |= n >> 8; - ++n; - - return n; -} - -bool presumedMulti64Mbc1(unsigned char const header[], unsigned rombanks) { - return header[0x147] == 1 && header[0x149] == 0 && rombanks == 64; -} - -bool hasBattery(unsigned char headerByte0x147) { - switch (headerByte0x147) { - case 0x03: - case 0x06: - case 0x09: - case 0x0F: - case 0x10: - case 0x13: - case 0x1B: - case 0x1E: - case 0xFE: // huc3 - case 0xFF: - return true; - } - - return false; -} - -bool hasRtc(unsigned headerByte0x147) { - switch (headerByte0x147) { - case 0x0F: - case 0x10: - case 0xFE: // huc3 - return true; - } - - return false; -} - -int asHex(char c) { - return c >= 'A' ? c - 'A' + 0xA : c - '0'; -} - -} - -Cartridge::Cartridge() -: rtc_(time_) -, huc3_(time_) -{ -} - -void Cartridge::setStatePtrs(SaveState &state) { - state.mem.vram.set(memptrs_.vramdata(), memptrs_.vramdataend() - memptrs_.vramdata()); - state.mem.sram.set(memptrs_.rambankdata(), memptrs_.rambankdataend() - memptrs_.rambankdata()); - state.mem.wram.set(memptrs_.wramdata(0), memptrs_.wramdataend() - memptrs_.wramdata(0)); -} - -void Cartridge::loadState(SaveState const &state) { - huc3_.loadState(state); - rtc_.loadState(state); - time_.loadState(state); - mbc_->loadState(state.mem); -} - -static bool isMbc2(unsigned char h147) { return h147 == 5 || h147 == 6; } - -static unsigned numRambanksFromH14x(unsigned char h147, unsigned char h149) { - switch (h149) { - case 0x00: return isMbc2(h147) ? 1 : 0; - case 0x01: - case 0x02: return 1; - case 0x03: return 4; - case 0x04: return 16; - case 0x05: return 8; - } - - return 4; -} - -LoadRes Cartridge::loadROM(char const *romfiledata, unsigned romfilelength, bool const forceDmg, bool const multicartCompat) { - enum Cartridgetype { type_plain, - type_mbc1, - type_mbc2, - type_mbc3, - type_mbc5, - type_huc1, - type_huc3 }; - Cartridgetype type = type_plain; - unsigned rambanks = 1; - unsigned rombanks = 2; - bool cgb = false; - - { - unsigned char header[0x150]; - if (romfilelength >= sizeof header) - std::memcpy(header, romfiledata, sizeof header); - else - return LOADRES_IO_ERROR; - - switch (header[0x0147]) { - case 0x00: type = type_plain; break; - case 0x01: - case 0x02: - case 0x03: type = type_mbc1; break; - case 0x05: - case 0x06: type = type_mbc2; break; - case 0x08: - case 0x09: type = type_plain; break; - case 0x0B: - case 0x0C: - case 0x0D: return LOADRES_UNSUPPORTED_MBC_MMM01; - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: type = type_mbc3; break; - case 0x15: - case 0x16: - case 0x17: return LOADRES_UNSUPPORTED_MBC_MBC4; - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: type = type_mbc5; break; - case 0x20: return LOADRES_UNSUPPORTED_MBC_MBC6; - case 0x22: return LOADRES_UNSUPPORTED_MBC_MBC7; - case 0xFC: return LOADRES_UNSUPPORTED_MBC_POCKET_CAMERA; - case 0xFD: return LOADRES_UNSUPPORTED_MBC_TAMA5; - case 0xFE: type = type_huc3; break; - case 0xFF: type = type_huc1; break; - default: return LOADRES_BAD_FILE_OR_UNKNOWN_MBC; - } - - /*switch (header[0x0148]) { - case 0x00: rombanks = 2; break; - case 0x01: rombanks = 4; break; - case 0x02: rombanks = 8; break; - case 0x03: rombanks = 16; break; - case 0x04: rombanks = 32; break; - case 0x05: rombanks = 64; break; - case 0x06: rombanks = 128; break; - case 0x07: rombanks = 256; break; - case 0x08: rombanks = 512; break; - case 0x52: rombanks = 72; break; - case 0x53: rombanks = 80; break; - case 0x54: rombanks = 96; break; - default: return -1; - }*/ - - rambanks = numRambanksFromH14x(header[0x147], header[0x149]); - cgb = !forceDmg; - } - std::size_t const filesize = romfilelength; - rombanks = std::max(pow2ceil(filesize / rombank_size()), 2u); - - mbc_.reset(); - memptrs_.reset(rombanks, rambanks, cgb ? 8 : 2); - rtc_.set(false, 0); - huc3_.set(false); - - std::memcpy(memptrs_.romdata(), romfiledata, (filesize / rombank_size() * rombank_size())); - std::memset(memptrs_.romdata() + filesize / rombank_size() * rombank_size(), - 0xFF, - (rombanks - filesize / rombank_size()) * rombank_size()); - enforce8bit(memptrs_.romdata(), rombanks * rombank_size()); - - switch (type) { - case type_plain: mbc_.reset(new Mbc0(memptrs_)); break; - case type_mbc1: - if (multicartCompat && presumedMulti64Mbc1(memptrs_.romdata(), rombanks)) { - mbc_.reset(new Mbc1Multi64(memptrs_)); - } else - mbc_.reset(new Mbc1(memptrs_)); - - break; - case type_mbc2: mbc_.reset(new Mbc2(memptrs_)); break; - case type_mbc3: - mbc_.reset(new Mbc3(memptrs_, hasRtc(memptrs_.romdata()[0x147]) ? &rtc_ : 0)); - break; - case type_mbc5: mbc_.reset(new Mbc5(memptrs_)); break; - case type_huc1: mbc_.reset(new HuC1(memptrs_)); break; - case type_huc3: - huc3_.set(true); - mbc_.reset(new HuC3(memptrs_, &huc3_)); - break; - } - - return LOADRES_OK; -} - -void Cartridge::loadSavedata(char const *data, unsigned long const cc) { - if (hasBattery(memptrs_.romdata()[0x147])) { - int length = memptrs_.rambankdataend() - memptrs_.rambankdata(); - std::memcpy(memptrs_.rambankdata(), data, length); - data += length; - enforce8bit(memptrs_.rambankdata(), length); - } - - if (hasRtc(memptrs_.romdata()[0x147])) { - timeval basetime; - basetime.tv_sec = (*data++); - basetime.tv_sec = basetime.tv_sec << 8 | (*data++); - basetime.tv_sec = basetime.tv_sec << 8 | (*data++); - basetime.tv_sec = basetime.tv_sec << 8 | (*data++); - basetime.tv_usec = (*data++); - basetime.tv_usec = basetime.tv_usec << 8 | (*data++); - basetime.tv_usec = basetime.tv_usec << 8 | (*data++); - basetime.tv_usec = basetime.tv_usec << 8 | (*data++); - - time_.setBaseTime(basetime, cc); - } -} - -int Cartridge::saveSavedataLength() { - int ret = 0; - if (hasBattery(memptrs_.romdata()[0x147])) { - ret = memptrs_.rambankdataend() - memptrs_.rambankdata(); - } - if (hasRtc(memptrs_.romdata()[0x147])) { - ret += 8; - } - return ret; -} - -void Cartridge::saveSavedata(char *dest, unsigned long const cc) { - if (hasBattery(memptrs_.romdata()[0x147])) { - int length = memptrs_.rambankdataend() - memptrs_.rambankdata(); - std::memcpy(dest, memptrs_.rambankdata(), length); - dest += length; - } - - if (hasRtc(memptrs_.romdata()[0x147])) { - timeval basetime = time_.baseTime(cc); - *dest++ = (basetime.tv_sec >> 24 & 0xFF); - *dest++ = (basetime.tv_sec >> 16 & 0xFF); - *dest++ = (basetime.tv_sec >> 8 & 0xFF); - *dest++ = (basetime.tv_sec & 0xFF); - *dest++ = (basetime.tv_usec >> 24 & 0xFF); - *dest++ = (basetime.tv_usec >> 16 & 0xFF); - *dest++ = (basetime.tv_usec >> 8 & 0xFF); - *dest++ = (basetime.tv_usec & 0xFF); - } -} - -bool Cartridge::getMemoryArea(int which, unsigned char **data, int *length) const { - if (!data || !length) - return false; - - switch (which) - { - case 0: - *data = memptrs_.vramdata(); - *length = memptrs_.vramdataend() - memptrs_.vramdata(); - return true; - case 1: - *data = memptrs_.romdata(); - *length = memptrs_.romdataend() - memptrs_.romdata(); - return true; - case 2: - *data = memptrs_.wramdata(0); - *length = memptrs_.wramdataend() - memptrs_.wramdata(0); - return true; - case 3: - *data = memptrs_.rambankdata(); - *length = memptrs_.rambankdataend() - memptrs_.rambankdata(); - return true; - - default: - return false; - } - return false; -} - -SYNCFUNC(Cartridge) -{ - SSS(huc3_); - SSS(memptrs_); - SSS(time_); - SSS(rtc_); - TSS(mbc_); -} diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h deleted file mode 100644 index 9c575148fe..0000000000 --- a/libgambatte/src/mem/cartridge.h +++ /dev/null @@ -1,103 +0,0 @@ -// -// Copyright (C) 2007-2010 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef CARTRIDGE_H -#define CARTRIDGE_H - -#include "loadres.h" -#include "memptrs.h" -#include "time.h" -#include "rtc.h" -#include "huc3.h" -#include "savestate.h" -#include -#include -#include -#include "newstate.h" - -namespace gambatte { - -class Mbc { -public: - virtual ~Mbc() {} - virtual unsigned char curRomBank() const = 0; - virtual void romWrite(unsigned P, unsigned data, unsigned long cycleCounter) = 0; - virtual void loadState(SaveState::Mem const &ss) = 0; - virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0; - - templatevoid SyncState(NewState *ns) - { - // can't have virtual templates, so.. - SyncState(ns, isReader); - } - virtual void SyncState(NewState *ns, bool isReader) = 0; -}; - -class Cartridge { -public: - Cartridge(); - void setStatePtrs(SaveState &); - void loadState(SaveState const &); - bool loaded() const { return mbc_.get(); } - unsigned char const * rmem(unsigned area) const { return memptrs_.rmem(area); } - unsigned char * wmem(unsigned area) const { return memptrs_.wmem(area); } - unsigned char * vramdata() const { return memptrs_.vramdata(); } - unsigned char * romdata(unsigned area) const { return memptrs_.romdata(area); } - unsigned char * wramdata(unsigned area) const { return memptrs_.wramdata(area); } - unsigned char const * rdisabledRam() const { return memptrs_.rdisabledRam(); } - unsigned char const * rsrambankptr() const { return memptrs_.rsrambankptr(); } - unsigned char * wsrambankptr() const { return memptrs_.wsrambankptr(); } - unsigned char * vrambankptr() const { return memptrs_.vrambankptr(); } - OamDmaSrc oamDmaSrc() const { return memptrs_.oamDmaSrc(); } - bool isInOamDmaConflictArea(unsigned p) const { return memptrs_.isInOamDmaConflictArea(p); } - void setVrambank(unsigned bank) { memptrs_.setVrambank(bank); } - void setWrambank(unsigned bank) { memptrs_.setWrambank(bank); } - void setOamDmaSrc(OamDmaSrc oamDmaSrc) { memptrs_.setOamDmaSrc(oamDmaSrc); } - unsigned char curRomBank() const { return mbc_->curRomBank(); } - void mbcWrite(unsigned addr, unsigned data, unsigned long const cc) { mbc_->romWrite(addr, data, cc); } - bool isCgb() const { return gambatte::isCgb(memptrs_); } - void resetCc(unsigned long const oldCc, unsigned long const newCc) { time_.resetCc(oldCc, newCc); } - void speedChange(unsigned long const cc) { time_.speedChange(cc); } - void setTimeMode(bool useCycles, unsigned long const cc) { time_.setTimeMode(useCycles, cc); } - void setRtcDivisorOffset(long const rtcDivisorOffset) { time_.setRtcDivisorOffset(rtcDivisorOffset); } - void rtcWrite(unsigned data, unsigned long const cc) { rtc_.write(data, cc); } - unsigned char rtcRead() const { return *rtc_.activeData(); } - void loadSavedata(char const *data, unsigned long cycleCounter); - int saveSavedataLength(); - void saveSavedata(char *dest, unsigned long cycleCounter); - bool getMemoryArea(int which, unsigned char **data, int *length) const; - LoadRes loadROM(char const *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat); - char const * romTitle() const { return reinterpret_cast(memptrs_.romdata() + 0x134); } - bool isHuC3() const { return huc3_.isHuC3(); } - unsigned char HuC3Read(unsigned p, unsigned long const cc) { return huc3_.read(p, cc); } - void HuC3Write(unsigned p, unsigned data, unsigned long const cc) { huc3_.write(p, data, cc); } - -private: - MemPtrs memptrs_; - Time time_; - Rtc rtc_; - HuC3Chip huc3_; - std::unique_ptr mbc_; - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/mem/huc3.cpp b/libgambatte/src/mem/huc3.cpp deleted file mode 100644 index 785555fd53..0000000000 --- a/libgambatte/src/mem/huc3.cpp +++ /dev/null @@ -1,201 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "huc3.h" -#include "../savestate.h" -#include - -namespace gambatte { - -HuC3Chip::HuC3Chip(Time &time) -: time_(time) -, haltTime_(0) -, dataTime_(0) -, writingTime_(0) -, ramValue_(0) -, shift_(0) -, ramflag_(0) -, modeflag_(HUC3_NONE) -, irBaseCycle_(0) -, enabled_(false) -, lastLatchData_(false) -, halted_(false) -, irReceivingPulse_(false) -{ -} - -void HuC3Chip::doLatch(unsigned long const cc) { - std::uint32_t tmp = time(cc); - - unsigned minute = (tmp / 60) % 1440; - unsigned day = (tmp / 86400) & 0xFFF; - dataTime_ = (day << 12) | minute; -} - -//void HuC3Chip::setStatePtrs(SaveState &state) { -// state.huc3.haltTime.set(haltTime_, sizeof haltTime_); -// state.huc3.dataTime.set(dataTime_, sizeof dataTime_); -// state.huc3.writingTime.set(writingTime_, sizeof writingTime_); -// state.huc3.irBaseCycle.set(irBaseCycle_, sizeof irBaseCycle_); -// state.huc3.halted.set(halted_, sizeof halted_); -// state.huc3.shift.set(shift_, sizeof shift_); -// state.huc3.ramValue.set(ramValue_, sizeof ramValue_); -// state.huc3.modeflag.set(modeflag_, sizeof modeflag_); -// state.huc3.irReceivingPulse.set(irReceivingPulse_, sizeof irReceivingPulse_); -//} - -void HuC3Chip::loadState(SaveState const &state) { - haltTime_ = state.huc3.haltTime; - dataTime_ = state.huc3.dataTime; - ramValue_ = state.huc3.ramValue; - shift_ = state.huc3.shift; - halted_ = state.huc3.halted; - modeflag_ = state.huc3.modeflag; - writingTime_ = state.huc3.writingTime; - irBaseCycle_ = state.huc3.irBaseCycle; - irReceivingPulse_ = state.huc3.irReceivingPulse; -} - -unsigned char HuC3Chip::read(unsigned /*p*/, unsigned long const cc) { - // should only reach here with ramflag = 0B-0E - if(ramflag_ == 0x0E) { - // INFRARED - if(!irReceivingPulse_) { - irReceivingPulse_ = true; - irBaseCycle_ = cc; - } - unsigned long cyclesSinceStart = cc - irBaseCycle_; - unsigned char modulation = (cyclesSinceStart/105) & 1; // 4194304 Hz CPU, 40000 Hz remote signal - unsigned long timeUs = cyclesSinceStart*36/151; // actually *1000000/4194304 - // sony protocol - if(timeUs < 10000) { - // initialization allowance - return 0; - } - else if(timeUs < 10000 + 2400) { - // initial mark - return modulation; - } - else if(timeUs < 10000 + 2400 + 600) { - // initial space - return 0; - } - else { - // send data - timeUs -= 13000; - // write 20 bits (any 20 seem to do) - unsigned int data = 0xFFFFF; - for(unsigned long mask = 1UL << (20-1); mask; mask >>= 1) { - unsigned int markTime = (data & mask) ? 1200 : 600; - if(timeUs < markTime) { return modulation; } - timeUs -= markTime; - if(timeUs < 600) { return 0; } - timeUs -= 600; - } - - return 0; - } - } - if(ramflag_ < 0x0B || ramflag_ > 0x0D) { - //printf("[HuC3] error, hit huc3 read with ramflag=%02X\n", ramflag_); - return 0xFF; - } - if(ramflag_ == 0x0D) return 1; - else return ramValue_; -} - -void HuC3Chip::write(unsigned /*p*/, unsigned data, unsigned long const cc) { - // as above - if(ramflag_ == 0x0B) { - // command - switch(data & 0xF0) { - case 0x10: - // read time - doLatch(cc); - if(modeflag_ == HUC3_READ) { - ramValue_ = (dataTime_ >> shift_) & 0x0F; - shift_ += 4; - if(shift_ > 24) shift_ = 0; - } - break; - case 0x30: - // write time - if(modeflag_ == HUC3_WRITE) { - if(shift_ == 0) writingTime_ = 0; - if(shift_ < 24) { - writingTime_ |= (data & 0x0F) << shift_; - shift_ += 4; - if(shift_ == 24) { - updateTime(cc); - modeflag_ = HUC3_READ; - } - } - } - break; - case 0x40: - // some kind of mode shift - switch(data & 0x0F) { - case 0x0: - // shift reset? - shift_ = 0; - break; - case 0x3: - // write time? - modeflag_ = HUC3_WRITE; - shift_ = 0; - break; - case 0x7: - modeflag_ = HUC3_READ; - shift_ = 0; - break; - // others are unimplemented so far - } - break; - case 0x50: - // ??? - break; - case 0x60: - modeflag_ = HUC3_READ; // ??? - break; - } - } - // do nothing for 0C/0D yet -} - -void HuC3Chip::updateTime(unsigned long const cc) { - unsigned minute = (writingTime_ & 0xFFF) % 1440; - unsigned day = (writingTime_ & 0xFFF000) >> 12; - std::uint32_t seconds = minute*60 + day*86400; - time_.reset(seconds, cc); - haltTime_ = seconds; - -} -SYNCFUNC(HuC3Chip) -{ - NSS(haltTime_); - NSS(dataTime_); - NSS(writingTime_); - NSS(ramValue_); - NSS(shift_); - NSS(halted_); - NSS(modeflag_); - NSS(irBaseCycle_); - NSS(irReceivingPulse_); -} -} - diff --git a/libgambatte/src/mem/huc3.h b/libgambatte/src/mem/huc3.h deleted file mode 100644 index 00b0db38a0..0000000000 --- a/libgambatte/src/mem/huc3.h +++ /dev/null @@ -1,76 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef HuC3Chip_H -#define HuC3Chip_H - -enum -{ - HUC3_READ = 0, - HUC3_WRITE = 1, - HUC3_NONE = 2 -}; - -#include "time.h" - -namespace gambatte { - - struct SaveState; - - class HuC3Chip { - public: - HuC3Chip(Time &time); - //void setStatePtrs(SaveState &); - void loadState(SaveState const& state); - void setRamflag(unsigned char ramflag) { ramflag_ = ramflag; irReceivingPulse_ = false; } - bool isHuC3() const { return enabled_; } - - void set(bool enabled) { - enabled_ = enabled; - } - - unsigned char read(unsigned p, unsigned long const cc); - void write(unsigned p, unsigned data, unsigned long cycleCounter); - - private: - Time &time_; - std::uint32_t haltTime_; - unsigned dataTime_; - unsigned writingTime_; - unsigned char ramValue_; - unsigned char shift_; - unsigned char ramflag_; - unsigned char modeflag_; - unsigned long irBaseCycle_; - bool enabled_; - bool lastLatchData_; - bool halted_; - bool irReceivingPulse_; - - void doLatch(unsigned long cycleCounter); - void updateTime(unsigned long cycleCounter); - - std::uint32_t time(unsigned long const cc) { - return halted_ ? haltTime_ : time_.get(cc); - } - public: - templatevoid SyncState(NewState* ns); - }; -} - -#endif \ No newline at end of file diff --git a/libgambatte/src/mem/memptrs.cpp b/libgambatte/src/mem/memptrs.cpp deleted file mode 100644 index 82fd17a9bb..0000000000 --- a/libgambatte/src/mem/memptrs.cpp +++ /dev/null @@ -1,241 +0,0 @@ -// -// Copyright (C) 2007-2010 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "memptrs.h" -#include -#include - -using namespace gambatte; - -namespace { - - template struct OamDmaConflictMap; - template struct OamDmaConflictMap { enum { r = 0xFCFF }; }; - template struct OamDmaConflictMap { enum { r = 0xFCFF }; }; - template struct OamDmaConflictMap { enum { r = 0x0300 }; }; - template struct OamDmaConflictMap { enum { r = cgb ? 0xF000 : 0xFCFF }; }; - template struct OamDmaConflictMap { enum { r = cgb ? 0xFCFF : 0x0000 }; }; - - template - bool isInOamDmaConflictArea(OamDmaSrc src, unsigned p) - { - static unsigned short const m[] = { - OamDmaConflictMap::r, - OamDmaConflictMap::r, - OamDmaConflictMap::r, - OamDmaConflictMap::r, - OamDmaConflictMap::r, - 0 }; - return p < mm_oam_begin && (m[src] >> (p >> 12) & 1); - } - - template - void disconnectOamDmaAreas(unsigned char const* (&rmem)[0x10], unsigned char* (&wmem)[0x10]) - { - if (OamDmaConflictMap::r & 0x00FF) - std::fill_n(rmem, 8, static_cast(0)); - if (OamDmaConflictMap::r & 0x0C00) - rmem[0xB] = rmem[0xA] = wmem[0xB] = wmem[0xA] = 0; - if (OamDmaConflictMap::r & 0x7000) - rmem[0xE] = rmem[0xD] = rmem[0xC] = wmem[0xE] = wmem[0xD] = wmem[0xC] = 0; - } - - template - void disconnectOamDmaAreas(unsigned char const* (&rmem)[0x10], unsigned char* (&wmem)[0x10], - OamDmaSrc src) - { - switch (src) { - case oam_dma_src_rom: disconnectOamDmaAreas(rmem, wmem); break; - case oam_dma_src_sram: disconnectOamDmaAreas(rmem, wmem); break; - case oam_dma_src_vram: disconnectOamDmaAreas(rmem, wmem); break; - case oam_dma_src_wram: disconnectOamDmaAreas(rmem, wmem); break; - case oam_dma_src_invalid: disconnectOamDmaAreas(rmem, wmem); break; - case oam_dma_src_off: break; - } - } - -} // unnamed namespace. - -MemPtrs::MemPtrs() -: rmem_() -, wmem_() -, romdata_() -, wramdata_() -, vrambankptr_(0) -, rsrambankptr_(0) -, wsrambankptr_(0) -, rambankdata_(0) -, wramdataend_(0) -, oamDmaSrc_(oam_dma_src_off) -, curRomBank_(1) -, memchunk_len(0) -{ -} - -void MemPtrs::reset(unsigned const rombanks, unsigned const rambanks, unsigned const wrambanks) { - int const num_disabled_ram_areas = 2; - memchunk_.reset( - pre_rom_pad_size() - + rombanks * rombank_size() - + max_num_vrambanks * vrambank_size() - + rambanks * rambank_size() - + wrambanks * wrambank_size() - + num_disabled_ram_areas * rambank_size()); - - romdata_[0] = romdata(); - rambankdata_ = romdata_[0] + rombanks * rombank_size() + max_num_vrambanks * vrambank_size(); - wramdata_[0] = rambankdata_ + rambanks * rambank_size(); - wramdataend_ = wramdata_[0] + wrambanks * wrambank_size(); - - std::fill_n(rdisabledRamw(), rambank_size(), 0xFF); - - oamDmaSrc_ = oam_dma_src_off; - rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0]; - rmem_[0xC] = wmem_[0xC] = wramdata_[0] - mm_wram_begin; - rmem_[0xE] = wmem_[0xE] = wramdata_[0] - mm_wram_mirror_begin; - setRombank(1); - setRambank(0, 0); - setVrambank(0); - setWrambank(1); - - // we save only the ram areas - memchunk_saveoffs = vramdata() - memchunk_; - memchunk_savelen = wramdataend() - memchunk_ - memchunk_saveoffs; -} - -void MemPtrs::setRombank0(unsigned bank) { - romdata_[0] = romdata() + bank * rombank_size(); - rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0]; - disconnectOamDmaAreas(); -} - -void MemPtrs::setRombank(unsigned bank) { - curRomBank_ = bank; - romdata_[1] = romdata() + bank * rombank_size() - mm_rom1_begin; - rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1]; - disconnectOamDmaAreas(); -} - -void MemPtrs::setRambank(unsigned const flags, unsigned const rambank) { - unsigned char* srambankptr = 0; - if (!(flags & rtc_en)) { - srambankptr = rambankdata() != rambankdataend() - ? rambankdata_ + rambank * rambank_size() - mm_sram_begin - : wdisabledRam() - mm_sram_begin; - } - - rsrambankptr_ = (flags & read_en) && srambankptr != wdisabledRam() - mm_sram_begin - ? srambankptr - : rdisabledRamw() - mm_sram_begin; - wsrambankptr_ = flags & write_en - ? srambankptr - : wdisabledRam() - mm_sram_begin; - rmem_[0xB] = rmem_[0xA] = rsrambankptr_; - wmem_[0xB] = wmem_[0xA] = wsrambankptr_; - disconnectOamDmaAreas(); -} - -void MemPtrs::setWrambank(unsigned bank) { - wramdata_[1] = wramdata_[0] + (bank & 0x07 ? bank & 0x07 : 1) * wrambank_size(); - rmem_[0xD] = wmem_[0xD] = wramdata_[1] - mm_wram1_begin; - disconnectOamDmaAreas(); -} - -void MemPtrs::setOamDmaSrc(OamDmaSrc oamDmaSrc) { - rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0]; - rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1]; - rmem_[0xB] = rmem_[0xA] = rsrambankptr_; - wmem_[0xB] = wmem_[0xA] = wsrambankptr_; - rmem_[0xC] = wmem_[0xC] = wramdata_[0] - mm_wram_begin; - rmem_[0xD] = wmem_[0xD] = wramdata_[1] - mm_wram1_begin; - rmem_[0xE] = wmem_[0xE] = wramdata_[0] - mm_wram_mirror_begin; - - oamDmaSrc_ = oamDmaSrc; - disconnectOamDmaAreas(); -} - -void MemPtrs::disconnectOamDmaAreas() { - return isCgb(*this) - ? ::disconnectOamDmaAreas(rmem_, wmem_, oamDmaSrc_) - : ::disconnectOamDmaAreas(rmem_, wmem_, oamDmaSrc_); -} - -bool MemPtrs::isInOamDmaConflictArea(unsigned p) const -{ - return isCgb(*this) - ? ::isInOamDmaConflictArea(oamDmaSrc_, p) - : ::isInOamDmaConflictArea(oamDmaSrc_, p); -} - -// all pointers here are relative to memchunk_ -#define MSS(a) RSS(a,memchunk_) -#define MSL(a) RSL(a,memchunk_) - -SYNCFUNC(MemPtrs) -{ - NSS(memchunk_len); - NSS(memchunk_saveoffs); - NSS(memchunk_savelen); - - PSS(memchunk_ + memchunk_saveoffs, memchunk_savelen); - - MSS(rmem_[0x0]); - MSS(wmem_[0x0]); - MSS(rmem_[0x1]); - MSS(wmem_[0x1]); - MSS(rmem_[0x2]); - MSS(wmem_[0x2]); - MSS(rmem_[0x3]); - MSS(wmem_[0x3]); - MSS(rmem_[0x4]); - MSS(wmem_[0x4]); - MSS(rmem_[0x5]); - MSS(wmem_[0x5]); - MSS(rmem_[0x6]); - MSS(wmem_[0x6]); - MSS(rmem_[0x7]); - MSS(wmem_[0x7]); - MSS(rmem_[0x8]); - MSS(wmem_[0x8]); - MSS(rmem_[0x9]); - MSS(wmem_[0x9]); - MSS(rmem_[0xa]); - MSS(wmem_[0xa]); - MSS(rmem_[0xb]); - MSS(wmem_[0xb]); - MSS(rmem_[0xc]); - MSS(wmem_[0xc]); - MSS(rmem_[0xd]); - MSS(wmem_[0xd]); - MSS(rmem_[0xe]); - MSS(wmem_[0xe]); - MSS(rmem_[0xf]); - MSS(wmem_[0xf]); - MSS(romdata_[0]); - MSS(romdata_[1]); - MSS(wramdata_[0]); - MSS(wramdata_[1]); - MSS(vrambankptr_); - MSS(rsrambankptr_); - MSS(wsrambankptr_); - MSS(rambankdata_); - MSS(wramdataend_); - NSS(oamDmaSrc_); - NSS(curRomBank_); -} - diff --git a/libgambatte/src/mem/memptrs.h b/libgambatte/src/mem/memptrs.h deleted file mode 100644 index 6191624481..0000000000 --- a/libgambatte/src/mem/memptrs.h +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright (C) 2007-2010 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef MEMPTRS_H -#define MEMPTRS_H - -#include "newstate.h" -#include "array.h" - -namespace gambatte { - -enum OamDmaSrc { - oam_dma_src_rom, - oam_dma_src_sram, - oam_dma_src_vram, - oam_dma_src_wram, - oam_dma_src_invalid, - oam_dma_src_off }; - -enum { - mm_rom_begin = 0x0000, - mm_rom1_begin = 0x4000, - mm_vram_begin = 0x8000, - mm_sram_begin = 0xA000, - mm_wram_begin = 0xC000, - mm_wram1_begin = 0xD000, - mm_wram_mirror_begin = 0xE000, - mm_oam_begin = 0xFE00, - mm_io_begin = 0xFF00, - mm_hram_begin = 0xFF80 }; - -enum { max_num_vrambanks = 2 }; -inline std::size_t rambank_size() { return 0x2000; } -inline std::size_t rombank_size() { return 0x4000; } -inline std::size_t vrambank_size() { return 0x2000; } -inline std::size_t wrambank_size() { return 0x1000; } - -class MemPtrs { -public: - enum RamFlag { read_en = 1, write_en = 2, rtc_en = 4 }; - - MemPtrs(); - void reset(unsigned rombanks, unsigned rambanks, unsigned wrambanks); - - unsigned char const* rmem(unsigned area) const { return rmem_[area]; } - unsigned char* wmem(unsigned area) const { return wmem_[area]; } - unsigned char* romdata() const { return memchunk_ + pre_rom_pad_size(); } - unsigned char* romdata(unsigned area) const { return romdata_[area]; } - unsigned char* romdataend() const { return rambankdata_ - max_num_vrambanks * vrambank_size(); } - unsigned char* vramdata() const { return romdataend(); } - unsigned char* vramdataend() const { return rambankdata_; } - unsigned char* rambankdata() const { return rambankdata_; } - unsigned char* rambankdataend() const { return wramdata_[0]; } - unsigned char* wramdata(unsigned area) const { return wramdata_[area]; } - unsigned char* wramdataend() const { return wramdataend_; } - unsigned char const* rdisabledRam() const { return rdisabledRamw(); } - unsigned char const* rsrambankptr() const { return rsrambankptr_; } - unsigned char* wsrambankptr() const { return wsrambankptr_; } - unsigned char* vrambankptr() const { return vrambankptr_; } - OamDmaSrc oamDmaSrc() const { return oamDmaSrc_; } - bool isInOamDmaConflictArea(unsigned p) const; - - void setRombank0(unsigned bank); - void setRombank(unsigned bank); - void setRambank(unsigned ramFlags, unsigned rambank); - void setVrambank(unsigned bank) { vrambankptr_ = vramdata() + bank * vrambank_size() - mm_vram_begin; } - void setWrambank(unsigned bank); - void setOamDmaSrc(OamDmaSrc oamDmaSrc); - -private: - unsigned char const *rmem_[0x10]; - unsigned char *wmem_[0x10]; - unsigned char *romdata_[2]; - unsigned char *wramdata_[2]; - unsigned char *vrambankptr_; - unsigned char *rsrambankptr_; - unsigned char *wsrambankptr_; - SimpleArray memchunk_; - unsigned char *rambankdata_; - unsigned char *wramdataend_; - OamDmaSrc oamDmaSrc_; - - unsigned curRomBank_; - - int memchunk_len; - int memchunk_saveoffs; - int memchunk_savelen; - - static std::size_t pre_rom_pad_size() { return mm_rom1_begin; } - void disconnectOamDmaAreas(); - unsigned char * rdisabledRamw() const { return wramdataend_; } - unsigned char * wdisabledRam() const { return wramdataend_ + rambank_size(); } - -public: - templatevoid SyncState(NewState *ns); -}; - -inline bool isCgb(MemPtrs const& memptrs) { - int const num_cgb_wrambanks = 8; - std::size_t const wramsize = memptrs.wramdataend() - memptrs.wramdata(0); - return wramsize == num_cgb_wrambanks * wrambank_size(); -} - -} - -#endif diff --git a/libgambatte/src/mem/rtc.cpp b/libgambatte/src/mem/rtc.cpp deleted file mode 100644 index 5b79c04d7b..0000000000 --- a/libgambatte/src/mem/rtc.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "rtc.h" -#include "../savestate.h" -#include - -namespace gambatte { - -Rtc::Rtc(Time &time) -: time_(time) -, activeData_(0) -, activeSet_(0) -, haltTime_(0) -, index_(5) -, dataDh_(0) -, dataDl_(0) -, dataH_(0) -, dataM_(0) -, dataS_(0) -, enabled_(false) -, lastLatchData_(false) -{ -} - -void Rtc::doLatch(unsigned long const cc) { - std::uint32_t tmp = time(cc); - - if (tmp >= 0x200 * 86400) { - tmp %= 0x200 * 86400; - time_.set(tmp, cc); - dataDh_ |= 0x80; - } - - dataDl_ = (tmp / 86400) & 0xFF; - dataDh_ &= 0xFE; - dataDh_ |= ((tmp / 86400) & 0x100) >> 8; - tmp %= 86400; - - dataH_ = tmp / 3600; - tmp %= 3600; - - dataM_ = tmp / 60; - tmp %= 60; - - dataS_ = tmp; -} - -void Rtc::doSwapActive() { - if (!enabled_ || index_ > 4) { - activeData_ = 0; - activeSet_ = 0; - } else switch (index_) { - case 0x00: - activeData_ = &dataS_; - activeSet_ = &Rtc::setS; - break; - case 0x01: - activeData_ = &dataM_; - activeSet_ = &Rtc::setM; - break; - case 0x02: - activeData_ = &dataH_; - activeSet_ = &Rtc::setH; - break; - case 0x03: - activeData_ = &dataDl_; - activeSet_ = &Rtc::setDl; - break; - case 0x04: - activeData_ = &dataDh_; - activeSet_ = &Rtc::setDh; - break; - } -} - -void Rtc::loadState(SaveState const &state) { - haltTime_ = state.rtc.haltTime; - dataDh_ = state.rtc.dataDh; - dataDl_ = state.rtc.dataDl; - dataH_ = state.rtc.dataH; - dataM_ = state.rtc.dataM; - dataS_ = state.rtc.dataS; - lastLatchData_ = state.rtc.lastLatchData; - doSwapActive(); -} - -void Rtc::setDh(unsigned const newDh, unsigned const long cc) { - std::uint32_t seconds = time(cc); - std::uint32_t const oldHighdays = (seconds / 86400) & 0x100; - seconds -= oldHighdays * 86400; - seconds += ((newDh & 0x1) << 8) * 86400; - time_.set(seconds, cc); - - if ((dataDh_ ^ newDh) & 0x40) { - if (newDh & 0x40) - haltTime_ = seconds; - else - time_.set(haltTime_, cc); - } -} - -void Rtc::setDl(unsigned const newLowdays, unsigned const long cc) { - std::uint32_t seconds = time(cc); - std::uint32_t const oldLowdays = (seconds / 86400) & 0xFF; - seconds -= oldLowdays * 86400; - seconds += newLowdays * 86400; - time_.set(seconds, cc); -} - -void Rtc::setH(unsigned const newHours, unsigned const long cc) { - std::uint32_t seconds = time(cc); - std::uint32_t const oldHours = (seconds / 3600) % 24; - seconds -= oldHours * 3600; - seconds += newHours * 3600; - time_.set(seconds, cc); -} - -void Rtc::setM(unsigned const newMinutes, unsigned const long cc) { - std::uint32_t seconds = time(cc); - std::uint32_t const oldMinutes = (seconds / 60) % 60; - seconds -= oldMinutes * 60; - seconds += newMinutes * 60; - time_.set(seconds, cc); -} - -void Rtc::setS(unsigned const newSeconds, unsigned const long cc) { - std::uint32_t seconds = time(cc); - seconds -= seconds % 60; - seconds += newSeconds; - time_.reset(seconds, cc); -} - -SYNCFUNC(Rtc) -{ - EBS(activeData_, 0); - EVS(activeData_, &dataS_, 1); - EVS(activeData_, &dataM_, 2); - EVS(activeData_, &dataH_, 3); - EVS(activeData_, &dataDl_, 4); - EVS(activeData_, &dataDh_, 5); - EES(activeData_, NULL); - - EBS(activeSet_, 0); - EVS(activeSet_, &Rtc::setS, 1); - EVS(activeSet_, &Rtc::setM, 2); - EVS(activeSet_, &Rtc::setH, 3); - EVS(activeSet_, &Rtc::setDl, 4); - EVS(activeSet_, &Rtc::setDh, 5); - EES(activeSet_, NULL); - - NSS(haltTime_); - NSS(index_); - NSS(dataDh_); - NSS(dataDl_); - NSS(dataH_); - NSS(dataM_); - NSS(dataS_); - NSS(enabled_); - NSS(lastLatchData_); -} - -} diff --git a/libgambatte/src/mem/rtc.h b/libgambatte/src/mem/rtc.h deleted file mode 100644 index 853027ed58..0000000000 --- a/libgambatte/src/mem/rtc.h +++ /dev/null @@ -1,89 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef RTC_H -#define RTC_H - -#include -#include "time.h" -#include "newstate.h" - -namespace gambatte { - -struct SaveState; - -class Rtc { -public: - Rtc(Time &time); - unsigned char const * activeData() const { return activeData_; } - - void latch(unsigned data, unsigned long const cc) { - if (!lastLatchData_ && data == 1) - doLatch(cc); - - lastLatchData_ = data; - } - - void loadState(SaveState const &state); - - void set(bool enabled, unsigned bank) { - bank &= 0xF; - bank -= 8; - - enabled_ = enabled; - index_ = bank; - doSwapActive(); - } - - void write(unsigned data, unsigned long const cc) { - (this->*activeSet_)(data, cc); - *activeData_ = data; - } - -private: - Time &time_; - unsigned char *activeData_; - void (Rtc::*activeSet_)(unsigned, unsigned long); - std::uint32_t haltTime_; - unsigned char index_; - unsigned char dataDh_; - unsigned char dataDl_; - unsigned char dataH_; - unsigned char dataM_; - unsigned char dataS_; - bool enabled_; - bool lastLatchData_; - - void doLatch(unsigned long cycleCounter); - void doSwapActive(); - void setDh(unsigned newDh, unsigned long cycleCounter); - void setDl(unsigned newLowdays, unsigned long cycleCounter); - void setH(unsigned newHours, unsigned long cycleCounter); - void setM(unsigned newMinutes, unsigned long cycleCounter); - void setS(unsigned newSeconds, unsigned long cycleCounter); - - std::uint32_t time(unsigned long const cc) { - return dataDh_ & 0x40 ? haltTime_ : time_.get(cc); - } -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/mem/time.cpp b/libgambatte/src/mem/time.cpp deleted file mode 100644 index f85433bea9..0000000000 --- a/libgambatte/src/mem/time.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "time.h" -#include "../savestate.h" - -namespace gambatte { - -static timeval operator-(timeval l, timeval r) { - timeval t; - t.tv_sec = l.tv_sec - r.tv_sec; - t.tv_usec = l.tv_usec - r.tv_usec; - if (t.tv_usec < 0) { - t.tv_sec--; - t.tv_usec += 1000000; - } - return t; -} - -Time::Time() -: useCycles_(true) -, rtcDivisor_(0x400000) -{ -} - -void Time::loadState(SaveState const &state) { - seconds_ = state.time.seconds; - lastTime_.tv_sec = state.time.lastTimeSec; - lastTime_.tv_usec = state.time.lastTimeUsec; - lastCycles_ = state.time.lastCycles; - ds_ = state.mem.ioamhram.get()[0x14D] >> 7; -} - -std::uint32_t Time::get(unsigned long const cc) { - update(cc); - return seconds_; -} - -void Time::set(std::uint32_t seconds, unsigned long const cc) { - update(cc); - seconds_ = seconds; -} - -void Time::reset(std::uint32_t seconds, unsigned long const cc) { - set(seconds, cc); - lastTime_ = now(); - lastCycles_ = cc; -} - -void Time::resetCc(unsigned long const oldCc, unsigned long const newCc) { - update(oldCc); - lastCycles_ -= oldCc - newCc; -} - -void Time::speedChange(unsigned long const cc) { - update(cc); - - if (useCycles_) { - unsigned long diff = cc - lastCycles_; - lastCycles_ = cc - (ds_ ? diff >> 1 : diff << 1); - } - - ds_ = !ds_; -} - -timeval Time::baseTime(unsigned long const cc) { - if (useCycles_) - timeFromCycles(cc); - - timeval baseTime = lastTime_; - baseTime.tv_sec -= seconds_; - return baseTime; -} - -void Time::setBaseTime(timeval baseTime, unsigned long const cc) { - seconds_ = (now() - baseTime).tv_sec; - lastTime_ = baseTime; - lastTime_.tv_sec += seconds_; - - if (useCycles_) - cyclesFromTime(cc); -} - -void Time::setTimeMode(bool useCycles, unsigned long const cc) { - if (useCycles != useCycles_) { - if (useCycles_) - timeFromCycles(cc); - else - cyclesFromTime(cc); - - useCycles_ = useCycles; - } -} - -void Time::update(unsigned long const cc) { - if (useCycles_) { - std::uint32_t diff = (cc - lastCycles_) / (rtcDivisor_ << ds_); - seconds_ += diff; - lastCycles_ += diff * (rtcDivisor_ << ds_); - } else { - std::uint32_t diff = (now() - lastTime_).tv_sec; - seconds_ += diff; - lastTime_.tv_sec += diff; - } -} - -void Time::cyclesFromTime(unsigned long const cc) { - update(cc); - timeval diff = now() - lastTime_; - lastCycles_ = cc - diff.tv_usec * ((rtcDivisor_ << ds_) / 1000000.0f); -} - -void Time::timeFromCycles(unsigned long const cc) { - update(cc); - unsigned long diff = cc - lastCycles_; - timeval usec = { 0, (long)(diff / ((rtcDivisor_ << ds_) / 1000000.0f)) }; - lastTime_ = now() - usec; -} - -SYNCFUNC(Time) -{ - NSS(seconds_); - NSS(lastTime_.tv_sec); - NSS(lastTime_.tv_usec); - NSS(lastCycles_); - NSS(useCycles_); - NSS(ds_); -} - -} diff --git a/libgambatte/src/mem/time.h b/libgambatte/src/mem/time.h deleted file mode 100644 index 3b720bea78..0000000000 --- a/libgambatte/src/mem/time.h +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef TIME_H -#define TIME_H - -#include -#include -#include -#include "newstate.h" - -namespace gambatte { - -struct SaveState; - -struct timeval { - std::uint32_t tv_sec; - std::uint32_t tv_usec; -}; - -class Time { -public: - static timeval now() { - long long micros = std::chrono::duration_cast( - std::chrono::high_resolution_clock::now().time_since_epoch()) - .count(); - timeval t; - t.tv_usec = micros % 1000000; - t.tv_sec = micros / 1000000; - return t; - } - - Time(); - void loadState(SaveState const &state); - - std::uint32_t get(unsigned long cycleCounter); - void set(std::uint32_t seconds, unsigned long cycleCounter); - void reset(std::uint32_t seconds, unsigned long cycleCounter); - void resetCc(unsigned long oldCc, unsigned long newCc); - void speedChange(unsigned long cycleCounter); - - timeval baseTime(unsigned long cycleCounter); - void setBaseTime(timeval baseTime, unsigned long cycleCounter); - void setTimeMode(bool useCycles, unsigned long cycleCounter); - void setRtcDivisorOffset(long const rtcDivisorOffset) { rtcDivisor_ = 0x400000L + rtcDivisorOffset; } - -private: - std::uint32_t seconds_; - timeval lastTime_; - unsigned long lastCycles_; - bool useCycles_; - unsigned long rtcDivisor_; - bool ds_; - - void update(unsigned long cycleCounter); - void cyclesFromTime(unsigned long cycleCounter); - void timeFromCycles(unsigned long cycleCounter); - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp deleted file mode 100644 index 9714cd1489..0000000000 --- a/libgambatte/src/memory.cpp +++ /dev/null @@ -1,1329 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "memory.h" -#include "gambatte.h" -#include "savestate.h" -#include "sound.h" -#include "video.h" -#include -#include - -using namespace gambatte; - -namespace { - - int const oam_size = 4 * lcd_num_oam_entries; - - void decCycles(unsigned long& counter, unsigned long dec) { - if (counter != disabled_time) - counter -= dec; - } - - int serialCntFrom(unsigned long cyclesUntilDone, bool cgbFast) { - return cgbFast ? (cyclesUntilDone + 0xF) >> 4 : (cyclesUntilDone + 0x1FF) >> 9; - } - -} // unnamed namespace. - -Memory::Memory(Interrupter const& interrupter) -: readCallback_(0) -, writeCallback_(0) -, execCallback_(0) -, cdCallback_(0) -, linkCallback_(0) -, bios_(0) -, getInput_(0) -, divLastUpdate_(0) -, lastOamDmaUpdate_(disabled_time) -, lcd_(ioamhram_, 0, VideoInterruptRequester(intreq_)) -, interrupter_(interrupter) -, dmaSource_(0) -, dmaDestination_(0) -, oamDmaPos_(-2u & 0xFF) -, oamDmaStartPos_(0) -, serialCnt_(0) -, blanklcd_(false) -, LINKCABLE_(false) -, linkClockTrigger_(false) -, haltHdmaState_(hdma_low) -{ - intreq_.setEventTime(1l * lcd_vres * lcd_cycles_per_line); - intreq_.setEventTime(0); -} - -Memory::~Memory() { - delete []bios_; -} - -void Memory::setStatePtrs(SaveState &state) { - state.mem.ioamhram.set(ioamhram_, sizeof ioamhram_); - - cart_.setStatePtrs(state); - lcd_.setStatePtrs(state); - psg_.setStatePtrs(state); -} - -void Memory::loadState(SaveState const &state) { - biosMode_ = state.mem.biosMode; - stopped_ = state.mem.stopped; - psg_.loadState(state); - lcd_.loadState(state, state.mem.oamDmaPos < oam_size ? cart_.rdisabledRam() : ioamhram_); - tima_.loadState(state, TimaInterruptRequester(intreq_)); - cart_.loadState(state); - intreq_.loadState(state); - - intreq_.setEventTime(state.mem.nextSerialtime > state.cpu.cycleCounter - ? state.mem.nextSerialtime - : state.cpu.cycleCounter); - intreq_.setEventTime(state.mem.unhaltTime); - lastOamDmaUpdate_ = state.mem.lastOamDmaUpdate; - dmaSource_ = state.mem.dmaSource; - dmaDestination_ = state.mem.dmaDestination; - oamDmaPos_ = state.mem.oamDmaPos; - oamDmaStartPos_ = 0; - haltHdmaState_ = static_cast(std::min(1u * state.mem.haltHdmaState, 1u * hdma_requested)); - serialCnt_ = intreq_.eventTime(intevent_serial) != disabled_time - ? serialCntFrom(intreq_.eventTime(intevent_serial) - state.cpu.cycleCounter, - ioamhram_[0x102] & isCgb() * 2) - : 8; - - cart_.setVrambank(ioamhram_[0x14F] & isCgb()); - cart_.setOamDmaSrc(oam_dma_src_off); - cart_.setWrambank(isCgb() && (ioamhram_[0x170] & 0x07) ? ioamhram_[0x170] & 0x07 : 1); - - if (lastOamDmaUpdate_ != disabled_time) { - if (lastOamDmaUpdate_ > state.cpu.cycleCounter) { - oamDmaStartPos_ = (oamDmaPos_ + (lastOamDmaUpdate_ - state.cpu.cycleCounter) / 4) & 0xFF; - lastOamDmaUpdate_ = state.cpu.cycleCounter; - } - oamDmaInitSetup(); - - unsigned oamEventPos = oamDmaPos_ < oam_size ? oam_size : oamDmaStartPos_; - intreq_.setEventTime( - lastOamDmaUpdate_ + ((oamEventPos - oamDmaPos_) & 0xFF) * 4); - } - - intreq_.setEventTime(ioamhram_[0x140] & lcdc_en - ? lcd_.nextMode1IrqTime() - : state.cpu.cycleCounter); - blanklcd_ = false; - - if (!isCgb()) - std::fill_n(cart_.vramdata() + vrambank_size(), vrambank_size(), 0); -} - -void Memory::setEndtime(unsigned long cc, unsigned long inc) { - if (intreq_.eventTime(intevent_blit) <= cc) { - intreq_.setEventTime(intreq_.eventTime(intevent_blit) - + (lcd_cycles_per_frame << isDoubleSpeed())); - } - - intreq_.setEventTime(cc + (inc << isDoubleSpeed())); -} - -void Memory::updateSerial(unsigned long const cc) { - if (!LINKCABLE_) { - if (intreq_.eventTime(intevent_serial) != disabled_time) { - if (intreq_.eventTime(intevent_serial) <= cc) { - ioamhram_[0x101] = (((ioamhram_[0x101] + 1) << serialCnt_) - 1) & 0xFF; - ioamhram_[0x102] &= 0x7F; - intreq_.flagIrq(8, intreq_.eventTime(intevent_serial)); - intreq_.setEventTime(disabled_time); - } else { - int const targetCnt = serialCntFrom(intreq_.eventTime(intevent_serial) - cc, - ioamhram_[0x102] & isCgb() * 2); - ioamhram_[0x101] = (((ioamhram_[0x101] + 1) << (serialCnt_ - targetCnt)) - 1) & 0xFF; - serialCnt_ = targetCnt; - } - } - } else { - if (intreq_.eventTime(intevent_serial) != disabled_time) { - if (intreq_.eventTime(intevent_serial) <= cc) { - linkClockTrigger_ = true; - intreq_.setEventTime(disabled_time); - if (linkCallback_) - linkCallback_(); - } - } - } -} - -void Memory::updateTimaIrq(unsigned long cc) { - while (intreq_.eventTime(intevent_tima) <= cc) - tima_.doIrqEvent(TimaInterruptRequester(intreq_)); -} - -void Memory::updateIrqs(unsigned long cc) { - updateSerial(cc); - updateTimaIrq(cc); - lcd_.update(cc); -} - -unsigned long Memory::event(unsigned long cc) { - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc); - - switch (intreq_.minEventId()) { - case intevent_unhalt: - if ((lcd_.hdmaIsEnabled() && lcd_.isHdmaPeriod(cc) && haltHdmaState_ == hdma_low) - || haltHdmaState_ == hdma_requested) { - flagHdmaReq(intreq_); - } - - intreq_.unhalt(); - intreq_.setEventTime(disabled_time); - stopped_ = false; - break; - case intevent_end: - intreq_.setEventTime(disabled_time - 1); - - while (cc >= intreq_.minEventTime() - && intreq_.eventTime(intevent_end) != disabled_time) { - cc = event(cc); - } - - intreq_.setEventTime(disabled_time); - - break; - case intevent_blit: - { - bool const lcden = ioamhram_[0x140] & lcdc_en; - unsigned long blitTime = intreq_.eventTime(intevent_blit); - - if (lcden | blanklcd_) { - lcd_.updateScreen(blanklcd_, cc); - intreq_.setEventTime(disabled_time); - intreq_.setEventTime(disabled_time); - - while (cc >= intreq_.minEventTime()) - cc = event(cc); - } else - blitTime += lcd_cycles_per_frame << isDoubleSpeed(); - - blanklcd_ = lcden ^ 1; - intreq_.setEventTime(blitTime); - } - break; - case intevent_serial: - updateSerial(cc); - break; - case intevent_oam: - if (lastOamDmaUpdate_ != disabled_time) { - unsigned const oamEventPos = oamDmaPos_ < oam_size ? oam_size : oamDmaStartPos_; - intreq_.setEventTime( - lastOamDmaUpdate_ + ((oamEventPos - oamDmaPos_) & 0xFF) * 4); - } - else - intreq_.setEventTime(disabled_time); - - break; - case intevent_dma: - interrupter_.prefetch(cc, *this); - cc = dma(cc); - if (haltHdmaState_ == hdma_requested) { - haltHdmaState_ = hdma_low; - intreq_.setMinIntTime(cc); - cc -= 4; - } - break; - case intevent_tima: - tima_.doIrqEvent(TimaInterruptRequester(intreq_)); - break; - case intevent_video: - lcd_.update(cc); - break; - case intevent_interrupts: - if (stopped_) { - intreq_.setEventTime(disabled_time); - break; - } - - if (halted()) { - cc += 4 * (isCgb() || cc - intreq_.eventTime(intevent_interrupts) < 2); - if (cc > lastOamDmaUpdate_) - updateOamDma(cc); - if ((lcd_.hdmaIsEnabled() && lcd_.isHdmaPeriod(cc) && haltHdmaState_ == hdma_low) - || haltHdmaState_ == hdma_requested) { - flagHdmaReq(intreq_); - } - - intreq_.unhalt(); - intreq_.setEventTime(disabled_time); - } - - if (ime()) { - di(); - cc = interrupter_.interrupt(cc, *this); - } - - break; - } - - return cc; -} - -unsigned long Memory::dma(unsigned long cc) { - bool const doubleSpeed = isDoubleSpeed(); - unsigned dmaSrc = dmaSource_; - unsigned dmaDest = dmaDestination_; - unsigned dmaLength = ((ioamhram_[0x155] & 0x7F) + 1) * 0x10; - unsigned length = hdmaReqFlagged(intreq_) ? 0x10 : dmaLength; - - if (1ul * dmaDest + length >= 0x10000) { - length = 0x10000 - dmaDest; - ioamhram_[0x155] |= 0x80; - } - - dmaLength -= length; - - if (!(ioamhram_[0x140] & lcdc_en)) - dmaLength = 0; - - unsigned long lOamDmaUpdate = lastOamDmaUpdate_; - lastOamDmaUpdate_ = disabled_time; - - while (length--) { - unsigned const src = dmaSrc++ & 0xFFFF; - unsigned const data = (src & -vrambank_size()) == mm_vram_begin || src >= mm_oam_begin - ? 0xFF - : read(src, cc); - - cc += 2 + 2 * doubleSpeed; - - if (cc - 3 > lOamDmaUpdate && !halted()) { - oamDmaPos_ = (oamDmaPos_ + 1) & 0xFF; - lOamDmaUpdate += 4; - if (oamDmaPos_ == oamDmaStartPos_) - startOamDma(lOamDmaUpdate); - - if (oamDmaPos_ < oam_size) { - ioamhram_[src & 0xFF] = data; - } - else if (oamDmaPos_ == oam_size) { - endOamDma(lOamDmaUpdate); - if (oamDmaStartPos_ == 0) - lOamDmaUpdate = disabled_time; - } - } - - nontrivial_write(mm_vram_begin | dmaDest++ % vrambank_size(), data, cc); - } - - lastOamDmaUpdate_ = lOamDmaUpdate; - ackDmaReq(intreq_); - cc += 4; - - dmaSource_ = dmaSrc; - dmaDestination_ = dmaDest; - ioamhram_[0x155] = halted() - ? ioamhram_[0x155] | 0x80 - : ((dmaLength / 0x10 - 1) & 0xFF) | (ioamhram_[0x155] & 0x80); - - if ((ioamhram_[0x155] & 0x80) && lcd_.hdmaIsEnabled()) { - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc); - - lcd_.disableHdma(cc); - } - - return cc; -} - -void Memory::freeze(unsigned long cc) { - // permanently halt CPU. - // simply halt and clear IE to avoid unhalt from occuring, - // which avoids additional state to represent a "frozen" state. - nontrivial_ff_write(0xFF, 0, cc); - ackDmaReq(intreq_); - intreq_.halt(); -} - -bool Memory::halt(unsigned long cc) { - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc); - - haltHdmaState_ = lcd_.hdmaIsEnabled() && lcd_.isHdmaPeriod(cc) - ? hdma_high : hdma_low; - bool const hdmaReq = hdmaReqFlagged(intreq_); - if (hdmaReq) - haltHdmaState_ = hdma_requested; - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc + 4); - - ackDmaReq(intreq_); - intreq_.halt(); - return hdmaReq; -} - -unsigned Memory::pendingIrqs(unsigned long cc) { - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc); - - updateIrqs(cc); - return intreq_.pendingIrqs(); -} - -void Memory::ackIrq(unsigned bit, unsigned long cc) { - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc); - - // TODO: adjust/extend IRQ assertion time rather than use the odd cc offsets? - // NOTE: a minimum offset of 2 is required for the LCD due to implementation assumptions w.r.t. cc headroom. - updateSerial(cc + 3 + isCgb()); - updateTimaIrq(cc + 2 + isCgb()); - lcd_.update(cc + 2); - intreq_.ackIrq(bit); -} - -unsigned long Memory::stop(unsigned long cc, bool &skip) { - // FIXME: this is incomplete. - intreq_.setEventTime(cc + 0x20000 + 4); - - // speed change. - if (ioamhram_[0x14D] & isCgb()) { - tima_.speedChange(TimaInterruptRequester(intreq_)); - // DIV reset. - nontrivial_ff_write(0x04, 0, cc); - haltHdmaState_ = lcd_.hdmaIsEnabled() && lcd_.isHdmaPeriod(cc) - ? hdma_high : hdma_low; - skip = hdmaReqFlagged(intreq_); - if (skip && isDoubleSpeed()) - haltHdmaState_ = hdma_requested; - unsigned long const cc_ = cc + 8 * !isDoubleSpeed(); - if (cc_ >= cc + 4) { - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc + 4); - if (!skip || isDoubleSpeed()) - ackDmaReq(intreq_); - intreq_.halt(); - } - psg_.speedChange(cc_, isDoubleSpeed()); - lcd_.speedChange(cc_); - cart_.speedChange(cc_); - ioamhram_[0x14D] ^= 0x81; - // TODO: perhaps make this a bit nicer? - intreq_.setEventTime(ioamhram_[0x140] & lcdc_en - ? lcd_.nextMode1IrqTime() - : cc + (lcd_cycles_per_frame << isDoubleSpeed())); - if (intreq_.eventTime(intevent_end) > cc_) { - intreq_.setEventTime(cc_ - + (isDoubleSpeed() - ? (intreq_.eventTime(intevent_end) - cc_) * 2 - : (intreq_.eventTime(intevent_end) - cc_) / 2)); - } - if (cc_ < cc + 4) { - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc + 4); - if (!skip || !isDoubleSpeed()) - ackDmaReq(intreq_); - intreq_.halt(); - } - // ensure that no updates with a previous cc occur. - cc += 8; - } - else { - // FIXME: test and implement stop correctly. - skip = halt(cc); - cc += 4; - - stopped_ = true; - intreq_.setEventTime(disabled_time); - } - - return cc; -} - -void Memory::decEventCycles(IntEventId eventId, unsigned long dec) { - if (intreq_.eventTime(eventId) != disabled_time) - intreq_.setEventTime(eventId, intreq_.eventTime(eventId) - dec); -} - -unsigned long Memory::resetCounters(unsigned long cc) { - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc); - - updateIrqs(cc); - - unsigned long const dec = cc < 0x20000 - ? 0 - : (cc & -0x10000l) - 0x10000; - decCycles(divLastUpdate_, dec); - decCycles(lastOamDmaUpdate_, dec); - decEventCycles(intevent_serial, dec); - decEventCycles(intevent_oam, dec); - decEventCycles(intevent_blit, dec); - decEventCycles(intevent_end, dec); - decEventCycles(intevent_unhalt, dec); - - unsigned long const oldCC = cc; - cc -= dec; - intreq_.resetCc(oldCC, cc); - cart_.resetCc(oldCC, cc); - tima_.resetCc(oldCC, cc, TimaInterruptRequester(intreq_)); - lcd_.resetCc(oldCC, cc); - psg_.resetCounter(cc, oldCC, isDoubleSpeed()); - return cc; -} - -void Memory::updateInput() { - unsigned state = 0xF; - - if ((ioamhram_[0x100] & 0x30) != 0x30 && getInput_) { - unsigned input = (*getInput_)(); - unsigned dpad_state = ~input >> 4; - unsigned button_state = ~input; - if (!(ioamhram_[0x100] & 0x10)) - state &= dpad_state; - if (!(ioamhram_[0x100] & 0x20)) - state &= button_state; - - if (state != 0xF && (ioamhram_[0x100] & 0xF) == 0xF) - intreq_.flagIrq(0x10); - } - - ioamhram_[0x100] = (ioamhram_[0x100] & -0x10u) | state; -} - -void Memory::updateOamDma(unsigned long const cc) { - unsigned char const *const oamDmaSrc = oamDmaSrcPtr(); - unsigned cycles = (cc - lastOamDmaUpdate_) >> 2; - - if (halted()) { - lastOamDmaUpdate_ += 4 * cycles; - } - else while (cycles--) { - oamDmaPos_ = (oamDmaPos_ + 1) & 0xFF; - lastOamDmaUpdate_ += 4; - if (oamDmaPos_ == oamDmaStartPos_) - startOamDma(lastOamDmaUpdate_); - - if (oamDmaPos_ < oam_size) { - if (oamDmaSrc) ioamhram_[oamDmaPos_] = oamDmaSrc[oamDmaPos_]; - else if (cart_.isHuC3()) ioamhram_[oamDmaPos_] = cart_.HuC3Read(oamDmaPos_, cc); - else ioamhram_[oamDmaPos_] = cart_.rtcRead(); - } - else if (oamDmaPos_ == oam_size) { - endOamDma(lastOamDmaUpdate_); - if (oamDmaStartPos_ == 0) { - lastOamDmaUpdate_ = disabled_time; - break; - } - } - } -} - -void Memory::oamDmaInitSetup() { - if (ioamhram_[0x146] < mm_sram_begin / 0x100) { - cart_.setOamDmaSrc(ioamhram_[0x146] < mm_vram_begin / 0x100 ? oam_dma_src_rom : oam_dma_src_vram); - } - else if (ioamhram_[0x146] < 0x100 - isCgb() * 0x20) { - cart_.setOamDmaSrc(ioamhram_[0x146] < mm_wram_begin / 0x100 ? oam_dma_src_sram : oam_dma_src_wram); - } - else - cart_.setOamDmaSrc(oam_dma_src_invalid); -} - -unsigned char const* Memory::oamDmaSrcPtr() const { - switch (cart_.oamDmaSrc()) { - case oam_dma_src_rom: - return cart_.romdata(ioamhram_[0x146] >> 6) + ioamhram_[0x146] * 0x100l; - case oam_dma_src_sram: - return cart_.rsrambankptr() ? cart_.rsrambankptr() + ioamhram_[0x146] * 0x100l : 0; - case oam_dma_src_vram: - return cart_.vrambankptr() + ioamhram_[0x146] * 0x100l; - case oam_dma_src_wram: - return cart_.wramdata(ioamhram_[0x146] >> 4 & 1) + (ioamhram_[0x146] * 0x100l & 0xFFF); - case oam_dma_src_invalid: - case oam_dma_src_off: - break; - } - - return cart_.rdisabledRam(); -} - -void Memory::startOamDma(unsigned long cc) { - oamDmaPos_ = 0; - oamDmaStartPos_ = 0; - lcd_.oamChange(cart_.rdisabledRam(), cc); -} - -void Memory::endOamDma(unsigned long cc) { - if (oamDmaStartPos_ == 0) { - oamDmaPos_ = -2u & 0xFF; - cart_.setOamDmaSrc(oam_dma_src_off); - } - lcd_.oamChange(ioamhram_, cc); -} - -unsigned Memory::nontrivial_ff_read(unsigned const p, unsigned long const cc) { - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc); - - switch (p) { - case 0x00: - updateInput(); - break; - case 0x01: - case 0x02: - updateSerial(cc); - break; - case 0x04: - return (cc - tima_.divLastUpdate()) >> 8 & 0xFF; - case 0x05: - ioamhram_[0x105] = tima_.tima(cc); - break; - case 0x0F: - updateIrqs(cc); - ioamhram_[0x10F] = intreq_.ifreg(); - break; - case 0x26: - if (ioamhram_[0x126] & 0x80) { - psg_.generateSamples(cc, isDoubleSpeed()); - ioamhram_[0x126] = 0xF0 | psg_.getStatus(); - } else - ioamhram_[0x126] = 0x70; - - break; - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - psg_.generateSamples(cc, isDoubleSpeed()); - return psg_.waveRamRead(p & 0xF); - case 0x41: - return ioamhram_[0x141] | lcd_.getStat(ioamhram_[0x145], cc); - case 0x44: - return lcd_.getLyReg(cc); - case 0x69: - return lcd_.cgbBgColorRead(ioamhram_[0x168] & 0x3F, cc); - case 0x6B: - return lcd_.cgbSpColorRead(ioamhram_[0x16A] & 0x3F, cc); - default: - break; - } - - return ioamhram_[p + 0x100]; -} - -unsigned Memory::nontrivial_read(unsigned const p, unsigned long const cc) { - if (p < mm_hram_begin) { - if (lastOamDmaUpdate_ != disabled_time) { - updateOamDma(cc); - - if (cart_.isInOamDmaConflictArea(p) && oamDmaPos_ < oam_size) { - int const r = isCgb() && cart_.oamDmaSrc() != oam_dma_src_wram && p >= mm_wram_begin - ? cart_.wramdata(ioamhram_[0x146] >> 4 & 1)[p & 0xFFF] - : ioamhram_[oamDmaPos_]; - if (isCgb() && cart_.oamDmaSrc() == oam_dma_src_vram) - ioamhram_[oamDmaPos_] = 0; - - return r; - } - } - - if (p < mm_wram_begin) { - if (p < mm_vram_begin) - return cart_.romdata(p >> 14)[p]; - - if (p < mm_sram_begin) { - if (!lcd_.vramReadable(cc)) - return 0xFF; - - if (p < 0x9000) { - if (lcd_.vramExactlyReadable(cc)) { - return 0x00; - } - } - - return cart_.vrambankptr()[p]; - } - - if (cart_.rsrambankptr()) - return cart_.rsrambankptr()[p]; - - if (cart_.isHuC3()) - return cart_.HuC3Read(p, cc); - - return cart_.rtcRead(); - } - - if (p < mm_oam_begin) - return cart_.wramdata(p >> 12 & 1)[p & 0xFFF]; - - long const ffp = static_cast(p) - mm_io_begin; - if (ffp >= 0) - return nontrivial_ff_read(ffp, cc); - - if (!lcd_.oamReadable(cc) || oamDmaPos_ < oam_size) - return 0xFF; - } - - return ioamhram_[p - mm_oam_begin]; -} - -unsigned Memory::nontrivial_peek(unsigned const p) { - if (p < 0xC000) { - if (p < 0x8000) - return cart_.romdata(p >> 14)[p]; - - if (p < 0xA000) { - return cart_.vrambankptr()[p]; - } - - if (cart_.rsrambankptr()) - return cart_.rsrambankptr()[p]; - - return cart_.rtcRead(); // verified side-effect free - } - if (p < 0xFE00) - return cart_.wramdata(p >> 12 & 1)[p & 0xFFF]; - if (p >= 0xFF00 && p < 0xFF80) - return nontrivial_ff_peek(p); - return ioamhram_[p - 0xFE00]; -} - -unsigned Memory::nontrivial_ff_peek(unsigned const p) { - // some regs may be somewhat wrong with this - return ioamhram_[p - 0xFE00]; -} - -void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long const cc) { - if (lastOamDmaUpdate_ != disabled_time) - updateOamDma(cc); - - switch (p & 0xFF) { - case 0x00: - if ((data ^ ioamhram_[0x100]) & 0x30) { - ioamhram_[0x100] = (ioamhram_[0x100] & ~0x30u) | (data & 0x30); - updateInput(); - } - - return; - case 0x01: - updateSerial(cc); - break; - case 0x02: - updateSerial(cc); - serialCnt_ = 8; - - if ((data & 0x81) == 0x81) { - intreq_.setEventTime(data & isCgb() * 2 - ? cc - (cc - tima_.divLastUpdate()) % 8 + 0x10 * serialCnt_ - : cc - (cc - tima_.divLastUpdate()) % 0x100 + 0x200 * serialCnt_); - } else - intreq_.setEventTime(disabled_time); - - data |= 0x7E - isCgb() * 2; - break; - case 0x04: - if (intreq_.eventTime(intevent_serial) != disabled_time - && intreq_.eventTime(intevent_serial) > cc) { - unsigned long const t = intreq_.eventTime(intevent_serial); - unsigned long const n = ioamhram_[0x102] & isCgb() * 2 - ? t + (cc - t) % 8 - 2 * ((cc - t) & 4) - : t + (cc - t) % 0x100 - 2 * ((cc - t) & 0x80); - intreq_.setEventTime(std::max(cc, n)); - } - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.divReset(isDoubleSpeed()); - tima_.divReset(cc, TimaInterruptRequester(intreq_)); - return; - case 0x05: - tima_.setTima(data, cc, TimaInterruptRequester(intreq_)); - break; - case 0x06: - tima_.setTma(data, cc, TimaInterruptRequester(intreq_)); - break; - case 0x07: - data |= 0xF8; - tima_.setTac(data, cc, TimaInterruptRequester(intreq_), agbMode_); - break; - case 0x0F: - updateIrqs(cc + 1 + isDoubleSpeed()); - intreq_.setIfreg(0xE0 | data); - return; - case 0x10: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr10(data); - data |= 0x80; - break; - case 0x11: - if (!psg_.isEnabled()) { - if (isCgb()) - return; - - data &= 0x3F; - } - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr11(data); - data |= 0x3F; - break; - case 0x12: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr12(data); - break; - case 0x13: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr13(data); - return; - case 0x14: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr14(data, isDoubleSpeed()); - data |= 0xBF; - break; - case 0x16: - if (!psg_.isEnabled()) { - if (isCgb()) - return; - - data &= 0x3F; - } - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr21(data); - data |= 0x3F; - break; - case 0x17: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr22(data); - break; - case 0x18: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr23(data); - return; - case 0x19: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr24(data, isDoubleSpeed()); - data |= 0xBF; - break; - case 0x1A: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr30(data); - data |= 0x7F; - break; - case 0x1B: - if (!psg_.isEnabled() && isCgb()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr31(data); - return; - case 0x1C: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr32(data); - data |= 0x9F; - break; - case 0x1D: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr33(data); - return; - case 0x1E: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr34(data); - data |= 0xBF; - break; - case 0x20: - if (!psg_.isEnabled() && isCgb()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr41(data); - return; - case 0x21: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr42(data); - break; - case 0x22: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr43(data); - break; - case 0x23: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setNr44(data); - data |= 0xBF; - break; - case 0x24: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.setSoVolume(data); - break; - case 0x25: - if (!psg_.isEnabled()) - return; - - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.mapSo(data); - break; - case 0x26: - if ((ioamhram_[0x126] ^ data) & 0x80) { - psg_.generateSamples(cc, isDoubleSpeed()); - - if (!(data & 0x80)) { - for (unsigned i = 0x10; i < 0x26; ++i) - ff_write(i, 0, cc); - - psg_.setEnabled(false); - } - else { - psg_.reset(isDoubleSpeed()); - psg_.setEnabled(true); - } - } - - data = (data & 0x80) | (ioamhram_[0x126] & 0x7F); - break; - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - psg_.generateSamples(cc, isDoubleSpeed()); - psg_.waveRamWrite(p & 0xF, data); - break; - case 0x40: - if (ioamhram_[0x140] != data) { - if ((ioamhram_[0x140] ^ data) & lcdc_en) { - unsigned const stat = data & lcdc_en ? ioamhram_[0x141] : lcd_.getStat(ioamhram_[0x145], cc); - bool const hdmaEnabled = lcd_.hdmaIsEnabled(); - - lcd_.lcdcChange(data, cc); - ioamhram_[0x144] = 0; - ioamhram_[0x141] &= 0xF8; - - if (data & lcdc_en) { - if (ioamhram_[0x141] & lcdstat_lycirqen && ioamhram_[0x145] == 0 && !(stat & lcdstat_lycflag)) - intreq_.flagIrq(2); - - intreq_.setEventTime(blanklcd_ - ? lcd_.nextMode1IrqTime() - : lcd_.nextMode1IrqTime() + (lcd_cycles_per_frame << isDoubleSpeed())); - } - else { - ioamhram_[0x141] |= stat & lcdstat_lycflag; - intreq_.setEventTime( - cc + (lcd_cycles_per_line * 4 << isDoubleSpeed())); - - if (hdmaEnabled) - flagHdmaReq(intreq_); - } - } - else - lcd_.lcdcChange(data, cc); - - ioamhram_[0x140] = data; - } - - return; - case 0x41: - lcd_.lcdstatChange(data, cc); - if (!(ioamhram_[0x140] & lcdc_en) && (ioamhram_[0x141] & lcdstat_lycflag) - && (~ioamhram_[0x141] & lcdstat_lycirqen & (isCgb() ? data : -1))) { - intreq_.flagIrq(2); - } - data = (ioamhram_[0x141] & 0x87) | (data & 0x78); - break; - case 0x42: - lcd_.scyChange(data, cc); - break; - case 0x43: - lcd_.scxChange(data, cc); - break; - case 0x45: - lcd_.lycRegChange(data, cc); - break; - case 0x46: - lastOamDmaUpdate_ = cc; - oamDmaStartPos_ = (oamDmaPos_ + 2) & 0xFF; - intreq_.setEventTime(std::min(intreq_.eventTime(intevent_oam), cc + 8)); - ioamhram_[0x146] = data; - oamDmaInitSetup(); - return; - case 0x47: - if (!isCgb() || isCgbDmg()) - lcd_.dmgBgPaletteChange(data, cc); - - break; - case 0x48: - if (!isCgb() || isCgbDmg()) - lcd_.dmgSpPalette1Change(data, cc); - - break; - case 0x49: - if (!isCgb() || isCgbDmg()) - lcd_.dmgSpPalette2Change(data, cc); - - break; - case 0x4A: - lcd_.wyChange(data, cc); - break; - case 0x4B: - lcd_.wxChange(data, cc); - break; - case 0x4C: - if (!biosMode_) - return; - - break; - case 0x4D: - if (isCgb() && !isCgbDmg()) - ioamhram_[0x14D] = (ioamhram_[0x14D] & ~1u) | (data & 1); - - return; - case 0x4F: - if (isCgb() && !isCgbDmg()) { - cart_.setVrambank(data & 1); - ioamhram_[0x14F] = 0xFE | data; - } - - return; - case 0x50: - if (!biosMode_) - return; - - if (isCgb() && (ioamhram_[0x14C] & 0x04)) { - lcd_.copyCgbPalettesToDmg(); - lcd_.setCgbDmg(true); - } - - biosMode_ = false; - return; - case 0x51: - dmaSource_ = data << 8 | (dmaSource_ & 0xFF); - return; - case 0x52: - dmaSource_ = (dmaSource_ & 0xFF00) | (data & 0xF0); - return; - case 0x53: - dmaDestination_ = data << 8 | (dmaDestination_ & 0xFF); - return; - case 0x54: - dmaDestination_ = (dmaDestination_ & 0xFF00) | (data & 0xF0); - return; - case 0x55: - if (isCgb()) { - ioamhram_[0x155] = data & 0x7F; - - if (lcd_.hdmaIsEnabled()) { - if (!(data & 0x80)) { - ioamhram_[0x155] |= 0x80; - lcd_.disableHdma(cc); - } - } else { - if (data & 0x80) { - if (ioamhram_[0x140] & lcdc_en) { - lcd_.enableHdma(cc); - } else - flagHdmaReq(intreq_); - } else - flagGdmaReq(intreq_); - } - } - - return; - case 0x56: - if (isCgb()) - ioamhram_[0x156] = data | 0x3E; - - return; - case 0x68: - if (isCgb()) - ioamhram_[0x168] = data | 0x40; - - return; - case 0x69: - if (isCgb()) { - unsigned index = ioamhram_[0x168] & 0x3F; - lcd_.cgbBgColorChange(index, data, cc); - ioamhram_[0x168] = (ioamhram_[0x168] & ~0x3Fu) - | ((index + (ioamhram_[0x168] >> 7)) & 0x3F); - } - - return; - case 0x6A: - if (isCgb()) - ioamhram_[0x16A] = data | 0x40; - - return; - case 0x6B: - if (isCgb()) { - unsigned index = ioamhram_[0x16A] & 0x3F; - lcd_.cgbSpColorChange(index, data, cc); - ioamhram_[0x16A] = (ioamhram_[0x16A] & ~0x3Fu) - | ((index + (ioamhram_[0x16A] >> 7)) & 0x3F); - } - - return; - case 0x6C: - if (isCgb()) - ioamhram_[0x16C] = data | 0xFE; - - return; - case 0x70: - if (isCgb() && !isCgbDmg()) { - cart_.setWrambank(data & 0x07 ? data & 0x07 : 1); - ioamhram_[0x170] = data | 0xF8; - } - - return; - case 0x72: - case 0x73: - case 0x74: - if (isCgb()) - break; - - return; - case 0x75: - if (isCgb()) - ioamhram_[0x175] = data | 0x8F; - - return; - case 0xFF: - intreq_.setIereg(data); - break; - default: - return; - } - - ioamhram_[p + 0x100] = data; -} - -void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned long const cc) { - if (lastOamDmaUpdate_ != disabled_time) { - updateOamDma(cc); - - if (cart_.isInOamDmaConflictArea(p) && oamDmaPos_ < oam_size) { - if (isCgb()) { - if (p < mm_wram_begin) - ioamhram_[oamDmaPos_] = cart_.oamDmaSrc() != oam_dma_src_vram ? data : 0; - else if (cart_.oamDmaSrc() != oam_dma_src_wram) - cart_.wramdata(ioamhram_[0x146] >> 4 & 1)[p & 0xFFF] = data; - } - else { - ioamhram_[oamDmaPos_] = cart_.oamDmaSrc() == oam_dma_src_wram - ? ioamhram_[oamDmaPos_] & data - : data; - } - - return; - } - } - - if (p < mm_oam_begin) { - if (p < mm_sram_begin) { - if (p < mm_vram_begin) { - cart_.mbcWrite(p, data, cc); - } - else if (lcd_.vramWritable(cc)) { - lcd_.vramChange(cc); - cart_.vrambankptr()[p] = data; - } - } - else if (p < mm_wram_begin) { - if (cart_.wsrambankptr()) - cart_.wsrambankptr()[p] = data; - else if (cart_.isHuC3()) - cart_.HuC3Write(p, data, cc); - else - cart_.rtcWrite(data, cc); - } - else - cart_.wramdata(p >> 12 & 1)[p & 0xFFF] = data; - } - else if (p - mm_hram_begin >= 0x7Fu) { - long const ffp = static_cast(p) - mm_io_begin; - if (ffp < 0) { - if (lcd_.oamWritable(cc) && oamDmaPos_ >= oam_size - && (p < mm_oam_begin + oam_size || isCgb())) { - lcd_.oamChange(cc); - ioamhram_[p - mm_oam_begin] = data; - } - } - else - nontrivial_ff_write(ffp, data, cc); - } - else - ioamhram_[p - mm_oam_begin] = data; -} - -LoadRes Memory::loadROM(char const *romfiledata, unsigned romfilelength, unsigned const flags) { - bool const forceDmg = flags & GB::LoadFlag::FORCE_DMG; - bool const multicartCompat = flags & GB::LoadFlag::MULTICART_COMPAT; - - if (LoadRes const fail = cart_.loadROM(romfiledata, romfilelength, forceDmg, multicartCompat)) - return fail; - - psg_.init(cart_.isCgb()); - lcd_.reset(ioamhram_, cart_.vramdata(), cart_.isCgb()); - - agbMode_ = flags & GB::LoadFlag::GBA_CGB; - - return LOADRES_OK; -} - -std::size_t Memory::fillSoundBuffer(unsigned long cc) { - psg_.generateSamples(cc, isDoubleSpeed()); - return psg_.fillBuffer(); -} - -void Memory::setCgbPalette(unsigned *lut) { - lcd_.setCgbPalette(lut); -} - -bool Memory::getMemoryArea(int which, unsigned char **data, int *length) { - if (!data || !length) - return false; - - switch (which) - { - case 4: // oam - *data = &ioamhram_[0]; - *length = 160; - return true; - case 5: // hram - *data = &ioamhram_[384]; - *length = 128; - return true; - case 6: // bgpal - *data = (unsigned char *)lcd_.bgPalette(); - *length = 32; - return true; - case 7: // sppal - *data = (unsigned char *)lcd_.spPalette(); - *length = 32; - return true; - default: // pass to cartridge - return cart_.getMemoryArea(which, data, length); - } -} - -int Memory::linkStatus(int which) -{ - switch (which) - { - case 256: // ClockSignaled - return linkClockTrigger_; - case 257: // AckClockSignal - linkClockTrigger_ = false; - return 0; - case 258: // GetOut - return ioamhram_[0x101] & 0xff; - case 259: // connect link cable - LINKCABLE_ = true; - return 0; - default: // ShiftIn - if (ioamhram_[0x102] & 0x80) // was enabled - { - ioamhram_[0x101] = which; - ioamhram_[0x102] &= 0x7F; - intreq_.flagIrq(8); - } - return 0; - } - - return -1; -} - -SYNCFUNC(Memory) -{ - SSS(cart_); - NSS(ioamhram_); - NSS(divLastUpdate_); - NSS(lastOamDmaUpdate_); - SSS(intreq_); - SSS(tima_); - SSS(lcd_); - SSS(psg_); - NSS(dmaSource_); - NSS(dmaDestination_); - NSS(oamDmaPos_); - NSS(serialCnt_); - NSS(blanklcd_); - NSS(biosMode_); - NSS(stopped_); - NSS(LINKCABLE_); - NSS(linkClockTrigger_); -} diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h deleted file mode 100644 index b8fd9bc2df..0000000000 --- a/libgambatte/src/memory.h +++ /dev/null @@ -1,339 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef MEMORY_H -#define MEMORY_H - -static unsigned char const agbOverride[0xD] = { 0xFF, 0x00, 0xCD, 0x03, 0x35, 0xAA, 0x31, 0x90, 0x94, 0x00, 0x00, 0x00, 0x00 }; - -#include "mem/cartridge.h" -#include "interrupter.h" -#include "sound.h" -#include "tima.h" -#include "video.h" -#include "newstate.h" -#include "gambatte.h" - -namespace gambatte { - -class FilterInfo; - -class Memory { -public: - explicit Memory(Interrupter const &interrupter); - ~Memory(); - - bool loaded() const { return cart_.loaded(); } - unsigned curRomBank() const { return cart_.curRomBank(); } - char const * romTitle() const { return cart_.romTitle(); } - int debugGetLY() const { return lcd_.debugGetLY(); } - void setStatePtrs(SaveState &state); - void loadState(SaveState const &state); - void loadSavedata(char const *data, unsigned long const cc) { cart_.loadSavedata(data, cc); } - int saveSavedataLength() {return cart_.saveSavedataLength(); } - void saveSavedata(char *dest, unsigned long const cc) { cart_.saveSavedata(dest, cc); } - void updateInput(); - - void setBios(char const *buffer, std::size_t size) { - delete []bios_; - bios_ = new unsigned char[size]; - memcpy(bios_, buffer, size); - biosSize_ = size; - } - - bool getMemoryArea(int which, unsigned char **data, int *length); - - unsigned long stop(unsigned long cycleCounter, bool& skip); - bool isCgb() const { return lcd_.isCgb(); } - bool isCgbDmg() const { return lcd_.isCgbDmg(); } - bool ime() const { return intreq_.ime(); } - bool halted() const { return intreq_.halted(); } - unsigned long nextEventTime() const { return intreq_.minEventTime(); } - void setLayers(unsigned mask) { lcd_.setLayers(mask); } - bool isActive() const { return intreq_.eventTime(intevent_end) != disabled_time; } - - long cyclesSinceBlit(unsigned long cc) const { - if (cc < intreq_.eventTime(intevent_blit)) - return -1; - - return (cc - intreq_.eventTime(intevent_blit)) >> isDoubleSpeed(); - } - - void freeze(unsigned long cc); - bool halt(unsigned long cc); - void ei(unsigned long cycleCounter) { if (!ime()) { intreq_.ei(cycleCounter); } } - void di() { intreq_.di(); } - - unsigned pendingIrqs(unsigned long cc); - void ackIrq(unsigned bit, unsigned long cc); - - unsigned readBios(unsigned p) { - if(isCgb() && agbMode_ && p >= 0xF3 && p < 0x100) { - return (agbOverride[p-0xF3] + bios_[p]) & 0xFF; - } - return bios_[p]; - } - - unsigned ff_read(unsigned p, unsigned long cc) { - if (readCallback_) - readCallback_(p, (cc - basetime_) >> 1); - return p < 0x80 ? nontrivial_ff_read(p, cc) : ioamhram_[p + 0x100]; - } - - struct CDMapResult - { - eCDLog_AddrType type; - unsigned addr; - }; - - CDMapResult CDMap(const unsigned p) const - { - if(p < 0x4000) - { - CDMapResult ret = { eCDLog_AddrType_ROM, p }; - return ret; - } - else if(p < 0x8000) - { - unsigned bank = cart_.rmem(p >> 12) - cart_.rmem(0); - unsigned addr = p + bank; - CDMapResult ret = { eCDLog_AddrType_ROM, addr }; - return ret; - } - else if(p < 0xA000) {} - else if(p < 0xC000) - { - if(cart_.wsrambankptr()) - { - //not bankable. but. we're not sure how much might be here - unsigned char *data; - int length; - bool has = cart_.getMemoryArea(3,&data,&length); - unsigned addr = p & (length-1); - if(has && length!=0) - { - CDMapResult ret = { eCDLog_AddrType_CartRAM, addr }; - return ret; - } - } - } - else if(p < 0xE000) - { - unsigned bank = cart_.wramdata(p >> 12 & 1) - cart_.wramdata(0); - unsigned addr = (p & 0xFFF) + bank; - CDMapResult ret = { eCDLog_AddrType_WRAM, addr }; - return ret; - } - else if(p < 0xFF80) {} - else - { - ////this is just for debugging, really, it's pretty useless - //CDMapResult ret = { eCDLog_AddrType_HRAM, (P-0xFF80) }; - //return ret; - } - - CDMapResult ret = { eCDLog_AddrType_None }; - return ret; - } - - unsigned read(unsigned p, unsigned long cc) { - if (readCallback_) - readCallback_(p, (cc - basetime_) >> 1); - if(biosMode_) { - if (p < biosSize_ && !(p >= 0x100 && p < 0x200)) - return readBios(p); - } - else if(cdCallback_) { - CDMapResult map = CDMap(p); - if(map.type != eCDLog_AddrType_None) - cdCallback_(map.addr, map.type, eCDLog_Flags_Data); - } - return cart_.rmem(p >> 12) ? cart_.rmem(p >> 12)[p] : nontrivial_read(p, cc); - } - - unsigned read_excb(unsigned p, unsigned long cc, bool first) { - if (execCallback_) - execCallback_(p, (cc - basetime_) >> 1); - if (biosMode_) { - if(p < biosSize_ && !(p >= 0x100 && p < 0x200)) - return readBios(p); - } - else if(cdCallback_) { - CDMapResult map = CDMap(p); - if(map.type != eCDLog_AddrType_None) - cdCallback_(map.addr, map.type, first ? eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand); - } - return cart_.rmem(p >> 12) ? cart_.rmem(p >> 12)[p] : nontrivial_read(p, cc); - } - - unsigned peek(unsigned p) { - if (biosMode_ && p < biosSize_ && !(p >= 0x100 && p < 0x200)) { - return readBios(p); - } - return cart_.rmem(p >> 12) ? cart_.rmem(p >> 12)[p] : nontrivial_peek(p); - } - - void write_nocb(unsigned p, unsigned data, unsigned long cc) { - if (cart_.wmem(p >> 12)) { - cart_.wmem(p >> 12)[p] = data; - } else - nontrivial_write(p, data, cc); - } - - void write(unsigned p, unsigned data, unsigned long cc) { - if (cart_.wmem(p >> 12)) { - cart_.wmem(p >> 12)[p] = data; - } else - nontrivial_write(p, data, cc); - if (writeCallback_) - writeCallback_(p, (cc - basetime_) >> 1); - if(cdCallback_ && !biosMode_) { - CDMapResult map = CDMap(p); - if(map.type != eCDLog_AddrType_None) - cdCallback_(map.addr, map.type, eCDLog_Flags_Data); - } - } - - void ff_write(unsigned p, unsigned data, unsigned long cc) { - if (p - 0x80u < 0x7Fu) { - ioamhram_[p + 0x100] = data; - } else - nontrivial_ff_write(p, data, cc); - if (writeCallback_) - writeCallback_(0xff00 + p, (cc - basetime_) >> 1); - if(cdCallback_ && !biosMode_) - { - CDMapResult map = CDMap(0xff00 + p); - if(map.type != eCDLog_AddrType_None) - cdCallback_(map.addr, map.type, eCDLog_Flags_Data); - } - } - - unsigned long event(unsigned long cycleCounter); - unsigned long resetCounters(unsigned long cycleCounter); - LoadRes loadROM(char const *romfiledata, unsigned romfilelength, unsigned flags); - - void setInputGetter(unsigned (*getInput)()) { - getInput_ = getInput; - } - - void setReadCallback(MemoryCallback callback) { - this->readCallback_ = callback; - } - void setWriteCallback(MemoryCallback callback) { - this->writeCallback_ = callback; - } - void setExecCallback(MemoryCallback callback) { - this->execCallback_ = callback; - } - void setCDCallback(CDCallback cdc) { - this->cdCallback_ = cdc; - } - - void setScanlineCallback(void (*callback)(), int sl) { - lcd_.setScanlineCallback(callback, sl); - } - - void setLinkCallback(void(*callback)()) { - this->linkCallback_ = callback; - } - - void setEndtime(unsigned long cc, unsigned long inc); - void setBasetime(unsigned long cc) { basetime_ = cc; } - - void setSoundBuffer(uint_least32_t *buf) { psg_.setBuffer(buf); } - std::size_t fillSoundBuffer(unsigned long cc); - - void setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch) { - lcd_.setVideoBuffer(videoBuf, pitch); - } - - void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) { - lcd_.setDmgPaletteColor(palNum, colorNum, rgb32); - } - - void blackScreen() { - lcd_.blackScreen(); - } - - void setCgbPalette(unsigned *lut); - void setTimeMode(bool useCycles, unsigned long const cc) { - cart_.setTimeMode(useCycles, cc); - } - void setRtcDivisorOffset(long const rtcDivisorOffset) { cart_.setRtcDivisorOffset(rtcDivisorOffset); } - - int linkStatus(int which); - -private: - Cartridge cart_; - unsigned char ioamhram_[0x200]; - unsigned char *bios_; - std::size_t biosSize_; - unsigned (*getInput_)(); - unsigned long divLastUpdate_; - unsigned long lastOamDmaUpdate_; - InterruptRequester intreq_; - Tima tima_; - LCD lcd_; - PSG psg_; - Interrupter interrupter_; - unsigned short dmaSource_; - unsigned short dmaDestination_; - unsigned char oamDmaPos_; - unsigned char oamDmaStartPos_; - unsigned char serialCnt_; - bool blanklcd_; - bool biosMode_; - bool agbMode_; - unsigned long basetime_; - bool stopped_; - enum HdmaState { hdma_low, hdma_high, hdma_requested } haltHdmaState_; - - MemoryCallback readCallback_; - MemoryCallback writeCallback_; - MemoryCallback execCallback_; - CDCallback cdCallback_; - void(*linkCallback_)(); - bool LINKCABLE_; - bool linkClockTrigger_; - - void decEventCycles(IntEventId eventId, unsigned long dec); - void oamDmaInitSetup(); - void updateOamDma(unsigned long cycleCounter); - void startOamDma(unsigned long cycleCounter); - void endOamDma(unsigned long cycleCounter); - unsigned char const * oamDmaSrcPtr() const; - unsigned long dma(unsigned long cc); - unsigned nontrivial_ff_read(unsigned p, unsigned long cycleCounter); - unsigned nontrivial_read(unsigned p, unsigned long cycleCounter); - void nontrivial_ff_write(unsigned p, unsigned data, unsigned long cycleCounter); - void nontrivial_write(unsigned p, unsigned data, unsigned long cycleCounter); - unsigned nontrivial_peek(unsigned p); - unsigned nontrivial_ff_peek(unsigned p); - void updateSerial(unsigned long cc); - void updateTimaIrq(unsigned long cc); - void updateIrqs(unsigned long cc); - bool isDoubleSpeed() const { return lcd_.isDoubleSpeed(); } - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/minkeeper.h b/libgambatte/src/minkeeper.h deleted file mode 100644 index 322d746d7c..0000000000 --- a/libgambatte/src/minkeeper.h +++ /dev/null @@ -1,168 +0,0 @@ -// -// Copyright (C) 2009 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef MINKEEPER_H -#define MINKEEPER_H - -#include -#include "newstate.h" - -namespace min_keeper_detail { - -template struct CeiledLog2 { enum { r = 1 + CeiledLog2<(n + 1) / 2>::r }; }; -template<> struct CeiledLog2<1> { enum { r = 0 }; }; - -template struct CeiledDiv2n { enum { r = CeiledDiv2n<(v + 1) / 2, n - 1>::r }; }; -template struct CeiledDiv2n { enum { r = v }; }; -// alternatively: template struct CeiledDiv2n { enum { r = (v + (1 << n) - 1) >> n }; }; - -template class T, int n> struct Sum { enum { r = T::r + Sum::r }; }; -template class T> struct Sum { enum { r = 0 }; }; - -} - -// Keeps track of minimum value identified by id as values change. -// Higher ids prioritized (as min value) if values are equal. (Can be inverted by swapping < for <=). -// Higher ids can be faster to change when the number of ids isn't a power of 2. -// Thus, the ones that change more frequently should have higher ids if priority allows for it. -template -class MinKeeper { -public: - explicit MinKeeper(unsigned long initValue); - int min() const { return a_[0]; } - unsigned long minValue() const { return minValue_; } - - template - void setValue(unsigned long cnt) { - values_[id] = cnt; - updateValue(*this); - } - - void setValue(int id, unsigned long cnt) { - values_[id] = cnt; - updateValueLut.call(id >> 1, *this); - } - - unsigned long value(int id) const { return values_[id]; } - -private: - enum { height = min_keeper_detail::CeiledLog2::r }; - template struct Num { enum { r = min_keeper_detail::CeiledDiv2n::r }; }; - template struct Sum { enum { r = min_keeper_detail::Sum::r }; }; - - template - struct UpdateValue { - enum { p = Sum::r + id - , c0 = Sum::r + id * 2 - , c1 = id * 2 + 1 < Num::r ? c0 + 1 : c0 }; - static void updateValue(MinKeeper &m) { - m.a_[p] = m.values_[m.a_[c0]] < m.values_[m.a_[c1]] ? m.a_[c0] : m.a_[c1]; - UpdateValue::updateValue(m); - } - }; - - template - struct UpdateValue { - static void updateValue(MinKeeper &m) { - m.minValue_ = m.values_[m.a_[0]]; - } - }; - - class UpdateValueLut { - public: - UpdateValueLut() { FillLut::r - 1, 0>::fillLut(*this); } - void call(int id, MinKeeper &mk) const { lut_[id](mk); } - - private: - template - struct FillLut { - static void fillLut(UpdateValueLut & l) { - l.lut_[id] = updateValue; - FillLut::fillLut(l); - } - }; - - template - struct FillLut<-1, dummy> { - static void fillLut(UpdateValueLut &) {} - }; - - void (*lut_[Num::r])(MinKeeper &); - }; - - static UpdateValueLut updateValueLut; - unsigned long values_[ids]; - unsigned long minValue_; - int a_[Sum::r]; - - template static void updateValue(MinKeeper &m); - - -public: - // not sure if i understood everything in minkeeper correctly, so something might be missing here? - template - void SyncState(gambatte::NewState *ns) - { - NSS(values_); - NSS(minValue_); - NSS(a_); - } -}; - -template typename MinKeeper::UpdateValueLut MinKeeper::updateValueLut; - -template -MinKeeper::MinKeeper(unsigned long const initValue) { - std::fill(values_, values_ + ids, initValue); - - // todo: simplify/less template bloat. - - for (int i = 0; i < Num::r; ++i) { - int const c0 = i * 2; - int const c1 = c0 + 1 < ids ? c0 + 1 : c0; - a_[Sum::r + i] = values_[c0] < values_[c1] ? c0 : c1; - } - - int n = Num::r; - int offset = Sum::r; - while (offset) { - int const pn = (n + 1) >> 1; - int const poff = offset - pn; - for (int i = 0; i < pn; ++i) { - int const c0 = offset + i * 2; - int const c1 = i * 2 + 1 < n ? c0 + 1 : c0; - a_[poff + i] = values_[a_[c0]] < values_[a_[c1]] ? a_[c0] : a_[c1]; - } - - offset = poff; - n = pn; - } - - minValue_ = values_[a_[0]]; -} - -template -template -void MinKeeper::updateValue(MinKeeper &m) { - enum { c0 = id * 2 - , c1 = c0 + 1 < ids ? c0 + 1 : c0 }; - m.a_[Sum::r + id] = m.values_[c0] < m.values_[c1] ? c0 : c1; - UpdateValue::updateValue(m); -} - -#endif diff --git a/libgambatte/src/newstate.cpp b/libgambatte/src/newstate.cpp deleted file mode 100644 index 4aae0b1679..0000000000 --- a/libgambatte/src/newstate.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "newstate.h" -#include -#include - -namespace gambatte { - -NewStateDummy::NewStateDummy() - :length(0) -{ -} -void NewStateDummy::Save(void const *ptr, size_t size, char const *name) -{ - length += size; -} -void NewStateDummy::Load(void *ptr, size_t size, char const *name) -{ -} - -NewStateExternalBuffer::NewStateExternalBuffer(char *buffer, long maxlength) - :buffer(buffer), length(0), maxlength(maxlength) -{ -} - -void NewStateExternalBuffer::Save(void const *ptr, size_t size, char const *name) -{ - if (maxlength - length >= (long)size) - { - std::memcpy(buffer + length, ptr, size); - } - length += size; -} - -void NewStateExternalBuffer::Load(void *ptr, size_t size, char const *name) -{ - char *dst = static_cast(ptr); - if (maxlength - length >= (long)size) - { - std::memcpy(dst, buffer + length, size); - } - length += size; -} - -NewStateExternalFunctions::NewStateExternalFunctions(const FPtrs *ff) - :Save_(ff->Save_), - Load_(ff->Load_), - EnterSection_(ff->EnterSection_), - ExitSection_(ff->ExitSection_) -{ -} - -void NewStateExternalFunctions::Save(void const *ptr, size_t size, char const *name) -{ - Save_(ptr, size, name); -} -void NewStateExternalFunctions::Load(void *ptr, size_t size, char const *name) -{ - Load_(ptr, size, name); -} -void NewStateExternalFunctions::EnterSection(char const *name) -{ - EnterSection_(name); -} -void NewStateExternalFunctions::ExitSection(char const *name) -{ - ExitSection_(name); -} - - -} diff --git a/libgambatte/src/newstate.h b/libgambatte/src/newstate.h deleted file mode 100644 index 1ad9088224..0000000000 --- a/libgambatte/src/newstate.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef NEWSTATE_H -#define NEWSTATE_H - -#include -#include - -namespace gambatte { - -class NewState -{ -public: - virtual void Save(void const *ptr, std::size_t size, char const *name) = 0; - virtual void Load(void *ptr, std::size_t size, char const *name) = 0; - virtual void EnterSection(char const *name) { } - virtual void ExitSection(char const *name) { } -}; - -class NewStateDummy : public NewState -{ -private: - long length; -public: - NewStateDummy(); - long GetLength() { return length; } - void Rewind() { length = 0; } - virtual void Save(void const *ptr, std::size_t size, char const *name); - virtual void Load(void *ptr, std::size_t size, char const *name); -}; - -class NewStateExternalBuffer : public NewState -{ -private: - char *const buffer; - long length; - const long maxlength; -public: - NewStateExternalBuffer(char *buffer, long maxlength); - long GetLength() { return length; } - void Rewind() { length = 0; } - bool Overflow() { return length > maxlength; } - virtual void Save(void const *ptr, std::size_t size, char const *name); - virtual void Load(void *ptr, std::size_t size, char const *name); -}; - -struct FPtrs -{ - void (*Save_)(void const *ptr, std::size_t size, char const *name); - void (*Load_)(void *ptr, std::size_t size, char const *name); - void (*EnterSection_)(char const *name); - void (*ExitSection_)(char const *name); -}; - -class NewStateExternalFunctions : public NewState -{ -private: - void (*Save_)(void const *ptr, std::size_t size, char const *name); - void (*Load_)(void *ptr, std::size_t size, char const *name); - void (*EnterSection_)(char const *name); - void (*ExitSection_)(char const *name); -public: - NewStateExternalFunctions(const FPtrs *ff); - virtual void Save(void const *ptr, std::size_t size, char const *name); - virtual void Load(void *ptr, std::size_t size, char const *name); - virtual void EnterSection(char const *name); - virtual void ExitSection(char const *name); -}; - -// defines and explicitly instantiates -#define SYNCFUNC(x)\ - template void x::SyncState(NewState *ns);\ - template void x::SyncState(NewState *ns);\ - templatevoid x::SyncState(NewState *ns) - -// N = normal variable -// P = pointer to fixed size data -// S = "sub object" -// T = "ptr to sub object" -// R = pointer, store its offset from some other pointer -// E = general purpose cased value "enum" - - -// first line is default value in converted enum; last line is default value in argument x -#define EBS(x,d) do { int _ttmp = (d); if (isReader) ns->Load(&_ttmp, sizeof _ttmp, #x); if (0) -#define EVS(x,v,n) else if (!isReader && (x) == (v)) _ttmp = (n); else if (isReader && _ttmp == (n)) (x) = (v) -#define EES(x,d) else if (isReader) (x) = (d); if (!isReader) ns->Save(&_ttmp, sizeof _ttmp, #x); } while (0) - -#define RSS(x,b) do { if (isReader)\ -{ std::ptrdiff_t _ttmp; ns->Load(&_ttmp, sizeof _ttmp, #x); (x) = (_ttmp == (std::ptrdiff_t)0xdeadbeef ? 0 : (b) + _ttmp); }\ - else\ -{ std::ptrdiff_t _ttmp = (x) == 0 ? 0xdeadbeef : (x) - (b); ns->Save(&_ttmp, sizeof _ttmp, #x); } } while (0) - -#define PSS(x,s) do { if (isReader) ns->Load((x), (s), #x); else ns->Save((x), (s), #x); } while (0) - -#define NSS(x) do { if (isReader) ns->Load(&(x), sizeof x, #x); else ns->Save(&(x), sizeof x, #x); } while (0) - -#define SSS(x) do { ns->EnterSection(#x); (x).SyncState(ns); ns->ExitSection(#x); } while (0) - -#define TSS(x) do { ns->EnterSection(#x); (x)->SyncState(ns); ns->ExitSection(#x); } while (0) - -} - -#endif diff --git a/libgambatte/src/savestate.h b/libgambatte/src/savestate.h deleted file mode 100644 index 64388e247d..0000000000 --- a/libgambatte/src/savestate.h +++ /dev/null @@ -1,225 +0,0 @@ -// -// Copyright (C) 2008 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef SAVESTATE_H -#define SAVESTATE_H - -#include -#include - -namespace gambatte { - -class SaverList; - -struct SaveState { - template - class Ptr { - public: - Ptr() : ptr(0), size_(0) {} - T const * get() const { return ptr; } - std::size_t size() const { return size_; } - void set(T *p, std::size_t size) { ptr = p; size_ = size; } - - friend class SaverList; - friend void setInitState(SaveState &, bool); - private: - T *ptr; - std::size_t size_; - }; - - struct CPU { - unsigned long cycleCounter; - unsigned short pc; - unsigned short sp; - unsigned char a; - unsigned char b; - unsigned char c; - unsigned char d; - unsigned char e; - unsigned char f; - unsigned char h; - unsigned char l; - unsigned char opcode; - unsigned char /*bool*/ prefetched; - unsigned char /*bool*/ skip; - } cpu; - - struct Mem { - Ptr vram; - Ptr sram; - Ptr wram; - Ptr ioamhram; - unsigned long divLastUpdate; - unsigned long timaLastUpdate; - unsigned long tmatime; - unsigned long nextSerialtime; - unsigned long lastOamDmaUpdate; - unsigned long minIntTime; - unsigned long unhaltTime; - unsigned short rombank; - unsigned short dmaSource; - unsigned short dmaDestination; - unsigned char rambank; - unsigned char oamDmaPos; - unsigned char haltHdmaState; - unsigned char HuC3RAMflag; - unsigned char /*bool*/ IME; - unsigned char /*bool*/ halted; - unsigned char /*bool*/ enableRam; - unsigned char /*bool*/ rambankMode; - unsigned char /*bool*/ hdmaTransfer; - unsigned char /*bool*/ biosMode; - unsigned char /*bool*/ stopped; - } mem; - - struct PPU { - Ptr bgpData; - Ptr objpData; - //SpriteMapper::OamReader - Ptr oamReaderBuf; - Ptr oamReaderSzbuf; - - unsigned long videoCycles; - unsigned long enableDisplayM0Time; - unsigned short lastM0Time; - unsigned short nextM0Irq; - unsigned short tileword; - unsigned short ntileword; - unsigned char spAttribList[10]; - unsigned char spByte0List[10]; - unsigned char spByte1List[10]; - unsigned char winYPos; - unsigned char xpos; - unsigned char endx; - unsigned char reg0; - unsigned char reg1; - unsigned char attrib; - unsigned char nattrib; - unsigned char state; - unsigned char nextSprite; - unsigned char currentSprite; - unsigned char lyc; - unsigned char m0lyc; - unsigned char oldWy; - unsigned char winDrawState; - unsigned char wscx; - unsigned char /*bool*/ weMaster; - unsigned char /*bool*/ pendingLcdstatIrq; - unsigned char /*bool*/ notCgbDmg; - } ppu; - - struct SPU { - struct Duty { - unsigned long nextPosUpdate; - unsigned char nr3; - unsigned char pos; - unsigned char /*bool*/ high; - }; - - struct Env { - unsigned long counter; - unsigned char volume; - }; - - struct LCounter { - unsigned long counter; - unsigned short lengthCounter; - }; - - struct { - struct { - unsigned long counter; - unsigned short shadow; - unsigned char nr0; - unsigned char /*bool*/ neg; - } sweep; - Duty duty; - Env env; - LCounter lcounter; - unsigned char nr4; - unsigned char /*bool*/ master; - } ch1; - - struct { - Duty duty; - Env env; - LCounter lcounter; - unsigned char nr4; - unsigned char /*bool*/ master; - } ch2; - - struct { - Ptr waveRam; - LCounter lcounter; - unsigned long waveCounter; - unsigned long lastReadTime; - unsigned char nr3; - unsigned char nr4; - unsigned char wavePos; - unsigned char sampleBuf; - unsigned char /*bool*/ master; - } ch3; - - struct { - struct { - unsigned long counter; - unsigned short reg; - } lfsr; - Env env; - LCounter lcounter; - unsigned char nr4; - unsigned char /*bool*/ master; - } ch4; - - unsigned long cycleCounter; - unsigned char lastUpdate; - } spu; - - struct Time { - unsigned long seconds; - unsigned long lastTimeSec; - unsigned long lastTimeUsec; - unsigned long lastCycles; - } time; - - struct RTC { - unsigned long haltTime; - unsigned char dataDh; - unsigned char dataDl; - unsigned char dataH; - unsigned char dataM; - unsigned char dataS; - unsigned char /*bool*/ lastLatchData; - } rtc; - - struct HuC3 { - unsigned long haltTime; - unsigned long dataTime; - unsigned long writingTime; - unsigned long irBaseCycle; - unsigned char /*bool*/ halted; - unsigned char shift; - unsigned char ramValue; - unsigned char modeflag; - unsigned char /*bool*/ irReceivingPulse; - } huc3; -}; - -} - -#endif diff --git a/libgambatte/src/sound.cpp b/libgambatte/src/sound.cpp deleted file mode 100644 index e6db1c9d55..0000000000 --- a/libgambatte/src/sound.cpp +++ /dev/null @@ -1,230 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "sound.h" -#include "savestate.h" -#include -#include - -/* - Frame Sequencer - - Step Length Ctr Vol Env Sweep - - - - - - - - - - - - - - - - - - - - - -S0 0 Clock - Clock -S1 1 - Clock - - 2 Clock - - - 3 - - - - 4 Clock - Clock - 5 - - - - 6 Clock - - - 7 - - - - - - - - - - - - - - - - - - - - - - - - - Rate 256 Hz 64 Hz 128 Hz - -S0) start step on sound power on. -S1) step gets immediately incremented at power on if closer to previous edge than next. -Clock) clock timer on transition to step. - -*/ - -using namespace gambatte; - -PSG::PSG() -: buffer_(0) -, bufferPos_(0) -, lastUpdate_(0) -, cycleCounter_(0) -, soVol_(0) -, rsum_(0x8000) // initialize to 0x8000 to prevent borrows from high word, xor away later -, enabled_(false) -{ -} - -void PSG::init(bool cgb) { - ch1_.init(cgb); - ch3_.init(cgb); -} - -void PSG::reset(bool ds) { - int const divOffset = lastUpdate_ & ds; - unsigned long const cc = cycleCounter_ + divOffset; - // cycleCounter >> 12 & 7 represents the frame sequencer position. - cycleCounter_ = (cc & 0xFFF) + 2 * (~(cc + 1 + !ds) & 0x800); - lastUpdate_ = ((lastUpdate_ + 3) & -4) - !ds; - ch1_.reset(); - ch2_.reset(); - ch3_.reset(); - ch4_.reset(cycleCounter_); -} - -void PSG::divReset(bool ds) { - int const divOffset = lastUpdate_ & ds; - unsigned long const cc = cycleCounter_ + divOffset; - cycleCounter_ = (cc & -0x1000) + 2 * (cc & 0x800) - divOffset; - ch1_.resetCc(cc - divOffset, cycleCounter_); - ch2_.resetCc(cc - divOffset, cycleCounter_); - ch3_.resetCc(cc - divOffset, cycleCounter_); - ch4_.resetCc(cc - divOffset, cycleCounter_); -} - -void PSG::speedChange(unsigned long const cpuCc, bool const ds) { - generateSamples(cpuCc, ds); - lastUpdate_ -= ds; - // correct for cycles since DIV reset (if any). - if (!ds) { - unsigned long const cc = cycleCounter_; - unsigned const divCycles = cc & 0xFFF; - cycleCounter_ = cc - divCycles / 2 - lastUpdate_ % 2; - ch1_.resetCc(cc, cycleCounter_); - ch2_.resetCc(cc, cycleCounter_); - ch3_.resetCc(cc, cycleCounter_); - ch4_.resetCc(cc, cycleCounter_); - } -} - -void PSG::setStatePtrs(SaveState &state) { - ch3_.setStatePtrs(state); -} - -void PSG::loadState(SaveState const &state) { - ch1_.loadState(state); - ch2_.loadState(state); - ch3_.loadState(state); - ch4_.loadState(state); - - cycleCounter_ = state.spu.cycleCounter; - lastUpdate_ = state.cpu.cycleCounter - (1 - state.spu.lastUpdate) % 4u; - setSoVolume(state.mem.ioamhram.get()[0x124]); - mapSo(state.mem.ioamhram.get()[0x125]); - enabled_ = state.mem.ioamhram.get()[0x126] >> 7 & 1; -} - -inline void PSG::accumulateChannels(unsigned long const cycles) { - unsigned long const cc = cycleCounter_; - uint_least32_t* const buf = buffer_ + bufferPos_; - std::memset(buf, 0, cycles * sizeof * buf); - ch1_.update(buf, soVol_, cc, cc + cycles); - ch2_.update(buf, soVol_, cc, cc + cycles); - ch3_.update(buf, soVol_, cc, cc + cycles); - ch4_.update(buf, soVol_, cc, cc + cycles); - cycleCounter_ = (cc + cycles) % SoundUnit::counter_max; -} - -void PSG::generateSamples(unsigned long const cpuCc, bool const doubleSpeed) { - unsigned long const cycles = (cpuCc - lastUpdate_) >> (1 + doubleSpeed); - lastUpdate_ += cycles << (1 + doubleSpeed); - - if (cycles) - accumulateChannels(cycles); - - bufferPos_ += cycles; -} - -void PSG::resetCounter(unsigned long newCc, unsigned long oldCc, bool doubleSpeed) { - generateSamples(oldCc, doubleSpeed); - lastUpdate_ = newCc - (oldCc - lastUpdate_); -} - -std::size_t PSG::fillBuffer() { - uint_least32_t sum = rsum_; - uint_least32_t *b = buffer_; - std::size_t n = bufferPos_; - - if (std::size_t n2 = n >> 3) { - n -= n2 << 3; - - do { - sum += b[0]; - b[0] = sum ^ 0x8000; - sum += b[1]; - b[1] = sum ^ 0x8000; - sum += b[2]; - b[2] = sum ^ 0x8000; - sum += b[3]; - b[3] = sum ^ 0x8000; - sum += b[4]; - b[4] = sum ^ 0x8000; - sum += b[5]; - b[5] = sum ^ 0x8000; - sum += b[6]; - b[6] = sum ^ 0x8000; - sum += b[7]; - b[7] = sum ^ 0x8000; - - b += 8; - } while (--n2); - } - - while (n--) { - sum += *b; - // xor away the initial rsum value of 0x8000 (which prevents - // borrows from the high word) from the low word - *b++ = sum ^ 0x8000; - } - - rsum_ = sum; - - return bufferPos_; -} - -static bool isBigEndianSampleOrder() { - union { - uint_least32_t ul32; - unsigned char uc[sizeof(uint_least32_t)]; - } u; - u.ul32 = -0x10000; - return u.uc[0]; -} - -static unsigned long so1Mul() { return isBigEndianSampleOrder() ? 0x00000001 : 0x00010000; } -static unsigned long so2Mul() { return isBigEndianSampleOrder() ? 0x00010000 : 0x00000001; } - -void PSG::setSoVolume(unsigned nr50) { - soVol_ = ((nr50 & 0x7) + 1) * so1Mul() * 64 - + ((nr50 >> 4 & 0x7) + 1) * so2Mul() * 64; -} - -void PSG::mapSo(unsigned nr51) { - unsigned long so = nr51 * so1Mul() + (nr51 >> 4) * so2Mul(); - ch1_.setSo((so & 0x00010001) * 0xFFFF, cycleCounter_); - ch2_.setSo((so >> 1 & 0x00010001) * 0xFFFF, cycleCounter_); - ch3_.setSo((so >> 2 & 0x00010001) * 0xFFFF); - ch4_.setSo((so >> 3 & 0x00010001) * 0xFFFF, cycleCounter_); -} - -unsigned PSG::getStatus() const { - return ch1_.isActive() - | ch2_.isActive() << 1 - | ch3_.isActive() << 2 - | ch4_.isActive() << 3; -} - -// the buffer and position are not saved, as they're set and flushed on each runfor() call -SYNCFUNC(PSG) -{ - SSS(ch1_); - SSS(ch2_); - SSS(ch3_); - SSS(ch4_); - NSS(lastUpdate_); - NSS(cycleCounter_); - NSS(soVol_); - NSS(rsum_); - NSS(enabled_); -} diff --git a/libgambatte/src/sound.h b/libgambatte/src/sound.h deleted file mode 100644 index 232d52a518..0000000000 --- a/libgambatte/src/sound.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef SOUND_H -#define SOUND_H - -#include "sound/channel1.h" -#include "sound/channel2.h" -#include "sound/channel3.h" -#include "sound/channel4.h" -#include "newstate.h" - -namespace gambatte { - -class PSG { -public: - PSG(); - void init(bool cgb); - void reset(bool ds); - void divReset(bool ds); - void setStatePtrs(SaveState &state); - void loadState(SaveState const &state); - - void generateSamples(unsigned long cycleCounter, bool doubleSpeed); - void resetCounter(unsigned long newCc, unsigned long oldCc, bool doubleSpeed); - void speedChange(unsigned long cc, bool doubleSpeed); - std::size_t fillBuffer(); - void setBuffer(uint_least32_t *buf) { buffer_ = buf; bufferPos_ = 0; } - - bool isEnabled() const { return enabled_; } - void setEnabled(bool value) { enabled_ = value; } - - void setNr10(unsigned data) { ch1_.setNr0(data); } - void setNr11(unsigned data) { ch1_.setNr1(data, cycleCounter_); } - void setNr12(unsigned data) { ch1_.setNr2(data, cycleCounter_); } - void setNr13(unsigned data) { ch1_.setNr3(data, cycleCounter_); } - void setNr14(unsigned data, bool ds) { ch1_.setNr4(data, cycleCounter_, !(lastUpdate_ & ds)); } - - void setNr21(unsigned data) { ch2_.setNr1(data, cycleCounter_); } - void setNr22(unsigned data) { ch2_.setNr2(data, cycleCounter_); } - void setNr23(unsigned data) { ch2_.setNr3(data, cycleCounter_); } - void setNr24(unsigned data, bool ds) { ch2_.setNr4(data, cycleCounter_, !(lastUpdate_ & ds)); } - - void setNr30(unsigned data) { ch3_.setNr0(data); } - void setNr31(unsigned data) { ch3_.setNr1(data, cycleCounter_); } - void setNr32(unsigned data) { ch3_.setNr2(data); } - void setNr33(unsigned data) { ch3_.setNr3(data); } - void setNr34(unsigned data) { ch3_.setNr4(data, cycleCounter_); } - unsigned waveRamRead(unsigned index) const { return ch3_.waveRamRead(index, cycleCounter_); } - void waveRamWrite(unsigned index, unsigned data) { ch3_.waveRamWrite(index, data, cycleCounter_); } - - void setNr41(unsigned data) { ch4_.setNr1(data, cycleCounter_); } - void setNr42(unsigned data) { ch4_.setNr2(data, cycleCounter_); } - void setNr43(unsigned data) { ch4_.setNr3(data, cycleCounter_); } - void setNr44(unsigned data) { ch4_.setNr4(data, cycleCounter_); } - - void setSoVolume(unsigned nr50); - void mapSo(unsigned nr51); - unsigned getStatus() const; - -private: - Channel1 ch1_; - Channel2 ch2_; - Channel3 ch3_; - Channel4 ch4_; - uint_least32_t *buffer_; - std::size_t bufferPos_; - unsigned long lastUpdate_; - unsigned long cycleCounter_; - unsigned long soVol_; - uint_least32_t rsum_; - bool enabled_; - - void accumulateChannels(unsigned long cycles); - - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/sound/channel1.cpp b/libgambatte/src/sound/channel1.cpp deleted file mode 100644 index 58d90edbf1..0000000000 --- a/libgambatte/src/sound/channel1.cpp +++ /dev/null @@ -1,259 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "channel1.h" -#include "psgdef.h" -#include "../savestate.h" -#include - -using namespace gambatte; - -Channel1::SweepUnit::SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit) -: disableMaster_(disabler) -, dutyUnit_(dutyUnit) -, shadow_(0) -, nr0_(0) -, neg_(false) -, cgb_(false) -{ -} - -unsigned Channel1::SweepUnit::calcFreq() { - unsigned const freq = nr0_ & psg_nr10_neg - ? shadow_ - (shadow_ >> (nr0_ & psg_nr10_rsh)) - : shadow_ + (shadow_ >> (nr0_ & psg_nr10_rsh)); - if (nr0_ & psg_nr10_neg) - neg_ = true; - if (freq & 2048) - disableMaster_(); - - return freq; -} - -void Channel1::SweepUnit::event() { - unsigned long const period = (nr0_ & psg_nr10_time) / (1u * psg_nr10_time & -psg_nr10_time); - - if (period) { - unsigned const freq = calcFreq(); - - if (!(freq & 2048) && nr0_ & psg_nr10_rsh) { - shadow_ = freq; - dutyUnit_.setFreq(freq, counter_); - calcFreq(); - } - - counter_ += period << 14; - } else - counter_ += 8ul << 14; -} - -void Channel1::SweepUnit::nr0Change(unsigned newNr0) { - if (neg_ && !(newNr0 & 0x08)) - disableMaster_(); - - nr0_ = newNr0; -} - -void Channel1::SweepUnit::nr4Init(unsigned long const cc) { - neg_ = false; - shadow_ = dutyUnit_.freq(); - - unsigned const period = (nr0_ & psg_nr10_time) / (1u * psg_nr10_time & -psg_nr10_time); - unsigned const rsh = nr0_ & psg_nr10_rsh; - - if (period | rsh) - counter_ = ((((cc + 2 + cgb_ * 2) >> 14) + (period ? period : 8)) << 14) + 2; - else - counter_ = counter_disabled; - - if (rsh) - calcFreq(); -} - -void Channel1::SweepUnit::reset() { - counter_ = counter_disabled; -} - -void Channel1::SweepUnit::loadState(SaveState const &state) { - counter_ = std::max(state.spu.ch1.sweep.counter, state.spu.cycleCounter); - shadow_ = state.spu.ch1.sweep.shadow; - nr0_ = state.spu.ch1.sweep.nr0; - neg_ = state.spu.ch1.sweep.neg; -} - -template -void Channel1::SweepUnit::SyncState(NewState *ns) -{ - NSS(counter_); - NSS(shadow_); - NSS(nr0_); - NSS(neg_); - NSS(cgb_); -} - -Channel1::Channel1() -: staticOutputTest_(*this, dutyUnit_) -, disableMaster_(master_, dutyUnit_) -, lengthCounter_(disableMaster_, 0x3F) -, envelopeUnit_(staticOutputTest_) -, sweepUnit_(disableMaster_, dutyUnit_) -, nextEventUnit_(0) -, soMask_(0) -, prevOut_(0) -, nr4_(0) -, master_(false) -{ - setEvent(); -} - -void Channel1::setEvent() { - nextEventUnit_ = &sweepUnit_; - if (envelopeUnit_.counter() < nextEventUnit_->counter()) - nextEventUnit_ = &envelopeUnit_; - if (lengthCounter_.counter() < nextEventUnit_->counter()) - nextEventUnit_ = &lengthCounter_; -} - -void Channel1::setNr0(unsigned data) { - sweepUnit_.nr0Change(data); - setEvent(); -} - -void Channel1::setNr1(unsigned data, unsigned long cc) { - lengthCounter_.nr1Change(data, nr4_, cc); - dutyUnit_.nr1Change(data, cc); - setEvent(); -} - -void Channel1::setNr2(unsigned data, unsigned long cc) { - if (envelopeUnit_.nr2Change(data)) - disableMaster_(); - else - staticOutputTest_(cc); - - setEvent(); -} - -void Channel1::setNr3(unsigned data, unsigned long cc) { - dutyUnit_.nr3Change(data, cc); - setEvent(); -} - -void Channel1::setNr4(unsigned data, unsigned long cc, unsigned long ref) { - lengthCounter_.nr4Change(nr4_, data, cc); - dutyUnit_.nr4Change(data, cc, ref, master_); - nr4_ = data; - - if (nr4_ & psg_nr4_init) { - nr4_ -= psg_nr4_init; - master_ = !envelopeUnit_.nr4Init(cc); - sweepUnit_.nr4Init(cc); - staticOutputTest_(cc); - } - - setEvent(); -} - -void Channel1::setSo(unsigned long soMask, unsigned long cc) { - soMask_ = soMask; - staticOutputTest_(cc); - setEvent(); -} - -void Channel1::reset() { - dutyUnit_.reset(); - envelopeUnit_.reset(); - sweepUnit_.reset(); - setEvent(); -} - -void Channel1::init(bool cgb) { - sweepUnit_.init(cgb); -} - -void Channel1::loadState(SaveState const &state) { - sweepUnit_.loadState(state); - dutyUnit_.loadState(state.spu.ch1.duty, state.mem.ioamhram.get()[0x111], - state.spu.ch1.nr4, state.spu.cycleCounter); - envelopeUnit_.loadState(state.spu.ch1.env, state.mem.ioamhram.get()[0x112], - state.spu.cycleCounter); - lengthCounter_.loadState(state.spu.ch1.lcounter, state.spu.cycleCounter); - - nr4_ = state.spu.ch1.nr4; - master_ = state.spu.ch1.master; -} - -void Channel1::update(uint_least32_t* buf, unsigned long const soBaseVol, unsigned long cc, unsigned long const end) { - unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0; - unsigned long const outLow = outBase * -15; - - while (cc < end) { - unsigned long const outHigh = master_ - ? outBase * (envelopeUnit_.getVolume() * 2l - 15) - : outLow; - unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), end); - unsigned long out = dutyUnit_.isHighState() ? outHigh : outLow; - - while (dutyUnit_.counter() <= nextMajorEvent) { - *buf = out - prevOut_; - prevOut_ = out; - buf += dutyUnit_.counter() - cc; - cc = dutyUnit_.counter(); - dutyUnit_.event(); - out = dutyUnit_.isHighState() ? outHigh : outLow; - } - if (cc < nextMajorEvent) { - *buf = out - prevOut_; - prevOut_ = out; - buf += nextMajorEvent - cc; - cc = nextMajorEvent; - } - if (nextEventUnit_->counter() == nextMajorEvent) { - nextEventUnit_->event(); - setEvent(); - } - } - - if (cc >= SoundUnit::counter_max) { - dutyUnit_.resetCounters(cc); - lengthCounter_.resetCounters(cc); - envelopeUnit_.resetCounters(cc); - sweepUnit_.resetCounters(cc); - } -} - -SYNCFUNC(Channel1) -{ - SSS(lengthCounter_); - SSS(dutyUnit_); - SSS(envelopeUnit_); - SSS(sweepUnit_); - - EBS(nextEventUnit_, 0); - EVS(nextEventUnit_, &dutyUnit_, 1); - EVS(nextEventUnit_, &sweepUnit_, 2); - EVS(nextEventUnit_, &envelopeUnit_, 3); - EVS(nextEventUnit_, &lengthCounter_, 4); - EES(nextEventUnit_, NULL); - - NSS(soMask_); - NSS(prevOut_); - - NSS(nr4_); - NSS(master_); -} diff --git a/libgambatte/src/sound/channel1.h b/libgambatte/src/sound/channel1.h deleted file mode 100644 index 99e03431f8..0000000000 --- a/libgambatte/src/sound/channel1.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef SOUND_CHANNEL1_H -#define SOUND_CHANNEL1_H - -#include "duty_unit.h" -#include "envelope_unit.h" -#include "gbint.h" -#include "length_counter.h" -#include "master_disabler.h" -#include "static_output_tester.h" -#include "newstate.h" - -namespace gambatte { - -struct SaveState; - -class Channel1 { -public: - Channel1(); - void setNr0(unsigned data); - void setNr1(unsigned data, unsigned long cc); - void setNr2(unsigned data, unsigned long cc); - void setNr3(unsigned data, unsigned long cc); - void setNr4(unsigned data, unsigned long cc, unsigned long ref); - void setSo(unsigned long soMask, unsigned long cc); - bool isActive() const { return master_; } - void update(uint_least32_t* buf, unsigned long soBaseVol, unsigned long cc, unsigned long end); - void reset(); - void resetCc(unsigned long cc, unsigned long ncc) { dutyUnit_.resetCc(cc, ncc); } - void init(bool cgb); - void loadState(SaveState const &state); - -private: - class SweepUnit : public SoundUnit { - public: - SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit); - virtual void event(); - void nr0Change(unsigned newNr0); - void nr4Init(unsigned long cycleCounter); - void reset(); - void resetCc(unsigned long cc, unsigned long ncc) { dutyUnit_.resetCc(cc, ncc); } - void init(bool cgb) { cgb_ = cgb; } - void loadState(SaveState const &state); - - private: - MasterDisabler &disableMaster_; - DutyUnit &dutyUnit_; - unsigned short shadow_; - unsigned char nr0_; - bool neg_; - bool cgb_; - - unsigned calcFreq(); - - public: - templatevoid SyncState(NewState *ns); - }; - - friend class StaticOutputTester; - - StaticOutputTester staticOutputTest_; - DutyMasterDisabler disableMaster_; - LengthCounter lengthCounter_; - DutyUnit dutyUnit_; - EnvelopeUnit envelopeUnit_; - SweepUnit sweepUnit_; - SoundUnit *nextEventUnit_; - unsigned long soMask_; - unsigned long prevOut_; - unsigned char nr4_; - bool master_; - - void setEvent(); - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/sound/channel2.cpp b/libgambatte/src/sound/channel2.cpp deleted file mode 100644 index efbfa18670..0000000000 --- a/libgambatte/src/sound/channel2.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "channel2.h" -#include "psgdef.h" -#include "../savestate.h" -#include - -using namespace gambatte; - -Channel2::Channel2() -: staticOutputTest_(*this, dutyUnit_) -, disableMaster_(master_, dutyUnit_) -, lengthCounter_(disableMaster_, 0x3F) -, envelopeUnit_(staticOutputTest_) -, soMask_(0) -, prevOut_(0) -, nr4_(0) -, master_(false) -{ - setEvent(); -} - -void Channel2::setEvent() { - nextEventUnit = &envelopeUnit_; - if (lengthCounter_.counter() < nextEventUnit->counter()) - nextEventUnit = &lengthCounter_; -} - -void Channel2::setNr1(unsigned data, unsigned long cc) { - lengthCounter_.nr1Change(data, nr4_, cc); - dutyUnit_.nr1Change(data, cc); - setEvent(); -} - -void Channel2::setNr2(unsigned data, unsigned long cc) { - if (envelopeUnit_.nr2Change(data)) - disableMaster_(); - else - staticOutputTest_(cc); - - setEvent(); -} - -void Channel2::setNr3(unsigned data, unsigned long cc) { - dutyUnit_.nr3Change(data, cc); - setEvent(); -} - -void Channel2::setNr4(unsigned data, unsigned long cc, unsigned long ref) { - lengthCounter_.nr4Change(nr4_, data, cc); - nr4_ = data; - - if (nr4_ & psg_nr4_init) { - nr4_ -= psg_nr4_init; - master_ = !envelopeUnit_.nr4Init(cc); - staticOutputTest_(cc); - } - - dutyUnit_.nr4Change(data, cc, ref, master_); - setEvent(); -} - -void Channel2::setSo(unsigned long soMask, unsigned long cc) { - soMask_ = soMask; - staticOutputTest_(cc); - setEvent(); -} - -void Channel2::reset() { - dutyUnit_.reset(); - envelopeUnit_.reset(); - setEvent(); -} - -void Channel2::loadState(SaveState const &state) { - dutyUnit_.loadState(state.spu.ch2.duty, state.mem.ioamhram.get()[0x116], - state.spu.ch2.nr4, state.spu.cycleCounter); - envelopeUnit_.loadState(state.spu.ch2.env, state.mem.ioamhram.get()[0x117], - state.spu.cycleCounter); - lengthCounter_.loadState(state.spu.ch2.lcounter, state.spu.cycleCounter); - - nr4_ = state.spu.ch2.nr4; - master_ = state.spu.ch2.master; -} - -void Channel2::update(uint_least32_t* buf, unsigned long const soBaseVol, unsigned long cc, unsigned long const end) { - unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0; - unsigned long const outLow = outBase * -15; - - while (cc < end) { - unsigned long const outHigh = master_ - ? outBase * (envelopeUnit_.getVolume() * 2l - 15) - : outLow; - unsigned long const nextMajorEvent = std::min(nextEventUnit->counter(), end); - unsigned long out = dutyUnit_.isHighState() ? outHigh : outLow; - - while (dutyUnit_.counter() <= nextMajorEvent) { - *buf += out - prevOut_; - prevOut_ = out; - buf += dutyUnit_.counter() - cc; - cc = dutyUnit_.counter(); - dutyUnit_.event(); - out = dutyUnit_.isHighState() ? outHigh : outLow; - } - if (cc < nextMajorEvent) { - *buf += out - prevOut_; - prevOut_ = out; - buf += nextMajorEvent - cc; - cc = nextMajorEvent; - } - if (nextEventUnit->counter() == nextMajorEvent) { - nextEventUnit->event(); - setEvent(); - } - } - - if (cc >= SoundUnit::counter_max) { - dutyUnit_.resetCounters(cc); - lengthCounter_.resetCounters(cc); - envelopeUnit_.resetCounters(cc); - } -} - -SYNCFUNC(Channel2) -{ - SSS(lengthCounter_); - SSS(dutyUnit_); - SSS(envelopeUnit_); - - EBS(nextEventUnit, 0); - EVS(nextEventUnit, &dutyUnit_, 1); - EVS(nextEventUnit, &envelopeUnit_, 2); - EVS(nextEventUnit, &lengthCounter_, 3); - EES(nextEventUnit, NULL); - - NSS(soMask_); - NSS(prevOut_); - - NSS(nr4_); - NSS(master_); -} - diff --git a/libgambatte/src/sound/channel2.h b/libgambatte/src/sound/channel2.h deleted file mode 100644 index 978b9bc8ed..0000000000 --- a/libgambatte/src/sound/channel2.h +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef SOUND_CHANNEL2_H -#define SOUND_CHANNEL2_H - -#include "duty_unit.h" -#include "envelope_unit.h" -#include "gbint.h" -#include "length_counter.h" -#include "static_output_tester.h" -#include "newstate.h" - -namespace gambatte { - -struct SaveState; - -class Channel2 { -public: - Channel2(); - void setNr1(unsigned data, unsigned long cc); - void setNr2(unsigned data, unsigned long cc); - void setNr3(unsigned data, unsigned long cc); - void setNr4(unsigned data, unsigned long cc, unsigned long ref); - void setSo(unsigned long soMask, unsigned long cc); - bool isActive() const { return master_; } - void update(uint_least32_t* buf, unsigned long soBaseVol, unsigned long cc, unsigned long end); - void reset(); - void resetCc(unsigned long cc, unsigned long ncc) { dutyUnit_.resetCc(cc, ncc); } - void loadState(SaveState const &state); - -private: - friend class StaticOutputTester; - - StaticOutputTester staticOutputTest_; - DutyMasterDisabler disableMaster_; - LengthCounter lengthCounter_; - DutyUnit dutyUnit_; - EnvelopeUnit envelopeUnit_; - SoundUnit *nextEventUnit; - unsigned long soMask_; - unsigned long prevOut_; - unsigned char nr4_; - bool master_; - - void setEvent(); - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/sound/channel3.cpp b/libgambatte/src/sound/channel3.cpp deleted file mode 100644 index 0f6cdb3eee..0000000000 --- a/libgambatte/src/sound/channel3.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "channel3.h" -#include "psgdef.h" -#include "../savestate.h" -#include -#include - -using namespace gambatte; - -namespace { - unsigned toPeriod(unsigned nr3, unsigned nr4) { - return 0x800 - ((nr4 << 8 & 0x700) | nr3); - } -} - -Channel3::Channel3() -: disableMaster_(master_, waveCounter_) -, lengthCounter_(disableMaster_, 0xFF) -, soMask_(0) -, prevOut_(0) -, waveCounter_(SoundUnit::counter_disabled) -, lastReadTime_(0) -, nr0_(0) -, nr3_(0) -, nr4_(0) -, wavePos_(0) -, rshift_(4) -, sampleBuf_(0) -, master_(false) -, cgb_(false) -{ -} - -void Channel3::setNr0(unsigned data) { - nr0_ = data & psg_nr4_init; - if (!nr0_) - disableMaster_(); -} - -void Channel3::setNr2(unsigned data) { - rshift_ = std::min((data >> 5 & 3) - 1, 4u); -} - -void Channel3::setNr4(unsigned const data, unsigned long const cc) { - lengthCounter_.nr4Change(nr4_, data, cc); - nr4_ = data & ~(1u * psg_nr4_init); - - if (data & nr0_) { - if (!cgb_ && waveCounter_ == cc + 1) { - int const pos = (wavePos_ + 1) / 2 % sizeof waveRam_; - - if (pos < 4) - waveRam_[0] = waveRam_[pos]; - else - std::memcpy(waveRam_, waveRam_ + (pos & ~3), 4); - } - - master_ = true; - wavePos_ = 0; - lastReadTime_ = waveCounter_ = cc + toPeriod(nr3_, data) + 3; - } -} - -void Channel3::setSo(unsigned long soMask) { - soMask_ = soMask; -} - -void Channel3::reset() { - sampleBuf_ = 0; -} - -void Channel3::resetCc(unsigned long cc, unsigned long newCc) { - lastReadTime_ -= cc - newCc; - if (waveCounter_ != SoundUnit::counter_disabled) - waveCounter_ -= cc - newCc; -} - -void Channel3::init(bool cgb) { - cgb_ = cgb; -} - -void Channel3::setStatePtrs(SaveState &state) { - state.spu.ch3.waveRam.set(waveRam_, sizeof waveRam_); -} - -void Channel3::loadState(SaveState const &state) { - lengthCounter_.loadState(state.spu.ch3.lcounter, state.spu.cycleCounter); - - waveCounter_ = std::max(state.spu.ch3.waveCounter, state.spu.cycleCounter); - lastReadTime_ = state.spu.ch3.lastReadTime; - nr3_ = state.spu.ch3.nr3; - nr4_ = state.spu.ch3.nr4; - wavePos_ = state.spu.ch3.wavePos % (2 * sizeof waveRam_); - sampleBuf_ = state.spu.ch3.sampleBuf; - master_ = state.spu.ch3.master; - - nr0_ = state.mem.ioamhram.get()[0x11A] & psg_nr4_init; - setNr2(state.mem.ioamhram.get()[0x11C]); -} - -void Channel3::updateWaveCounter(unsigned long const cc) { - if (cc >= waveCounter_) { - unsigned const period = toPeriod(nr3_, nr4_); - unsigned long const periods = (cc - waveCounter_) / period; - - lastReadTime_ = waveCounter_ + periods * period; - waveCounter_ = lastReadTime_ + period; - wavePos_ = (wavePos_ + periods + 1) % (2 * sizeof waveRam_); - sampleBuf_ = waveRam_[wavePos_ / 2]; - } -} - -void Channel3::update(uint_least32_t* buf, unsigned long const soBaseVol, unsigned long cc, unsigned long const end) { - unsigned long const outBase = nr0_ ? soBaseVol & soMask_ : 0; - - if (outBase && rshift_ != 4) { - while (std::min(waveCounter_, lengthCounter_.counter()) <= end) { - unsigned pos = wavePos_; - unsigned const period = toPeriod(nr3_, nr4_), rsh = rshift_; - unsigned long const nextMajorEvent = - std::min(lengthCounter_.counter(), end); - unsigned long cnt = waveCounter_, prevOut = prevOut_; - unsigned long out = master_ - ? ((pos % 2 ? sampleBuf_ & 0xF : sampleBuf_ >> 4) >> rsh) * 2l - 15 - : -15; - out *= outBase; - while (cnt <= nextMajorEvent) { - *buf += out - prevOut; - prevOut = out; - buf += cnt - cc; - cc = cnt; - cnt += period; - ++pos; - unsigned const s = waveRam_[pos / 2 % sizeof waveRam_]; - out = ((pos % 2 ? s & 0xF : s >> 4) >> rsh) * 2l - 15; - out *= outBase; - } - if (cnt != waveCounter_) { - wavePos_ = pos % (2 * sizeof waveRam_); - sampleBuf_ = waveRam_[wavePos_ / 2]; - prevOut_ = prevOut; - waveCounter_ = cnt; - lastReadTime_ = cc; - } - if (cc < nextMajorEvent) { - *buf += out - prevOut_; - prevOut_ = out; - buf += nextMajorEvent - cc; - cc = nextMajorEvent; - } - if (lengthCounter_.counter() == nextMajorEvent) - lengthCounter_.event(); - } - if (cc < end) { - unsigned long out = master_ - ? ((wavePos_ % 2 ? sampleBuf_ & 0xF : sampleBuf_ >> 4) >> rshift_) * 2l - 15 - : -15; - out *= outBase; - *buf += out - prevOut_; - prevOut_ = out; - cc = end; - } - } - else { - unsigned long const out = outBase * -15; - *buf += out - prevOut_; - prevOut_ = out; - cc = end; - while (lengthCounter_.counter() <= cc) { - updateWaveCounter(lengthCounter_.counter()); - lengthCounter_.event(); - } - - updateWaveCounter(cc); - } - - if (cc >= SoundUnit::counter_max) { - lengthCounter_.resetCounters(cc); - lastReadTime_ -= SoundUnit::counter_max; - if (waveCounter_ != SoundUnit::counter_disabled) - waveCounter_ -= SoundUnit::counter_max; - } -} - -SYNCFUNC(Channel3) -{ - NSS(waveRam_); - - SSS(lengthCounter_); - - NSS(soMask_); - NSS(prevOut_); - NSS(waveCounter_); - NSS(lastReadTime_); - - NSS(nr0_); - NSS(nr3_); - NSS(nr4_); - NSS(wavePos_); - NSS(rshift_); - NSS(sampleBuf_); - - NSS(master_); - NSS(cgb_); -} diff --git a/libgambatte/src/sound/channel3.h b/libgambatte/src/sound/channel3.h deleted file mode 100644 index a64ce4f5c3..0000000000 --- a/libgambatte/src/sound/channel3.h +++ /dev/null @@ -1,110 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef SOUND_CHANNEL3_H -#define SOUND_CHANNEL3_H - -#include "gbint.h" -#include "length_counter.h" -#include "master_disabler.h" -#include "newstate.h" - -namespace gambatte { - -struct SaveState; - -class Channel3 { -public: - Channel3(); - bool isActive() const { return master_; } - bool isCgb() const { return cgb_; } - void reset(); - void resetCc(unsigned long cc, unsigned long newCc); - void init(bool cgb); - void setStatePtrs(SaveState &state); - void loadState(SaveState const &state); - void setNr0(unsigned data); - void setNr1(unsigned data, unsigned long cc) { lengthCounter_.nr1Change(data, nr4_, cc); } - void setNr2(unsigned data); - void setNr3(unsigned data) { nr3_ = data; } - void setNr4(unsigned data, unsigned long cc); - void setSo(unsigned long soMask); - void update(uint_least32_t* buf, unsigned long soBaseVol, unsigned long cc, unsigned long end); - - unsigned waveRamRead(unsigned index, unsigned long cc) const { - if (master_) { - if (!cgb_ && cc != lastReadTime_) - return 0xFF; - - index = wavePos_ / 2; - } - - return waveRam_[index]; - } - - void waveRamWrite(unsigned index, unsigned data, unsigned long cc) { - if (master_) { - if (!cgb_ && cc != lastReadTime_) - return; - - index = wavePos_ / 2; - } - - waveRam_[index] = data; - } - -private: - class Ch3MasterDisabler : public MasterDisabler { - public: - Ch3MasterDisabler(bool &m, unsigned long &wC) : MasterDisabler(m), waveCounter_(wC) {} - - virtual void operator()() { - MasterDisabler::operator()(); - waveCounter_ = SoundUnit::counter_disabled; - } - - private: - unsigned long &waveCounter_; - }; - - unsigned char waveRam_[0x10]; - Ch3MasterDisabler disableMaster_; - LengthCounter lengthCounter_; - unsigned long soMask_; - unsigned long prevOut_; - unsigned long waveCounter_; - unsigned long lastReadTime_; - unsigned char nr0_; - unsigned char nr3_; - unsigned char nr4_; - unsigned char wavePos_; - unsigned char rshift_; - unsigned char sampleBuf_; - bool master_; - bool cgb_; - - void updateWaveCounter(unsigned long cc); - - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/sound/channel4.cpp b/libgambatte/src/sound/channel4.cpp deleted file mode 100644 index 17c7fde5a1..0000000000 --- a/libgambatte/src/sound/channel4.cpp +++ /dev/null @@ -1,274 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "channel4.h" -#include "psgdef.h" -#include "../savestate.h" -#include - -using namespace gambatte; - -namespace { - static unsigned long toPeriod(unsigned const nr3) { - unsigned s = nr3 / (1u * psg_nr43_s & -psg_nr43_s) + 3; - unsigned r = nr3 & psg_nr43_r; - - if (!r) { - r = 1; - --s; - } - - return r << s; - } -} - -Channel4::Lfsr::Lfsr() -: backupCounter_(counter_disabled) -, reg_(0x7FFF) -, nr3_(0) -, master_(false) -{ -} - -void Channel4::Lfsr::updateBackupCounter(unsigned long const cc) { - if (backupCounter_ <= cc) { - unsigned long const period = toPeriod(nr3_); - unsigned long periods = (cc - backupCounter_) / period + 1; - backupCounter_ += periods * period; - - if (master_ && nr3_ < 0xE * (1u * psg_nr43_s & -psg_nr43_s)) { - if (nr3_ & psg_nr43_7biten) { - while (periods > 6) { - unsigned const xored = (reg_ << 1 ^ reg_) & 0x7E; - reg_ = (reg_ >> 6 & ~0x7Eu) | xored | xored << 8; - periods -= 6; - } - - unsigned const xored = ((reg_ ^ reg_ >> 1) << (7 - periods)) & 0x7F; - reg_ = (reg_ >> periods & ~(0x80u - (0x80 >> periods))) | xored | xored << 8; - } - else { - while (periods > 15) { - reg_ = reg_ ^ reg_ >> 1; - periods -= 15; - } - - reg_ = reg_ >> periods | (((reg_ ^ reg_ >> 1) << (15 - periods)) & 0x7FFF); - } - } - } -} - -void Channel4::Lfsr::reviveCounter(unsigned long cc) { - updateBackupCounter(cc); - counter_ = backupCounter_; -} - -inline void Channel4::Lfsr::event() { - if (nr3_ < 0xE * (1u * psg_nr43_s & -psg_nr43_s)) { - unsigned const shifted = reg_ >> 1; - unsigned const xored = (reg_ ^ shifted) & 1; - reg_ = shifted | xored << 14; - - if (nr3_ & psg_nr43_7biten) - reg_ = (reg_ & ~0x40u) | xored << 6; - } - - counter_ += toPeriod(nr3_); - backupCounter_ = counter_; -} - -void Channel4::Lfsr::nr3Change(unsigned newNr3, unsigned long cc) { - updateBackupCounter(cc); - nr3_ = newNr3; - counter_ = cc; -} - -void Channel4::Lfsr::nr4Init(unsigned long cc) { - disableMaster(); - updateBackupCounter(cc); - master_ = true; - backupCounter_ += 4; - counter_ = backupCounter_; -} - -void Channel4::Lfsr::reset(unsigned long cc) { - nr3_ = 0; - disableMaster(); - backupCounter_ = cc + toPeriod(nr3_); -} - -void Channel4::Lfsr::resetCc(unsigned long cc, unsigned long newCc) { - updateBackupCounter(cc); - backupCounter_ -= cc - newCc; - if (counter_ != counter_disabled) - counter_ -= cc - newCc; -} - -void Channel4::Lfsr::resetCounters(unsigned long oldCc) { - updateBackupCounter(oldCc); - backupCounter_ -= counter_max; - SoundUnit::resetCounters(oldCc); -} - -void Channel4::Lfsr::loadState(SaveState const &state) { - counter_ = backupCounter_ = std::max(state.spu.ch4.lfsr.counter, state.spu.cycleCounter); - reg_ = state.spu.ch4.lfsr.reg; - master_ = state.spu.ch4.master; - nr3_ = state.mem.ioamhram.get()[0x122]; -} - -template -void Channel4::Lfsr::SyncState(NewState *ns) -{ - NSS(counter_); - NSS(backupCounter_); - NSS(reg_); - NSS(nr3_); - NSS(master_); -} - -Channel4::Channel4() -: staticOutputTest_(*this, lfsr_) -, disableMaster_(master_, lfsr_) -, lengthCounter_(disableMaster_, 0x3F) -, envelopeUnit_(staticOutputTest_) -, nextEventUnit_(0) -, soMask_(0) -, prevOut_(0) -, nr4_(0) -, master_(false) -{ - setEvent(); -} - -void Channel4::setEvent() { - nextEventUnit_ = &envelopeUnit_; - if (lengthCounter_.counter() < nextEventUnit_->counter()) - nextEventUnit_ = &lengthCounter_; -} - -void Channel4::setNr1(unsigned data, unsigned long cc) { - lengthCounter_.nr1Change(data, nr4_, cc); - setEvent(); -} - -void Channel4::setNr2(unsigned data, unsigned long cc) { - if (envelopeUnit_.nr2Change(data)) - disableMaster_(); - else - staticOutputTest_(cc); - - setEvent(); -} - -void Channel4::setNr4(unsigned const data, unsigned long const cc) { - lengthCounter_.nr4Change(nr4_, data, cc); - nr4_ = data; - - if (nr4_ & psg_nr4_init) { - nr4_ -= psg_nr4_init; - master_ = !envelopeUnit_.nr4Init(cc); - if (master_) - lfsr_.nr4Init(cc); - - staticOutputTest_(cc); - } - - setEvent(); -} - -void Channel4::setSo(unsigned long soMask, unsigned long cc) { - soMask_ = soMask; - staticOutputTest_(cc); - setEvent(); -} - -void Channel4::reset(unsigned long cc) { - lfsr_.reset(cc); - envelopeUnit_.reset(); - setEvent(); -} - -void Channel4::loadState(SaveState const &state) { - lfsr_.loadState(state); - envelopeUnit_.loadState(state.spu.ch4.env, state.mem.ioamhram.get()[0x121], - state.spu.cycleCounter); - lengthCounter_.loadState(state.spu.ch4.lcounter, state.spu.cycleCounter); - - nr4_ = state.spu.ch4.nr4; - master_ = state.spu.ch4.master; -} - -void Channel4::update(uint_least32_t* buf, unsigned long const soBaseVol, unsigned long cc, unsigned long const end) { - unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0; - unsigned long const outLow = outBase * -15; - - while (cc < end) { - unsigned long const outHigh = outBase * (envelopeUnit_.getVolume() * 2l - 15); - unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), end); - unsigned long out = lfsr_.isHighState() ? outHigh : outLow; - if (lfsr_.counter() <= nextMajorEvent) { - Lfsr lfsr = lfsr_; - while (lfsr.counter() <= nextMajorEvent) { - *buf += out - prevOut_; - prevOut_ = out; - buf += lfsr.counter() - cc; - cc = lfsr.counter(); - lfsr.event(); - out = lfsr.isHighState() ? outHigh : outLow; - } - lfsr_ = lfsr; - } - if (cc < nextMajorEvent) { - *buf += out - prevOut_; - prevOut_ = out; - buf += nextMajorEvent - cc; - cc = nextMajorEvent; - } - if (nextEventUnit_->counter() == nextMajorEvent) { - nextEventUnit_->event(); - setEvent(); - } - } - - if (cc >= SoundUnit::counter_max) { - lengthCounter_.resetCounters(cc); - lfsr_.resetCounters(cc); - envelopeUnit_.resetCounters(cc); - } -} - -SYNCFUNC(Channel4) -{ - SSS(lengthCounter_); - SSS(envelopeUnit_); - SSS(lfsr_); - - EBS(nextEventUnit_, 0); - EVS(nextEventUnit_, &lfsr_, 1); - EVS(nextEventUnit_, &envelopeUnit_, 2); - EVS(nextEventUnit_, &lengthCounter_, 3); - EES(nextEventUnit_, NULL); - - NSS(soMask_); - NSS(prevOut_); - - NSS(nr4_); - NSS(master_); -} diff --git a/libgambatte/src/sound/channel4.h b/libgambatte/src/sound/channel4.h deleted file mode 100644 index 629ba11b92..0000000000 --- a/libgambatte/src/sound/channel4.h +++ /dev/null @@ -1,105 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef SOUND_CHANNEL4_H -#define SOUND_CHANNEL4_H - -#include "envelope_unit.h" -#include "gbint.h" -#include "length_counter.h" -#include "master_disabler.h" -#include "static_output_tester.h" -#include "newstate.h" - -namespace gambatte { - -struct SaveState; - -class Channel4 { -public: - Channel4(); - void setNr1(unsigned data, unsigned long cc); - void setNr2(unsigned data, unsigned long cc); - void setNr3(unsigned data, unsigned long cc) { lfsr_.nr3Change(data, cc); } - void setNr4(unsigned data, unsigned long cc); - void setSo(unsigned long soMask, unsigned long cc); - bool isActive() const { return master_; } - void update(uint_least32_t* buf, unsigned long soBaseVol, unsigned long cc, unsigned long end); - void reset(unsigned long cc); - void resetCc(unsigned long cc, unsigned long newCc) { lfsr_.resetCc(cc, newCc); } - void loadState(SaveState const &state); - -private: - class Lfsr : public SoundUnit { - public: - Lfsr(); - virtual void event(); - virtual void resetCounters(unsigned long oldCc); - bool isHighState() const { return ~reg_ & 1; } - void nr3Change(unsigned newNr3, unsigned long cc); - void nr4Init(unsigned long cc); - void reset(unsigned long cc); - void resetCc(unsigned long cc, unsigned long newCc); - void loadState(SaveState const &state); - void disableMaster() { killCounter(); master_ = false; reg_ = 0x7FFF; } - void killCounter() { counter_ = counter_disabled; } - void reviveCounter(unsigned long cc); - - private: - unsigned long backupCounter_; - unsigned short reg_; - unsigned char nr3_; - bool master_; - - void updateBackupCounter(unsigned long cc); - - public: - templatevoid SyncState(NewState *ns); - }; - - class Ch4MasterDisabler : public MasterDisabler { - public: - Ch4MasterDisabler(bool &m, Lfsr &lfsr) : MasterDisabler(m), lfsr_(lfsr) {} - virtual void operator()() { MasterDisabler::operator()(); lfsr_.disableMaster(); } - - private: - Lfsr &lfsr_; - }; - - friend class StaticOutputTester; - - StaticOutputTester staticOutputTest_; - Ch4MasterDisabler disableMaster_; - LengthCounter lengthCounter_; - EnvelopeUnit envelopeUnit_; - Lfsr lfsr_; - SoundUnit *nextEventUnit_; - unsigned long soMask_; - unsigned long prevOut_; - unsigned char nr4_; - bool master_; - - void setEvent(); - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/sound/duty_unit.cpp b/libgambatte/src/sound/duty_unit.cpp deleted file mode 100644 index 2c91fa10d3..0000000000 --- a/libgambatte/src/sound/duty_unit.cpp +++ /dev/null @@ -1,169 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "duty_unit.h" -#include "psgdef.h" -#include - -namespace { - - int const duty_pattern_len = 8; - - bool toOutState(unsigned duty, unsigned pos) { - return 0x7EE18180 >> (duty * duty_pattern_len + pos) & 1; - } - - unsigned toPeriod(unsigned freq) { - return (2048 - freq) * 2; - } - -} - -using namespace gambatte; - -DutyUnit::DutyUnit() -: nextPosUpdate_(counter_disabled) -, period_(4096) -, pos_(0) -, duty_(0) -, inc_(0) -, high_(false) -, enableEvents_(true) -{ -} - -void DutyUnit::updatePos(unsigned long const cc) { - if (cc >= nextPosUpdate_) { - unsigned long const inc = (cc - nextPosUpdate_) / period_ + 1; - nextPosUpdate_ += period_ * inc; - pos_ = (pos_ + inc) % duty_pattern_len; - high_ = toOutState(duty_, pos_); - } -} - -void DutyUnit::setCounter() { - static unsigned char const nextStateDistance[][duty_pattern_len] = { - { 7, 6, 5, 4, 3, 2, 1, 1 }, - { 1, 6, 5, 4, 3, 2, 1, 2 }, - { 1, 4, 3, 2, 1, 4, 3, 2 }, - { 1, 6, 5, 4, 3, 2, 1, 2 } - }; - - if (enableEvents_ && nextPosUpdate_ != counter_disabled) { - unsigned const npos = (pos_ + 1) % duty_pattern_len; - counter_ = nextPosUpdate_; - inc_ = nextStateDistance[duty_][npos]; - if (toOutState(duty_, npos) == high_) { - counter_ += period_ * inc_; - inc_ = nextStateDistance[duty_][(npos + inc_) % duty_pattern_len]; - } - } else - counter_ = counter_disabled; -} - -void DutyUnit::setFreq(unsigned newFreq, unsigned long cc) { - updatePos(cc); - period_ = toPeriod(newFreq); - setCounter(); -} - -void DutyUnit::event() { - static unsigned char const inc[][2] = { - { 1, 7 }, - { 2, 6 }, - { 4, 4 }, - { 6, 2 } - }; - - high_ ^= true; - counter_ += inc_ * period_; - inc_ = inc[duty_][high_]; -} - -void DutyUnit::nr1Change(unsigned newNr1, unsigned long cc) { - updatePos(cc); - duty_ = newNr1 >> 6; - setCounter(); -} - -void DutyUnit::nr3Change(unsigned newNr3, unsigned long cc) { - setFreq((freq() & 0x700) | newNr3, cc); -} - -void DutyUnit::nr4Change(unsigned const newNr4, unsigned long const cc, unsigned long const ref, bool const master) { - setFreq((newNr4 << 8 & 0x700) | (freq() & 0xFF), cc); - - if (newNr4 & psg_nr4_init) { - nextPosUpdate_ = cc - (cc - ref) % 2 + period_ + 4 - (master << 1); - setCounter(); - } -} - -void DutyUnit::reset() { - pos_ = 0; - high_ = false; - nextPosUpdate_ = counter_disabled; - setCounter(); -} - -void DutyUnit::resetCc(unsigned long cc, unsigned long newCc) { - if (nextPosUpdate_ == counter_disabled) - return; - - updatePos(cc); - nextPosUpdate_ -= cc - newCc; - setCounter(); -} - -void DutyUnit::loadState(SaveState::SPU::Duty const &dstate, - unsigned const nr1, unsigned const nr4, unsigned long const cc) { - nextPosUpdate_ = std::max(dstate.nextPosUpdate, cc); - pos_ = dstate.pos & 7; - high_ = dstate.high; - duty_ = nr1 >> 6; - period_ = toPeriod((nr4 << 8 & 0x700) | dstate.nr3); - enableEvents_ = true; - setCounter(); -} - -void DutyUnit::resetCounters(unsigned long cc) { - resetCc(cc, cc - counter_max); -} - -void DutyUnit::killCounter() { - enableEvents_ = false; - setCounter(); -} - -void DutyUnit::reviveCounter(unsigned long const cc) { - updatePos(cc); - enableEvents_ = true; - setCounter(); -} - -SYNCFUNC(DutyUnit) -{ - NSS(counter_); - NSS(nextPosUpdate_); - NSS(period_); - NSS(pos_); - NSS(duty_); - NSS(inc_); - NSS(high_); - NSS(enableEvents_); -} diff --git a/libgambatte/src/sound/duty_unit.h b/libgambatte/src/sound/duty_unit.h deleted file mode 100644 index 902beaad74..0000000000 --- a/libgambatte/src/sound/duty_unit.h +++ /dev/null @@ -1,76 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef DUTY_UNIT_H -#define DUTY_UNIT_H - -#include "sound_unit.h" -#include "master_disabler.h" -#include "../savestate.h" -#include "newstate.h" - -namespace gambatte { - -class DutyUnit : public SoundUnit { -public: - DutyUnit(); - virtual void event(); - virtual void resetCounters(unsigned long oldCc); - bool isHighState() const { return high_; } - void nr1Change(unsigned newNr1, unsigned long cc); - void nr3Change(unsigned newNr3, unsigned long cc); - void nr4Change(unsigned newNr4, unsigned long cc, unsigned long ref, bool master); - void reset(); - void resetCc(unsigned long cc, unsigned long newCc); - void loadState(SaveState::SPU::Duty const &dstate, unsigned nr1, unsigned nr4, unsigned long cc); - void killCounter(); - void reviveCounter(unsigned long cc); - - //intended for use by SweepUnit only. - unsigned freq() const { return 2048 - (period_ >> 1); } - void setFreq(unsigned newFreq, unsigned long cc); - -private: - unsigned long nextPosUpdate_; - unsigned short period_; - unsigned char pos_; - unsigned char duty_; - unsigned char inc_; - bool high_; - bool enableEvents_; - - void setCounter(); - void setDuty(unsigned nr1); - void updatePos(unsigned long cc); - -public: - templatevoid SyncState(NewState *ns); -}; - -class DutyMasterDisabler : public MasterDisabler { -public: - DutyMasterDisabler(bool &m, DutyUnit &dutyUnit) : MasterDisabler(m), dutyUnit_(dutyUnit) {} - virtual void operator()() { MasterDisabler::operator()(); dutyUnit_.killCounter(); } - -private: - DutyUnit &dutyUnit_; -}; - -} - -#endif diff --git a/libgambatte/src/sound/envelope_unit.cpp b/libgambatte/src/sound/envelope_unit.cpp deleted file mode 100644 index 02369c0a41..0000000000 --- a/libgambatte/src/sound/envelope_unit.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "envelope_unit.h" -#include "psgdef.h" -#include - -using namespace gambatte; - -EnvelopeUnit::VolOnOffEvent EnvelopeUnit::nullEvent_; - -EnvelopeUnit::EnvelopeUnit(VolOnOffEvent &volOnOffEvent) -: volOnOffEvent_(volOnOffEvent) -, nr2_(0) -, volume_(0) -{ -} - -void EnvelopeUnit::reset() { - counter_ = counter_disabled; -} - -void EnvelopeUnit::loadState(SaveState::SPU::Env const &estate, unsigned nr2, unsigned long cc) { - counter_ = std::max(estate.counter, cc); - volume_ = estate.volume; - nr2_ = nr2; -} - -void EnvelopeUnit::event() { - unsigned long const period = nr2_ & psg_nr2_step; - - if (period) { - unsigned newVol = volume_; - if (nr2_ & psg_nr2_inc) - ++newVol; - else - --newVol; - - if (newVol < 0x10) { - volume_ = newVol; - if (volume_ < 2) - volOnOffEvent_(counter_); - - counter_ += period << 15; - } - else - counter_ = counter_disabled; - } - else - counter_ += 8ul << 15; -} - -bool EnvelopeUnit::nr2Change(unsigned const newNr2) { - if (!(nr2_ & psg_nr2_step) && counter_ != counter_disabled) - ++volume_; - else if (!(nr2_ & psg_nr2_inc)) - volume_ += 2; - - if ((nr2_ ^ newNr2) & psg_nr2_inc) - volume_ = 0x10 - volume_; - - volume_ &= 0xF; - nr2_ = newNr2; - return !(newNr2 & (psg_nr2_initvol | psg_nr2_inc)); -} - -bool EnvelopeUnit::nr4Init(unsigned long const cc) { - unsigned long period = nr2_ & psg_nr2_step ? nr2_ & psg_nr2_step : 8; - - if (((cc + 2) & 0x7000) == 0x0000) - ++period; - - counter_ = cc - ((cc - 0x1000) & 0x7FFF) + period * 0x8000; - - volume_ = nr2_ / (1u * psg_nr2_initvol & -psg_nr2_initvol); - return !(nr2_ & (psg_nr2_initvol | psg_nr2_inc)); -} - -SYNCFUNC(EnvelopeUnit) -{ - NSS(counter_); - NSS(nr2_); - NSS(volume_); -} diff --git a/libgambatte/src/sound/envelope_unit.h b/libgambatte/src/sound/envelope_unit.h deleted file mode 100644 index 4705dfc6f5..0000000000 --- a/libgambatte/src/sound/envelope_unit.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef ENVELOPE_UNIT_H -#define ENVELOPE_UNIT_H - -#include "sound_unit.h" -#include "../savestate.h" -#include "newstate.h" - -namespace gambatte { - -class EnvelopeUnit : public SoundUnit { -public: - struct VolOnOffEvent { - virtual ~VolOnOffEvent() {} - virtual void operator()(unsigned long /*cc*/) {} - }; - - explicit EnvelopeUnit(VolOnOffEvent &volOnOffEvent = nullEvent_); - void event(); - bool dacIsOn() const { return nr2_ & 0xF8; } - unsigned getVolume() const { return volume_; } - bool nr2Change(unsigned newNr2); - bool nr4Init(unsigned long cycleCounter); - void reset(); - void loadState(SaveState::SPU::Env const &estate, unsigned nr2, unsigned long cc); - -private: - static VolOnOffEvent nullEvent_; - VolOnOffEvent &volOnOffEvent_; - unsigned char nr2_; - unsigned char volume_; - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/sound/length_counter.cpp b/libgambatte/src/sound/length_counter.cpp deleted file mode 100644 index 50ac6310e9..0000000000 --- a/libgambatte/src/sound/length_counter.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "length_counter.h" -#include "master_disabler.h" -#include "psgdef.h" -#include - -using namespace gambatte; - -LengthCounter::LengthCounter(MasterDisabler &disabler, unsigned const mask) -: disableMaster_(disabler) -, lengthCounter_(0) -, lengthMask_(mask) -{ - nr1Change(0, 0, 0); -} - -void LengthCounter::event() { - counter_ = counter_disabled; - lengthCounter_ = 0; - disableMaster_(); -} - -void LengthCounter::nr1Change(unsigned const newNr1, unsigned const nr4, unsigned long const cc) { - lengthCounter_ = (~newNr1 & lengthMask_) + 1; - counter_ = nr4 & psg_nr4_lcen - ? ((cc >> 13) + lengthCounter_) << 13 - : 1 * counter_disabled; -} - -void LengthCounter::nr4Change(unsigned const oldNr4, unsigned const newNr4, unsigned long const cc) { - if (counter_ != counter_disabled) - lengthCounter_ = (counter_ >> 13) - (cc >> 13); - - unsigned dec = 0; - if (newNr4 & psg_nr4_lcen) { - dec = ~cc >> 12 & 1; - if (!(oldNr4 & psg_nr4_lcen) && lengthCounter_) { - if (!(lengthCounter_ -= dec)) - disableMaster_(); - } - } - - if (newNr4 & psg_nr4_init && !lengthCounter_) - lengthCounter_ = lengthMask_ + 1 - dec; - - counter_ = newNr4 & psg_nr4_lcen && lengthCounter_ - ? ((cc >> 13) + lengthCounter_) << 13 - : 1 * counter_disabled; -} - -void LengthCounter::loadState(SaveState::SPU::LCounter const &lstate, unsigned long const cc) { - counter_ = std::max(lstate.counter, cc); - lengthCounter_ = lstate.lengthCounter; -} - -SYNCFUNC(LengthCounter) -{ - NSS(counter_); - NSS(lengthCounter_); -} diff --git a/libgambatte/src/sound/length_counter.h b/libgambatte/src/sound/length_counter.h deleted file mode 100644 index 31727945f0..0000000000 --- a/libgambatte/src/sound/length_counter.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef LENGTH_COUNTER_H -#define LENGTH_COUNTER_H - -#include "sound_unit.h" -#include "../savestate.h" -#include "newstate.h" - -namespace gambatte { - -class MasterDisabler; - -class LengthCounter : public SoundUnit { -public: - LengthCounter(MasterDisabler &disabler, unsigned lengthMask); - virtual void event(); - void nr1Change(unsigned newNr1, unsigned nr4, unsigned long cc); - void nr4Change(unsigned oldNr4, unsigned newNr4, unsigned long cc); - void loadState(SaveState::SPU::LCounter const &lstate, unsigned long cc); - -private: - MasterDisabler &disableMaster_; - unsigned short lengthCounter_; - unsigned char const lengthMask_; - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/sound/master_disabler.h b/libgambatte/src/sound/master_disabler.h deleted file mode 100644 index a9c16adec1..0000000000 --- a/libgambatte/src/sound/master_disabler.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef MASTER_DISABLER_H -#define MASTER_DISABLER_H - -namespace gambatte { - -class MasterDisabler { -public: - explicit MasterDisabler(bool &master) : master_(master) {} - virtual ~MasterDisabler() {} - virtual void operator()() { master_ = false; } - -private: - bool &master_; -}; - -} - -#endif diff --git a/libgambatte/src/sound/psgdef.h b/libgambatte/src/sound/psgdef.h deleted file mode 100644 index e0aa66eb32..0000000000 --- a/libgambatte/src/sound/psgdef.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef PSGDEF_H -#define PSGDEF_H - -namespace gambatte { - - enum { - psg_nr10_rsh = 0x07, - psg_nr10_neg = 0x08, - psg_nr10_time = 0x70 - }; - - enum { - psg_nr2_step = 0x07, - psg_nr2_inc = 0x08, - psg_nr2_initvol = 0xF0 - }; - - enum { - psg_nr43_r = 0x07, - psg_nr43_7biten = 0x08, - psg_nr43_s = 0xF0 - }; - - enum { - psg_nr4_lcen = 0x40, - psg_nr4_init = 0x80 - }; - -} - -#endif \ No newline at end of file diff --git a/libgambatte/src/sound/sound_unit.h b/libgambatte/src/sound/sound_unit.h deleted file mode 100644 index c990939c9c..0000000000 --- a/libgambatte/src/sound/sound_unit.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef SOUND_UNIT_H -#define SOUND_UNIT_H - -namespace gambatte { - -class SoundUnit { -public: - enum { counter_max = 0x80000000u, counter_disabled = 0xFFFFFFFFu }; - - virtual ~SoundUnit() {} - virtual void event() = 0; - - virtual void resetCounters(unsigned long /*oldCc*/) { - if (counter_ != counter_disabled) - counter_ -= counter_max; - } - - unsigned long counter() const { return counter_; } - -protected: - SoundUnit() : counter_(counter_disabled) {} - unsigned long counter_; -}; - -} - -#endif diff --git a/libgambatte/src/sound/static_output_tester.h b/libgambatte/src/sound/static_output_tester.h deleted file mode 100644 index 0d7edbbf99..0000000000 --- a/libgambatte/src/sound/static_output_tester.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef STATIC_OUTPUT_TESTER_H -#define STATIC_OUTPUT_TESTER_H - -#include "envelope_unit.h" - -namespace gambatte { - -template -class StaticOutputTester : public EnvelopeUnit::VolOnOffEvent { -public: - StaticOutputTester(Channel const &ch, Unit &unit) : ch_(ch), unit_(unit) {} - void operator()(unsigned long cc); - -private: - Channel const &ch_; - Unit &unit_; -}; - -template -void StaticOutputTester::operator()(unsigned long cc) { - if (ch_.soMask_ && ch_.master_ && ch_.envelopeUnit_.getVolume()) - unit_.reviveCounter(cc); - else - unit_.killCounter(); -} - -} - -#endif diff --git a/libgambatte/src/tima.cpp b/libgambatte/src/tima.cpp deleted file mode 100644 index 854d247367..0000000000 --- a/libgambatte/src/tima.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "tima.h" -#include "savestate.h" - -using namespace gambatte; - -namespace { - unsigned char const timaClock[4] = { 10, 4, 6, 8 }; -} - -namespace gambatte { - -Tima::Tima() -: divLastUpdate_(0) -, lastUpdate_(0) -, tmatime_(disabled_time) -, tima_(0) -, tma_(0) -, tac_(0) -{ -} - -void Tima::loadState(SaveState const &state, TimaInterruptRequester timaIrq) { - divLastUpdate_ = state.mem.divLastUpdate - 0x100l * state.mem.ioamhram.get()[0x104]; - lastUpdate_ = state.mem.timaLastUpdate; - tmatime_ = state.mem.tmatime; - tima_ = state.mem.ioamhram.get()[0x105]; - tma_ = state.mem.ioamhram.get()[0x106]; - tac_ = state.mem.ioamhram.get()[0x107]; - - unsigned long nextIrqEventTime = disabled_time; - if (tac_ & 4) { - nextIrqEventTime = tmatime_ != disabled_time && tmatime_ > state.cpu.cycleCounter - ? tmatime_ - : lastUpdate_ + ((256l - tima_) << timaClock[tac_ & 3]) + 3; - } - - timaIrq.setNextIrqEventTime(nextIrqEventTime); -} - -void Tima::resetCc(unsigned long const oldCc, unsigned long const newCc, TimaInterruptRequester timaIrq) { - if (tac_ & 0x04) { - updateIrq(oldCc, timaIrq); - updateTima(oldCc); - - unsigned long const dec = oldCc - newCc; - lastUpdate_ -= dec; - timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() - dec); - - if (tmatime_ != disabled_time) - tmatime_ -= dec; - } -} - -void Tima::updateTima(unsigned long const cc) { - unsigned long const ticks = (cc - lastUpdate_) >> timaClock[tac_ & 3]; - lastUpdate_ += ticks << timaClock[tac_ & 3]; - - if (cc >= tmatime_) { - if (cc >= tmatime_ + 4) - tmatime_ = disabled_time; - - tima_ = tma_; - } - - unsigned long tmp = tima_ + ticks; - while (tmp > 0x100) - tmp -= 0x100 - tma_; - - if (tmp == 0x100) { - tmp = 0; - tmatime_ = lastUpdate_ + 3; - if (cc >= tmatime_) { - if (cc >= tmatime_ + 4) - tmatime_ = disabled_time; - - tmp = tma_; - } - } - - tima_ = tmp; -} - -void Tima::setTima(unsigned const data, unsigned long const cc, TimaInterruptRequester timaIrq) { - if (tac_ & 0x04) { - updateIrq(cc, timaIrq); - updateTima(cc); - - if (tmatime_ - cc < 4) - tmatime_ = disabled_time; - - timaIrq.setNextIrqEventTime(lastUpdate_ + ((256l - data) << timaClock[tac_ & 3]) + 3); - } - - tima_ = data; -} - -void Tima::setTma(unsigned const data, unsigned long const cc, TimaInterruptRequester timaIrq) { - if (tac_ & 0x04) { - updateIrq(cc, timaIrq); - updateTima(cc); - } - - tma_ = data; -} - -void Tima::setTac(unsigned const data, unsigned long const cc, TimaInterruptRequester timaIrq, bool agbFlag) { - if (tac_ ^ data) { - unsigned long nextIrqEventTime = timaIrq.nextIrqEventTime(); - - if (tac_ & 0x04) { - unsigned const inc = ~(data >> 2 & (cc - divLastUpdate_) >> (timaClock[data & 3] - 1)) & 1; - lastUpdate_ -= (inc << (timaClock[tac_ & 3] - 1)) + 3; - nextIrqEventTime -= (inc << (timaClock[tac_ & 3] - 1)) + 3; - if (cc >= nextIrqEventTime) - timaIrq.flagIrq(); - - updateTima(cc); - tmatime_ = disabled_time; - nextIrqEventTime = disabled_time; - } - - if (data & 4) { - if (agbFlag) { - unsigned long diff = cc - divLastUpdate_; - if (((diff >> (timaClock[tac_ & 3] - 1)) & 1) == 1 && ((diff >> (timaClock[data & 3] - 1)) & 1) == 0) - tima_++; - } - - lastUpdate_ = cc - ((cc - divLastUpdate_) & ((1u << timaClock[data & 3]) - 1)); - nextIrqEventTime = lastUpdate_ + ((256l - tima_) << timaClock[data & 3]) + 3; - } - - timaIrq.setNextIrqEventTime(nextIrqEventTime); - } - - tac_ = data; -} - -void Tima::divReset(unsigned long cc, TimaInterruptRequester timaIrq) { - if (tac_ & 0x04) { - unsigned long nextIrqEventTime = timaIrq.nextIrqEventTime(); - lastUpdate_ -= (1u << (timaClock[tac_ & 3] - 1)) + 3; - nextIrqEventTime -= (1u << (timaClock[tac_ & 3] - 1)) + 3; - if (cc >= nextIrqEventTime) - timaIrq.flagIrq(); - - updateTima(cc); - lastUpdate_ = cc; - timaIrq.setNextIrqEventTime(lastUpdate_ + ((256l - tima_) << timaClock[tac_ & 3]) + 3); - } - - divLastUpdate_ = cc; -} - -void Tima::speedChange(TimaInterruptRequester timaIrq) { - if ((tac_ & 0x07) >= 0x05) { - lastUpdate_ -= 4; - timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() - 4); - } -} - -unsigned Tima::tima(unsigned long cc) { - if (tac_ & 0x04) - updateTima(cc); - - return tima_; -} - -void Tima::doIrqEvent(TimaInterruptRequester timaIrq) { - timaIrq.flagIrq(timaIrq.nextIrqEventTime()); - timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() - + ((256l - tma_) << timaClock[tac_ & 3])); -} - -SYNCFUNC(Tima) -{ - NSS(lastUpdate_); - NSS(divLastUpdate_); - NSS(tmatime_); - NSS(tima_); - NSS(tma_); - NSS(tac_); -} - -} diff --git a/libgambatte/src/tima.h b/libgambatte/src/tima.h deleted file mode 100644 index 8079dcccab..0000000000 --- a/libgambatte/src/tima.h +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef TIMA_H -#define TIMA_H - -#include "interruptrequester.h" - -namespace gambatte { - -class TimaInterruptRequester { -public: - explicit TimaInterruptRequester(InterruptRequester &intreq) : intreq_(intreq) {} - void flagIrq() const { intreq_.flagIrq(4); } - void flagIrq(unsigned long cc) const { intreq_.flagIrq(4, cc); } - unsigned long nextIrqEventTime() const { return intreq_.eventTime(intevent_tima); } - void setNextIrqEventTime(unsigned long time) const { intreq_.setEventTime(time); } - -private: - InterruptRequester &intreq_; -}; - -class Tima { -public: - Tima(); - void loadState(const SaveState &, TimaInterruptRequester timaIrq); - void resetCc(unsigned long oldCc, unsigned long newCc, TimaInterruptRequester timaIrq); - void setTima(unsigned tima, unsigned long cc, TimaInterruptRequester timaIrq); - void setTma(unsigned tma, unsigned long cc, TimaInterruptRequester timaIrq); - void setTac(unsigned tac, unsigned long cc, TimaInterruptRequester timaIrq, bool agbFlag); - void divReset(unsigned long cc, TimaInterruptRequester); - void speedChange(TimaInterruptRequester); - unsigned long divLastUpdate() const { return divLastUpdate_; } - unsigned tima(unsigned long cc); - void doIrqEvent(TimaInterruptRequester timaIrq); - -private: - unsigned long divLastUpdate_; - unsigned long lastUpdate_; - unsigned long tmatime_; - unsigned char tima_; - unsigned char tma_; - unsigned char tac_; - - void updateIrq(unsigned long const cc, TimaInterruptRequester timaIrq) { - while (cc >= timaIrq.nextIrqEventTime()) - doIrqEvent(timaIrq); - } - - void updateTima(unsigned long cc); - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/video.cpp b/libgambatte/src/video.cpp deleted file mode 100644 index 490c98ca1b..0000000000 --- a/libgambatte/src/video.cpp +++ /dev/null @@ -1,862 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "video.h" -#include "savestate.h" -#include -#include - -using namespace gambatte; - -unsigned long LCD::gbcToRgb32(const unsigned bgr15) { - unsigned long const r = bgr15 & 0x1F; - unsigned long const g = bgr15 >> 5 & 0x1F; - unsigned long const b = bgr15 >> 10 & 0x1F; - - return cgbColorsRgb32_[bgr15 & 0x7FFF]; -} - -namespace { - - // TODO: simplify cycle offsets. - - long const mode1_irq_frame_cycle = 1l * lcd_vres * lcd_cycles_per_line - 2; - int const mode2_irq_line_cycle = lcd_cycles_per_line - 4; - int const mode2_irq_line_cycle_ly0 = lcd_cycles_per_line - 2; - - unsigned long mode1IrqSchedule(LyCounter const& lyCounter, unsigned long cc) { - return lyCounter.nextFrameCycle(mode1_irq_frame_cycle, cc); - } - - unsigned long mode2IrqSchedule(unsigned const statReg, - LyCounter const& lyCounter, unsigned long const cc) { - if (!(statReg & lcdstat_m2irqen)) - return disabled_time; - - unsigned long const lastM2Fc = (lcd_vres - 1l) * lcd_cycles_per_line + mode2_irq_line_cycle; - unsigned long const ly0M2Fc = (lcd_lines_per_frame - 1l) * lcd_cycles_per_line + mode2_irq_line_cycle_ly0; - return lyCounter.frameCycles(cc) - lastM2Fc < ly0M2Fc - lastM2Fc || (statReg & lcdstat_m0irqen) - ? lyCounter.nextFrameCycle(ly0M2Fc, cc) - : lyCounter.nextLineCycle(mode2_irq_line_cycle, cc); - } - - unsigned long m0TimeOfCurrentLine( - unsigned long nextLyTime, - unsigned long lastM0Time, - unsigned long nextM0Time) { - return nextM0Time < nextLyTime ? nextM0Time : lastM0Time; - } - - bool isHdmaPeriod(LyCounter const& lyCounter, - unsigned long m0TimeOfCurrentLy, unsigned long cc) { - return lyCounter.ly() < lcd_vres - && cc + 3 + 3 * lyCounter.isDoubleSpeed() < lyCounter.time() - && cc >= m0TimeOfCurrentLy; - } - -} // unnamed namespace. - -void LCD::setDmgPalette(unsigned long palette[], const unsigned long dmgColors[], unsigned data) { - palette[0] = dmgColors[data & 3]; - palette[1] = dmgColors[data >> 2 & 3]; - palette[2] = dmgColors[data >> 4 & 3]; - palette[3] = dmgColors[data >> 6 & 3]; -} - -void LCD::setCgbPalette(unsigned *lut) { - for (int i = 0; i < 32768; i++) - cgbColorsRgb32_[i] = lut[i]; - refreshPalettes(); -} - -LCD::LCD(unsigned char const *oamram, unsigned char const *vram, - VideoInterruptRequester memEventRequester) -: ppu_(nextM0Time_, oamram, vram) -, bgpData_() -, objpData_() -, eventTimes_(memEventRequester) -, statReg_(0) -, scanlinecallback(0) -, scanlinecallbacksl(0) -{ - for (std::size_t i = 0; i < sizeof dmgColorsRgb32_ / sizeof dmgColorsRgb32_[0]; ++i) - dmgColorsRgb32_[i] = (3 - (i & 3)) * 85 * 0x010101ul; - std::memset( bgpData_, 0, sizeof bgpData_); - std::memset(objpData_, 0, sizeof objpData_); - - reset(oamram, vram, false); - setVideoBuffer(0, lcd_hres); -} - -void LCD::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb) { - ppu_.reset(oamram, vram, cgb); - lycIrq_.setCgb(cgb); - refreshPalettes(); -} - -void LCD::setStatePtrs(SaveState &state) { - state.ppu.bgpData.set( bgpData_, sizeof bgpData_); - state.ppu.objpData.set(objpData_, sizeof objpData_); - ppu_.setStatePtrs(state); -} - -void LCD::loadState(SaveState const &state, unsigned char const *const oamram) { - statReg_ = state.mem.ioamhram.get()[0x141]; - - ppu_.loadState(state, oamram); - lycIrq_.loadState(state); - mstatIrq_.loadState(state); - - if (ppu_.lcdc() & lcdc_en) { - nextM0Time_.predictNextM0Time(ppu_); - lycIrq_.reschedule(ppu_.lyCounter(), ppu_.now()); - - eventTimes_.setm(state.ppu.pendingLcdstatIrq - ? ppu_.now() + 1 - : 1 * disabled_time); - eventTimes_.setm( - state.ppu.oldWy != state.mem.ioamhram.get()[0x14A] - ? ppu_.now() + 2 - isDoubleSpeed() - : 1 * disabled_time); - eventTimes_.set(ppu_.lyCounter().time()); - eventTimes_.setm( - SpriteMapper::schedule(ppu_.lyCounter(), ppu_.now())); - eventTimes_.setm(lycIrq_.time()); - eventTimes_.setm(mode1IrqSchedule(ppu_.lyCounter(), ppu_.now())); - eventTimes_.setm( - mode2IrqSchedule(statReg_, ppu_.lyCounter(), ppu_.now())); - eventTimes_.setm(statReg_ & lcdstat_m0irqen - ? ppu_.now() + state.ppu.nextM0Irq - : 1 * disabled_time); - eventTimes_.setm(state.mem.hdmaTransfer - ? nextM0Time_.predictedNextM0Time() - : 1 * disabled_time); - } else for (int i = 0; i < num_memevents; ++i) - eventTimes_.set(MemEvent(i), disabled_time); - - refreshPalettes(); -} - -void LCD::refreshPalettes() { - if (isCgb() && !isCgbDmg()) { - for (int i = 0; i < max_num_palettes * num_palette_entries; ++i) { - ppu_.bgPalette()[i] = gbcToRgb32(bgpData_[2 * i] | bgpData_[2 * i + 1] * 0x100l); - ppu_.spPalette()[i] = gbcToRgb32(objpData_[2 * i] | objpData_[2 * i + 1] * 0x100l); - } - } else { - setDmgPalette(ppu_.bgPalette() , dmgColorsRgb32_ , bgpData_[0]); - setDmgPalette(ppu_.spPalette() , dmgColorsRgb32_ + 4, objpData_[0]); - setDmgPalette(ppu_.spPalette() + 4, dmgColorsRgb32_ + 8, objpData_[1]); - } -} - -void LCD::copyCgbPalettesToDmg() { - for(unsigned i = 0; i < 4; i++) { - dmgColorsRgb32_[i] = gbcToRgb32(bgpData_[i * 2] | bgpData_[i * 2 + 1] << 8); - } - for(unsigned i = 0; i < 8; i++) { - dmgColorsRgb32_[i + 4] = gbcToRgb32(objpData_[i * 2] | objpData_[i * 2 + 1] << 8); - } -} - -namespace { - -template -void clear(T *buf, unsigned long color, std::ptrdiff_t dpitch) { - unsigned lines = 144; - - while (lines--) { - std::fill_n(buf, 160, color); - buf += dpitch; - } -} - -} - -void LCD::updateScreen(bool const blanklcd, unsigned long const cycleCounter) { - update(cycleCounter); - - if (blanklcd && ppu_.frameBuf().fb()) { - unsigned long color = ppu_.cgb() ? gbcToRgb32(0xFFFF) : dmgColorsRgb32_[0]; - clear(ppu_.frameBuf().fb(), color, ppu_.frameBuf().pitch()); - } -} - -void LCD::blackScreen() { - if (ppu_.frameBuf().fb()) { - clear(ppu_.frameBuf().fb(), gbcToRgb32(0x0000), ppu_.frameBuf().pitch()); - } -} - -void LCD::resetCc(unsigned long const oldCc, unsigned long const newCc) { - update(oldCc); - ppu_.resetCc(oldCc, newCc); - - if (ppu_.lcdc() & lcdc_en) { - unsigned long const dec = oldCc - newCc; - - nextM0Time_.invalidatePredictedNextM0Time(); - lycIrq_.reschedule(ppu_.lyCounter(), newCc); - - for (int i = 0; i < num_memevents; ++i) { - if (eventTimes_(MemEvent(i)) != disabled_time) - eventTimes_.set(MemEvent(i), eventTimes_(MemEvent(i)) - dec); - } - - eventTimes_.set(ppu_.lyCounter().time()); - } -} - -void LCD::speedChange(unsigned long const cc) { - update(cc); - ppu_.speedChange(); - - if (ppu_.lcdc() & lcdc_en) { - nextM0Time_.predictNextM0Time(ppu_); - lycIrq_.reschedule(ppu_.lyCounter(), ppu_.now()); - - eventTimes_.set(ppu_.lyCounter().time()); - eventTimes_.setm(SpriteMapper::schedule(ppu_.lyCounter(), ppu_.now())); - eventTimes_.setm(lycIrq_.time()); - eventTimes_.setm(mode1IrqSchedule(ppu_.lyCounter(), ppu_.now())); - eventTimes_.setm(mode2IrqSchedule(statReg_, ppu_.lyCounter(), ppu_.now())); - - if (eventTimes_(memevent_m0irq) != disabled_time) { - eventTimes_.setm(ppu_.predictedNextXposTime(lcd_hres + 6)); - } - if (hdmaIsEnabled()) { - eventTimes_.setm(nextM0Time_.predictedNextM0Time()); - } - } -} - -unsigned long LCD::m0TimeOfCurrentLine(unsigned long const cc) { - if (cc >= nextM0Time_.predictedNextM0Time()) { - update(cc); - nextM0Time_.predictNextM0Time(ppu_); - } - - return ::m0TimeOfCurrentLine(ppu_.lyCounter().time(), ppu_.lastM0Time(), - nextM0Time_.predictedNextM0Time()); -} - -void LCD::enableHdma(unsigned long const cc) { - if (cc >= eventTimes_.nextEventTime()) - update(cc); - - if (::isHdmaPeriod(ppu_.lyCounter(), m0TimeOfCurrentLine(cc), cc + 4)) - eventTimes_.flagHdmaReq(); - - eventTimes_.setm(nextM0Time_.predictedNextM0Time()); -} - -void LCD::disableHdma(unsigned long const cycleCounter) { - if (cycleCounter >= eventTimes_.nextEventTime()) - update(cycleCounter); - - eventTimes_.setm(disabled_time); -} - -bool LCD::isHdmaPeriod(unsigned long const cc) { - if (cc >= eventTimes_.nextEventTime()) - update(cc); - - return ::isHdmaPeriod(ppu_.lyCounter(), m0TimeOfCurrentLine(cc), cc); -} - -bool LCD::vramReadable(unsigned long const cc) { - if (cc >= eventTimes_.nextEventTime()) - update(cc); - - return !(ppu_.lcdc() & lcdc_en) - || ppu_.lyCounter().ly() >= lcd_vres - || ppu_.inactivePeriodAfterDisplayEnable(cc + 1 - ppu_.cgb() + isDoubleSpeed()) - || ppu_.lyCounter().lineCycles(cc) + isDoubleSpeed() < 76u + 3 * ppu_.cgb() - || cc + 2 >= m0TimeOfCurrentLine(cc); -} - -bool LCD::vramExactlyReadable(unsigned long const cc) { - if (vramHasBeenExactlyRead) { - return false; - } - if (cc + 2 + isDoubleSpeed() == m0TimeOfCurrentLine(cc)) { - vramHasBeenExactlyRead = true; - } - return cc + 2 + isDoubleSpeed() == m0TimeOfCurrentLine(cc); -} - -bool LCD::vramWritable(unsigned long const cc) { - if (cc >= eventTimes_.nextEventTime()) - update(cc); - - return !(ppu_.lcdc() & lcdc_en) - || ppu_.lyCounter().ly() >= lcd_vres - || ppu_.inactivePeriodAfterDisplayEnable(cc + 1 - ppu_.cgb() + isDoubleSpeed()) - || ppu_.lyCounter().lineCycles(cc) + isDoubleSpeed() < 79 - || cc + 2 >= m0TimeOfCurrentLine(cc); -} - -bool LCD::cgbpAccessible(unsigned long const cc) { - if (cc >= eventTimes_.nextEventTime()) - update(cc); - - return !(ppu_.lcdc() & lcdc_en) - || ppu_.lyCounter().ly() >= lcd_vres - || ppu_.inactivePeriodAfterDisplayEnable(cc) - || ppu_.lyCounter().lineCycles(cc) + isDoubleSpeed() < 80 - || cc >= m0TimeOfCurrentLine(cc) + 2; -} - -void LCD::doCgbColorChange(unsigned char *pdata, - unsigned long *palette, unsigned index, unsigned data) { - pdata[index] = data; - index >>= 1; - palette[index] = gbcToRgb32(pdata[index * 2] | pdata[index * 2 + 1] << 8); -} - -void LCD::doCgbBgColorChange(unsigned index, unsigned data, unsigned long cc) { - if (cgbpAccessible(cc)) { - update(cc); - doCgbColorChange(bgpData_, ppu_.bgPalette(), index, data); - } -} - -void LCD::doCgbSpColorChange(unsigned index, unsigned data, unsigned long cc) { - if (cgbpAccessible(cc)) { - update(cc); - doCgbColorChange(objpData_, ppu_.spPalette(), index, data); - } -} - -bool LCD::oamReadable(unsigned long const cc) { - if (!(ppu_.lcdc() & lcdc_en) || ppu_.inactivePeriodAfterDisplayEnable(cc + 4)) - return true; - - if (cc >= eventTimes_.nextEventTime()) - update(cc); - - if (ppu_.lyCounter().lineCycles(cc) + 4 - isDoubleSpeed() >= lcd_cycles_per_line) - return ppu_.lyCounter().ly() >= lcd_vres - 1 && ppu_.lyCounter().ly() < lcd_lines_per_frame - 1; - - return ppu_.lyCounter().ly() >= lcd_vres || cc + 2 >= m0TimeOfCurrentLine(cc); -} - -bool LCD::oamWritable(unsigned long const cc) { - if (!(ppu_.lcdc() & lcdc_en) || ppu_.inactivePeriodAfterDisplayEnable(cc + 4 + isDoubleSpeed())) - return true; - - if (cc >= eventTimes_.nextEventTime()) - update(cc); - - if (ppu_.lyCounter().lineCycles(cc) + 3 + ppu_.cgb() >= lcd_cycles_per_line) - return ppu_.lyCounter().ly() >= lcd_vres - 1 && ppu_.lyCounter().ly() < lcd_lines_per_frame - 1; - - return ppu_.lyCounter().ly() >= lcd_vres || cc + 2 >= m0TimeOfCurrentLine(cc) - || (ppu_.lyCounter().lineCycles(cc) == 76 && !ppu_.cgb()); -} - -void LCD::mode3CyclesChange() { - nextM0Time_.invalidatePredictedNextM0Time(); - - if (eventTimes_(memevent_m0irq) != disabled_time - && eventTimes_(memevent_m0irq) > ppu_.now()) { - unsigned long t = ppu_.predictedNextXposTime(lcd_hres + 6); - eventTimes_.setm(t); - } - - if (eventTimes_(memevent_hdma) != disabled_time - && eventTimes_(memevent_hdma) > ppu_.lastM0Time()) { - nextM0Time_.predictNextM0Time(ppu_); - eventTimes_.setm(nextM0Time_.predictedNextM0Time()); - } -} - -void LCD::wxChange(unsigned newValue, unsigned long cycleCounter) { - update(cycleCounter + 1 + ppu_.cgb()); - ppu_.setWx(newValue); - mode3CyclesChange(); -} - -void LCD::wyChange(unsigned const newValue, unsigned long const cc) { - update(cc + 1 + ppu_.cgb()); - ppu_.setWy(newValue); - - // mode3CyclesChange(); - // (should be safe to wait until after wy2 delay, because no mode3 events are - // close to when wy1 is read.) - - // wy2 is a delayed version of wy for convenience (is this really simpler?). - if (ppu_.cgb() && (ppu_.lcdc() & lcdc_en)) { - eventTimes_.setm(cc + 6 - isDoubleSpeed()); - } - else { - update(cc + 2); - ppu_.updateWy2(); - mode3CyclesChange(); - } -} - -void LCD::scxChange(unsigned newScx, unsigned long cycleCounter) { - update(cycleCounter + 2 * ppu_.cgb()); - ppu_.setScx(newScx); - mode3CyclesChange(); -} - -void LCD::scyChange(unsigned newValue, unsigned long cycleCounter) { - update(cycleCounter + 2 * ppu_.cgb()); - ppu_.setScy(newValue); -} - -void LCD::oamChange(unsigned long cc) { - if (ppu_.lcdc() & lcdc_en) { - update(cc); - ppu_.oamChange(cc); - eventTimes_.setm(SpriteMapper::schedule(ppu_.lyCounter(), cc)); - } -} - -void LCD::oamChange(unsigned char const *oamram, unsigned long cc) { - update(cc); - ppu_.oamChange(oamram, cc); - - if (ppu_.lcdc() & lcdc_en) - eventTimes_.setm(SpriteMapper::schedule(ppu_.lyCounter(), cc)); -} - -void LCD::lcdcChange(unsigned const data, unsigned long const cc) { - unsigned const oldLcdc = ppu_.lcdc(); - - if ((oldLcdc ^ data) & lcdc_en) { - update(cc); - ppu_.setLcdc(data, cc); - - if (data & lcdc_en) { - lycIrq_.lcdReset(); - mstatIrq_.lcdReset(lycIrq_.lycReg()); - nextM0Time_.predictNextM0Time(ppu_); - lycIrq_.reschedule(ppu_.lyCounter(), cc); - - eventTimes_.set(ppu_.lyCounter().time()); - eventTimes_.setm( - SpriteMapper::schedule(ppu_.lyCounter(), cc)); - eventTimes_.setm(lycIrq_.time()); - eventTimes_.setm(mode1IrqSchedule(ppu_.lyCounter(), cc)); - eventTimes_.setm( - mode2IrqSchedule(statReg_, ppu_.lyCounter(), cc)); - if (statReg_ & lcdstat_m0irqen) { - eventTimes_.setm(ppu_.predictedNextXposTime(lcd_hres + 6)); - } - if (hdmaIsEnabled()) { - eventTimes_.setm(nextM0Time_.predictedNextM0Time()); - } - } - else for (int i = 0; i < num_memevents; ++i) - eventTimes_.set(MemEvent(i), disabled_time); - } - else if (data & lcdc_en) { - if (ppu_.cgb()) { - update(cc + 1); - ppu_.setLcdc((oldLcdc & ~(1u * lcdc_tdsel)) | (data & lcdc_tdsel), cc + 1); - update(cc + 2); - ppu_.setLcdc(data, cc + 2); - if ((oldLcdc ^ data) & lcdc_obj2x) { - unsigned long t = SpriteMapper::schedule(ppu_.lyCounter(), cc + 2); - eventTimes_.setm(t); - } - if ((oldLcdc ^ data) & lcdc_we) - mode3CyclesChange(); - } - else { - update(cc); - ppu_.setLcdc((oldLcdc & lcdc_obj2x) | (data & ~(1u * lcdc_obj2x)), cc); - if ((oldLcdc ^ data) & lcdc_obj2x) { - update(cc + 2); - ppu_.setLcdc(data, cc + 2); - unsigned long t = SpriteMapper::schedule(ppu_.lyCounter(), cc + 2); - eventTimes_.setm(t); - } - if ((oldLcdc ^ data) & (lcdc_we | lcdc_objen)) - mode3CyclesChange(); - } - } - else { - update(cc); - ppu_.setLcdc(data, cc); - } -} - -namespace { - -struct LyCnt { - unsigned ly; int timeToNextLy; - LyCnt(unsigned ly, int timeToNextLy) : ly(ly), timeToNextLy(timeToNextLy) {} -}; - -LyCnt const getLycCmpLy(LyCounter const &lyCounter, unsigned long cc) { - unsigned ly = lyCounter.ly(); - int timeToNextLy = lyCounter.time() - cc; - - if (ly == lcd_lines_per_frame - 1) { - int const lineTime = lyCounter.lineTime(); - if ((timeToNextLy -= (lineTime - 6 - 6 * lyCounter.isDoubleSpeed())) <= 0) - ly = 0, timeToNextLy += lineTime; - } - else if ((timeToNextLy -= (2 + 2 * lyCounter.isDoubleSpeed())) <= 0) - ++ly, timeToNextLy += lyCounter.lineTime(); - - return LyCnt(ly, timeToNextLy); -} - -bool statChangeTriggersM2IrqCgb(unsigned const old, - unsigned const data, int const ly, int const timeToNextLy, bool const ds) { - if ((old & lcdstat_m2irqen) - || (data & (lcdstat_m2irqen | lcdstat_m0irqen)) != lcdstat_m2irqen) { - return false; - } - if (ly < lcd_vres - 1) - return timeToNextLy <= (lcd_cycles_per_line - mode2_irq_line_cycle) * (1 + ds) && timeToNextLy > 2; - if (ly == lcd_vres - 1) - return timeToNextLy <= (lcd_cycles_per_line - mode2_irq_line_cycle) * (1 + ds) && timeToNextLy > 4 + 2 * ds; - if (ly == lcd_lines_per_frame - 1) - return timeToNextLy <= (lcd_cycles_per_line - mode2_irq_line_cycle_ly0) * (1 + ds) && timeToNextLy > 2; - return false; -} - -unsigned incLy(unsigned ly) { return ly == lcd_lines_per_frame - 1 ? 0 : ly + 1; } - -} // unnamed namespace. - -inline bool LCD::statChangeTriggersStatIrqDmg(unsigned const old, unsigned long const cc) { - LyCnt const lycCmp = getLycCmpLy(ppu_.lyCounter(), cc); - - if (ppu_.lyCounter().ly() < lcd_vres) { - int const m0_cycles_upper_bound = lcd_cycles_per_line - 80 - 160; - unsigned long m0IrqTime = eventTimes_(memevent_m0irq); - if (m0IrqTime == disabled_time && ppu_.lyCounter().time() - cc < m0_cycles_upper_bound) { - update(cc); - m0IrqTime = ppu_.predictedNextXposTime(lcd_hres + 6); - } - if (m0IrqTime == disabled_time || m0IrqTime < ppu_.lyCounter().time()) - return lycCmp.ly == lycIrq_.lycReg() && !(old & lcdstat_lycirqen); - - return !(old & lcdstat_m0irqen) - && !(lycCmp.ly == lycIrq_.lycReg() && (old & lcdstat_lycirqen)); - } - - return !(old & lcdstat_m1irqen) - && !(lycCmp.ly == lycIrq_.lycReg() && (old & lcdstat_lycirqen)); -} - -inline bool LCD::statChangeTriggersM0LycOrM1StatIrqCgb( - unsigned const old, unsigned const data, bool const lycperiod, - unsigned long const cc) { - int const ly = ppu_.lyCounter().ly(); - int const timeToNextLy = ppu_.lyCounter().time() - cc; - bool const ds = isDoubleSpeed(); - int const m1_irq_lc_inv = lcd_cycles_per_line - mode1_irq_frame_cycle % lcd_cycles_per_line; - - if (ly < lcd_vres - 1 || (ly == lcd_vres - 1 && timeToNextLy > m1_irq_lc_inv* (1 + ds))) { - if (eventTimes_(memevent_m0irq) < ppu_.lyCounter().time() - || timeToNextLy <= (ly < lcd_vres - 1 ? 4 + 4 * ds : 4 + 2 * ds)) { - return lycperiod && (data & lcdstat_lycirqen); - } - - if (old & lcdstat_m0irqen) - return false; - - return (data & lcdstat_m0irqen) - || (lycperiod && (data & lcdstat_lycirqen)); - } - - if (old & lcdstat_m1irqen && (ly < lcd_lines_per_frame - 1 || timeToNextLy > 3 + 3 * ds)) - return false; - - return ((data & lcdstat_m1irqen) - && (ly < lcd_lines_per_frame - 1 || timeToNextLy > 4 + 2 * ds)) - || (lycperiod && (data & lcdstat_lycirqen)); -} - -inline bool LCD::statChangeTriggersStatIrqCgb( - unsigned const old, unsigned const data, unsigned long const cc) { - if (!(data & ~old & (lcdstat_lycirqen - | lcdstat_m2irqen - | lcdstat_m1irqen - | lcdstat_m0irqen))) { - return false; - } - - int const ly = ppu_.lyCounter().ly(); - int const timeToNextLy = ppu_.lyCounter().time() - cc; - LyCnt const lycCmp = getLycCmpLy(ppu_.lyCounter(), cc); - bool const lycperiod = lycCmp.ly == lycIrq_.lycReg() - && lycCmp.timeToNextLy > 2; - if (lycperiod && (old & lcdstat_lycirqen)) - return false; - - return statChangeTriggersM0LycOrM1StatIrqCgb(old, data, lycperiod, cc) - || statChangeTriggersM2IrqCgb(old, data, ly, timeToNextLy, isDoubleSpeed()); -} - - -inline bool LCD::statChangeTriggersStatIrq(unsigned old, unsigned data, unsigned long cc) { - return ppu_.cgb() - ? statChangeTriggersStatIrqCgb(old, data, cc) - : statChangeTriggersStatIrqDmg(old, cc); -} - -void LCD::lcdstatChange(unsigned const data, unsigned long const cc) { - if (cc >= eventTimes_.nextEventTime()) - update(cc); - - unsigned const old = statReg_; - statReg_ = data; - lycIrq_.statRegChange(data, ppu_.lyCounter(), cc); - - if (ppu_.lcdc() & lcdc_en) { - if ((data & lcdstat_m0irqen) && eventTimes_(memevent_m0irq) == disabled_time) { - update(cc); - eventTimes_.setm(ppu_.predictedNextXposTime(lcd_hres + 6)); - } - - eventTimes_.setm(mode2IrqSchedule(data, ppu_.lyCounter(), cc)); - eventTimes_.setm(lycIrq_.time()); - - if (statChangeTriggersStatIrq(old, data, cc)) - eventTimes_.flagIrq(2); - } - - mstatIrq_.statRegChange(data, eventTimes_(memevent_m0irq), eventTimes_(memevent_m1irq), - eventTimes_(memevent_m2irq), cc, ppu_.cgb()); -} - -inline bool LCD::lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned data, unsigned long cc) { - int const timeToNextLy = ppu_.lyCounter().time() - cc; - if (ppu_.lyCounter().ly() < lcd_vres) { - return (statReg_ & lcdstat_m0irqen) - && eventTimes_(memevent_m0irq) > ppu_.lyCounter().time() - && data == ppu_.lyCounter().ly(); - } - - return (statReg_ & lcdstat_m1irqen) - && !(ppu_.lyCounter().ly() == lcd_lines_per_frame - 1 - && timeToNextLy <= 2 + 2 * isDoubleSpeed() + 2 * ppu_.cgb()); -} - -bool LCD::lycRegChangeTriggersStatIrq( - unsigned const old, unsigned const data, unsigned long const cc) { - if (!(statReg_ & lcdstat_lycirqen) || data >= lcd_lines_per_frame - || lycRegChangeStatTriggerBlockedByM0OrM1Irq(data, cc)) { - return false; - } - - LyCnt lycCmp = getLycCmpLy(ppu_.lyCounter(), cc); - if (lycCmp.timeToNextLy <= 4 + 4 * isDoubleSpeed() + 2 * ppu_.cgb()) { - if (old == lycCmp.ly && lycCmp.timeToNextLy > 2 * ppu_.cgb()) - return false; // simultaneous ly/lyc inc. lyc flag never goes low -> no trigger. - - lycCmp.ly = incLy(lycCmp.ly); - } - - return data == lycCmp.ly; -} - -void LCD::lycRegChange(unsigned const data, unsigned long const cc) { - unsigned const old = lycIrq_.lycReg(); - if (data == old) - return; - - if (cc >= eventTimes_.nextEventTime()) - update(cc); - - lycIrq_.lycRegChange(data, ppu_.lyCounter(), cc); - mstatIrq_.lycRegChange(data, eventTimes_(memevent_m0irq), - eventTimes_(memevent_m2irq), cc, isDoubleSpeed(), ppu_.cgb()); - - if (ppu_.lcdc() & lcdc_en) { - eventTimes_.setm(lycIrq_.time()); - - if (lycRegChangeTriggersStatIrq(old, data, cc)) { - if (ppu_.cgb() && !isDoubleSpeed()) { - eventTimes_.setm(cc + 5); - } - else - eventTimes_.flagIrq(2); - } - } -} - -unsigned LCD::getStat(unsigned const lycReg, unsigned long const cc) { - unsigned stat = 0; - - if (ppu_.lcdc() & lcdc_en) { - if (cc >= eventTimes_.nextEventTime()) - update(cc); - - unsigned const ly = ppu_.lyCounter().ly(); - int const timeToNextLy = ppu_.lyCounter().time() - cc; - int const lineCycles = lcd_cycles_per_line - (timeToNextLy >> isDoubleSpeed()); - long const frameCycles = 1l * ly * lcd_cycles_per_line + lineCycles; - if (frameCycles >= lcd_vres * lcd_cycles_per_line - 3 && frameCycles < lcd_cycles_per_frame - 3) { - if (frameCycles >= lcd_vres * lcd_cycles_per_line - 2 - && frameCycles < lcd_cycles_per_frame - 4 + isDoubleSpeed()) { - stat = 1; - } - } - else if (lineCycles < 77 || lineCycles >= lcd_cycles_per_line - 3) { - if (!ppu_.inactivePeriodAfterDisplayEnable(cc + 1)) - stat = 2; - } - else if (cc + 2 < m0TimeOfCurrentLine(cc)) { - if (!ppu_.inactivePeriodAfterDisplayEnable(cc + 1)) - stat = 3; - } - - LyCnt const lycCmp = getLycCmpLy(ppu_.lyCounter(), cc); - if (lycReg == lycCmp.ly && lycCmp.timeToNextLy > 2) - stat |= lcdstat_lycflag; - } - - return stat; -} - -inline void LCD::doMode2IrqEvent() { - unsigned const ly = eventTimes_(event_ly) - eventTimes_(memevent_m2irq) < 16 - ? incLy(ppu_.lyCounter().ly()) - : ppu_.lyCounter().ly(); - if (mstatIrq_.doM2Event(ly, statReg_, lycIrq_.lycReg())) - eventTimes_.flagIrq(2, eventTimes_(memevent_m2irq)); - - bool const ds = isDoubleSpeed(); - unsigned long next = lcd_cycles_per_frame; - if (!(statReg_ & lcdstat_m0irqen)) { - next = lcd_cycles_per_line; - if (ly == 0) { - next -= mode2_irq_line_cycle_ly0 - mode2_irq_line_cycle; - } - else if (ly == lcd_vres) { - next += lcd_cycles_per_line * (lcd_lines_per_frame - lcd_vres - 1) - + mode2_irq_line_cycle_ly0 - mode2_irq_line_cycle; - } - } - eventTimes_.setm(eventTimes_(memevent_m2irq) + (next << ds)); -} - -inline void LCD::event() { - switch (eventTimes_.nextEvent()) { - case event_mem: - switch (eventTimes_.nextMemEvent()) { - case memevent_m1irq: - eventTimes_.flagIrq(mstatIrq_.doM1Event(statReg_) ? 3 : 1, - eventTimes_(memevent_m1irq)); - eventTimes_.setm(eventTimes_(memevent_m1irq) - + (lcd_cycles_per_frame << isDoubleSpeed())); - break; - - case memevent_lycirq: - if (lycIrq_.doEvent(ppu_.lyCounter())) - eventTimes_.flagIrq(2, eventTimes_(memevent_lycirq)); - - eventTimes_.setm(lycIrq_.time()); - break; - - case memevent_spritemap: - eventTimes_.setm( - ppu_.doSpriteMapEvent(eventTimes_(memevent_spritemap))); - mode3CyclesChange(); - break; - - case memevent_hdma: - eventTimes_.flagHdmaReq(); - nextM0Time_.predictNextM0Time(ppu_); - eventTimes_.setm(nextM0Time_.predictedNextM0Time()); - break; - - case memevent_m2irq: - doMode2IrqEvent(); - break; - - case memevent_m0irq: - if (mstatIrq_.doM0Event(ppu_.lyCounter().ly(), statReg_, lycIrq_.lycReg())) - eventTimes_.flagIrq(2, eventTimes_(memevent_m0irq)); - - eventTimes_.setm(statReg_ & lcdstat_m0irqen - ? ppu_.predictedNextXposTime(lcd_hres + 6) - : 1 * disabled_time); - break; - - case memevent_oneshot_statirq: - eventTimes_.flagIrq(2); - eventTimes_.setm(disabled_time); - break; - - case memevent_oneshot_updatewy2: - ppu_.updateWy2(); - mode3CyclesChange(); - eventTimes_.setm(disabled_time); - break; - } - - break; - - case event_ly: - ppu_.doLyCountEvent(); - eventTimes_.set(ppu_.lyCounter().time()); - break; - } -} - -void LCD::update(unsigned long const cycleCounter) { - if (!(ppu_.lcdc() & lcdc_en)) - return; - - while (cycleCounter >= eventTimes_.nextEventTime()) { - ppu_.update(eventTimes_.nextEventTime()); - event(); - } - - ppu_.update(cycleCounter); -} - -void LCD::setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch) { - ppu_.setFrameBuf(videoBuf, pitch); -} - -void LCD::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32) { - if (palNum > 2 || colorNum > 3) - return; - - dmgColorsRgb32_[palNum * 4 + colorNum] = rgb32; - refreshPalettes(); -} - -// don't need to save or load rgb32 color data - -SYNCFUNC(LCD) -{ - SSS(ppu_); - NSS(dmgColorsRgb32_); - NSS(cgbColorsRgb32_); - NSS(bgpData_); - NSS(objpData_); - SSS(eventTimes_); - SSS(mstatIrq_); - SSS(lycIrq_); - SSS(nextM0Time_); - NSS(statReg_); - NSS(vramHasBeenExactlyRead); -} diff --git a/libgambatte/src/video.h b/libgambatte/src/video.h deleted file mode 100644 index 60e05bbf42..0000000000 --- a/libgambatte/src/video.h +++ /dev/null @@ -1,266 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef VIDEO_H -#define VIDEO_H - -#include "interruptrequester.h" -#include "minkeeper.h" -#include "video/lyc_irq.h" -#include "video/mstat_irq.h" -#include "video/next_m0_time.h" -#include "video/ppu.h" -#include "newstate.h" - -namespace gambatte { - -class VideoInterruptRequester { -public: - explicit VideoInterruptRequester(InterruptRequester &intreq) - : intreq_(intreq) - { - } - - void flagHdmaReq() const { if (!intreq_.halted()) gambatte::flagHdmaReq(intreq_); } - void flagIrq(unsigned bit) const { intreq_.flagIrq(bit); } - void flagIrq(unsigned bit, unsigned long cc) const { intreq_.flagIrq(bit, cc); } - void setNextEventTime(unsigned long time) const { intreq_.setEventTime(time); } - -private: - InterruptRequester &intreq_; -}; - -class LCD { -public: - LCD(unsigned char const *oamram, unsigned char const *vram, - VideoInterruptRequester memEventRequester); - void reset(unsigned char const *oamram, unsigned char const *vram, bool cgb); - void setCgbDmg(bool enabled) { ppu_.setCgbDmg(enabled); } - void setStatePtrs(SaveState &state); - void loadState(SaveState const &state, unsigned char const *oamram); - void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32); - void setCgbPalette(unsigned *lut); - void setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch); - void setLayers(unsigned mask) { ppu_.setLayers(mask); } - void copyCgbPalettesToDmg(); - - int debugGetLY() const { return ppu_.lyCounter().ly(); } - - void dmgBgPaletteChange(unsigned data, unsigned long cycleCounter) { - update(cycleCounter); - bgpData_[0] = data; - setDmgPalette(ppu_.bgPalette(), dmgColorsRgb32_, data); - } - - void dmgSpPalette1Change(unsigned data, unsigned long cycleCounter) { - update(cycleCounter); - objpData_[0] = data; - setDmgPalette(ppu_.spPalette(), dmgColorsRgb32_ + 4, data); - } - - void dmgSpPalette2Change(unsigned data, unsigned long cycleCounter) { - update(cycleCounter); - objpData_[1] = data; - setDmgPalette(ppu_.spPalette() + 4, dmgColorsRgb32_ + 8, data); - } - - void cgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter) { - if (bgpData_[index] != data) - doCgbBgColorChange(index, data, cycleCounter); - } - - void cgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter) { - if (objpData_[index] != data) - doCgbSpColorChange(index, data, cycleCounter); - } - - unsigned cgbBgColorRead(unsigned index, unsigned long cycleCounter) { - return ppu_.cgb() && cgbpAccessible(cycleCounter) ? bgpData_[index] : 0xFF; - } - - unsigned cgbSpColorRead(unsigned index, unsigned long cycleCounter) { - return ppu_.cgb() && cgbpAccessible(cycleCounter) ? objpData_[index] : 0xFF; - } - - void updateScreen(bool blanklcd, unsigned long cc); - void blackScreen(); - void resetCc(unsigned long oldCC, unsigned long newCc); - void speedChange(unsigned long cycleCounter); - bool vramReadable(unsigned long cycleCounter); - bool vramExactlyReadable(unsigned long cycleCounter); - bool vramWritable(unsigned long cycleCounter); - bool oamReadable(unsigned long cycleCounter); - bool oamWritable(unsigned long cycleCounter); - void wxChange(unsigned newValue, unsigned long cycleCounter); - void wyChange(unsigned newValue, unsigned long cycleCounter); - void oamChange(unsigned long cycleCounter); - void oamChange(const unsigned char *oamram, unsigned long cycleCounter); - void scxChange(unsigned newScx, unsigned long cycleCounter); - void scyChange(unsigned newValue, unsigned long cycleCounter); - void vramChange(unsigned long cycleCounter) { update(cycleCounter); } - unsigned getStat(unsigned lycReg, unsigned long cycleCounter); - - unsigned getLyReg(unsigned long const cc) { - unsigned lyReg = 0; - - if (ppu_.lcdc() & lcdc_en) { - if (cc >= ppu_.lyCounter().time()) - update(cc); - - lyReg = ppu_.lyCounter().ly(); - if (lyReg == lcd_lines_per_frame - 1) { - if (ppu_.lyCounter().time() - cc <= 2 * lcd_cycles_per_line - 2) - lyReg = 0; - } - else if (ppu_.lyCounter().time() - cc <= 10 - && ppu_.lyCounter().time() - cc <= 6u + 4 * isDoubleSpeed()) { - lyReg = ppu_.lyCounter().time() - cc == 6u + 4 * isDoubleSpeed() - ? lyReg & (lyReg + 1) - : lyReg + 1; - } - } - - return lyReg; - } - - unsigned long nextMode1IrqTime() const { return eventTimes_(memevent_m1irq); } - void lcdcChange(unsigned data, unsigned long cycleCounter); - void lcdstatChange(unsigned data, unsigned long cycleCounter); - void lycRegChange(unsigned data, unsigned long cycleCounter); - void enableHdma(unsigned long cycleCounter); - void disableHdma(unsigned long cycleCounter); - bool isHdmaPeriod(unsigned long cycleCounter); - bool hdmaIsEnabled() const { return eventTimes_(memevent_hdma) != disabled_time; } - void update(unsigned long cycleCounter); - bool isCgb() const { return ppu_.cgb(); } - bool isCgbDmg() const { return ppu_.cgbDmg(); } - bool isDoubleSpeed() const { return ppu_.lyCounter().isDoubleSpeed(); } - - unsigned long *bgPalette() { return ppu_.bgPalette(); } - unsigned long *spPalette() { return ppu_.spPalette(); } - - void setScanlineCallback(void (*callback)(), int sl) { scanlinecallback = callback; scanlinecallbacksl = sl; } - -private: - enum Event { event_mem, - event_ly, event_last = event_ly }; - - enum MemEvent { memevent_oneshot_statirq, - memevent_oneshot_updatewy2, - memevent_m1irq, - memevent_lycirq, - memevent_spritemap, - memevent_hdma, - memevent_m2irq, - memevent_m0irq, memevent_last = memevent_m0irq }; - - enum { num_events = event_last + 1 }; - enum { num_memevents = memevent_last + 1 }; - - class EventTimes { - public: - explicit EventTimes(VideoInterruptRequester memEventRequester) - : eventMin_(disabled_time) - , memEventMin_(disabled_time) - , memEventRequester_(memEventRequester) - { - } - - Event nextEvent() const { return static_cast(eventMin_.min()); } - unsigned long nextEventTime() const { return eventMin_.minValue(); } - unsigned long operator()(Event e) const { return eventMin_.value(e); } - template void set(unsigned long time) { eventMin_.setValue(time); } - void set(Event e, unsigned long time) { eventMin_.setValue(e, time); } - - MemEvent nextMemEvent() const { return static_cast(memEventMin_.min()); } - unsigned long nextMemEventTime() const { return memEventMin_.minValue(); } - unsigned long operator()(MemEvent e) const { return memEventMin_.value(e); } - - template - void setm(unsigned long time) { memEventMin_.setValue(time); setMemEvent(); } - void set(MemEvent e, unsigned long time) { memEventMin_.setValue(e, time); setMemEvent(); } - - void flagIrq(unsigned bit) { memEventRequester_.flagIrq(bit); } - void flagIrq(unsigned bit, unsigned long cc) { memEventRequester_.flagIrq(bit, cc); } - void flagHdmaReq() { memEventRequester_.flagHdmaReq(); } - - private: - MinKeeper eventMin_; - MinKeeper memEventMin_; - VideoInterruptRequester memEventRequester_; - - void setMemEvent() { - unsigned long nmet = nextMemEventTime(); - eventMin_.setValue(nmet); - memEventRequester_.setNextEventTime(nmet); - } - -public: - template - void SyncState(NewState *ns) - { - SSS(eventMin_); - SSS(memEventMin_); - } - }; - - PPU ppu_; - unsigned long dmgColorsRgb32_[3 * 4]; - unsigned long cgbColorsRgb32_[32768]; - unsigned char bgpData_[2 * max_num_palettes * num_palette_entries]; - unsigned char objpData_[2 * max_num_palettes * num_palette_entries]; - EventTimes eventTimes_; - MStatIrqEvent mstatIrq_; - LycIrq lycIrq_; - NextM0Time nextM0Time_; - unsigned char statReg_; - bool vramHasBeenExactlyRead = false; - - static void setDmgPalette(unsigned long palette[], - unsigned long const dmgColors[], - unsigned data); - - unsigned long gbcToRgb32(const unsigned bgr15); - void doCgbColorChange(unsigned char *const pdata, unsigned long *const palette, unsigned index, const unsigned data); - void refreshPalettes(); - void setDBuffer(); - void doMode2IrqEvent(); - void event(); - unsigned long m0TimeOfCurrentLine(unsigned long cc); - bool cgbpAccessible(unsigned long cycleCounter); - - bool lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned data, unsigned long cc); - bool lycRegChangeTriggersStatIrq(unsigned old, unsigned data, unsigned long cc); - bool statChangeTriggersM0LycOrM1StatIrqCgb(unsigned old, unsigned data, bool lycperiod, unsigned long cc); - bool statChangeTriggersStatIrqCgb(unsigned old, unsigned data, unsigned long cc); - bool statChangeTriggersStatIrqDmg(unsigned old, unsigned long cc); - bool statChangeTriggersStatIrq(unsigned old, unsigned data, unsigned long cc); - void mode3CyclesChange(); - void doCgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter); - void doCgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter); - - void (*scanlinecallback)(); - int scanlinecallbacksl; - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/video/lcddef.h b/libgambatte/src/video/lcddef.h deleted file mode 100644 index 0ef743537e..0000000000 --- a/libgambatte/src/video/lcddef.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef LCDDEF_H -#define LCDDEF_H - -namespace gambatte { - - enum { - lcdc_bgen = 0x01, - lcdc_objen = 0x02, - lcdc_obj2x = 0x04, - lcdc_bgtmsel = 0x08, - lcdc_tdsel = 0x10, - lcdc_we = 0x20, - lcdc_wtmsel = 0x40, - lcdc_en = 0x80 - }; - - enum { - lcdstat_lycflag = 0x04, - lcdstat_m0irqen = 0x08, - lcdstat_m1irqen = 0x10, - lcdstat_m2irqen = 0x20, - lcdstat_lycirqen = 0x40 - }; - - enum { - lcd_hres = 160, - lcd_vres = 144, - lcd_lines_per_frame = 154, - lcd_max_num_sprites_per_line = 10, - lcd_num_oam_entries = 40, - lcd_cycles_per_line = 456, - lcd_force_signed_enum1 = -1 - }; - enum { - lcd_cycles_per_frame = 1l * lcd_lines_per_frame * lcd_cycles_per_line, - lcd_force_signed_enum2 = -1 - }; - -} - -#endif diff --git a/libgambatte/src/video/ly_counter.cpp b/libgambatte/src/video/ly_counter.cpp deleted file mode 100644 index 1f985a23bc..0000000000 --- a/libgambatte/src/video/ly_counter.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "ly_counter.h" -#include "../savestate.h" - -namespace gambatte { - -LyCounter::LyCounter() -: time_(0) -, lineTime_(0) -, ly_(0) -, ds_(false) -{ - setDoubleSpeed(false); - reset(0, 0); -} - -void LyCounter::doEvent() { - ++ly_; - if (ly_ == lcd_lines_per_frame) - ly_ = 0; - - time_ = time_ + lineTime_; -} - -unsigned long LyCounter::nextLineCycle(unsigned const lineCycle, unsigned long const cc) const { - unsigned long tmp = time_ + (lineCycle << ds_); - if (tmp - cc > lineTime_) - tmp -= lineTime_; - - return tmp; -} - -unsigned long LyCounter::nextFrameCycle(unsigned long const frameCycle, unsigned long const cc) const { - unsigned long tmp = time_ + (((lcd_lines_per_frame - 1l - ly()) * lcd_cycles_per_line + frameCycle) << ds_); - if (tmp - cc > 1ul * lcd_cycles_per_frame << ds_) - tmp -= 1ul * lcd_cycles_per_frame << ds_; - - return tmp; -} - -void LyCounter::reset(unsigned long videoCycles, unsigned long lastUpdate) { - ly_ = videoCycles / lcd_cycles_per_line; - time_ = lastUpdate + ((lcd_cycles_per_line - - (videoCycles - 1l * ly_ * lcd_cycles_per_line)) << isDoubleSpeed()); -} - -void LyCounter::setDoubleSpeed(bool ds) { - ds_ = ds; - lineTime_ = lcd_cycles_per_line << ds; -} - -SYNCFUNC(LyCounter) -{ - NSS(time_); - NSS(lineTime_); - NSS(ly_); - NSS(ds_); -} - -} diff --git a/libgambatte/src/video/ly_counter.h b/libgambatte/src/video/ly_counter.h deleted file mode 100644 index 5700d052b1..0000000000 --- a/libgambatte/src/video/ly_counter.h +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef LY_COUNTER_H -#define LY_COUNTER_H - -#include "newstate.h" -#include "lcddef.h" - -namespace gambatte { - -struct SaveState; - -class LyCounter { -public: - LyCounter(); - void doEvent(); - bool isDoubleSpeed() const { return ds_; } - - unsigned long frameCycles(unsigned long cc) const { - return 1l * ly_ * lcd_cycles_per_line + lineCycles(cc); - } - - unsigned lineCycles(unsigned long cc) const { - return lcd_cycles_per_line - ((time_ - cc) >> isDoubleSpeed()); - } - - unsigned lineTime() const { return lineTime_; } - unsigned ly() const { return ly_; } - unsigned long nextLineCycle(unsigned lineCycle, unsigned long cycleCounter) const; - unsigned long nextFrameCycle(unsigned long frameCycle, unsigned long cycleCounter) const; - void reset(unsigned long videoCycles, unsigned long lastUpdate); - void setDoubleSpeed(bool ds); - unsigned long time() const { return time_; } - -private: - unsigned long time_; - unsigned short lineTime_; - unsigned char ly_; - bool ds_; - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/video/lyc_irq.cpp b/libgambatte/src/video/lyc_irq.cpp deleted file mode 100644 index 92ea67ea3c..0000000000 --- a/libgambatte/src/video/lyc_irq.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "lyc_irq.h" -#include "counterdef.h" -#include "lcddef.h" -#include "ly_counter.h" -#include "savestate.h" -#include - -using namespace gambatte; - -namespace { - - unsigned long schedule(unsigned statReg, - unsigned lycReg, LyCounter const& lyCounter, unsigned long cc) { - return (statReg & lcdstat_lycirqen) && lycReg < lcd_lines_per_frame - ? lyCounter.nextFrameCycle(lycReg - ? 1l * lycReg * lcd_cycles_per_line - 2 - : (lcd_lines_per_frame - 1l) * lcd_cycles_per_line + 6, cc) - : 1 * disabled_time; - } - - bool lycIrqBlockedByM2OrM1StatIrq(unsigned ly, unsigned statreg) { - return ly <= lcd_vres && ly > 0 - ? statreg & lcdstat_m2irqen - : statreg & lcdstat_m1irqen; - } - -} - -LycIrq::LycIrq() -: time_(disabled_time) -, lycRegSrc_(0) -, statRegSrc_(0) -, lycReg_(0) -, statReg_(0) -, cgb_(false) -{ -} - -void LycIrq::regChange(unsigned const statReg, - unsigned const lycReg, LyCounter const& lyCounter, unsigned long const cc) { - unsigned long const timeSrc = schedule(statReg, lycReg, lyCounter, cc); - statRegSrc_ = statReg; - lycRegSrc_ = lycReg; - time_ = std::min(time_, timeSrc); - - if (cgb_) { - if (time_ - cc > 6u + 4 * lyCounter.isDoubleSpeed() || (timeSrc != time_ && time_ - cc > 2)) - lycReg_ = lycReg; - if (time_ - cc > 2) - statReg_ = statReg; - } - else { - if (time_ - cc > 4 || timeSrc != time_) - lycReg_ = lycReg; - - statReg_ = statReg; - } -} - -bool LycIrq::doEvent(LyCounter const& lyCounter) { - bool flagIrq = false; - if ((statReg_ | statRegSrc_) & lcdstat_lycirqen) { - unsigned const cmpLy = lyCounter.ly() == lcd_lines_per_frame - 1 - ? 0 - : lyCounter.ly() + 1; - flagIrq = lycReg_ == cmpLy && !lycIrqBlockedByM2OrM1StatIrq(lycReg_, statReg_); - } - - lycReg_ = lycRegSrc_; - statReg_ = statRegSrc_; - time_ = schedule(statReg_, lycReg_, lyCounter, time_); - return flagIrq; -} - -void LycIrq::loadState(SaveState const &state) { - lycRegSrc_ = state.mem.ioamhram.get()[0x145]; - statRegSrc_ = state.mem.ioamhram.get()[0x141]; - lycReg_ = state.ppu.lyc; - statReg_ = statRegSrc_; -} - -void LycIrq::reschedule(LyCounter const &lyCounter, unsigned long cc) { - time_ = std::min(schedule(statReg_ , lycReg_ , lyCounter, cc), - schedule(statRegSrc_, lycRegSrc_, lyCounter, cc)); -} - -void LycIrq::lcdReset() { - statReg_ = statRegSrc_; - lycReg_ = lycRegSrc_; -} - -SYNCFUNC(LycIrq) -{ - NSS(time_); - NSS(lycRegSrc_); - NSS(statRegSrc_); - NSS(lycReg_); - NSS(statReg_); - NSS(cgb_); -} diff --git a/libgambatte/src/video/lyc_irq.h b/libgambatte/src/video/lyc_irq.h deleted file mode 100644 index 92958a9e36..0000000000 --- a/libgambatte/src/video/lyc_irq.h +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef VIDEO_LYC_IRQ_H -#define VIDEO_LYC_IRQ_H - -#include "newstate.h" - -namespace gambatte { - -struct SaveState; -class LyCounter; - -class LycIrq { -public: - LycIrq(); - bool doEvent(LyCounter const& lyCounter); - unsigned lycReg() const { return lycRegSrc_; } - void loadState(SaveState const &state); - unsigned long time() const { return time_; } - void setCgb(bool cgb) { cgb_ = cgb; } - void lcdReset(); - void reschedule(LyCounter const &lyCounter, unsigned long cc); - - void statRegChange(unsigned statReg, LyCounter const &lyCounter, unsigned long cc) { - regChange(statReg, lycRegSrc_, lyCounter, cc); - } - - void lycRegChange(unsigned lycReg, LyCounter const &lyCounter, unsigned long cc) { - regChange(statRegSrc_, lycReg, lyCounter, cc); - } - -private: - unsigned long time_; - unsigned char lycRegSrc_; - unsigned char statRegSrc_; - unsigned char lycReg_; - unsigned char statReg_; - bool cgb_; - - void regChange(unsigned statReg, unsigned lycReg, - LyCounter const &lyCounter, unsigned long cc); - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/video/mstat_irq.h b/libgambatte/src/video/mstat_irq.h deleted file mode 100644 index d00d1fa038..0000000000 --- a/libgambatte/src/video/mstat_irq.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef M0_IRQ_H -#define M0_IRQ_H - -#include "lcddef.h" -#include "../savestate.h" -#include "../newstate.h" - -namespace gambatte { - -class MStatIrqEvent { -public: - MStatIrqEvent() : lycReg_(0), statReg_(0) {} - void lcdReset(unsigned lycReg) { lycReg_ = lycReg; } - - void lycRegChange(unsigned lycReg, unsigned long nextM0IrqTime, - unsigned long nextM2IrqTime, unsigned long cc, bool ds, bool cgb) { - if (cc + 5 * cgb + 1 - ds < std::min(nextM0IrqTime, nextM2IrqTime)) - lycReg_ = lycReg; - } - - void statRegChange(unsigned statReg, unsigned long nextM0IrqTime, unsigned long nextM1IrqTime, - unsigned long nextM2IrqTime, unsigned long cc, bool cgb) { - if (cc + 2 * cgb < std::min(std::min(nextM0IrqTime, nextM1IrqTime), nextM2IrqTime)) - statReg_ = statReg; - } - - bool doM0Event(unsigned ly, unsigned statReg, unsigned lycReg) { - bool const flagIrq = ((statReg | statReg_) & lcdstat_m0irqen) - && (!(statReg_ & lcdstat_lycirqen) || ly != lycReg_); - lycReg_ = lycReg; - statReg_ = statReg; - return flagIrq; - } - - bool doM1Event(unsigned statReg) { - bool const flagIrq = (statReg & lcdstat_m1irqen) - && !(statReg_ & (lcdstat_m2irqen | lcdstat_m0irqen)); - statReg_ = statReg; - return flagIrq; - } - - bool doM2Event(unsigned ly, unsigned statReg, unsigned lycReg) { - bool const blockedByM1Irq = ly == 0 && (statReg_ & lcdstat_m1irqen); - bool const blockedByLycIrq = (statReg_ & lcdstat_lycirqen) - && (ly == 0 ? ly : ly - 1) == lycReg_; - bool const flagIrq = !blockedByM1Irq && !blockedByLycIrq; - lycReg_ = lycReg; - statReg_ = statReg; - return flagIrq; - } - - void loadState(SaveState const& state) { - lycReg_ = state.ppu.m0lyc; - statReg_ = state.mem.ioamhram.get()[0x141]; - } - -private: - unsigned char statReg_; - unsigned char lycReg_; - -public: - template - void SyncState(NewState *ns) - { - NSS(statReg_); - NSS(lycReg_); - } -}; - -} - -#endif diff --git a/libgambatte/src/video/next_m0_time.cpp b/libgambatte/src/video/next_m0_time.cpp deleted file mode 100644 index 008e3ba595..0000000000 --- a/libgambatte/src/video/next_m0_time.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "next_m0_time.h" -#include "ppu.h" - -void gambatte::NextM0Time::predictNextM0Time(PPU const &ppu) { - predictedNextM0Time_ = ppu.predictedNextXposTime(lcd_hres + 7); -} - -SYNCFUNC(gambatte::NextM0Time) -{ - NSS(predictedNextM0Time_); -} diff --git a/libgambatte/src/video/next_m0_time.h b/libgambatte/src/video/next_m0_time.h deleted file mode 100644 index 110c0a489b..0000000000 --- a/libgambatte/src/video/next_m0_time.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef NEXT_M0_TIME_H_ -#define NEXT_M0_TIME_H_ - -#include "newstate.h" - -namespace gambatte { - -class NextM0Time { -public: - NextM0Time() : predictedNextM0Time_(0) {} - void predictNextM0Time(class PPU const &v); - void invalidatePredictedNextM0Time() { predictedNextM0Time_ = 0; } - unsigned long predictedNextM0Time() const { return predictedNextM0Time_; } - -private: - unsigned long predictedNextM0Time_; - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/video/ppu.cpp b/libgambatte/src/video/ppu.cpp deleted file mode 100644 index 9c09069276..0000000000 --- a/libgambatte/src/video/ppu.cpp +++ /dev/null @@ -1,1931 +0,0 @@ -// -// Copyright (C) 2010 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "ppu.h" -#include "savestate.h" -#include -#include - -#include - -using namespace gambatte; - -namespace { - -#define PREP(u8) (((u8) << 7 & 0x80) | ((u8) << 5 & 0x40) | ((u8) << 3 & 0x20) | ((u8) << 1 & 0x10) \ - | ((u8) >> 1 & 0x08) | ((u8) >> 3 & 0x04) | ((u8) >> 5 & 0x02) | ((u8) >> 7 & 0x01)) - -#define EXPAND(u8) ((PREP(u8) << 7 & 0x4000) | (PREP(u8) << 6 & 0x1000) \ - | (PREP(u8) << 5 & 0x0400) | (PREP(u8) << 4 & 0x0100) \ - | (PREP(u8) << 3 & 0x0040) | (PREP(u8) << 2 & 0x0010) \ - | (PREP(u8) << 1 & 0x0004) | (PREP(u8) & 0x0001)) - -#define EXPAND_ROW(n) EXPAND((n)|0x0), EXPAND((n)|0x1), EXPAND((n)|0x2), EXPAND((n)|0x3), \ - EXPAND((n)|0x4), EXPAND((n)|0x5), EXPAND((n)|0x6), EXPAND((n)|0x7), \ - EXPAND((n)|0x8), EXPAND((n)|0x9), EXPAND((n)|0xA), EXPAND((n)|0xB), \ - EXPAND((n)|0xC), EXPAND((n)|0xD), EXPAND((n)|0xE), EXPAND((n)|0xF) - -#define EXPAND_TABLE EXPAND_ROW(0x00), EXPAND_ROW(0x10), EXPAND_ROW(0x20), EXPAND_ROW(0x30), \ - EXPAND_ROW(0x40), EXPAND_ROW(0x50), EXPAND_ROW(0x60), EXPAND_ROW(0x70), \ - EXPAND_ROW(0x80), EXPAND_ROW(0x90), EXPAND_ROW(0xA0), EXPAND_ROW(0xB0), \ - EXPAND_ROW(0xC0), EXPAND_ROW(0xD0), EXPAND_ROW(0xE0), EXPAND_ROW(0xF0) - -unsigned short const expand_lut[0x200] = { - EXPAND_TABLE, - -#undef PREP -#define PREP(u8) (u8) - - EXPAND_TABLE -}; - -#undef EXPAND_TABLE -#undef EXPAND_ROW -#undef EXPAND -#undef PREP - -#define DECLARE_FUNC(n, id) \ - enum { ID##n = id }; \ - void f##n (PPUPriv &); \ - unsigned predictCyclesUntilXpos_f##n (PPUPriv const &, int targetxpos, unsigned cycles); \ - PPUState const f##n##_ = { f##n, predictCyclesUntilXpos_f##n, ID##n } - -namespace M2_Ly0 { DECLARE_FUNC(0, 0); } -namespace M2_LyNon0 { DECLARE_FUNC(0, 0); DECLARE_FUNC(1, 0); } -namespace M3Start { DECLARE_FUNC(0, 0); DECLARE_FUNC(1, 0); } -namespace M3Loop { -namespace Tile { - DECLARE_FUNC(0, 0x80); - DECLARE_FUNC(1, 0x81); - DECLARE_FUNC(2, 0x82); - DECLARE_FUNC(3, 0x83); - DECLARE_FUNC(4, 0x84); - DECLARE_FUNC(5, 0x85); -} -namespace LoadSprites { - DECLARE_FUNC(0, 0x88); - DECLARE_FUNC(1, 0x89); - DECLARE_FUNC(2, 0x8A); - DECLARE_FUNC(3, 0x8B); - DECLARE_FUNC(4, 0x8C); - DECLARE_FUNC(5, 0x8D); -} -namespace StartWindowDraw { - DECLARE_FUNC(0, 0x90); - DECLARE_FUNC(1, 0x91); - DECLARE_FUNC(2, 0x92); - DECLARE_FUNC(3, 0x93); - DECLARE_FUNC(4, 0x94); - DECLARE_FUNC(5, 0x95); -} -} // namespace M3Loop - -#undef DECLARE_FUNC - -enum { - attr_cgbpalno = 0x07, attr_tdbank = 0x08, attr_dmgpalno = 0x10, attr_xflip = 0x20, - attr_yflip = 0x40, attr_bgpriority = 0x80 -}; -enum { win_draw_start = 1, win_draw_started = 2 }; - -int const max_m3start_cycles = 80; -int const tile_bpp = 2; -int const tile_bpp_mask = (1 << tile_bpp) - 1; -int const tile_len = 8; -int const tile_line_size = tile_bpp * tile_len / 8; -int const tile_size = tile_line_size * tile_len; -int const tile_map_begin = 0x1800; -int const tile_map_len = 0x20; -int const tile_map_size = tile_map_len * tile_map_len; -int const tile_pattern_table_size = 0x1000; -int const vram_bank_size = 0x2000; -int const xpos_end = 168; - -inline int spx(PPUPriv::Sprite const& s) { return s.spx; } - -inline int lcdcEn(PPUPriv const& p) { return p.lcdc & lcdc_en; } -inline int lcdcWinEn(PPUPriv const& p) { return p.lcdc & lcdc_we; } -inline int lcdcObj2x(PPUPriv const& p) { return p.lcdc & lcdc_obj2x; } -inline int lcdcObjEn(PPUPriv const& p) { return p.lcdc & lcdc_objen; } -inline int lcdcBgEn(PPUPriv const& p) { return p.lcdc & lcdc_bgen; } - -inline int weMasterCheckLy0LineCycle(bool cgb) { return 1 + cgb; } -inline int weMasterCheckPriorToLyIncLineCycle(bool /*cgb*/) { return 450; } -inline int weMasterCheckAfterLyIncLineCycle(bool /*cgb*/) { return 454; } -inline int m3StartLineCycle(bool cgb) { return 83 + cgb; } - -inline void nextCall(int const cycles, PPUState const &state, PPUPriv &p) { - int const c = p.cycles - cycles; - if (c >= 0) { - p.cycles = c; - return state.f(p); - } - - p.cycles = c; - p.nextCallPtr = &state; -} - -inline unsigned long const* cgbSpPalette(PPUPriv const& p, unsigned const attrib) { - if (!p.cgbDmg) - return p.spPalette + (attrib & attr_cgbpalno) * num_palette_entries; - else - return p.spPalette + (attrib & attr_dmgpalno ? num_palette_entries : 0); -} - -namespace M2_Ly0 { - void f0(PPUPriv& p) { - p.weMaster = lcdcWinEn(p) && 0 == p.wy; - p.winYPos = 0xFF; - nextCall(m3StartLineCycle(p.cgb) - weMasterCheckLy0LineCycle(p.cgb), M3Start::f0_, p); - } -} - -namespace M2_LyNon0 { - void f0(PPUPriv& p) { - p.weMaster |= lcdcWinEn(p) && p.lyCounter.ly() == p.wy; - nextCall(weMasterCheckAfterLyIncLineCycle(p.cgb) - - weMasterCheckPriorToLyIncLineCycle(p.cgb), f1_, p); - } - - void f1(PPUPriv& p) { - p.weMaster |= lcdcWinEn(p) && p.lyCounter.ly() + 1 == p.wy; - nextCall(lcd_cycles_per_line - weMasterCheckAfterLyIncLineCycle(p.cgb) + m3StartLineCycle(p.cgb), - M3Start::f0_, p); - } -} - -/* -namespace M2 { - struct SpriteLess { - bool operator()(Sprite lhs, Sprite rhs) const { - return lhs.spx < rhs.spx; - } - }; - - void f0(PPUPriv &p) { - std::memset(&p.spLut, 0, sizeof p.spLut); - p.reg0 = 0; - p.nextSprite = 0; - p.nextCallPtr = &f1_; - f1(p); - } - - void f1(PPUPriv &p) { - int const oam_entry_size = 4; - int const oam_size = oam_entry_size * lcd_num_oam_entries; - int cycles = p.cycles; - unsigned oampos = p.reg0; - unsigned nextSprite = p.nextSprite; - unsigned const nly = (p.lyCounter.ly() + 1 == lcd_lines_per_frame ? 0 : p.lyCounter.ly() + 1) - + (p.lyCounter.time() - (p.now - p.cycles) <= 4); - bool const ls = p.spriteMapper.largeSpritesSource(); - - do { - unsigned const spy = p.spriteMapper.oamram()[oampos]; - unsigned const spx = p.spriteMapper.oamram()[oampos + 1]; - unsigned const ydiff = spy - nly; - - if (ls ? ydiff < 2u * tile_len : ydiff - 1u * tile_len < 1u * tile_len) { - p.spriteList[nextSprite].spx = spx; - p.spriteList[nextSprite].line = 2 * tile_len - 1 - ydiff; - p.spriteList[nextSprite].oampos = oampos; - - if (++nextSprite == lcd_max_num_sprites_per_line) { - cycles -= (oam_size - oam_entry_size - oampos) >> 1; - oampos = oam_size - oam_entry_size; - } - } - - oampos += oam_entry_size; - } while ((cycles -= 2) >= 0 && oampos != oam_size); - - p.reg0 = oampos; - p.nextSprite = nextSprite; - p.cycles = cycles; - - if (oampos == oam_size) { - insertionSort(p.spriteList, p.spriteList + nextSprite, SpriteLess()); - p.spriteList[nextSprite].spx = 0xFF; - p.nextSprite = 0; - nextCall(0, M3Start::f0_, p); - } - } -} -*/ - -int loadTileDataByte0(PPUPriv const& p) { - unsigned const yoffset = p.winDrawState & win_draw_started - ? p.winYPos - : p.scy + p.lyCounter.ly(); - - return p.vram[tile_pattern_table_size - + vram_bank_size / attr_tdbank * (p.nattrib & attr_tdbank) - - ((2 * tile_size * p.reg1 | tile_pattern_table_size / lcdc_tdsel * p.lcdc) - & tile_pattern_table_size) - + p.reg1 * tile_size - + ((p.nattrib & attr_yflip ? -1 : 0) ^ yoffset) % tile_len * tile_line_size]; -} - -int loadTileDataByte1(PPUPriv const& p) { - unsigned const yoffset = p.winDrawState & win_draw_started - ? p.winYPos - : p.scy + p.lyCounter.ly(); - - return p.vram[tile_pattern_table_size - + vram_bank_size / attr_tdbank * (p.nattrib & attr_tdbank) - - ((2 * tile_size * p.reg1 | tile_pattern_table_size / lcdc_tdsel * p.lcdc) - & tile_pattern_table_size) - + p.reg1 * tile_size - + ((p.nattrib & attr_yflip ? -1 : 0) ^ yoffset) % tile_len * tile_line_size + 1]; -} - -namespace M3Start { - void f0(PPUPriv& p) { - p.xpos = 0; - - if ((p.winDrawState & win_draw_start) && lcdcWinEn(p)) { - p.winDrawState = win_draw_started; - p.wscx = tile_len + p.scx % tile_len; - ++p.winYPos; - } - else - p.winDrawState = 0; - - p.nextCallPtr = &f1_; - f1(p); - } - - void f1(PPUPriv& p) { - while (p.xpos < max_m3start_cycles) { - if (p.xpos % tile_len == p.scx % tile_len) - break; - - switch (p.xpos % tile_len) { - case 0: - if (p.winDrawState & win_draw_started) { - p.reg1 = p.vram[tile_map_size / lcdc_wtmsel * (p.lcdc & lcdc_wtmsel) - + tile_map_len / tile_len * (p.winYPos & (0x100 - tile_len)) - + p.wscx / tile_len % tile_map_len - + tile_map_begin]; - p.nattrib = p.vram[tile_map_size / lcdc_wtmsel * (p.lcdc & lcdc_wtmsel) - + tile_map_len / tile_len * (p.winYPos & (0x100 - tile_len)) - + p.wscx / tile_len % tile_map_len - + tile_map_begin + vram_bank_size]; - } - else { - p.reg1 = p.vram[((tile_map_size / lcdc_bgtmsel * p.lcdc | p.scx / tile_len) - & (tile_map_size + tile_map_len - 1)) - + tile_map_len / tile_len * ((p.scy + p.lyCounter.ly()) & (0x100 - tile_len)) - + tile_map_begin]; - p.nattrib = p.vram[((tile_map_size / lcdc_bgtmsel * p.lcdc | p.scx / tile_len) - & (tile_map_size + tile_map_len - 1)) - + tile_map_len / tile_len * ((p.scy + p.lyCounter.ly()) & (0x100 - tile_len)) - + tile_map_begin + vram_bank_size]; - } - - break; - case 2: - p.reg0 = loadTileDataByte0(p); - break; - case 4: - { - int const r1 = loadTileDataByte1(p); - p.ntileword = (expand_lut + (0x100 / attr_xflip * p.nattrib & 0x100))[p.reg0] - + (expand_lut + (0x100 / attr_xflip * p.nattrib & 0x100))[r1] * 2; - } - - break; - } - - ++p.xpos; - - if (--p.cycles < 0) - return; - } - - { - int const ly = p.lyCounter.ly(); - int const numSprites = p.spriteMapper.numSprites(ly); - unsigned char const* const sprites = p.spriteMapper.sprites(ly); - for (int i = 0; i < numSprites; ++i) { - int const pos = sprites[i]; - int const spy = p.spriteMapper.posbuf()[pos]; - int const spx = p.spriteMapper.posbuf()[pos + 1]; - - p.spriteList[i].spx = spx; - p.spriteList[i].line = ly + 2 * tile_len - spy; - p.spriteList[i].oampos = pos * 2; - p.spwordList[i] = 0; - } - - p.spriteList[numSprites].spx = 0xFF; - p.nextSprite = 0; - } - - p.xpos = 0; - p.endx = tile_len - p.scx % tile_len; - - static PPUState const* const flut[] = { - &M3Loop::Tile::f0_, - &M3Loop::Tile::f1_, - &M3Loop::Tile::f2_, - &M3Loop::Tile::f3_, - &M3Loop::Tile::f4_, - &M3Loop::Tile::f5_, - &M3Loop::Tile::f5_, - &M3Loop::Tile::f5_ - }; - - nextCall(1 - p.cgb, *flut[p.scx % tile_len], p); - } -} - -namespace M3Loop { - - void doFullTilesUnrolledDmg(PPUPriv& p, int const xend, uint_least32_t* const dbufline, - unsigned char const* const tileMapLine, unsigned const tileline, unsigned tileMapXpos) { - int const tileIndexSign = p.lcdc & lcdc_tdsel ? 0 : tile_pattern_table_size / tile_size / 2; - unsigned char const* const tileDataLine = p.vram + 2 * tile_size * tileIndexSign - + tileline * tile_line_size; - int xpos = p.xpos; - - do { - int nextSprite = p.nextSprite; - - if (spx(p.spriteList[nextSprite]) < xpos + tile_len) { - int cycles = p.cycles - tile_len; - - if (lcdcObjEn(p)) { - cycles -= std::max(11 - (spx(p.spriteList[nextSprite]) - xpos), 6); - for (int i = nextSprite + 1; spx(p.spriteList[i]) < xpos + tile_len; ++i) - cycles -= 6; - - if (cycles < 0) - break; - - p.cycles = cycles; - - do { - unsigned char const* const oam = p.spriteMapper.oamram(); - unsigned reg0, reg1 = oam[p.spriteList[nextSprite].oampos + 2] * tile_size; - unsigned const attrib = oam[p.spriteList[nextSprite].oampos + 3]; - unsigned const spline = (attrib & attr_yflip - ? p.spriteList[nextSprite].line ^ (2 * tile_len - 1) - : p.spriteList[nextSprite].line) * tile_line_size; - unsigned const ts = tile_size; - reg0 = p.vram[(lcdcObj2x(p) ? (reg1 & ~ts) | spline : reg1 | (spline & ~ts))]; - reg1 = p.vram[(lcdcObj2x(p) ? (reg1 & ~ts) | spline : reg1 | (spline & ~ts)) + 1]; - - p.spwordList[nextSprite] = - expand_lut[reg0 + (0x100 / attr_xflip * attrib & 0x100)] - + expand_lut[reg1 + (0x100 / attr_xflip * attrib & 0x100)] * 2; - p.spriteList[nextSprite].attrib = attrib; - ++nextSprite; - } while (spx(p.spriteList[nextSprite]) < xpos + tile_len); - } - else { - if (cycles < 0) - break; - - p.cycles = cycles; - - do { - ++nextSprite; - } while (spx(p.spriteList[nextSprite]) < xpos + tile_len); - } - - p.nextSprite = nextSprite; - } - else if (nextSprite - 1 < 0 || spx(p.spriteList[nextSprite - 1]) <= xpos - tile_len) { - if (!(p.cycles & -1ul * tile_len)) - break; - - int n = (std::min(spx(p.spriteList[nextSprite]), xend + tile_len - 1) - xpos) & -1u * tile_len; - n = std::min(n, p.cycles & -1ul * tile_len); - p.cycles -= n; - - unsigned ntileword = p.ntileword; - uint_least32_t* dst = dbufline + xpos - tile_len; - uint_least32_t* const dstend = dst + n; - xpos += n; - - if (!lcdcBgEn(p)) { - do { *dst++ = p.bgPalette[0]; } while (dst != dstend); - tileMapXpos += n / (1u * tile_len); - - unsigned const tno = tileMapLine[(tileMapXpos - 1) % tile_map_len]; - int const ts = tile_size; - ntileword = expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[0]] - + expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[1]] * 2; - } - else do { - dst[0] = p.bgPalette[ntileword & tile_bpp_mask]; - dst[1] = p.bgPalette[(ntileword & tile_bpp_mask << 1 * tile_bpp) >> 1 * tile_bpp]; - dst[2] = p.bgPalette[(ntileword & tile_bpp_mask << 2 * tile_bpp) >> 2 * tile_bpp]; - dst[3] = p.bgPalette[(ntileword & tile_bpp_mask << 3 * tile_bpp) >> 3 * tile_bpp]; - dst[4] = p.bgPalette[(ntileword & tile_bpp_mask << 4 * tile_bpp) >> 4 * tile_bpp]; - dst[5] = p.bgPalette[(ntileword & tile_bpp_mask << 5 * tile_bpp) >> 5 * tile_bpp]; - dst[6] = p.bgPalette[(ntileword & tile_bpp_mask << 6 * tile_bpp) >> 6 * tile_bpp]; - dst[7] = p.bgPalette[ntileword >> 7 * tile_bpp]; - dst += tile_len; - - unsigned const tno = tileMapLine[tileMapXpos % tile_map_len]; - int const ts = tile_size; - tileMapXpos = tileMapXpos % tile_map_len + 1; - ntileword = expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[0]] - + expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[1]] * 2; - } while (dst != dstend); - - - p.ntileword = ntileword; - continue; - } - else { - int cycles = p.cycles - tile_len; - if (cycles < 0) - break; - - p.cycles = cycles; - } - - - uint_least32_t* const dst = dbufline + (xpos - tile_len); - unsigned const tileword = -(p.lcdc & 1u * lcdc_bgen) & p.ntileword; - - dst[0] = p.bgPalette[tileword & tile_bpp_mask]; - dst[1] = p.bgPalette[(tileword & tile_bpp_mask << 1 * tile_bpp) >> 1 * tile_bpp]; - dst[2] = p.bgPalette[(tileword & tile_bpp_mask << 2 * tile_bpp) >> 2 * tile_bpp]; - dst[3] = p.bgPalette[(tileword & tile_bpp_mask << 3 * tile_bpp) >> 3 * tile_bpp]; - dst[4] = p.bgPalette[(tileword & tile_bpp_mask << 4 * tile_bpp) >> 4 * tile_bpp]; - dst[5] = p.bgPalette[(tileword & tile_bpp_mask << 5 * tile_bpp) >> 5 * tile_bpp]; - dst[6] = p.bgPalette[(tileword & tile_bpp_mask << 6 * tile_bpp) >> 6 * tile_bpp]; - dst[7] = p.bgPalette[tileword >> 7 * tile_bpp]; - - int i = nextSprite - 1; - - if (!lcdcObjEn(p)) { - do { - int const pos = spx(p.spriteList[i]) - xpos; - int const sa = pos * tile_bpp >= 0 - ? tile_len * tile_bpp - pos * tile_bpp - : tile_len * tile_bpp + pos * tile_bpp; - p.spwordList[i] = 1l * p.spwordList[i] >> sa; - --i; - } while (i >= 0 && spx(p.spriteList[i]) > xpos - tile_len); - } - else { - do { - int n; - int pos = spx(p.spriteList[i]) - xpos; - if (pos < 0) { - n = pos + tile_len; - pos = 0; - } - else - n = tile_len - pos; - - unsigned const attrib = p.spriteList[i].attrib; - long spword = p.spwordList[i]; - unsigned long const* const spPalette = p.spPalette - + (attrib & attr_dmgpalno) / (attr_dmgpalno / num_palette_entries); - uint_least32_t* d = dst + pos; - - if (!(attrib & attr_bgpriority)) { - int const bpp = tile_bpp, m = tile_bpp_mask; - switch (n) { - case 8: if (spword >> 7 * bpp) { d[7] = spPalette[spword >> 7 * bpp]; } // fall through - case 7: if (spword >> 6 * bpp & m) { d[6] = spPalette[spword >> 6 * bpp & m]; } // fall through - case 6: if (spword >> 5 * bpp & m) { d[5] = spPalette[spword >> 5 * bpp & m]; } // fall through - case 5: if (spword >> 4 * bpp & m) { d[4] = spPalette[spword >> 4 * bpp & m]; } // fall through - case 4: if (spword >> 3 * bpp & m) { d[3] = spPalette[spword >> 3 * bpp & m]; } // fall through - case 3: if (spword >> 2 * bpp & m) { d[2] = spPalette[spword >> 2 * bpp & m]; } // fall through - case 2: if (spword >> 1 * bpp & m) { d[1] = spPalette[spword >> 1 * bpp & m]; } // fall through - case 1: if (spword & m) { d[0] = spPalette[spword & m]; } - } - - spword >>= n * bpp; - - /*do { - if (spword & tile_bpp_mask) - dst[pos] = spPalette[spword & tile_bpp_mask]; - - spword >>= tile_bpp; - ++pos; - } while (--n);*/ - } - else { - unsigned tw = tileword >> pos * tile_bpp; - d += n; - n = -n; - - do { - if (spword & tile_bpp_mask) { - d[n] = tw & tile_bpp_mask - ? p.bgPalette[tw & tile_bpp_mask] - : spPalette[spword & tile_bpp_mask]; - } - - spword >>= tile_bpp; - tw >>= tile_bpp; - } while (++n); - } - - p.spwordList[i] = spword; - --i; - } while (i >= 0 && spx(p.spriteList[i]) > xpos - tile_len); - } - - - unsigned const tno = tileMapLine[tileMapXpos % tile_map_len]; - int const ts = tile_size; - tileMapXpos = tileMapXpos % tile_map_len + 1; - p.ntileword = expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[0]] - + expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[1]] * 2; - - xpos = xpos + tile_len; - } while (xpos < xend); - - p.xpos = xpos; - } - - void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t* const dbufline, - unsigned char const *const tileMapLine, unsigned const tileline, unsigned tileMapXpos) { - int const tileIndexSign = p.lcdc & lcdc_tdsel ? 0 : tile_pattern_table_size / tile_size / 2; - unsigned char const* const tileDataLine = p.vram + 2 * tile_size * tileIndexSign - + tileline * tile_line_size; - int xpos = p.xpos; - unsigned char const* const vram = p.vram; - unsigned const tdoffset = tileline * tile_line_size - + tile_pattern_table_size / lcdc_tdsel * (~p.lcdc & lcdc_tdsel); - - do { - int nextSprite = p.nextSprite; - - if (spx(p.spriteList[nextSprite]) < xpos + tile_len) { - int cycles = p.cycles - tile_len; - cycles -= std::max(11 - (spx(p.spriteList[nextSprite]) - xpos), 6); - for (int i = nextSprite + 1; spx(p.spriteList[i]) < xpos + tile_len; ++i) - cycles -= 6; - - if (cycles < 0) - break; - - p.cycles = cycles; - - do { - unsigned char const* const oam = p.spriteMapper.oamram(); - unsigned reg0, reg1 = oam[p.spriteList[nextSprite].oampos + 2] * tile_size; - unsigned const attrib = oam[p.spriteList[nextSprite].oampos + 3]; - unsigned const spline = (attrib & attr_yflip - ? p.spriteList[nextSprite].line ^ (2 * tile_len - 1) - : p.spriteList[nextSprite].line) * tile_line_size; - unsigned const ts = tile_size; - reg0 = vram[vram_bank_size / attr_tdbank * (attrib & attr_tdbank) - + (lcdcObj2x(p) ? (reg1 & ~ts) | spline : reg1 | (spline & ~ts))]; - reg1 = vram[vram_bank_size / attr_tdbank * (attrib & attr_tdbank) - + (lcdcObj2x(p) ? (reg1 & ~ts) | spline : reg1 | (spline & ~ts)) + 1]; - - p.spwordList[nextSprite] = - expand_lut[reg0 + (0x100 / attr_xflip * attrib & 0x100)] - + expand_lut[reg1 + (0x100 / attr_xflip * attrib & 0x100)] * 2; - p.spriteList[nextSprite].attrib = attrib; - ++nextSprite; - } while (spx(p.spriteList[nextSprite]) < xpos + tile_len); - - p.nextSprite = nextSprite; - } - else if (nextSprite - 1 < 0 || spx(p.spriteList[nextSprite - 1]) <= xpos - tile_len) { - if (!(p.cycles & -1ul * tile_len)) - break; - - int n = (std::min(spx(p.spriteList[nextSprite]), xend + tile_len - 1) - xpos) & -1u * tile_len; - n = std::min(n, p.cycles & -1ul * tile_len); - p.cycles -= n; - - unsigned ntileword = p.ntileword; - unsigned nattrib = p.nattrib; - uint_least32_t* dst = dbufline + xpos - tile_len; - uint_least32_t* const dstend = dst + n; - xpos += n; - - if (!lcdcBgEn(p) && p.cgbDmg) { - do { *dst++ = p.bgPalette[0]; } while (dst != dstend); - tileMapXpos += n / (1u * tile_len); - - unsigned const tno = tileMapLine[(tileMapXpos - 1) % tile_map_len]; - int const ts = tile_size; - ntileword = expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[0]] - + expand_lut[(tileDataLine + ts * tno - 2 * ts * (tno & tileIndexSign))[1]] * 2; - } - else do { - unsigned long const* const bgPalette = p.bgPalette - + (nattrib & attr_cgbpalno) * num_palette_entries; - dst[0] = bgPalette[ntileword & tile_bpp_mask]; - dst[1] = bgPalette[(ntileword & tile_bpp_mask << 1 * tile_bpp) >> 1 * tile_bpp]; - dst[2] = bgPalette[(ntileword & tile_bpp_mask << 2 * tile_bpp) >> 2 * tile_bpp]; - dst[3] = bgPalette[(ntileword & tile_bpp_mask << 3 * tile_bpp) >> 3 * tile_bpp]; - dst[4] = bgPalette[(ntileword & tile_bpp_mask << 4 * tile_bpp) >> 4 * tile_bpp]; - dst[5] = bgPalette[(ntileword & tile_bpp_mask << 5 * tile_bpp) >> 5 * tile_bpp]; - dst[6] = bgPalette[(ntileword & tile_bpp_mask << 6 * tile_bpp) >> 6 * tile_bpp]; - dst[7] = bgPalette[ntileword >> 7 * tile_bpp]; - dst += tile_len; - - unsigned const tno = tileMapLine[tileMapXpos % tile_map_len]; - nattrib = tileMapLine[tileMapXpos % tile_map_len + vram_bank_size]; - tileMapXpos = tileMapXpos % tile_map_len + 1; - - unsigned const tdo = tdoffset & ~(tno << 5); - unsigned char const* const td = vram + tno * tile_size - + (nattrib & attr_yflip ? tdo ^ tile_line_size * (tile_len - 1) : tdo) - + vram_bank_size / attr_tdbank * (nattrib & attr_tdbank); - unsigned short const* const explut = expand_lut + (0x100 / attr_xflip * nattrib & 0x100); - ntileword = explut[td[0]] + explut[td[1]] * 2; - } while (dst != dstend); - - - p.ntileword = ntileword; - p.nattrib = nattrib; - continue; - } - else { - int cycles = p.cycles - tile_len; - if (cycles < 0) - break; - - p.cycles = cycles; - } - - uint_least32_t* const dst = dbufline + (xpos - tile_len); - unsigned const tileword = ((p.lcdc & 1u * lcdc_bgen) | !p.cgbDmg) * p.ntileword;; - unsigned const attrib = p.nattrib; - unsigned long const* const bgPalette = p.bgPalette - + (attrib & attr_cgbpalno) * num_palette_entries; - dst[0] = bgPalette[tileword & tile_bpp_mask]; - dst[1] = bgPalette[(tileword & tile_bpp_mask << 1 * tile_bpp) >> 1 * tile_bpp]; - dst[2] = bgPalette[(tileword & tile_bpp_mask << 2 * tile_bpp) >> 2 * tile_bpp]; - dst[3] = bgPalette[(tileword & tile_bpp_mask << 3 * tile_bpp) >> 3 * tile_bpp]; - dst[4] = bgPalette[(tileword & tile_bpp_mask << 4 * tile_bpp) >> 4 * tile_bpp]; - dst[5] = bgPalette[(tileword & tile_bpp_mask << 5 * tile_bpp) >> 5 * tile_bpp]; - dst[6] = bgPalette[(tileword & tile_bpp_mask << 6 * tile_bpp) >> 6 * tile_bpp]; - dst[7] = bgPalette[tileword >> 7 * tile_bpp]; - - int i = nextSprite - 1; - - if (!lcdcObjEn(p)) { - do { - int const pos = spx(p.spriteList[i]) - xpos; - int const sa = pos * tile_bpp >= 0 - ? tile_len * tile_bpp - pos * tile_bpp - : tile_len * tile_bpp + pos * tile_bpp; - p.spwordList[i] = 1l * p.spwordList[i] >> sa; - --i; - } while (i >= 0 && spx(p.spriteList[i]) > xpos - tile_len); - } - else { - unsigned char idtab[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - unsigned const bgprioritymask = p.lcdc << 7; - - do { - int n; - int pos = spx(p.spriteList[i]) - xpos; - if (pos < 0) { - n = pos + tile_len; - pos = 0; - } - else - n = tile_len - pos; - - unsigned char const id = p.spriteList[i].oampos; - unsigned const sattrib = p.spriteList[i].attrib; - long spword = p.spwordList[i]; - unsigned long const* const spPalette = cgbSpPalette(p, sattrib); - - if (!((attrib | sattrib) & bgprioritymask)) { - unsigned char* const idt = idtab + pos; - uint_least32_t* const d = dst + pos; - - switch (n) { - case 8: if ((spword >> 7 * tile_bpp) && id < idt[7]) { - idt[7] = id; - d[7] = spPalette[spword >> 7 * tile_bpp]; - } // fall through - case 7: if ((spword >> 6 * tile_bpp & tile_bpp_mask) && id < idt[6]) { - idt[6] = id; - d[6] = spPalette[spword >> 6 * tile_bpp & tile_bpp_mask]; - } // fall through - case 6: if ((spword >> 5 * tile_bpp & tile_bpp_mask) && id < idt[5]) { - idt[5] = id; - d[5] = spPalette[spword >> 5 * tile_bpp & tile_bpp_mask]; - } // fall through - case 5: if ((spword >> 4 * tile_bpp & tile_bpp_mask) && id < idt[4]) { - idt[4] = id; - d[4] = spPalette[spword >> 4 * tile_bpp & tile_bpp_mask]; - } // fall through - case 4: if ((spword >> 3 * tile_bpp & tile_bpp_mask) && id < idt[3]) { - idt[3] = id; - d[3] = spPalette[spword >> 3 * tile_bpp & tile_bpp_mask]; - } // fall through - case 3: if ((spword >> 2 * tile_bpp & tile_bpp_mask) && id < idt[2]) { - idt[2] = id; - d[2] = spPalette[spword >> 2 * tile_bpp & tile_bpp_mask]; - } // fall through - case 2: if ((spword >> 1 * tile_bpp & tile_bpp_mask) && id < idt[1]) { - idt[1] = id; - d[1] = spPalette[spword >> 1 * tile_bpp & tile_bpp_mask]; - } // fall through - case 1: if ((spword & tile_bpp_mask) && id < idt[0]) { - idt[0] = id; - d[0] = spPalette[spword & tile_bpp_mask]; - } - } - - spword >>= n * tile_bpp; - - /*do { - if ((spword & tile_bpp_mask) && id < idtab[pos]) { - idtab[pos] = id; - dst[pos] = spPalette[spword & tile_bpp_mask]; - } - - spword >>= tile_bpp; - ++pos; - } while (--n);*/ - } - else { - unsigned tw = tileword >> pos * tile_bpp; - - do { - if ((spword & tile_bpp_mask) && id < idtab[pos]) { - idtab[pos] = id; - dst[pos] = tw & tile_bpp_mask - ? bgPalette[tw & tile_bpp_mask] - : spPalette[spword & tile_bpp_mask]; - } - - spword >>= tile_bpp; - tw >>= tile_bpp; - ++pos; - } while (--n); - } - - p.spwordList[i] = spword; - --i; - } while (i >= 0 && spx(p.spriteList[i]) > xpos - tile_len); - } - - - { - unsigned const tno = tileMapLine[tileMapXpos % tile_map_len]; - unsigned const nattrib = tileMapLine[tileMapXpos % tile_map_len + vram_bank_size]; - tileMapXpos = tileMapXpos % tile_map_len + 1; - - unsigned const tdo = tdoffset & ~(tno << 5); - unsigned char const* const td = vram + tno * tile_size - + (nattrib & attr_yflip ? tdo ^ tile_line_size * (tile_len - 1) : tdo) - + vram_bank_size / attr_tdbank * (nattrib & attr_tdbank); - unsigned short const* const explut = expand_lut + (0x100 / attr_xflip * nattrib & 0x100); - p.ntileword = explut[td[0]] + explut[td[1]] * 2; - p.nattrib = nattrib; - } - - xpos = xpos + tile_len; - } while (xpos < xend); - - p.xpos = xpos; - } - - void doFullTilesUnrolled(PPUPriv& p) { - int xpos = p.xpos; - int const xend = p.wx < p.xpos || p.wx >= xpos_end - ? lcd_hres + 1 - : static_cast(p.wx) - 7; - if (xpos >= xend) - return; - - uint_least32_t* const dbufline = p.framebuf.fbline(); - unsigned char const* tileMapLine; - unsigned tileline; - unsigned tileMapXpos; - if (p.winDrawState & win_draw_started) { - tileMapLine = p.vram + tile_map_size / lcdc_wtmsel * (p.lcdc & lcdc_wtmsel) - + tile_map_len / tile_len * (p.winYPos & (0x100 - tile_len)) - + tile_map_begin; - tileMapXpos = (xpos + p.wscx) / (1u * tile_len); - tileline = p.winYPos % tile_len; - } - else { - tileMapLine = p.vram + tile_map_size / lcdc_bgtmsel * (p.lcdc & lcdc_bgtmsel) - + tile_map_len / tile_len * ((p.scy + p.lyCounter.ly()) & (0x100 - tile_len)) - + tile_map_begin; - tileMapXpos = (p.scx + xpos + 1 - p.cgb) / (1u * tile_len); - tileline = (p.scy + p.lyCounter.ly()) % tile_len; - } - - if (xpos < tile_len) { - uint_least32_t prebuf[2 * tile_len]; - if (p.cgb) { - doFullTilesUnrolledCgb(p, std::min(tile_len, xend), prebuf + (tile_len - xpos), - tileMapLine, tileline, tileMapXpos); - } - else { - doFullTilesUnrolledDmg(p, std::min(tile_len, xend), prebuf + (tile_len - xpos), - tileMapLine, tileline, tileMapXpos); - } - - int const newxpos = p.xpos; - if (newxpos > tile_len) { - std::memcpy(dbufline, prebuf + (tile_len - xpos), (newxpos - tile_len) * sizeof * dbufline); - } - else if (newxpos < tile_len) - return; - - if (newxpos >= xend) - return; - - tileMapXpos += (newxpos - xpos) / (1u * tile_len); - } - - p.cgb - ? doFullTilesUnrolledCgb(p, xend, dbufline, tileMapLine, tileline, tileMapXpos) - : doFullTilesUnrolledDmg(p, xend, dbufline, tileMapLine, tileline, tileMapXpos); - } - - void plotPixel(PPUPriv& p) { - int const xpos = p.xpos; - unsigned const tileword = p.tileword; - - uint_least32_t* const fbline = p.framebuf.fbline(); - - if (p.wx == xpos - && (p.weMaster || (p.wy2 == p.lyCounter.ly() && lcdcWinEn(p))) - && xpos < lcd_hres + 7) { - if (p.winDrawState == 0 && lcdcWinEn(p)) { - p.winDrawState = win_draw_start | win_draw_started; - ++p.winYPos; - } - else if (!p.cgb && (p.winDrawState == 0 || xpos == lcd_hres + 6)) - p.winDrawState |= win_draw_start; - } - - unsigned const twdata = tileword & ((p.lcdc & lcdc_bgen) | (p.cgb * !p.cgbDmg)) * tile_bpp_mask; - unsigned long pixel = p.bgPalette[twdata + (p.attrib & attr_cgbpalno) * num_palette_entries]; - int i = static_cast(p.nextSprite) - 1; - - if (i >= 0 && spx(p.spriteList[i]) > xpos - tile_len) { - unsigned spdata = 0; - unsigned attrib = 0; - - if (p.cgb) { - unsigned minId = 0xFF; - - do { - if ((p.spwordList[i] & tile_bpp_mask) && p.spriteList[i].oampos < minId) { - spdata = p.spwordList[i] & tile_bpp_mask; - attrib = p.spriteList[i].attrib; - minId = p.spriteList[i].oampos; - } - - p.spwordList[i] >>= tile_bpp; - --i; - } while (i >= 0 && spx(p.spriteList[i]) > xpos - tile_len); - - if (spdata && lcdcObjEn(p) - && (!((attrib | p.attrib) & attr_bgpriority) || !twdata || !lcdcBgEn(p))) { - pixel = *(cgbSpPalette(p, attrib) + spdata); - } - } - else { - do { - if (p.spwordList[i] & tile_bpp_mask) { - spdata = p.spwordList[i] & tile_bpp_mask; - attrib = p.spriteList[i].attrib; - } - - p.spwordList[i] >>= tile_bpp; - --i; - } while (i >= 0 && spx(p.spriteList[i]) > xpos - tile_len); - - if (spdata && lcdcObjEn(p) && (!(attrib & attr_bgpriority) || !twdata)) - pixel = p.spPalette[(attrib & attr_dmgpalno ? num_palette_entries : 0) + spdata]; - } - } - - if (xpos - tile_len >= 0) - fbline[xpos - tile_len] = pixel; - - - p.xpos = xpos + 1; - p.tileword = tileword >> tile_bpp; - } - -static void plotPixelIfNoSprite(PPUPriv &p) { - if (p.spriteList[p.nextSprite].spx == p.xpos) { - if (!(lcdcObjEn(p) | p.cgb)) { - do { - ++p.nextSprite; - } while (p.spriteList[p.nextSprite].spx == p.xpos); - - plotPixel(p); - } - } else - plotPixel(p); -} - -unsigned long nextM2Time(PPUPriv const& p) { - int const nm2 = p.lyCounter.ly() < lcd_vres - 1 - ? weMasterCheckPriorToLyIncLineCycle(p.cgb) - : lcd_cycles_per_line * (lcd_lines_per_frame - p.lyCounter.ly()) - + weMasterCheckLy0LineCycle(p.cgb); - return p.lyCounter.time() - p.lyCounter.lineTime() + (nm2 << p.lyCounter.isDoubleSpeed()); -} - -void xposEnd(PPUPriv& p) { - p.lastM0Time = p.now - (p.cycles << p.lyCounter.isDoubleSpeed()); - - unsigned long const nextm2 = nextM2Time(p); - p.cycles = p.now >= nextm2 - ? static_cast((p.now - nextm2) >> p.lyCounter.isDoubleSpeed()) - : -static_cast((nextm2 - p.now) >> p.lyCounter.isDoubleSpeed()); - nextCall(0, p.lyCounter.ly() == lcd_vres - 1 ? M2_Ly0::f0_ : M2_LyNon0::f0_, p); -} - -bool handleWinDrawStartReq(PPUPriv const &p, int const xpos, unsigned char &winDrawState) { - bool const startWinDraw = (xpos < lcd_hres + 7 || p.cgb) - && (winDrawState &= win_draw_started); - if (!lcdcWinEn(p)) - winDrawState &= ~(1u * win_draw_started); - - return startWinDraw; -} - -static bool handleWinDrawStartReq(PPUPriv &p) { - return handleWinDrawStartReq(p, p.xpos, p.winDrawState); -} - -namespace StartWindowDraw { - void inc(PPUState const& nextf, PPUPriv& p) { - if (!lcdcWinEn(p) && p.cgb) { - plotPixelIfNoSprite(p); - - if (p.xpos == p.endx) { - if (p.xpos < xpos_end) { - nextCall(1, Tile::f0_, p); - } - else - xposEnd(p); - - return; - } - } - - nextCall(1, nextf, p); - } - - void f0(PPUPriv& p) { - if (p.xpos == p.endx) { - p.tileword = p.ntileword; - p.attrib = p.nattrib; - p.endx = std::min(1u * xpos_end, p.xpos + 1u * tile_len); - } - - p.wscx = tile_len - p.xpos; - - if (p.winDrawState & win_draw_started) { - p.reg1 = p.vram[tile_map_size / lcdc_wtmsel * (p.lcdc & lcdc_wtmsel) - + tile_map_len / tile_len * (p.winYPos & (0x100 - tile_len)) - + tile_map_begin]; - p.nattrib = p.vram[tile_map_size / lcdc_wtmsel * (p.lcdc & lcdc_wtmsel) - + tile_map_len / tile_len * (p.winYPos & (0x100 - tile_len)) - + tile_map_begin + vram_bank_size]; - } - else { - p.reg1 = p.vram[tile_map_size / lcdc_bgtmsel * (p.lcdc & lcdc_bgtmsel) - + tile_map_len / tile_len * ((p.scy + p.lyCounter.ly()) & (0x100 - tile_len)) - + tile_map_begin]; - p.nattrib = p.vram[tile_map_size / lcdc_bgtmsel * (p.lcdc & lcdc_bgtmsel) - + tile_map_len / tile_len * ((p.scy + p.lyCounter.ly()) & (0x100 - tile_len)) - + tile_map_begin + vram_bank_size]; - } - - inc(f1_, p); - } - - void f1(PPUPriv& p) { - inc(f2_, p); - } - - void f2(PPUPriv& p) { - p.reg0 = loadTileDataByte0(p); - inc(f3_, p); - } - - void f3(PPUPriv& p) { - inc(f4_, p); - } - - void f4(PPUPriv& p) { - int const r1 = loadTileDataByte1(p); - - p.ntileword = (expand_lut + (0x100 / attr_xflip * p.nattrib & 0x100))[p.reg0] - + (expand_lut + (0x100 / attr_xflip * p.nattrib & 0x100))[r1] * 2; - - inc(f5_, p); - } - - void f5(PPUPriv& p) { - inc(Tile::f0_, p); - } -} - -namespace LoadSprites { - void inc(PPUState const& nextf, PPUPriv& p) { - plotPixelIfNoSprite(p); - - if (p.xpos == p.endx) { - if (p.xpos < xpos_end) { - nextCall(1, Tile::f0_, p); - } - else - xposEnd(p); - } - else - nextCall(1, nextf, p); - } - - void f0(PPUPriv& p) { - p.reg1 = p.spriteMapper.oamram()[p.spriteList[p.currentSprite].oampos + 2]; - nextCall(1, f1_, p); - } - - void f1(PPUPriv& p) { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - p.spriteList[p.currentSprite].attrib = - p.spriteMapper.oamram()[p.spriteList[p.currentSprite].oampos + 3]; - inc(f2_, p); - } - - void f2(PPUPriv& p) { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - unsigned const spline = - (p.spriteList[p.currentSprite].attrib & attr_yflip - ? p.spriteList[p.currentSprite].line ^ (2 * tile_len - 1) - : p.spriteList[p.currentSprite].line) * tile_line_size; - unsigned const ts = tile_size; - p.reg0 = p.vram[vram_bank_size / attr_tdbank - * (p.spriteList[p.currentSprite].attrib & p.cgb * attr_tdbank) - + (lcdcObj2x(p) ? (p.reg1 * ts & ~ts) | spline : p.reg1 * ts | (spline & ~ts))]; - inc(f3_, p); - } - - void f3(PPUPriv& p) { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - inc(f4_, p); - } - - void f4(PPUPriv& p) { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - unsigned const spline = - (p.spriteList[p.currentSprite].attrib & attr_yflip - ? p.spriteList[p.currentSprite].line ^ (2 * tile_len - 1) - : p.spriteList[p.currentSprite].line) * tile_line_size; - unsigned const ts = tile_size; - p.reg1 = p.vram[vram_bank_size / attr_tdbank - * (p.spriteList[p.currentSprite].attrib & p.cgb * attr_tdbank) - + (lcdcObj2x(p) ? (p.reg1 * ts & ~ts) | spline : p.reg1 * ts | (spline & ~ts)) + 1]; - inc(f5_, p); - } - - void f5(PPUPriv& p) { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - plotPixelIfNoSprite(p); - - unsigned entry = p.currentSprite; - - if (entry == p.nextSprite) { - ++p.nextSprite; - } - else { - entry = p.nextSprite - 1; - p.spriteList[entry] = p.spriteList[p.currentSprite]; - } - - p.spwordList[entry] = - expand_lut[p.reg0 + (0x100 / attr_xflip * p.spriteList[entry].attrib & 0x100)] - + expand_lut[p.reg1 + (0x100 / attr_xflip * p.spriteList[entry].attrib & 0x100)] * 2; - p.spriteList[entry].spx = p.xpos; - - if (p.xpos == p.endx) { - if (p.xpos < xpos_end) { - nextCall(1, Tile::f0_, p); - } - else - xposEnd(p); - } - else { - p.nextCallPtr = &Tile::f5_; - nextCall(1, Tile::f5_, p); - } - } -} - -namespace Tile { - void inc(PPUState const& nextf, PPUPriv& p) { - plotPixelIfNoSprite(p); - - if (p.xpos == xpos_end) { - xposEnd(p); - } - else - nextCall(1, nextf, p); - } - - void f0(PPUPriv& p) { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - doFullTilesUnrolled(p); - - if (p.xpos == xpos_end) { - ++p.cycles; - return xposEnd(p); - } - - p.tileword = p.ntileword; - p.attrib = p.nattrib; - p.endx = std::min(1u * xpos_end, p.xpos + 1u * tile_len); - - if (p.winDrawState & win_draw_started) { - p.reg1 = p.vram[tile_map_size / lcdc_wtmsel * (p.lcdc & lcdc_wtmsel) - + tile_map_len / tile_len * (p.winYPos & (0x100 - tile_len)) - + (p.xpos + p.wscx) / tile_len % tile_map_len + tile_map_begin]; - p.nattrib = p.vram[tile_map_size / lcdc_wtmsel * (p.lcdc & lcdc_wtmsel) - + tile_map_len / tile_len * (p.winYPos & (0x100 - tile_len)) - + (p.xpos + p.wscx) / tile_len % tile_map_len + tile_map_begin - + vram_bank_size]; - } - else { - p.reg1 = p.vram[((tile_map_size / lcdc_bgtmsel * p.lcdc | (p.scx + p.xpos + 1u - p.cgb) / tile_len) - & (tile_map_size + tile_map_len - 1)) - + tile_map_len / tile_len * ((p.scy + p.lyCounter.ly()) & (0x100 - tile_len)) - + tile_map_begin]; - p.nattrib = p.vram[((tile_map_size / lcdc_bgtmsel * p.lcdc | (p.scx + p.xpos + 1u - p.cgb) / tile_len) - & (tile_map_size + tile_map_len - 1)) - + tile_map_len / tile_len * ((p.scy + p.lyCounter.ly()) & (0x100 - tile_len)) - + tile_map_begin + vram_bank_size]; - } - - inc(f1_, p); - } - - void f1(PPUPriv& p) { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - inc(f2_, p); - } - - void f2(PPUPriv& p) { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - p.reg0 = loadTileDataByte0(p); - inc(f3_, p); - } - - void f3(PPUPriv& p) { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - inc(f4_, p); - } - - void f4(PPUPriv& p) { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - int const r1 = loadTileDataByte1(p); - - p.ntileword = (expand_lut + (0x100 / attr_xflip * p.nattrib & 0x100))[p.reg0] - + (expand_lut + (0x100 / attr_xflip * p.nattrib & 0x100))[r1] * 2; - - plotPixelIfNoSprite(p); - - if (p.xpos == xpos_end) { - xposEnd(p); - } - else - nextCall(1, f5_, p); - } - - void f5(PPUPriv& p) { - int endx = p.endx; - p.nextCallPtr = &f5_; - - do { - if ((p.winDrawState & win_draw_start) && handleWinDrawStartReq(p)) - return StartWindowDraw::f0(p); - - if (p.spriteList[p.nextSprite].spx == p.xpos) { - if (lcdcObjEn(p) | p.cgb) { - p.currentSprite = p.nextSprite; - return LoadSprites::f0(p); - } - - do { - ++p.nextSprite; - } while (p.spriteList[p.nextSprite].spx == p.xpos); - } - - plotPixel(p); - - if (p.xpos == endx) { - if (endx < xpos_end) { - nextCall(1, f0_, p); - } - else - xposEnd(p); - - return; - } - } while (--p.cycles >= 0); - } -} - -} // namespace M3Loop - -namespace M2_Ly0 { - static unsigned predictCyclesUntilXpos_f0(PPUPriv const &p, unsigned winDrawState, - int targetxpos, unsigned cycles); -} - -namespace M2_LyNon0 { - static unsigned predictCyclesUntilXpos_f0(PPUPriv const &p, unsigned winDrawState, - int targetxpos, unsigned cycles); -} - -namespace M3Loop { - - unsigned predictCyclesUntilXposNextLine( - PPUPriv const& p, unsigned winDrawState, int const targetx) { - if (p.wx == lcd_hres + 6 && !p.cgb && p.xpos < lcd_hres + 7 - && (p.weMaster || (p.wy2 == p.lyCounter.ly() && lcdcWinEn(p)))) { - winDrawState = win_draw_start | (lcdcWinEn(p) ? win_draw_started : 0); - } - - unsigned const cycles = (nextM2Time(p) - p.now) >> p.lyCounter.isDoubleSpeed(); - - return p.lyCounter.ly() == lcd_vres - 1 - ? M2_Ly0::predictCyclesUntilXpos_f0(p, winDrawState, targetx, cycles) - : M2_LyNon0::predictCyclesUntilXpos_f0(p, winDrawState, targetx, cycles); - } - - -namespace StartWindowDraw { - static unsigned predictCyclesUntilXpos_fn(PPUPriv const &p, int xpos, - int endx, unsigned ly, unsigned nextSprite, bool weMaster, - unsigned winDrawState, int fno, int targetx, unsigned cycles); -} - -namespace Tile { - unsigned char const* addSpriteCycles(unsigned char const* nextSprite, - unsigned char const* spriteEnd, unsigned char const* const spxOf, - unsigned const maxSpx, unsigned const firstTileXpos, - unsigned prevSpriteTileNo, unsigned* const cyclesAccumulator) { - int sum = 0; - - for (; nextSprite < spriteEnd && spxOf[*nextSprite] <= maxSpx; ++nextSprite) { - int cycles = 6; - int const distanceFromTileStart = (spxOf[*nextSprite] - firstTileXpos) % tile_len; - unsigned const tileNo = (spxOf[*nextSprite] - firstTileXpos) & -tile_len; - - if (distanceFromTileStart < 5 && tileNo != prevSpriteTileNo) - cycles = 11 - distanceFromTileStart; - - prevSpriteTileNo = tileNo; - sum += cycles; - } - - *cyclesAccumulator += sum; - - return nextSprite; - } - - unsigned predictCyclesUntilXpos_fn(PPUPriv const& p, int const xpos, - int const endx, unsigned const ly, unsigned const nextSprite, - bool const weMaster, unsigned char winDrawState, int const fno, - int const targetx, unsigned cycles) { - if ((winDrawState & win_draw_start) - && handleWinDrawStartReq(p, xpos, winDrawState)) { - return StartWindowDraw::predictCyclesUntilXpos_fn(p, xpos, endx, - ly, nextSprite, weMaster, winDrawState, 0, targetx, cycles); - } - - if (xpos > targetx) - return predictCyclesUntilXposNextLine(p, winDrawState, targetx); - - enum { tileno_none = 1 }; // low bit set, so it will never be equal to an actual tile number. - - int nwx = 0xFF; - cycles += targetx - xpos; - - if (p.wx - 1u * xpos < targetx - 1u * xpos - && lcdcWinEn(p) && (weMaster || p.wy2 == ly) - && !(winDrawState & win_draw_started) - && (p.cgb || p.wx != lcd_hres + 6)) { - nwx = p.wx; - cycles += 6; - } - - if (lcdcObjEn(p) | p.cgb) { - unsigned char const* sprite = p.spriteMapper.sprites(ly); - unsigned char const* const spriteEnd = sprite + p.spriteMapper.numSprites(ly); - sprite += nextSprite; - - if (sprite < spriteEnd) { - int const spx = p.spriteMapper.posbuf()[*sprite + 1]; - unsigned firstTileXpos = endx % (1u * tile_len); // ok even if endx is capped at 168, - // because fno will be used. - unsigned prevSpriteTileNo = (xpos - firstTileXpos) & -tile_len; // this tile. all sprites on this - // tile will now add 6 cycles. - // except this one. - if (fno + spx - xpos < 5 && spx <= nwx) { - cycles += 11 - (fno + spx - xpos); - sprite += 1; - } - - if (nwx < targetx) { - sprite = addSpriteCycles(sprite, spriteEnd, p.spriteMapper.posbuf() + 1, - nwx, firstTileXpos, prevSpriteTileNo, &cycles); - firstTileXpos = nwx + 1; - prevSpriteTileNo = tileno_none; - } - - addSpriteCycles(sprite, spriteEnd, p.spriteMapper.posbuf() + 1, - targetx, firstTileXpos, prevSpriteTileNo, &cycles); - } - } - - return cycles; - } - - unsigned predictCyclesUntilXpos_fn(PPUPriv const& p, - int endx, int fno, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.xpos, endx, p.lyCounter.ly(), - p.nextSprite, p.weMaster, p.winDrawState, fno, targetx, cycles); - } - - unsigned predictCyclesUntilXpos_f0(PPUPriv const& p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, std::min(1u * xpos_end, p.xpos + 1u * tile_len), 0, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f1(PPUPriv const& p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.endx, 1, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f2(PPUPriv const& p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.endx, 2, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f3(PPUPriv const& p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.endx, 3, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f4(PPUPriv const& p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.endx, 4, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f5(PPUPriv const& p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.endx, 5, targetx, cycles); - } -} - -namespace StartWindowDraw { - unsigned predictCyclesUntilXpos_fn(PPUPriv const &p, int xpos, - int const endx, unsigned const ly, unsigned const nextSprite, bool const weMaster, - unsigned const winDrawState, int const fno, int const targetx, unsigned cycles) { - if (xpos > targetx) - return predictCyclesUntilXposNextLine(p, winDrawState, targetx); - - int cinc = 6 - fno; - - if (!lcdcWinEn(p) && p.cgb) { - int xinc = std::min(cinc, std::min(endx, targetx + 1) - xpos); - - if ((lcdcObjEn(p) | p.cgb) && p.spriteList[nextSprite].spx < xpos + xinc) { - xpos = p.spriteList[nextSprite].spx; - } else { - cinc = xinc; - xpos += xinc; - } - } - - cycles += cinc; - - if (xpos <= targetx) { - return Tile::predictCyclesUntilXpos_fn(p, xpos, std::min(xpos_end, xpos + tile_len), - ly, nextSprite, weMaster, winDrawState, 0, targetx, cycles); - } - - return cycles - 1; - } - - unsigned predictCyclesUntilXpos_fn(PPUPriv const &p, - int endx, int fno, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.xpos, endx, p.lyCounter.ly(), - p.nextSprite, p.weMaster, p.winDrawState, fno, targetx, cycles); - } - - unsigned predictCyclesUntilXpos_f0(PPUPriv const &p, int targetx, unsigned cycles) { - int endx = p.xpos == p.endx - ? std::min(1u * xpos_end, p.xpos + 1u * tile_len) - : p.endx; - return predictCyclesUntilXpos_fn(p, endx, 0, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f1(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.endx, 1, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f2(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.endx, 2, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f3(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.endx, 3, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f4(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.endx, 4, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f5(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, p.endx, 5, targetx, cycles); - } -} - -namespace LoadSprites { - unsigned predictCyclesUntilXpos_fn(PPUPriv const &p, - int const fno, int const targetx, unsigned cycles) { - unsigned nextSprite = p.nextSprite; - if (lcdcObjEn(p) | p.cgb) { - cycles += 6 - fno; - nextSprite += 1; - } - - return Tile::predictCyclesUntilXpos_fn(p, p.xpos, p.endx, p.lyCounter.ly(), - nextSprite, p.weMaster, p.winDrawState, 5, targetx, cycles); - } - - unsigned predictCyclesUntilXpos_f0(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, 0, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f1(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, 1, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f2(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, 2, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f3(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, 3, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f4(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, 4, targetx, cycles); - } - unsigned predictCyclesUntilXpos_f5(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_fn(p, 5, targetx, cycles); - } -} - -} // namespace M3Loop - -namespace M3Start { - unsigned predictCyclesUntilXpos_f1(PPUPriv const& p, unsigned xpos, unsigned ly, - bool weMaster, unsigned winDrawState, int targetx, unsigned cycles) { - cycles += std::min((p.scx - xpos) % tile_len, max_m3start_cycles - xpos) + 1 - p.cgb; - return M3Loop::Tile::predictCyclesUntilXpos_fn(p, 0, tile_len - p.scx % tile_len, ly, 0, - weMaster, winDrawState, std::min(p.scx % (1u * tile_len), 5u), targetx, cycles); - } - - unsigned predictCyclesUntilXpos_f0(PPUPriv const &p, unsigned ly, - bool weMaster, unsigned winDrawState, int targetx, unsigned cycles) { - winDrawState = (winDrawState & win_draw_start) && lcdcWinEn(p) ? win_draw_started : 0; - return predictCyclesUntilXpos_f1(p, 0, ly, weMaster, winDrawState, targetx, cycles); - } - - unsigned predictCyclesUntilXpos_f0(PPUPriv const &p, int targetx, unsigned cycles) { - unsigned ly = p.lyCounter.ly() + (p.lyCounter.time() - p.now < 16); - return predictCyclesUntilXpos_f0(p, ly, p.weMaster, p.winDrawState, targetx, cycles); - } - - unsigned predictCyclesUntilXpos_f1(PPUPriv const &p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_f1(p, p.xpos, p.lyCounter.ly(), p.weMaster, - p.winDrawState, targetx, cycles); - } -} - -namespace M2_Ly0 { - unsigned predictCyclesUntilXpos_f0(PPUPriv const& p, - unsigned winDrawState, int targetx, unsigned cycles) { - bool weMaster = lcdcWinEn(p) && 0 == p.wy; - unsigned ly = 0; - - return M3Start::predictCyclesUntilXpos_f0(p, ly, weMaster, winDrawState, targetx, - cycles + m3StartLineCycle(p.cgb) - weMasterCheckLy0LineCycle(p.cgb)); - - } - - unsigned predictCyclesUntilXpos_f0(PPUPriv const& p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_f0(p, p.winDrawState, targetx, cycles); - } -} - -namespace M2_LyNon0 { - unsigned predictCyclesUntilXpos_f1(PPUPriv const& p, bool weMaster, - unsigned winDrawState, int targetx, unsigned cycles) { - unsigned ly = p.lyCounter.ly() + 1; - weMaster |= lcdcWinEn(p) && ly == p.wy; - - return M3Start::predictCyclesUntilXpos_f0(p, ly, weMaster, winDrawState, targetx, - cycles + lcd_cycles_per_line - weMasterCheckAfterLyIncLineCycle(p.cgb) + m3StartLineCycle(p.cgb)); - } - - unsigned predictCyclesUntilXpos_f1(PPUPriv const& p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_f1(p, p.weMaster, p.winDrawState, targetx, cycles); - } - - unsigned predictCyclesUntilXpos_f0(PPUPriv const& p, - unsigned winDrawState, int targetx, unsigned cycles) { - bool weMaster = p.weMaster || (lcdcWinEn(p) && p.lyCounter.ly() == p.wy); - - return predictCyclesUntilXpos_f1(p, weMaster, winDrawState, targetx, - cycles + weMasterCheckAfterLyIncLineCycle(p.cgb) - - weMasterCheckPriorToLyIncLineCycle(p.cgb)); - } - - unsigned predictCyclesUntilXpos_f0(PPUPriv const& p, int targetx, unsigned cycles) { - return predictCyclesUntilXpos_f0(p, p.winDrawState, targetx, cycles); - } -} - -} // anon namespace - -PPUPriv::PPUPriv(NextM0Time &nextM0Time, unsigned char const *const oamram, unsigned char const *const vram) -: spriteList() -, spwordList() -, nextSprite(0) -, currentSprite(0xFF) -, vram(vram) -, nextCallPtr(&M2_Ly0::f0_) -, now(0) -, lastM0Time(0) -, cycles(-4396) -, tileword(0) -, ntileword(0) -, spriteMapper(nextM0Time, lyCounter, oamram) -, lcdc(0) -, scy(0) -, scx(0) -, wy(0) -, wy2(0) -, wx(0) -, winDrawState(0) -, wscx(0) -, winYPos(0) -, reg0(0) -, reg1(0) -, attrib(0) -, nattrib(0) -, xpos(0) -, endx(0) -, cgb(false) -, weMaster(false) -{ -} - -namespace { - -template -struct BSearch { - static std::size_t upperBound(T const a[], K e) { - if (e < a[start + len / 2]) - return BSearch::upperBound(a, e); - - return BSearch::upperBound(a, e); - } -}; - -template -struct BSearch { - static std::size_t upperBound(T const [], K ) { - return start; - } -}; - -template -std::size_t upperBound(T const a[], K e) { - return BSearch::upperBound(a, e); -} - -struct CycleState { - PPUState const *state; - long cycle; - operator long() const { return cycle; } -}; - -PPUState const * decodeM3LoopState(unsigned state) { - switch (state) { - case M3Loop::Tile::ID0: return &M3Loop::Tile::f0_; - case M3Loop::Tile::ID1: return &M3Loop::Tile::f1_; - case M3Loop::Tile::ID2: return &M3Loop::Tile::f2_; - case M3Loop::Tile::ID3: return &M3Loop::Tile::f3_; - case M3Loop::Tile::ID4: return &M3Loop::Tile::f4_; - case M3Loop::Tile::ID5: return &M3Loop::Tile::f5_; - - case M3Loop::LoadSprites::ID0: return &M3Loop::LoadSprites::f0_; - case M3Loop::LoadSprites::ID1: return &M3Loop::LoadSprites::f1_; - case M3Loop::LoadSprites::ID2: return &M3Loop::LoadSprites::f2_; - case M3Loop::LoadSprites::ID3: return &M3Loop::LoadSprites::f3_; - case M3Loop::LoadSprites::ID4: return &M3Loop::LoadSprites::f4_; - case M3Loop::LoadSprites::ID5: return &M3Loop::LoadSprites::f5_; - - case M3Loop::StartWindowDraw::ID0: return &M3Loop::StartWindowDraw::f0_; - case M3Loop::StartWindowDraw::ID1: return &M3Loop::StartWindowDraw::f1_; - case M3Loop::StartWindowDraw::ID2: return &M3Loop::StartWindowDraw::f2_; - case M3Loop::StartWindowDraw::ID3: return &M3Loop::StartWindowDraw::f3_; - case M3Loop::StartWindowDraw::ID4: return &M3Loop::StartWindowDraw::f4_; - case M3Loop::StartWindowDraw::ID5: return &M3Loop::StartWindowDraw::f5_; - } - - return 0; -} - -long cyclesUntilM0Upperbound(PPUPriv const& p) { - long cycles = xpos_end - p.xpos + 6; - for (int i = p.nextSprite; i < lcd_max_num_sprites_per_line && p.spriteList[i].spx < xpos_end; ++i) - cycles += 11; - - return cycles; -} - -void saveSpriteList(PPUPriv const& p, SaveState& ss) { - for (int i = 0; i < lcd_max_num_sprites_per_line; ++i) { - ss.ppu.spAttribList[i] = p.spriteList[i].attrib; - ss.ppu.spByte0List[i] = p.spwordList[i] & 0xFF; - ss.ppu.spByte1List[i] = p.spwordList[i] >> 8; - } - - ss.ppu.nextSprite = p.nextSprite; - ss.ppu.currentSprite = p.currentSprite; -} - -void loadSpriteList(PPUPriv& p, SaveState const& ss) { - if (ss.ppu.videoCycles < 1ul * lcd_vres * lcd_cycles_per_line && ss.ppu.xpos < xpos_end) { - int const ly = ss.ppu.videoCycles / lcd_cycles_per_line; - int const numSprites = p.spriteMapper.numSprites(ly); - unsigned char const* const sprites = p.spriteMapper.sprites(ly); - - for (int i = 0; i < numSprites; ++i) { - int const pos = sprites[i]; - int const spy = p.spriteMapper.posbuf()[pos]; - int const spx = p.spriteMapper.posbuf()[pos + 1]; - - p.spriteList[i].spx = spx; - p.spriteList[i].line = ly + 2 * tile_len - spy; - p.spriteList[i].oampos = pos * 2; - p.spriteList[i].attrib = ss.ppu.spAttribList[i] & 0xFF; - p.spwordList[i] = (ss.ppu.spByte1List[i] * 0x100l + ss.ppu.spByte0List[i]) & 0xFFFF; - } - - p.spriteList[numSprites].spx = 0xFF; - p.nextSprite = std::min(1u * ss.ppu.nextSprite, 1u * numSprites); - - while (p.spriteList[p.nextSprite].spx < ss.ppu.xpos) - ++p.nextSprite; - - p.currentSprite = std::min(p.nextSprite, ss.ppu.currentSprite); - } -} - -} - -void PPU::loadState(SaveState const& ss, unsigned char const* const oamram) { - PPUState const* const m3loopState = decodeM3LoopState(ss.ppu.state); - long const videoCycles = std::min(ss.ppu.videoCycles, lcd_cycles_per_frame - 1ul); - bool const ds = p_.cgb & ss.mem.ioamhram.get()[0x14D] >> 7; - long const lineCycles = static_cast(videoCycles) % lcd_cycles_per_line; - - p_.now = ss.cpu.cycleCounter; - p_.lcdc = ss.mem.ioamhram.get()[0x140]; - p_.lyCounter.setDoubleSpeed(ds); - p_.lyCounter.reset(videoCycles, ss.cpu.cycleCounter); - p_.spriteMapper.loadState(ss, oamram); - p_.winYPos = ss.ppu.winYPos; - p_.scy = ss.mem.ioamhram.get()[0x142]; - p_.scx = ss.mem.ioamhram.get()[0x143]; - p_.wy = ss.mem.ioamhram.get()[0x14A]; - p_.wy2 = ss.ppu.oldWy; - p_.wx = ss.mem.ioamhram.get()[0x14B]; - p_.xpos = std::min(1u * xpos_end, 1u * ss.ppu.xpos); - p_.endx = (p_.xpos & -1u * tile_len) + ss.ppu.endx % tile_len; - p_.endx = std::min(1u * xpos_end, p_.endx <= p_.xpos ? p_.endx + 1u * tile_len : p_.endx); - p_.reg0 = ss.ppu.reg0 & 0xFF; - p_.reg1 = ss.ppu.reg1 & 0xFF; - p_.tileword = ss.ppu.tileword & 0xFFFF; - p_.ntileword = ss.ppu.ntileword & 0xFFFF; - p_.attrib = ss.ppu.attrib & 0xFF; - p_.nattrib = ss.ppu.nattrib & 0xFF; - p_.wscx = ss.ppu.wscx; - p_.weMaster = ss.ppu.weMaster; - p_.winDrawState = ss.ppu.winDrawState & (win_draw_start | win_draw_started); - p_.lastM0Time = p_.now - ss.ppu.lastM0Time; - p_.cgbDmg = !ss.ppu.notCgbDmg; - loadSpriteList(p_, ss); - - if (m3loopState && videoCycles < 1l * lcd_vres * lcd_cycles_per_line && p_.xpos < xpos_end - && lineCycles + cyclesUntilM0Upperbound(p_) < weMasterCheckPriorToLyIncLineCycle(p_.cgb)) { - p_.nextCallPtr = m3loopState; - p_.cycles = -1; - } - else if (videoCycles < (lcd_vres - 1l) * lcd_cycles_per_line + m3StartLineCycle(p_.cgb) + max_m3start_cycles) { - CycleState const lineCycleStates[] = { - { &M3Start::f0_, m3StartLineCycle(p_.cgb) }, - { &M3Start::f1_, m3StartLineCycle(p_.cgb) + max_m3start_cycles }, - { &M2_LyNon0::f0_, weMasterCheckPriorToLyIncLineCycle(p_.cgb) }, - { &M2_LyNon0::f1_, weMasterCheckAfterLyIncLineCycle(p_.cgb) }, - { &M3Start::f0_, m3StartLineCycle(p_.cgb) + lcd_cycles_per_line } - }; - - std::size_t const pos = - upperBound(lineCycleStates, lineCycles); - - p_.cycles = lineCycles - lineCycleStates[pos].cycle; - p_.nextCallPtr = lineCycleStates[pos].state; - - if (&M3Start::f1_ == lineCycleStates[pos].state) { - p_.xpos = lineCycles - m3StartLineCycle(p_.cgb) + 1; - p_.cycles = -1; - } - } - else { - p_.cycles = videoCycles - lcd_cycles_per_frame - weMasterCheckLy0LineCycle(p_.cgb); - p_.nextCallPtr = &M2_Ly0::f0_; - } -} - -void PPU::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb) { - p_.vram = vram; - p_.cgb = cgb; - p_.cgbDmg = false; - p_.spriteMapper.reset(oamram, cgb); -} - -void PPU::resetCc(unsigned long const oldCc, unsigned long const newCc) { - unsigned long const dec = oldCc - newCc; - unsigned long const videoCycles = lcdcEn(p_) ? p_.lyCounter.frameCycles(p_.now) : 0; - - p_.now -= dec; - p_.lastM0Time = p_.lastM0Time ? p_.lastM0Time - dec : p_.lastM0Time; - p_.lyCounter.reset(videoCycles, p_.now); - p_.spriteMapper.resetCycleCounter(oldCc, newCc); -} - -void PPU::speedChange() { - unsigned long const now = p_.now; - unsigned long const videoCycles = lcdcEn(p_) ? p_.lyCounter.frameCycles(now) : 0; - - p_.now -= p_.lyCounter.isDoubleSpeed(); - p_.spriteMapper.resetCycleCounter(now, p_.now); - p_.lyCounter.setDoubleSpeed(!p_.lyCounter.isDoubleSpeed()); - p_.lyCounter.reset(videoCycles, p_.now); -} - -unsigned long PPU::predictedNextXposTime(unsigned xpos) const { - return p_.now - + (p_.nextCallPtr->predictCyclesUntilXpos_f(p_, xpos, -p_.cycles) << p_.lyCounter.isDoubleSpeed()); -} - -void PPU::setLcdc(unsigned const lcdc, unsigned long const cc) { - if ((p_.lcdc ^ lcdc) & lcdc & lcdc_en) { - p_.now = cc; - p_.lastM0Time = 0; - p_.lyCounter.reset(0, p_.now); - p_.spriteMapper.enableDisplay(cc); - p_.weMaster = (lcdc & lcdc_we) && 0 == p_.wy; - p_.winDrawState = 0; - p_.nextCallPtr = &M3Start::f0_; - p_.cycles = -(m3StartLineCycle(p_.cgb) + 2); - } - else if ((p_.lcdc ^ lcdc) & lcdc_we) { - if (!(lcdc & lcdc_we)) { - if (p_.winDrawState == win_draw_started || p_.xpos == xpos_end) - p_.winDrawState &= ~(1u * win_draw_started); - } - else if (p_.winDrawState == win_draw_start) { - p_.winDrawState |= win_draw_started; - ++p_.winYPos; - } - } - - if ((p_.lcdc ^ lcdc) & lcdc_obj2x) { - if (p_.lcdc & lcdc & lcdc_en) - p_.spriteMapper.oamChange(cc); - - p_.spriteMapper.setLargeSpritesSource(lcdc & lcdc_obj2x); - } - - p_.lcdc = lcdc; -} - -void PPU::update(unsigned long const cc) { - long const cycles = (cc - p_.now) >> p_.lyCounter.isDoubleSpeed(); - - p_.now += cycles << p_.lyCounter.isDoubleSpeed(); - p_.cycles += cycles; - - if (p_.cycles >= 0) { - p_.framebuf.setFbline(p_.lyCounter.ly()); - p_.nextCallPtr->f(p_); - } -} - -SYNCFUNC(PPU) -{ - NSS(p_.bgPalette); - NSS(p_.spPalette); - NSS(p_.spriteList); - NSS(p_.spwordList); - NSS(p_.nextSprite); - NSS(p_.currentSprite); - NSS(p_.layersMask); - - EBS(p_.nextCallPtr, 0); - EVS(p_.nextCallPtr, &M2_Ly0::f0_, 1); - EVS(p_.nextCallPtr, &M2_LyNon0::f0_, 2); - EVS(p_.nextCallPtr, &M2_LyNon0::f1_, 3); - EVS(p_.nextCallPtr, &M3Start::f0_, 4); - EVS(p_.nextCallPtr, &M3Start::f1_, 5); - EVS(p_.nextCallPtr, &M3Loop::Tile::f0_, 6); - EVS(p_.nextCallPtr, &M3Loop::Tile::f1_, 7); - EVS(p_.nextCallPtr, &M3Loop::Tile::f2_, 8); - EVS(p_.nextCallPtr, &M3Loop::Tile::f3_, 9); - EVS(p_.nextCallPtr, &M3Loop::Tile::f4_, 10); - EVS(p_.nextCallPtr, &M3Loop::Tile::f5_, 11); - EVS(p_.nextCallPtr, &M3Loop::LoadSprites::f0_, 12); - EVS(p_.nextCallPtr, &M3Loop::LoadSprites::f1_, 13); - EVS(p_.nextCallPtr, &M3Loop::LoadSprites::f2_, 14); - EVS(p_.nextCallPtr, &M3Loop::LoadSprites::f3_, 15); - EVS(p_.nextCallPtr, &M3Loop::LoadSprites::f4_, 16); - EVS(p_.nextCallPtr, &M3Loop::LoadSprites::f5_, 17); - EVS(p_.nextCallPtr, &M3Loop::StartWindowDraw::f0_, 18); - EVS(p_.nextCallPtr, &M3Loop::StartWindowDraw::f1_, 19); - EVS(p_.nextCallPtr, &M3Loop::StartWindowDraw::f2_, 20); - EVS(p_.nextCallPtr, &M3Loop::StartWindowDraw::f3_, 21); - EVS(p_.nextCallPtr, &M3Loop::StartWindowDraw::f4_, 22); - EVS(p_.nextCallPtr, &M3Loop::StartWindowDraw::f5_, 23); - EES(p_.nextCallPtr, NULL); - - NSS(p_.now); - NSS(p_.lastM0Time); - NSS(p_.cycles); - - NSS(p_.tileword); - NSS(p_.ntileword); - - SSS(p_.spriteMapper); - SSS(p_.lyCounter); - - NSS(p_.lcdc); - NSS(p_.scy); - NSS(p_.scx); - NSS(p_.wy); - NSS(p_.wy2); - NSS(p_.wx); - NSS(p_.winDrawState); - NSS(p_.wscx); - NSS(p_.winYPos); - NSS(p_.reg0); - NSS(p_.reg1); - NSS(p_.attrib); - NSS(p_.nattrib); - NSS(p_.xpos); - NSS(p_.endx); - - NSS(p_.cgb); - NSS(p_.cgbDmg); - NSS(p_.weMaster); -} diff --git a/libgambatte/src/video/ppu.h b/libgambatte/src/video/ppu.h deleted file mode 100644 index b711cea3dd..0000000000 --- a/libgambatte/src/video/ppu.h +++ /dev/null @@ -1,163 +0,0 @@ -// -// Copyright (C) 2010 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef PPU_H -#define PPU_H - -#include "lcddef.h" -#include "ly_counter.h" -#include "sprite_mapper.h" -#include "gbint.h" -#include - -#include "newstate.h" - -namespace gambatte { - -enum { - layer_mask_bg = 1, - layer_mask_obj = 2, - layer_mask_window = 4 }; -enum { - max_num_palettes = 8, - num_palette_entries = 4, - ppu_force_signed_enum = -1 }; - -class PPUFrameBuf { -public: - PPUFrameBuf() : buf_(0), fbline_(nullfbline()), pitch_(0) {} - uint_least32_t * fb() const { return buf_; } - uint_least32_t * fbline() const { return fbline_; } - std::ptrdiff_t pitch() const { return pitch_; } - void setBuf(uint_least32_t *buf, std::ptrdiff_t pitch) { buf_ = buf; pitch_ = pitch; fbline_ = nullfbline(); } - void setFbline(unsigned ly) { fbline_ = buf_ ? buf_ + std::ptrdiff_t(ly) * pitch_ : nullfbline(); } - -private: - uint_least32_t *buf_; - uint_least32_t *fbline_; - std::ptrdiff_t pitch_; - - static uint_least32_t * nullfbline() { static uint_least32_t nullfbline_[160]; return nullfbline_; } -}; - -struct PPUPriv; - -struct PPUState { - void (*f)(PPUPriv &v); - unsigned (*predictCyclesUntilXpos_f)(PPUPriv const &v, int targetxpos, unsigned cycles); - unsigned char id; -}; - -struct PPUPriv { - unsigned long bgPalette[max_num_palettes * num_palette_entries]; - unsigned long spPalette[max_num_palettes * num_palette_entries]; - struct Sprite { unsigned char spx, oampos, line, attrib; } spriteList[lcd_max_num_sprites_per_line + 1]; - unsigned short spwordList[lcd_max_num_sprites_per_line + 1]; - unsigned char nextSprite; - unsigned char currentSprite; - unsigned layersMask; - - unsigned char const *vram; - PPUState const *nextCallPtr; - - unsigned long now; - unsigned long lastM0Time; - long cycles; - - unsigned tileword; - unsigned ntileword; - - SpriteMapper spriteMapper; - LyCounter lyCounter; - PPUFrameBuf framebuf; - - unsigned char lcdc; - unsigned char scy; - unsigned char scx; - unsigned char wy; - unsigned char wy2; - unsigned char wx; - unsigned char winDrawState; - unsigned char wscx; - unsigned char winYPos; - unsigned char reg0; - unsigned char reg1; - unsigned char attrib; - unsigned char nattrib; - unsigned char xpos; - unsigned char endx; - - bool cgb; - bool cgbDmg; - bool weMaster; - - PPUPriv(NextM0Time &nextM0Time, unsigned char const *oamram, unsigned char const *vram); -}; - -class PPU { -public: - PPU(NextM0Time &nextM0Time, unsigned char const *oamram, unsigned char const *vram) - : p_(nextM0Time, oamram, vram) - { - } - - unsigned long * bgPalette() { return p_.bgPalette; } - bool cgb() const { return p_.cgb; } - bool cgbDmg() const { return p_.cgbDmg; } - void doLyCountEvent() { p_.lyCounter.doEvent(); } - unsigned long doSpriteMapEvent(unsigned long time) { return p_.spriteMapper.doEvent(time); } - PPUFrameBuf const & frameBuf() const { return p_.framebuf; } - - bool inactivePeriodAfterDisplayEnable(unsigned long cc) const { - return p_.spriteMapper.inactivePeriodAfterDisplayEnable(cc); - } - - unsigned long lastM0Time() const { return p_.lastM0Time; } - unsigned lcdc() const { return p_.lcdc; } - void loadState(SaveState const &state, unsigned char const *oamram); - LyCounter const & lyCounter() const { return p_.lyCounter; } - unsigned long now() const { return p_.now; } - void oamChange(unsigned long cc) { p_.spriteMapper.oamChange(cc); } - void oamChange(unsigned char const *oamram, unsigned long cc) { p_.spriteMapper.oamChange(oamram, cc); } - unsigned long predictedNextXposTime(unsigned xpos) const; - void reset(unsigned char const *oamram, unsigned char const *vram, bool cgb); - void setCgbDmg(bool enabled) { p_.cgbDmg = enabled; } - void resetCc(unsigned long oldCc, unsigned long newCc); - void setFrameBuf(uint_least32_t *buf, std::ptrdiff_t pitch) { p_.framebuf.setBuf(buf, pitch); } - void setLcdc(unsigned lcdc, unsigned long cc); - void setScx(unsigned scx) { p_.scx = scx; } - void setScy(unsigned scy) { p_.scy = scy; } - void setStatePtrs(SaveState &ss) { p_.spriteMapper.setStatePtrs(ss); } - void setWx(unsigned wx) { p_.wx = wx; } - void setWy(unsigned wy) { p_.wy = wy; } - void updateWy2() { p_.wy2 = p_.wy; } - void speedChange(); - unsigned long * spPalette() { return p_.spPalette; } - void update(unsigned long cc); - void setLayers(unsigned mask) { p_.layersMask = mask; } - -private: - PPUPriv p_; - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif diff --git a/libgambatte/src/video/sprite_mapper.cpp b/libgambatte/src/video/sprite_mapper.cpp deleted file mode 100644 index 2bc5cdcdb8..0000000000 --- a/libgambatte/src/video/sprite_mapper.cpp +++ /dev/null @@ -1,209 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#include "sprite_mapper.h" -#include "counterdef.h" -#include "next_m0_time.h" -#include "../insertion_sort.h" -#include - -using namespace gambatte; - -namespace { - -class SpxLess { -public: - explicit SpxLess(unsigned char const *spxlut) : spxlut_(spxlut) {} - - bool operator()(unsigned char lhs, unsigned char rhs) const { - return spxlut_[lhs] < spxlut_[rhs]; - } - -private: - unsigned char const *const spxlut_; -}; - -unsigned toPosCycles(unsigned long const cc, LyCounter const& lyCounter) { - unsigned lc = lyCounter.lineCycles(cc) + 1; - if (lc >= lcd_cycles_per_line) - lc -= lcd_cycles_per_line; - - return lc; -} - -} - -SpriteMapper::OamReader::OamReader(LyCounter const &lyCounter, unsigned char const *oamram) -: lyCounter_(lyCounter) -, oamram_(oamram) -, cgb_(false) -{ - reset(oamram, false); -} - -void SpriteMapper::OamReader::reset(unsigned char const* const oamram, bool const cgb) { - oamram_ = oamram; - cgb_ = cgb; - setLargeSpritesSrc(false); - lu_ = 0; - lastChange_ = 0xFF; - std::fill_n(lsbuf_, sizeof lsbuf_ / sizeof * lsbuf_, largeSpritesSrc_); - for (int i = 0; i < lcd_num_oam_entries; ++i) { - buf_[2 * i] = oamram[4 * i]; - buf_[2 * i + 1] = oamram[4 * i + 1]; - } -} - -void SpriteMapper::OamReader::update(unsigned long const cc) { - if (cc > lu_) { - if (changed()) { - unsigned const lulc = toPosCycles(lu_, lyCounter_); - unsigned pos = std::min(lulc, 2u * lcd_num_oam_entries); - unsigned distance = 2 * lcd_num_oam_entries; - - if ((cc - lu_) >> lyCounter_.isDoubleSpeed() < lcd_cycles_per_line) { - unsigned cclc = toPosCycles(cc, lyCounter_); - distance = std::min(cclc, 2u * lcd_num_oam_entries) - - pos + (cclc < lulc ? 2 * lcd_num_oam_entries : 0); - } - - { - unsigned targetDistance = - lastChange_ - pos + (lastChange_ <= pos ? 2 * lcd_num_oam_entries : 0); - if (targetDistance <= distance) { - distance = targetDistance; - lastChange_ = 0xFF; - } - } - - while (distance--) { - if (!(pos & 1)) { - if (pos == 2 * lcd_num_oam_entries) - pos = 0; - if (cgb_) - lsbuf_[pos / 2] = largeSpritesSrc_; - - buf_[pos] = oamram_[2 * pos]; - buf_[pos + 1] = oamram_[2 * pos + 1]; - } - else - lsbuf_[pos / 2] = (lsbuf_[pos / 2] & cgb_) | largeSpritesSrc_; - - ++pos; - } - } - - lu_ = cc; - } -} - -void SpriteMapper::OamReader::change(unsigned long cc) { - update(cc); - lastChange_ = std::min(toPosCycles(lu_, lyCounter_), 2u * lcd_num_oam_entries); -} - -void SpriteMapper::OamReader::setStatePtrs(SaveState& state) { - state.ppu.oamReaderBuf.set(buf_, sizeof buf_ / sizeof * buf_); - state.ppu.oamReaderSzbuf.set(lsbuf_, sizeof lsbuf_ / sizeof * lsbuf_); -} - -void SpriteMapper::OamReader::loadState(SaveState const& ss, unsigned char const* const oamram) { - oamram_ = oamram; - largeSpritesSrc_ = ss.mem.ioamhram.get()[0x140] >> 2 & 1; - lu_ = ss.ppu.enableDisplayM0Time; - change(lu_); -} - -SYNCFUNC(SpriteMapper::OamReader) -{ - NSS(buf_); - NSS(lsbuf_); - - NSS(lu_); - NSS(lastChange_); - NSS(largeSpritesSrc_); - NSS(cgb_); -} - -void SpriteMapper::OamReader::enableDisplay(unsigned long cc) { - std::fill_n(buf_, sizeof buf_ / sizeof * buf_, 0); - std::fill_n(lsbuf_, sizeof lsbuf_ / sizeof * lsbuf_, false); - lu_ = cc + (2 * lcd_num_oam_entries << lyCounter_.isDoubleSpeed()) + 1; - lastChange_ = 2 * lcd_num_oam_entries; -} - -SpriteMapper::SpriteMapper(NextM0Time &nextM0Time, - LyCounter const &lyCounter, - unsigned char const *oamram) -: nextM0Time_(nextM0Time) -, oamReader_(lyCounter, oamram) -{ - clearMap(); -} - -void SpriteMapper::reset(unsigned char const *oamram, bool cgb) { - oamReader_.reset(oamram, cgb); - clearMap(); -} - -void SpriteMapper::clearMap() { - std::fill_n(num_, sizeof num_ / sizeof * num_, 1 * need_sorting_flag); -} - -void SpriteMapper::mapSprites() { - clearMap(); - - for (int i = 0; i < lcd_num_oam_entries; ++i) { - int const spriteHeight = 8 + 8 * largeSprites(i); - unsigned const bottomPos = posbuf()[2 * i] - 17 + spriteHeight; - - if (bottomPos < lcd_vres - 1u + spriteHeight) { - int ly = std::max(static_cast(bottomPos) + 1 - spriteHeight, 0); - int const end = std::min(bottomPos, lcd_vres - 1u) + 1; - - do { - if (num_[ly] < need_sorting_flag + lcd_max_num_sprites_per_line) - spritemap_[ly][num_[ly]++ - need_sorting_flag] = 2 * i; - } while (++ly != end); - } - } - - nextM0Time_.invalidatePredictedNextM0Time(); -} - -void SpriteMapper::sortLine(unsigned const ly) const { - num_[ly] &= ~(1u * need_sorting_flag); - insertionSort(spritemap_[ly], spritemap_[ly] + num_[ly], - SpxLess(posbuf() + 1)); -} - -unsigned long SpriteMapper::doEvent(unsigned long const time) { - oamReader_.update(time); - mapSprites(); - return oamReader_.changed() - ? time + oamReader_.lineTime() - : static_cast(disabled_time); -} - -SYNCFUNC(SpriteMapper) -{ - NSS(spritemap_); - NSS(num_); - - SSS(oamReader_); -} diff --git a/libgambatte/src/video/sprite_mapper.h b/libgambatte/src/video/sprite_mapper.h deleted file mode 100644 index b474f7d864..0000000000 --- a/libgambatte/src/video/sprite_mapper.h +++ /dev/null @@ -1,125 +0,0 @@ -// -// Copyright (C) 2007 by sinamas -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2 as -// published by the Free Software Foundation. -// -// 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 version 2 for more details. -// -// You should have received a copy of the GNU General Public License -// version 2 along with this program; if not, write to the -// Free Software Foundation, Inc., -// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -// - -#ifndef SPRITE_MAPPER_H -#define SPRITE_MAPPER_H - -#include "ly_counter.h" -#include "../savestate.h" -#include "newstate.h" - -namespace gambatte { - -class NextM0Time; - -class SpriteMapper { -public: - SpriteMapper(NextM0Time &nextM0Time, - LyCounter const &lyCounter, - unsigned char const *oamram); - void reset(unsigned char const *oamram, bool cgb); - unsigned long doEvent(unsigned long time); - bool largeSprites(int spno) const { return oamReader_.largeSprites(spno); } - int numSprites(unsigned ly) const { return num_[ly] & ~(1u * need_sorting_flag); } - void oamChange(unsigned long cc) { oamReader_.change(cc); } - void oamChange(unsigned char const *oamram, unsigned long cc) { oamReader_.change(oamram, cc); } - unsigned char const * oamram() const { return oamReader_.oam(); } - unsigned char const * posbuf() const { return oamReader_.spritePosBuf(); } - - void resetCycleCounter(unsigned long oldCc, unsigned long newCc) { - oamReader_.update(oldCc); - oamReader_.resetCycleCounter(oldCc, newCc); - } - - void setLargeSpritesSource(bool src) { oamReader_.setLargeSpritesSrc(src); } - - unsigned char const* sprites(unsigned ly) const { - if (num_[ly] & need_sorting_flag) - sortLine(ly); - - return spritemap_[ly]; - } - - void setStatePtrs(SaveState &state) { oamReader_.setStatePtrs(state); } - void enableDisplay(unsigned long cc) { oamReader_.enableDisplay(cc); } - - void loadState(SaveState const &state, unsigned char const *oamram) { - oamReader_.loadState(state, oamram); - mapSprites(); - } - - bool inactivePeriodAfterDisplayEnable(unsigned long cc) const { - return oamReader_.inactivePeriodAfterDisplayEnable(cc); - } - - static unsigned long schedule(LyCounter const& lyCounter, unsigned long cc) { - return lyCounter.nextLineCycle(2 * lcd_num_oam_entries, cc); - } - -private: - class OamReader { - public: - OamReader(LyCounter const &lyCounter, unsigned char const *oamram); - void reset(unsigned char const *oamram, bool cgb); - void change(unsigned long cc); - void change(unsigned char const *oamram, unsigned long cc) { change(cc); oamram_ = oamram; } - bool changed() const { return lastChange_ != 0xFF; } - bool largeSprites(int spNo) const { return lsbuf_[spNo]; } - unsigned char const * oam() const { return oamram_; } - void resetCycleCounter(unsigned long oldCc, unsigned long newCc) { lu_ -= oldCc - newCc; } - void setLargeSpritesSrc(bool src) { largeSpritesSrc_ = src; } - void update(unsigned long cc); - unsigned char const * spritePosBuf() const { return buf_; } - void setStatePtrs(SaveState &state); - void enableDisplay(unsigned long cc); - void loadState(SaveState const &ss, unsigned char const *oamram); - bool inactivePeriodAfterDisplayEnable(unsigned long cc) const { return cc < lu_; } - unsigned lineTime() const { return lyCounter_.lineTime(); } - - private: - unsigned char buf_[2 * lcd_num_oam_entries]; - bool lsbuf_[lcd_num_oam_entries]; - LyCounter const &lyCounter_; - unsigned char const *oamram_; - unsigned long lu_; - unsigned char lastChange_; - bool largeSpritesSrc_; - bool cgb_; - - public: - templatevoid SyncState(NewState *ns); - }; - - enum { need_sorting_flag = 0x80 }; - - mutable unsigned char spritemap_[lcd_vres][lcd_max_num_sprites_per_line]; - mutable unsigned char num_[lcd_vres]; - NextM0Time &nextM0Time_; - OamReader oamReader_; - - void clearMap(); - void mapSprites(); - void sortLine(unsigned ly) const; - -public: - templatevoid SyncState(NewState *ns); -}; - -} - -#endif